Aller au contenu principal

Session 132duodecimus (suite 2) — Port floortile (decoder 16 tiles 64×64)

Port du dernier format binaire AB3D2 incompatible : INCLUDES/floortile, le
buffer compile contenant les 16 textures de sol que le moteur Amiga charge en
RAM et echantillonne au runtime.

Source de reference

Analyse du code de rendu floor dans hires.s (sources ASM AB3D2) :

 move.l  Draw_FloorTexturesPtr_l, a0    ; base = floortile en RAM
 adda.w  whichtile, a0                  ; whichtile = byte offset (WORD)
 ; ... boucle de scan ...
 move.b  (a0, d6.w*4), d3               ; d6 = T*256 + S, T,S in [0..63]

La cle est :
whichtile est un byte offset direct (WORD 16-bit) lu depuis le footer
du polygone. Pas un index de tile multiplie a la volee.
– L’instruction move.b (a0,d6.w*4),d3 impose un stride de 4 bytes entre
cols, identique au format newtexturemaps (vectobj).

Donc le fichier de 65536 bytes est structure comme newtexturemaps mais avec
une seule banque : 64 rows x 256 cols x 4 bytes/col = 65536 bytes. Les 16
tiles sont interleaved dans ce buffer via le couple (slot, col_group) :
slot (0..3) : index du byte au sein du groupe de 4
col_group (0..3) : decalage horizontal de col_group * 64 cols

Pour la tile N, whichtile = (N/4) * 256 + (N%4), et pour x,y in [0..63] :

 byte_offset = whichtile + y * 1024 + x * 4
 palette_idx = floortile[byte_offset] (unsigned byte)
 rgba        = palette256[palette_idx]

Verification : tile 15 (whichtile=771) au pixel (63,63) donne offset 65535,
soit la derniere case du buffer. Aucun debordement.

Format binaire (confirme par taille)

 INCLUDES/floortile : 65536 bytes = 64 KB
   = 16 tiles x 64 x 64 x 1 byte useful per pixel
   = 64 rows x 256 cols x 4 bytes/col (layout en memoire)

65536 bytes verifie sur disque dans original/INCLUDES/floortile.

Nouveau fichier : tools/convert/FloorTileDecoder.java

Classe utilitaire avec :
int whichtileFor(int tileIdx) : calcule le byte offset pour la tile N
BufferedImage renderTile(byte[], int[], int) : rend une tile en RGBA avec
index 0 traite comme transparent (cf. convention TextureMapConverter)
BufferedImage renderTileOpaque(byte[], int[], int) : version opaque pour
les sols (qui n’utilisent pas la transparence en pratique)
BufferedImage renderInterleavedAtlas(byte[], int[]) : atlas diagnostic
256×256 montrant les 4 slots empiles, pour valider visuellement le mapping
int decodeAllToPng(Path, int[], Path) : decode les 16 tiles vers
floor_01.png .. floor_16.png + atlas diagnostic

tools/convert/AssetConverter.java (modifie)

convertFloors() essaie maintenant en priorite le decodage de
INCLUDES/floortile (via FloorTileDecoder.decodeAllToPng). En cas d’absence
ou d’erreur, retombe sur l’ancien comportement (PNG IFF pre-extraits dans
floors/iff/). Si meme ca echoue, damier de fallback comme avant.

Nouveau helper prive findFloortile(Path root) cherche dans l’ordre :
1. <root>/INCLUDES/floortile (layout Amiga, majuscules)
2. <root>/includes/floortile (variante minuscules)
3. <root>/floortile (au cas ou copyResources l’a applati)

Le code legacy reste 100% intact pour les anciens setups.

Tests : FloorTileDecoderTest.java (15 tests)

Couvre :
whichtileFor : tile 0/1/3/4/7/15 + rejet hors plage
– borne haute : verification que tile 15 pixel (63,63) tombe a offset 65535 < 65536
renderTileOpaque : sampling correct du buffer (tile 0, 1, 4, 15) avec
buffer synthetique ou byte[i] = i & 0xFF
– mapping palette : verification byte -> palette[byte] -> pixel
renderTile : index 0 -> alpha 0 ; autres index -> alpha 0xFF
– validation : buffer trop court / null, palette trop petite
– atlas : taille 256×256, mapping slot S, row R -> y = S*64 + R

Question ouverte : ordre des tiles N -> (col_group, slot)

L’ordre exact dans lequel FLOORCONVERT (le programme d’origine) ecrit les
fichiers source FLOOR.1 .. FLOOR.16 parmi les 16 emplacements interleaved
n’est pas explicite dans la doc Amiga (HOW2ConvertFloorGraphics, etc). On a
adopte la convention la plus simple :

  • col_group = N / 4 : tiles 0-3 dans col_group 0, 4-7 dans col_group 1, etc.
  • slot = N % 4 : rotations dans les 4 slots du col_group

Si le rendu reel n’est pas conforme, les pixels eux-memes seront corrects
(la formule de sampling est rigoureusement celle de l’ASM), mais l’ordre des
PNG en sortie pourra etre permute. L’atlas diagnostic
floortile_atlas.png (4 slots empiles) permet de juger d’un coup d’oeil quel
ordre matche la realite, et on pourra renumeroter les sorties si besoin.

Limitations connues

  • Pas de gestion shade/luminosite : le rendu PNG actuel utilise la palette
    256 directe sans passer par la shade table (qui sert au rendu temps-reel
    pour la luminosite distance-based dans le moteur Amiga). Pour des PNG
    statiques c’est suffisant. Si on veut un rendu plus fidele a une luminosite
    donnee, il faudra ajouter floor256pal (= shade table 64×256) en parametre
    et appliquer palette[shadeTable[shade*256 + idx]].
  • Pas de support per-level override : le code ASM gere
    Draw_LevelFloorTexturesPtr_l pour des floortile per-niveau
    (levels/level_X/floortile). Pour l’instant on convertit uniquement le
    floortile global. Les tiles per-level pourront etre ajoutees a la pipeline
    niveau-par-niveau si besoin.

A verifier sur sortie reelle

./gradlew test                      # 15 nouveaux tests doivent passer
./gradlew convertAssets             # produit assets/Textures/floors/floor_01..16.png + floortile_atlas.png

Observer visuellement :
1. Les 16 PNG individuels doivent ressembler a des textures de sol coherentes
(pas de bruit, pas de damier).
2. L’atlas floortile_atlas.png (256×256, 4 slots empiles) doit montrer
4 bandes horizontales avec des motifs differents.
3. L’ordre de numerotation peut etre legerement different de l’ordre Amiga
d’origine (cf. « Question ouverte » ci-dessus). Si les motifs sont corrects
mais permutes, le decoder est OK ; il suffira de renommer.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *