PAL / ALP / LHT / SHD — палитры и таблицы поиска цветов
Источник: coreprime/kbot @ 0ab97bf · Редактировать на GitHub
Весь мир Total Annihilation нарисован в 256 цветах. Эту палитру хранит файл
.pal, а файлы.alp,.shdи.lht— построенные на её основе таблицы поиска, с помощью которых движок смешивает, затеняет и освещает пиксели, не выходя из пространства индексированных цветов.Ни у одного из четырёх нет заголовка, поля версии или сжатия. Файл
.palзанимает 1 024 байта (256 × RGBx),.alp— 65 536 байт (256 строк по 256 индексов палитры), а.shd/.lht— по 8 192 байта (32 строки по 256 индексов палитры).
palettes/palette.pal — отрисовка командой kbot pal swatch
Tip
Попробуйте сами.
kbot pal info palettes/palette.pal # one-liner
kbot pal describe palettes/palette.pal # full RGB dump
kbot pal swatch palettes/palette.pal -o pal.png --cell 24
# Render a lookup table, coloured by the palette:
# .alp as 256×256 cells, .shd / .lht as 256×32 cells
kbot pal lookup palettes/palette.alp --palette palettes/palette.pal --target alp.png
kbot pal lookup palettes/palette.shd --target shd.png
# TA: Kingdoms: the palette is usually a PCX next to its tables
kbot pal lookup palettes/aramon.alp --palette palettes/aramon.pcx --target aramon.png
# Round-trip to editor-friendly formats
kbot pal convert palettes/palette.pal -o palette.gpl # GIMP
kbot pal convert palettes/palette.pal -o palette.txt --format jasc # JASC
См. справку по kbot pal в описании командной строки.
Из Go. Используйте formats/pal:
import "github.com/coreprime/kbot/formats/pal"
p, _ := pal.LoadFromFile("palettes/palette.pal")
fmt.Printf("RGB[0] = %v (black; sprites key it per frame)\n", p.Colors[0])
for i, c := range p.Colors {
fmt.Printf("%3d #%02x%02x%02x\n", i, c.R, c.G, c.B)
}
Устройство на диске (.pal)
typedef struct {
uint8 R;
uint8 G;
uint8 B;
uint8 A; // Unused. Cavedog files have this as 0 throughout.
} PALEntry;
PALEntry entries[256]; // 256 × 4 = 1024 bytes
Ни сигнатуры, ни версии нет. Игра загружает palettes/<name>.pal так
(pal.LoadNamed из kbot-io делает то же самое, и через него студия и
обозреватель ресурсов загружают palette.pal для любой отрисовки TA:
набора тайлов, миникарт, рельефа в песочнице, объектов, текстур и цветов
моделей):
- 1 024 байта или больше: первые 1 024 байта — палитра, остальное игнорируется.
- Пустой или отсутствует: палитра берётся из
palettes/<name>.pcx— последние 768 байт этого файла, независимо от того, стоит ли перед ними маркер0x0C. Затем TA 3.1c заново строит таблицы.alp,.shdи.lhtдля этих цветов. - От 1 до 1 023 байт: непригоден; игра читает 1 024 байта, выходя за конец файла. kbot сообщает об ошибке (а студия переходит на встроенную палитру TA).
.pal — каноническая палитра TA
Байты R, G, B, A каждой записи буквально означают красный,
зелёный, синий, не используется. Индекс 0 — обычный чёрный.
Тайлы рельефа, миникарты и фоны рисуют его непрозрачным (62 из 275
оригинальных карт используют его в своих тайлах). Прозрачность решается
для каждого изображения отдельно, а не палитрой: прозрачны байт ключевого
цвета кадра GAF (часто 9, иногда 0) и его пропущенные пиксели, а
текстуры моделей выбираются без ключевого цвета.
| Индекс | Соглашение TA | Примечания |
|---|---|---|
0 |
Чёрный | Непрозрачен в рельефе, миникартах и фонах; прозрачен только в кадрах спрайтов с ключевым цветом 0. |
9 |
«Волшебный розовый» | Инструменты редактирования заливают им прозрачные области в PCX/GAF перед кодированием; во время игры не прозрачен. |
16–95 |
Циклы цветов игроков | Движок подменяет их для каждой стороны, чтобы перекрашивать юниты. |
223–254 |
Зарезервированы | В основном используются циклами командных цветов и спецэффектами. |
255 |
Чистый белый | Часто используется для сердцевины лазерных лучей. |
Note
256 троек RGB выбраны не случайно. Cavedog вручную настроила
палитру так, чтобы для каждого основного семейства материалов (металл,
органика, вода, небо, лава, …) были плавные градиенты. Если заменить
записи, чтобы добавить «новый» цвет, обычно ломается каждый юнит,
который брал цвета из этого градиента. Группы градиентов показывает
вывод pal describe.
.alp / .shd / .lht — таблицы поиска цветов
Эти три файла не содержат данных RGB: каждый байт — индекс палитры. В каждой таблице одна строка из 256 записей на каждого партнёра по смешиванию или уровень, а столбцы — это 256 исходных цветов:
| Файл | Размер | Строк | Запись [r][c] |
|---|---|---|---|
.alp (alpha) |
65 536 | 256 | Индекс, ближайший к среднему цветов r и c: смесь пополам, используется для полупрозрачной отрисовки. Таблица симметрична, и [c][c] равно c. |
.shd (shade) |
8 192 | 32 | Индекс, ближайший к цвету c, умноженному на r × 0.06875: строка 0 — чёрная, строки 14–15 почти не меняют цвета, более высокие строки делают их ярче. |
.lht (light) |
8 192 | 32 | Индекс, ближайший к цвету c, умноженному на 1 + r/30, — от неизменного (строка 0) до примерно вдвое более яркого. |
uint8 alp[256][256]; // blend = alp[a][b]
uint8 shd[32][256]; // shaded = shd[level][c]
uint8 lht[32][256]; // lit = lht[level][c]
На практике движок никогда не смешивает цвета арифметически — он выполняет поиск по таблице, поэтому итоговый пиксель — всегда настоящий индекс палитры, который можно нарисовать через существующий 8-битный конвейер. Вот почему все тени в TA выглядят как более тёмная версия того же градиента, а не как «50% чёрного поверх»: каждый затенённый результат — это индекс палитры, ближайший к математической смеси.
Игра использует файл таблицы, только если его размер точно совпадает;
отсутствующая таблица или таблица любого другого размера строится заново
из палитры. Поэтому kbot pal lookup отвергает файлы любого другого
размера. TA: Kingdoms поставляет таблицы тех же размеров почти для каждой
палитры в своей папке palettes/; большинство этих палитр — файлы PCX, и
kbot pal lookup --palette принимает как .pal, так и .pcx.
Important
Таблица поиска — это не палитра. Если отрисовать .alp через
kbot pal describe, вы увидите бессмысленные значения RGB, потому что
байты — не RGB. Чтобы увидеть, что таблица делает на самом деле,
используйте kbot pal lookup — передайте парный .pal, чтобы каждую
ячейку можно было окрасить в цвет записи палитры, на которую она
указывает.
Разбор примера — palette.pal
Первые 16 записей стандартной палитры TA:
| Инд. | Hex | R G B | Роль |
|---|---|---|---|
| 0 | #000000 |
0 0 0 | Чёрный (непрозрачен в рельефе; ключевой цвет некоторых кадров спрайтов) |
| 1 | #800000 |
128 0 0 | Тёмно-красный |
| 2 | #008000 |
0 128 0 | Тёмно-зелёный |
| 3 | #808000 |
128 128 0 | Оливковый |
| 4 | #000080 |
0 0 128 | Тёмно-синий (тень воды) |
| 5 | #800080 |
128 0 128 | Тёмно-пурпурный |
| 6 | #008080 |
0 128 128 | Тёмно-бирюзовый |
| 7 | #808080 |
128 128 128 | Средне-серый |
| 8 | #C0DCC0 |
192 220 192 | Бледно-зелёный |
| 9 | #5454FC |
84 84 252 | «Волшебный розовый» (прозрачность в редакторах) |
| 10–15 | #000000 × 6 |
0 0 0 | Зарезервированное заполнение |
kbot pal describe palettes/palette.pal выводит всю таблицу.
Разбор примера — palette.alp и palette.shd как таблицы поиска
Отрисовка таблиц с палитрой в качестве источника цветов
(kbot pal lookup … --cell 2):
palette.alp: 256 × 256 ячеек. Строка a, столбец b показывают смесь цветов a и b;
диагональ воспроизводит каждый цвет.
palette.shd: 256 × 32 ячейки. Каждый столбец — исходный цвет;
строки идут от чёрного (строка 0) через сам цвет к более ярким оттенкам.
Как читать таблицу оттенков: столбец 80 (средне-серый) начинается с
чёрного в строке 0, поднимается через более тёмные серые своего
градиента, примерно в строках 14 и 15 доходит до самого себя, а затем
светлеет. Движку никогда не нужно умножать значения RGB — он просто
читает shd[level][c].
Преобразование палитр для редакторов
kbot pal convert понимает несколько удобных для редакторов выходных
форматов:
| Формат | Расширение | Инструмент |
|---|---|---|
Двоичный .PAL TA |
.pal |
Сам формат; пригодится, чтобы записать файл заново после правок. |
| GIMP Palette | .gpl |
GIMP, Krita, Inkscape. |
| JASC-PAL (текст) | .pal / .txt (--format jasc) |
Paint Shop Pro, Aseprite. |
| Образцы в PNG | .png (через kbot pal swatch) |
Наглядная справка; как палитру не загрузить. |
Обратное направление — импорт .gpl или .pal (JASC) обратно в
двоичный .pal TA — работает, если в исходнике 256 записей.
Note
В палитре TA 13 повторяющихся троек RGB. Если ваш редактор при
импорте удаляет повторяющиеся цвета (некоторые так делают), записи
пропадут, и палитра незаметно превратится в палитру на 243 записи.
kbot pal info сообщает число повторов, чтобы разницу можно было
заметить; для проверки прогоните палитру туда и обратно через
kbot pal convert -o roundtrip.pal.
Подводные камни
Warning
Четвёртый байт записи — не альфа-канал. Это неиспользуемый байт
заполнения, который Cavedog всегда ставила в 0x00. Некоторые открытые
инструменты для палитр читают его как альфу и потом отказываются
отображать палитру (alpha=0 везде ⇒ всё прозрачно). kbot игнорирует
его при чтении и записывает 0x00.
- Индекс 0 сам по себе не прозрачен. Рельеф, миникарты и фоны рисуют его чёрным; кадр спрайта прозрачен только там, где это говорит его собственный ключевой цвет (или серия пропусков). Отрисовка рельефа и миникарт в kbot использует непрозрачную палитру.
- Без магических чисел проверка слабая. Единственный способ
убедиться в правдоподобности
.pal— потребовать не меньше 1024 байт и (по желанию) чтобы байт альфы был нулевым в каждой записи. - Таблицу поиска неправильного размера игра игнорирует и строит заново из палитры.
.alp/.lht/.shdне взаимозаменяемы. Они настроены на разные эффекты; если поменять их местами, тени или освещение будут заметно неправильными.- TA: Kingdoms использует палитры сторон, встроенные в PCX, а не
схему с глобальным
.pal. Приём с PCX-носителем описан в PCX.
Типичные размеры
| Файл | Размер | Примечания |
|---|---|---|
palette.pal |
1 024 байта | Из более длинного файла игра читает первые 1 024 байта. |
palette.alp |
65 536 байт | 256 × 256 индексов палитры. |
palette.shd / palette.lht |
8 192 байта | 32 × 256 индексов палитры. |
Экспорт GIMP .gpl |
~5 КБ | Текстовый формат, намного больше двоичного. |
Экспорт JASC .pal (текст) |
~3 КБ | То же. |
PNG из kbot pal swatch |
1–10 КБ | Зависит от размера --cell. |
| Всего файлов палитр в стандартной TA | ~15 файлов | Один канонический набор palette.* и несколько дополнительных палитр интерфейса. |