PAL / ALP / LHT / SHD: paletas y tablas de consulta de color
Fuente: coreprime/kbot @ 0ab97bf · Editar en GitHub
Total Annihilation distribuyó todo su mundo en 256 colores. El archivo
.palcontiene esa paleta; los archivos.alp,.shdy.lhtson tablas de consulta construidas a partir de ella que el motor usa para mezclar, sombrear e iluminar píxeles sin salir del espacio de color indexado.Ninguno de los cuatro tiene cabecera, campo de versión ni compresión. Un
.palocupa 1024 bytes (256 × RGBx); un.alp, 65 536 bytes (256 filas de 256 índices de la paleta), y.shd/.lht, 8192 bytes cada uno (32 filas de 256 índices de la paleta).
palettes/palette.pal, renderizada con kbot pal swatch
Tip
Pruébalo tú mismo.
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
Consulta la referencia de kbot pal de la CLI.
Desde Go. Usa 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)
}
Estructura en disco (.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
No hay firma ni versión. El juego carga palettes/<name>.pal así (el
pal.LoadNamed de kbot-io hace lo mismo, y el studio y el explorador de
recursos cargan palette.pal a través de él en todos los renderizados de
TA: pool de casillas, minimapas, terreno del sandbox, elementos, texturas
y colores de los modelos):
- 1024 bytes o más: los primeros 1024 bytes son la paleta; el resto se ignora.
- Vacío o ausente: la paleta se toma de
palettes/<name>.pcx: los últimos 768 bytes de ese archivo, vaya o no precedidos de una marca0x0C. Después, TA 3.1c reconstruye las tablas.alp,.shdy.lhtpara esos colores. - De 1 a 1023 bytes: no sirve; el juego lee 1024 bytes y se sale del final del archivo. kbot da un error (y el studio recurre a la paleta de TA integrada).
.pal: la paleta canónica de TA
Los bytes R, G, B, A de cada entrada significan literalmente
rojo, verde, azul, sin uso. El índice 0 es un negro normal.
Las casillas del terreno, los minimapas y los fondos lo dibujan opaco (62
de los 275 mapas de la versión comercial lo usan en sus casillas). La
transparencia se decide en cada imagen, no en la paleta: el byte clave de
un fotograma GAF (a menudo 9, a veces 0) y sus píxeles saltados son
transparentes, y las texturas de los modelos se muestrean sin color
clave.
| Índice | Convención de TA | Notas |
|---|---|---|
0 |
Negro | Opaco en el terreno, los minimapas y los fondos; transparente solo en los fotogramas de sprite cuyo color clave es 0. |
9 |
«Rosa mágico» | Las herramientas de edición lo usan como color de relleno de las zonas transparentes en PCX/GAF antes de codificar; no es transparente durante la partida. |
16–95 |
Ciclos de color de jugador | El motor los cambia según el bando para recolorear las unidades. |
223–254 |
Reservado | Los usan sobre todo los ciclos de color de equipo y los efectos especiales. |
255 |
Blanco puro | Se usa a menudo para el núcleo de los láseres. |
Note
Los 256 tripletes RGB no son arbitrarios. Cavedog ajustó la paleta
a mano para que hubiera rampas suaves en cada una de las grandes
familias de materiales (metal, orgánico, agua, cielo, lava, …).
Sustituir entradas para meter un color «nuevo» en un mod suele
estropear todas las unidades que tomaban colores de esa rampa. Consulta
la salida de pal describe para ver cómo se agrupan las rampas.
.alp / .shd / .lht: tablas de consulta de color
Estos tres archivos no son datos RGB: cada byte es un índice de la paleta. Cada tabla tiene una fila de 256 entradas por cada color con el que se mezcla o por cada nivel, y sus columnas son los 256 colores de origen:
| Archivo | Tamaño | Filas | Entrada [r][c] |
|---|---|---|---|
.alp (alfa) |
65 536 | 256 | El índice más cercano a la media de los colores r y c: una mezcla a partes iguales, que se usa para dibujar con translucidez. Es simétrica, y [c][c] es c. |
.shd (sombra) |
8192 | 32 | El índice más cercano al color c escalado por r × 0.06875: la fila 0 es negra, las filas 14–15 dejan los colores casi sin cambios y las filas superiores los aclaran. |
.lht (luz) |
8192 | 32 | El índice más cercano al color c escalado por 1 + r/30, desde sin cambios (fila 0) hasta aproximadamente el doble de brillante. |
uint8 alp[256][256]; // blend = alp[a][b]
uint8 shd[32][256]; // shaded = shd[level][c]
uint8 lht[32][256]; // lit = lht[level][c]
En la práctica: el motor nunca mezcla colores aritméticamente, sino que consulta una tabla, así que el píxel resultante es siempre un índice real de la paleta que se puede dibujar con el proceso de 8 bpp existente. Por eso todas las sombras de TA parecen una versión más oscura de la misma rampa de color, y no «negro al 50 % superpuesto»: cada resultado sombreado es el índice de la paleta más cercano a esa mezcla matemática.
El juego solo usa un archivo de tabla cuando su tamaño es exacto; una
tabla que falta o que tiene cualquier otro tamaño se reconstruye a partir
de la paleta. Por eso kbot pal lookup rechaza los archivos de cualquier
otro tamaño. TA: Kingdoms distribuye tablas de los mismos tamaños para
casi todas las paletas de su carpeta palettes/; la mayoría de esas
paletas son archivos PCX, y kbot pal lookup --palette acepta tanto un
.pcx como un .pal.
Important
Una tabla de consulta no es una paleta. Si renderizas un .alp con
kbot pal describe verás valores RGB sin sentido, porque los bytes no
son RGB. Usa kbot pal lookup para ver lo que hacen de verdad: pásale
el .pal que la acompaña para que cada celda de consulta se pueda
colorear con la entrada de la paleta a la que se resuelve.
Ejemplo desarrollado: palette.pal
Las 16 primeras entradas de la paleta original de TA:
| Índ. | Hex | R G B | Papel |
|---|---|---|---|
| 0 | #000000 |
0 0 0 | Negro (opaco en el terreno; el color clave de algunos fotogramas de sprite) |
| 1 | #800000 |
128 0 0 | Rojo oscuro |
| 2 | #008000 |
0 128 0 | Verde oscuro |
| 3 | #808000 |
128 128 0 | Oliva |
| 4 | #000080 |
0 0 128 | Azul oscuro (sombra del agua) |
| 5 | #800080 |
128 0 128 | Magenta oscuro |
| 6 | #008080 |
0 128 128 | Cian oscuro |
| 7 | #808080 |
128 128 128 | Gris medio |
| 8 | #C0DCC0 |
192 220 192 | Verde pálido |
| 9 | #5454FC |
84 84 252 | «Rosa mágico» (transparencia del editor) |
| 10–15 | #000000 × 6 |
0 0 0 | Relleno reservado |
kbot pal describe palettes/palette.pal imprime la tabla completa.
Ejemplo desarrollado: palette.alp y palette.shd como tablas de consulta
Las tablas renderizadas con la paleta como fuente de color
(kbot pal lookup … --cell 2):
palette.alp: 256 × 256 celdas. La fila a, columna b muestra la mezcla de los colores a y b;
la diagonal reproduce cada color.
palette.shd: 256 × 32 celdas. Cada columna es un color de origen;
las filas van del negro (fila 0), pasando por el propio color, hasta tonos más claros.
Cómo leer la tabla de sombras: la columna 80 (gris medio) empieza en
negro en la fila 0, sube por los grises más oscuros de su rampa, llega a
sí misma hacia las filas 14 y 15 y después se aclara. El motor nunca
necesita multiplicar valores RGB: solo lee shd[level][c].
Convertir paletas para los editores
kbot pal convert entiende varios formatos de salida cómodos para los
editores:
| Formato | Extensión | Herramienta |
|---|---|---|
.PAL binario de TA |
.pal |
El propio formato; útil para volver a generarlo tras editarlo. |
| GIMP Palette | .gpl |
GIMP, Krita, Inkscape. |
| JASC-PAL (texto) | .pal / .txt (--format jasc) |
Paint Shop Pro, Aseprite. |
| Muestrario PNG | .png (con kbot pal swatch) |
Referencia visual; no se puede cargar como paleta. |
La dirección contraria (importar un .gpl o un .pal JASC de vuelta a
un .pal binario de TA) funciona siempre que el origen tenga 256
entradas.
Note
La paleta de TA tiene 13 tripletes RGB duplicados. Si tu editor
elimina los colores duplicados al importar (algunos lo hacen),
perderás entradas y la paleta pasará sin avisar a tener 243 entradas.
kbot pal info indica cuántos duplicados hay para que puedas detectar
la diferencia; haz el viaje de ida y vuelta con
kbot pal convert -o roundtrip.pal para comprobarlo.
Escollos
Warning
El 4.º byte de cada entrada no es alfa. Es un byte de relleno sin
uso que Cavedog siempre ponía a 0x00. Varias herramientas de paletas
de código abierto lo leen como alfa y luego no consiguen renderizar la
paleta (alfa=0 en todas partes ⇒ todo transparente). kbot lo ignora al
leer y escribe 0x00 al generar.
- El índice 0 no es transparente por sí mismo. El terreno, los minimapas y los fondos lo dibujan negro; un fotograma de sprite solo es transparente donde lo indica su propio color clave (o un tramo de salto). Los renderizados de terreno y minimapa de kbot usan una paleta opaca.
- Sin números mágicos, la validación es débil. La única forma de
comprobar que un
.pales razonable es exigir al menos 1024 bytes y (opcionalmente) que el byte alfa sea cero en todas las entradas. - El juego ignora una tabla de consulta de tamaño incorrecto y la reconstruye a partir de la paleta.
.alp/.lht/.shdno son intercambiables. Están ajustadas para efectos distintos; si las intercambias, obtendrás sombras o iluminación visiblemente incorrectas.- TA: Kingdoms usa paletas por bando incrustadas en PCX, no el
sistema del
.palglobal. Consulta PCX para ver el truco del PCX portador.
Tamaños habituales
| Archivo | Tamaño | Notas |
|---|---|---|
palette.pal |
1024 bytes | De un archivo más largo, el juego lee los primeros 1024 bytes. |
palette.alp |
65 536 bytes | 256 × 256 índices de la paleta. |
palette.shd / palette.lht |
8192 bytes | 32 × 256 índices de la paleta. |
Exportación .gpl de GIMP |
~5 KB | Formato de texto, mucho más grande que el binario. |
Exportación .pal JASC (texto) |
~3 KB | Lo mismo. |
PNG de kbot pal swatch |
1–10 KB | Depende del tamaño de --cell. |
| Total de archivos de paleta en TA original | ~15 archivos | Un conjunto canónico palette.* más unas cuantas paletas alternativas de la interfaz. |