Symptome
Depuis la session 78 le passkey (et potentiellement d’autres vectobj a faces multiples) montrait des pixels d’autres modeles (mantis notamment) sur certaines faces en tournant autour. Le hack envisage en s132 (forcer Unshaded sans ColorMap) etait un contournement, pas un fix.
Diagnostic ASM (objdrawhires.s/drawpol l.2540-2559)
move.l #$3fffff,d1
...
and.l d1,d5 ; d5 = xbitpos & 0x3FFFFF
and.l d1,d6 ; d6 = ybitpos & 0x3FFFFF
move.l d6,d0
asr.l #8,d0 ; d0[15:8] = bits[21:16] de ybitpos = V mod 64
swap d5
move.b d5,d0 ; d0[7:0] = bits[21:16] de xbitpos = U mod 64
move.b (a0,d0.w*4),d3 ; sample byte
L’adresse byte echantillonnee est :
byte_addr = base + bank*65536 + texOffset + V*1024 + U*4
= base + bank*65536 + (rowStart + V)*1024
+ (colStart + U)*4 + slot
avec U = U_byte & 63 et V = V_byte & 63 (mask $3FFFFF).
Conclusion ASM : (colStart + U) n’est PAS modulo 64 ; il varie librement de 0 a 318 dans le strip 256 colonnes. (rowStart + V) peut aller jusqu’a 94 (cross-bank dans le bank suivant meme slot).
Cause racine (session 78)
Le code de la session 78 avait suppose a tort que chaque strip 256×64 etait subdivise en 4 sous-tiles 64×64 et faisait :
int colRaw = colIn64 + vtxU[v];
int colFinal = colRaw % 64; // <-- FAUX wrap dans la sous-tile
int pixelX = tileCol * 64 + colFinal;
Quand colStart % 64 + vtxU > 63, le polygone retombait au debut de SA tile (ex : colStart=50, vtxU=30 donnait col 16 au lieu de col 80). Si le pixel a col 16 etait visuellement different (ex : tile mantis voisine), la face affichait la mauvaise texture.
| colStart | vtxU | ASM (correct) | Java avant fix | Java apres fix |
|---|---|---|---|---|
| 50 | 30 | 80 | 16 ❌ | 80 ✓ |
| 80 | 50 | 130 | 66 ❌ | 130 ✓ |
| 80 | 20 | 100 | 100 ✓ | 100 ✓ |
Fix
VectObjConverter.readPolygons() : suppression de la subdivision artificielle 4 tiles x 64 cols et utilisation des coordonnees absolues du strip 256×64.
int xh = vtxU[v] & 63; // U byte mod 64 (mask $3FFFFF de l'ASM)
int yh = vtxV[v] & 63; // V byte mod 64
int colFinal = colStart + xh; // [0, 318]
int rowFinal = rowStart + yh; // [0, 94]
// Clamp pour les cas rares (atlas actuel ne supporte pas le cross-strip)
if (colFinal > 255) colFinal = 255;
if (rowFinal > 63) rowFinal = 63;
int pixelX = colFinal;
int pixelY = tileRow * 64 + rowFinal;
Limitations residuelles
Les deux cas suivants sont encore clampés plutôt que rendus correctement :
colFinal > 255: ASM continuerait sur la ligne suivante du meme bank/slot. Rare en pratique (polygones avec colStart eleve ET grande sweep U). Clamp a 255.rowFinal > 63: ASM continuerait dans le bank suivant meme slot. L’atlas actuel(bank*4+slot)*64ne place pas bank1/slot0 apres bank0/slot0 (il place bank0/slot1). Clamp a 63 en attendant une eventuelle restructuration de l’atlas vers le layout par-slot (bank0,bank1,bank0,bank1,…).
Procedure de validation
gradle convertVectobjs # regenerer les .j3o avec les UVs corriges
gradle run # passkey doit montrer une texture coherente
A verifier visuellement :
– Passkey : faces toutes coherentes (or/jaune), plus de pixels mantis
– Crab, mantis, autres aliens : aspect inchange (cas avec colStart % 64 + vtxU <= 63 etaient deja corrects)
– Armes, generateurs : meme verification
Fichiers modifies
VectObjConverter.java: suppression detileCol/colIn64/rowIn64, remplacement parcolStart/rowStartdirects.