Contexte
Les stats de la phase A revision 3 ont confirme qu’au moins 50% des effets
de lumiere visuels des niveaux principaux (A=48%, B=50%, E=60%, M=57%, etc.)
viennent des animations Amiga {@code BrightPulse1..5} et
{@code BrightFlicker1..2}. Sans phase B, ces effets restent figes a la valeur
de phase=0 (souvent {@code Lb=0}, donc invisibles).
L’utilisateur a confirme : sols-verre qui devraient pulser, lampes qui
devraient clignoter, halos d’eclairage des couloirs – tout etait fige.
Mecanisme reproduit
Dans l’ASM, la routine {@code brightanim} (newanims.s:690) avance d’une frame
dans chaque pattern toutes les 5 frames Amiga (= ~100ms a 50 Hz). Pour chaque
sommet anime ({@code highByte != 0}) la luminosite courante est obtenue par
interpolation lineaire entre {@code Lb_static} (low byte) et la valeur du
pattern courant, ponderee par {@code phase} (4 bits du high byte) :
Lb_dyn = Lb_static + ((animValue[animIdx-1] - Lb_static) * phase) >> 4
Puis le mapping ASM-fidele de la phase A est applique :
– {@code Rb_point = (Lb_dyn * 397) >> 8 +/- 300}
– {@code wallBright = abs(Rb_point) + Wb}
– {@code intensity = clamp((wallBright – WB_MIN) / (WB_MAX – WB_MIN), MIN, 1)}
Modifications
world/BrightnessCalc.java
– Ajout des 7 patterns hardcodes dans ANIM_PATTERNS[][] portes directement
de newanims.s lignes 58-98 :
– BrightPulse1..5 : 40 valeurs chacun (montee 1->20, descente 20->1, avec
differents points de depart)
– BrightFlicker1 : 58 valeurs (lampe avec coupures breves : 20-1-20-1-20-1)
– BrightFlicker2 : 36 valeurs negatives -5..-10 (effet flamme/sombre)
– Ajout de computeLbDynamic(rawWord, tickCounter) : interpolation ASM-fidele
– Ajout de computePointRbDynamic(rawWord, tickCounter) : Rb avec animation
– Ajout de isAnimated(rawWord) : detection rapide d’un sommet anime
tools/LevelSceneBuilder.java
– Payload des walls etendu de 11 → 14 floats : ajout de
[leftRawWord, rightRawWord, wbZone] pour permettre au runtime de
re-calculer l’intensite chaque tick.
– buildWallGeo() collecte une liste compacte d’animation entries
(vertexBufferIdx, rawWord, wbZone) au format CSV et la stocke en UserData
"animEntries" de la geometry. Pour chaque sub-quad anime :
– Si leftRaw est anime : entries pour BL et TL (= sommets gauche)
– Si rightRaw est anime : entries pour BR et TR (= sommets droit)
– Marque le buffer Color des meshes animes en Usage.Stream pour autoriser
les updates GPU.
world/AnimBrightnessSystem.java (NOUVEAU – 158 lignes)
– AppState qui scanne le levelScene au attach pour collecter tous les meshes
animes (= avec UserData "animEntries").
– Maintient un compteur global de ticks qui avance toutes les TICK_INTERVAL_SEC
(= 100ms, calibre sur l’ASM DOALLANIMS::thistime).
– Chaque update, si tick a avance, recalcule les vertex colors de chaque
sommet anime (pas les autres) et flagge le buffer Color comme dirty.
– Methode setAnimationEnabled(boolean) pour reproduire le toggle ASM
Anim_LightingEnabled_b.
app/GameAppState.java
– Ajout du champ animBrightnessSystem.
– Attache le systeme apres chargement du levelScene + scan recursif depuis
le node "geometry".
– Detache proprement dans cleanup().
Resultats attendus
- Sols-verre pulsants dans level A zone 3 et autres : animation continue
qui inonde la zone de lumiere (pattern BrightPulse3 typique). - Lampes qui clignotent : pattern BrightFlicker1 (longues phases ON
entrecoupees de coupures breves). - Effets de flamme : pattern BrightFlicker2 (assombrissement aleatoire).
- Niveau I (0% anime) reste statique comme prevu, levels D/K (peu eclaires)
conservent leur ambiance sombre, levels A/B/E/M voient ~50% de leurs murs
s’animer.
Limitations restantes
- Sols/plafonds : le
zone.brightnesspeut aussi avoir une animation
(high byte != 0) mais ce n’est pas encore implemente. Pour l’instant on
anime uniquement les murs (la majorite des effets visuels). Si necessaire,
une session future pourra etendreAnimBrightnessSystemaux poly
horizontaux. - Halos dynamiques (explosions, tirs) : phase D, plus tard.
- Performance : pour les niveaux a 1000+ entries animees (level M=966),
on a 1 update toutes les 100ms = 10 Hz. La boucle de mise a jour est
simple (juste 3 floats par entry) donc ca devrait passer sans souci, mais
a surveiller sur des hardware modestes.