Aller au contenu principal

Session 62 — VectObj : textures atlas + UV par vertex

Objectif

Remplacer les vertex-colors aplaties (flat shading derive du texOffset) par de
vraies textures. Les armes, monstres et decors affichent desormais les pixels
d’origine issus de newtexturemaps.

Decouverte du format texture (analyse ASM drawpol l.2546-2559)

drawpol:
    move.l  d6, d0
    asr.l   #8, d0           ; d0 = (d6 >> 8) = 14 bits U_int
    swap    d5
    move.b  d5, d0           ; low byte de d0 = V_int (byte @ +3)
    move.b  (a0, d0.w*4), d3 ; sample texel byte

Le d0 final = (U_int << 8) | V_int, puis d0 * 4 donne le byte offset final.
Ce *4 revele un layout interleaved 4-chunky :
– adjacent en V = +4 bytes
– adjacent en U (dans le meme bloc de 4 colonnes) = +1 byte
– bloc de 4 colonnes interleaved = 256 bytes (64 pixels * 4 bytes)

Layout newtexturemaps (128 KB = 2 banques * 64 KB)

byte layout d'une banque (65536 bytes) :
  block 0 (bytes 0..255)  : 4 colonnes interleaved
    byte[0]   byte[1]   byte[2]   byte[3]     <- row 0, col 0,1,2,3
    byte[4]   byte[5]   byte[6]   byte[7]     <- row 1, col 0,1,2,3
    ...                                      (64 rows, 256 bytes)
  block 1 (bytes 256..511) : 4 colonnes suivantes (4..7)
  ...
  block 255 (bytes 65280..65535) : colonnes 1020..1023

Une banque = 256 blocs * 256 bytes = 65536 = 1024 colonnes de 64 pixels.
Les textures sont des strips verticaux de 64 pixels comme les murs du jeu.

Modifications TextureMapConverter

  • Layout interleaved 4-chunky implemente dans la generation des PNG
  • Nouvelle sortie texturemaps_atlas.png (1024×128) = bank0 + bank1 empiles
  • Nouvelles methodes publiques texOffsetToColumn() et texOffsetToBank()
  • sampleColor() mis a jour pour le nouveau layout

Modifications VectObjConverter

  • Record Triangle etendu : positions + UV par vertex + couleur shade
  • readPolygons() genere les UV atlas pour chaque vertex :
    java
    int baseCol = TextureMapConverter.texOffsetToColumn(rawTexOffset);
    int baseRow = TextureMapConverter.texOffsetToBank(rawTexOffset) * 64;
    float uCol = (baseCol + vtxU[v]) / 1024f;
    float vRow = (baseRow + vtxV[v]) / 128f;
  • buildGeometry() emet maintenant Type.TexCoord en plus de Position/Normal/Color
  • buildMaterial() charge Textures/vectobj/texturemaps_atlas.png en ColorMap
    avec NearestNoMipMaps + MagFilter.Nearest pour le look retro pixel-art

Configuration materiau

Unshaded.j3md :
  ColorMap    = texturemaps_atlas.png (nearest filtering)
  VertexColor = true  (module par brightness par-poly)
  FaceCullMode.Off    (front+back visible)
  WrapMode.Repeat     (permet U > 1 pour tiling)

Le pixel final = texture * vertex_color, donc le brightness par poly module
correctement la texture (eclairage directionnel preserve).

Fallback propre

Si texturemaps_atlas.png n’existe pas encore (premier run avant
./gradlew convertTextureMaps), buildMaterial() tombe sur vertex-color seul
avec un WARN dans les logs – le comportement session 58-61 reste fonctionnel.

Pipeline

./gradlew convertTextureMaps   # genere les PNG atlas
./gradlew convertVectObj       # puis regenere les .j3o avec UVs + texture

Known limitation

La correspondance exacte byte U,V du vertex → pixel dans l’atlas est une
premiere approximation : on traite U et V comme des pixels directs dans une
region 64×64 ancree a la colonne du texOffset. L’ASM fait une indexation plus
complexe (fixed-point 16.16 avec mask 0x3FFFFF) dont l’equivalence exacte en
UV normalisees demandera peut-etre un ajustement dans une future session si
certaines textures apparaissent decalees ou mal echelonnees.

Laisser un commentaire

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