PAL / ALP / LHT / SHD — パレットと色のルックアップテーブル
Total Annihilationは、その世界のすべてを256色で描いていました。
.palファイルはそのパレットを格納し、.alp、.shd、.lhtの各ファイルは、そこから作られたルックアップテーブルです。エンジンはこれらを使い、インデックスカラーの色空間から出ることなく、ピクセルの混色、陰影付け、明るさの調整を行います。4つのどれにも、ヘッダー、バージョンのフィールド、圧縮はありません。
.palは1,024バイト(256 × RGBx)、.alpは65,536バイト(256個のパレットインデックスが256行)、.shd/.lhtはそれぞれ8,192バイト(256個のパレットインデックスが32行)です。
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
CLIの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を次のように読み込みます(kbot-ioのpal.LoadNamedも同じ処理を行い、スタジオとアセットエクスプローラーは、TAのあらゆる描画でこれを通じてpalette.palを読み込みます。タイルプール、ミニマップ、サンドボックスの地形、地形物、テクスチャ、モデルの色がその対象です)。
- 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はごく普通の黒です。地形のタイル、ミニマップ、背景はこれを不透明で描きます(製品版の275のマップのうち62がタイルにこれを使っています)。透過はパレットではなく画像ごとに決まります。GAFのフレームのキーのバイト(多くは9、ときに0)とスキップされたピクセルが透過になり、モデルのテクスチャはキーなしでサンプリングされます。
| インデックス | TAでの慣習 | 備考 |
|---|---|---|
0 |
黒 | 地形、ミニマップ、背景では不透明。キーが0のスプライトのフレームでだけ透過。 |
9 |
「マジックピンク」 | エディター系のツールが、エンコード前のPCX/GAFで透過にする領域の塗りつぶし色として使う。実行時には透過にならない。 |
16–95 |
プレイヤーカラーの循環 | エンジンが陣営ごとにこれを入れ替えて、ユニットの色を変える。 |
223–254 |
予約 | 主にチームカラーの循環と特殊効果に使われる。 |
255 |
純白 | レーザーの芯によく使われる。 |
Note
256個のRGBの3つ組は、適当に決められたものではありません。Cavedogはパレットを手作業で調整し、主な素材の系統(金属、有機物、水、空、溶岩など)ごとになめらかなグラデーションが得られるようにしています。「新しい」色を入れるためにエントリを置き換えると、たいていはそのグラデーションを使って描かれていたユニットがすべて崩れます。グラデーションのまとまりについてはpal describeの出力を参照してください。
.alp / .shd / .lht — 色のルックアップテーブル
この3つのファイルはRGBのデータではありません。どのバイトもパレットインデックスです。各テーブルは、混色の相手または段階ごとに256エントリの行を1つ持ち、列は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)から、約2倍の明るさまで。 |
uint8 alp[256][256]; // blend = alp[a][b]
uint8 shd[32][256]; // shaded = shd[level][c]
uint8 lht[32][256]; // lit = lht[level][c]
実際のところ、エンジンは色を算術的に混ぜることは一切なく、テーブルを引くだけです。そのため、得られるピクセルは常に実在するパレットインデックスで、既存の8bppの描画パイプラインでそのまま描けます。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
標準のTAパレットの最初の16エントリ:
| インデックス | 16進 | 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は、エディターで扱いやすいいくつかの出力形式に対応しています。
| 形式 | 拡張子 | ツール |
|---|---|---|
バイナリのTA .PAL |
.pal |
この形式そのもの。編集後に書き出し直すときに便利。 |
| GIMPパレット | .gpl |
GIMP、Krita、Inkscape。 |
| JASC-PAL(テキスト) | .pal / .txt(--format jasc) |
Paint Shop Pro、Aseprite。 |
| PNGの色見本 | .png(kbot pal swatchで出力) |
目で見るための参考。パレットとしては読み込めない。 |
逆方向、つまり.gplや.pal(JASC)をバイナリのTA .palに読み込み直す変換も、元のファイルに256エントリあれば機能します。
Note
TAのパレットには、重複したRGBの3つ組が13個あります。エディターが読み込み時に色の重複を除くと(そうするものもあります)、エントリが失われ、パレットは知らないうちに243エントリのパレットになってしまいます。kbot pal infoは重複の数を報告するので、違いに気づくことができます。確認するにはkbot pal convert -o roundtrip.palでラウンドトリップしてください。
注意点
Warning
各エントリの4バイト目はアルファではありません。Cavedogが常に0x00にしていた、使われない埋め草のバイトです。オープンソースのパレットツールのいくつかはこれをアルファとして読み、パレットを描画できなくなります(どこでもalpha=0 ⇒ すべて透過)。kbotは読み込み時にこれを無視し、書き出し時には0x00を出力します。
- インデックス0は、それだけでは透過になりません。地形、ミニマップ、背景はこれを黒として描きます。スプライトのフレームが透過になるのは、そのフレーム自身のキー(またはスキップのラン)が指定する場所だけです。kbotの地形とミニマップの描画では、不透明のパレットを使います。
- マジックナンバーがないので、検証は弱くなります。
.palの妥当性を確かめる方法は、少なくとも1024バイトあることと、(任意で)すべてのエントリでアルファのバイトが0であることを求めることくらいです。 - サイズの違うルックアップテーブルはゲームに無視され、パレットから作り直されます。
.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 KB | テキスト形式で、バイナリよりずっと大きい。 |
JASCの.pal(テキスト)への書き出し |
約3 KB | 同上。 |
kbot pal swatchのPNG |
1–10 KB | --cellのサイズによる。 |
| 標準のTAに含まれるパレットファイルの合計 | 約15ファイル | 正規のpalette.*一式と、UI用の別パレットがいくつか。 |