====== field -section9- : backgrounds ====== ===== Organisation générale de la section ===== La section 9 est divisée en trois : * L'en-tête * Les Zones Sprites (2 ou 4 zones) * Les données brutes de l'image Les textes colorés sont les truc importants ou les truc explicités plus bas dans la page ^Position^Taille^Description^^ ^Header^^^^ ^0|2 octets^0^| ^2|2 octets|1 (utilise des palettes) ou 2 (n'utilise pas de palettes)^| ^4|1 octet^1 (activé, si 0 le jeu ne lit pas la suite)^| ^5|7 octets^PALETTE|| ^12|20 octets|Activité des premiers pixels des palettes -**actPixPal**-^| ^32|4 octets^0|| ^36|4 octets^BACK|| ^[[#sprites_infos_zone_1|Zone Sprites 1]]^^^^ ^40|2 octets|Pseudo-Largeur^| ^42|2 octets|Pseudo-Hauteur^| ^44|2 octets|**Nombre de sprites Infos 1**^| ^46|2 octets|Si =1 : utilise des palettes, Si =2 : utilise les couleurs directement^| ^48|2 octets^0^| ^50|**nbSprites1** * 52|**Sprites Infos 1**^| ^50 + NbSprite1 * 52|2 octets^0|| ^52 + NbSprite1 * 52|1 octet^Si =0 La zone 2 n'existe pas.|| ^[[#sprites_infos_zone_2|Zone Sprites 2]]^^^^ ^53 + NbSprite1 * 52|2 octets|Pseudo-Largeur^640| ^55 + NbSprite1 * 52|2 octets|Pseudo-Hauteur^480| ^57 + NbSprite1 * 52|2 octets|**Nombre de sprites Infos 2**^| ^59 + NbSprite1 * 52|16 octets|??? ([[:ff7:technique:field:bg:plus|en savoir plus...]])^| ^75 + NbSprite1 * 52|2 octets^0|| ^77 + NbSprite1 * 52|**nbSprites2** * 52|**Sprites Infos 2**^| ^77 + 52 (NbSprite1 + NbSprite2)|2 octets^0|| ^79 + 52 (NbSprite1 + NbSprite2)|1 octet^Si =0 La zone 3 n'existe pas.|| ^[[#sprites_infos_zone_3|Zone Sprites 3]]^^^^ ^80 + 52 (NbSprite1 + NbSprite2)|2 octets|Pseudo-Largeur^640| ^82 + 52 (NbSprite1 + NbSprite2)|2 octets|Pseudo-Hauteur^480| ^84 + 52 (NbSprite1 + NbSprite2)|2 octets|**Nombre de sprites Infos 3**^| ^86 + 52 (NbSprite1 + NbSprite2)|12 octets^0^| ^98 + 52 (NbSprite1 + NbSprite2)|**nbSprites3** * 52|**Sprites Infos 3**^| ^98 + 52 (NbSprite1 + NbSprite2 + NbSprite3)|2 octets^0|| ^100 + 52 (NbSprite1 + NbSprite2 + NbSprite3)|1 octet^Si =0 La zone 4 n'existe pas.|| ^[[#sprites_infos_zone_4|Zone Sprites 4]]^^^^ ^101 + 52 (NbSprite1 + NbSprite2 + NbSprite3)|2 octets|Pseudo-Largeur^640| ^103 + 52 (NbSprite1 + NbSprite2 + NbSprite3)|2 octets|Pseudo-Hauteur^480| ^105 + 52 (NbSprite1 + NbSprite2 + NbSprite3)|2 octets|**Nombre de sprites Infos 4**^| ^107 + 52 (NbSprite1 + NbSprite2 + NbSprite3)|2 octets^0^| ^109 + 52 (NbSprite1 + NbSprite2 + NbSprite3)|8 octets|??? ([[:ff7:technique:field:bg:plus|en savoir plus...]])^| ^117 + 52 (NbSprite1 + NbSprite2 + NbSprite3)|2 octets^0^| ^119 + 52 (NbSprite1 + NbSprite2 + NbSprite3)|**nbSprites4** * 52|**Sprites Infos 4**^| ^119 + 52 (NbSprite1 + NbSprite2 + NbSprite3 + NbSprite4)|2 octets^0|| ^[[#les_donnees_de_l_image|Données]]^^^^ ^121 + 52 (NbSprite1 + NbSprite2 + NbSprite3 + NbSprite4)|7 octets^TEXTURE|| ^128 + 52 (NbSprite1 + NbSprite2 + NbSprite3 + NbSprite4)|nb de pages * 65 540 + 84|**[[#les_donnees_de_l_image|Données de l'image]]**^| ^212 + 52 (NbSprite1 + NbSprite2 + NbSprite3 + NbSprite4) + nb de pages * 65 540|3 octets^END^^ ===== Sprite Data : organisation ===== Dans chaque zone, Il y a **nbSprites** sprites Infos de 52 octets. Un Sprite Infos fait donc 52 octets, il commence et finit toujours par 2 octets nuls. Un sprite info donne tout ce qu'il faut pour construire un sprite de 16*16 pixels (ou 32*32 pixels) et pour le placer dans l'image finale. Voila comment est fait un sprite Infos (en fonction de la zone) : ==== Sprites Infos zone 1 ==== ^0|2 octets^0|| ^2|2 octets|**Position cible X**|| ^4|2 octets|**Position cible Y**|| ^6|2 octets|//Inutilisé//|| ^8|2 octets|//Inutilisé//|| ^10|2 octets|**Position source X**|| ^12|2 octets|**Position source Y**|| ^14|2 octets|//Inutilisé//|| ^16|2 octets|//Inutilisé//|| ^18|2 octets|//Inutilisé// (largeur tile : 16 ou 0)|| ^20|2 octets|//Inutilisé// (hauteur tile : 16 ou 0)|| ^22|2 octets|**Numéro palette**^Commence à la palette n°0| ^24|2 octets|**Id**^4095| ^26|1 octet|//Inutilisé//|| ^27|1 octet|//Inutilisé//|| ^28|1 octet^0|| ^29|1 octet^0|| ^30|2 octets^0|| ^32|2 octets|**Page**^| ^34|2 octets|//Inutilisé//|| ^36|2 octets|Octets par couleur^0 (peu de couleurs), 1 (palettes) ou 2 (sans palettes)| ^38|4 octets|//Inutilisé//|| ^42|4 octets|Coordonnée X texture^| ^46|4 octets|Coordonnée Y texture^| ^50|2 octets^0|| ==== Sprites Infos zone 2 ==== ^0|2 octets^0|| ^2|2 octets|**Position cible X**|| ^4|2 octets|**Position cible Y**|| ^6|2 octets|//Inutilisé//|| ^8|2 octets|//Inutilisé//|| ^10|2 octets|**Position source X**|| ^12|2 octets|**Position source Y**|| ^14|2 octets|**Position source X (2)** (pour les effectPages)|| ^16|2 octets|**Position source Y (2)** (pour les effectPages)|| ^18|2 octets|Largeur bloc^16| ^20|2 octets|Hauteur bloc^16| ^22|2 octets|**Numéro palette**^Commence à la palette n°0| ^24|2 octets|**Id**^| ^26|1 octet|**Paramètre**^| ^27|1 octet|**État**^| ^28|1 octet|Transparence par addition^Booléen| ^29|1 octet|Transparence par addition ?^Booléen| ^30|2 octets|Transparence par addition ?^0, 1, 2 ou 3| ^32|2 octets|**Page**^| ^34|2 octets|**EffectPage**^| ^36|2 octets|Octets par couleur^0 (peu de couleurs), 1 (palettes) ou 2 (sans palettes)| ^38|4 octets|Coordonnée Z^| ^42|4 octets|Coordonnée X texture^| ^46|4 octets|Coordonnée Y texture^| ^50|2 octets^0|| ==== Sprites Infos zone 3 ==== ^0|2 octets^0|| ^2|2 octets|**Position cible X**|| ^4|2 octets|**Position cible Y**|| ^6|2 octets^0|| ^8|2 octets^0|| ^10|2 octets|**Position source X**^| ^12|2 octets|**Position source Y**^| ^14|2 octets|**Position source X (2)** (pour les effectPages)^| ^16|2 octets|**Position source Y (2)** (pour les effectPages)^| ^18|2 octets|Largeur bloc^32| ^20|2 octets|Hauteur bloc^32| ^22|2 octets|**Numéro palette**^Commence à la palette n°0| ^24|2 octets|**Id**^4096| ^26|1 octet|**Paramètre**^| ^27|1 octet|**État**^| ^28|1 octet|Transparence par addition^Booléen| ^29|1 octet|Transparence par addition ?^Booléen| ^30|2 octets|Transparence par addition ?^0 ou 1| ^32|2 octets|**Page**^| ^34|2 octets|**effectPage**^| ^36|2 octets|Type de palette^0 (peu de couleurs) ou 1 (palette normale) ou 2 (sans palettes)| ^38|4 octets^0|| ^42|4 octets|Coordonnée X texture^| ^46|4 octets|Coordonnée Y texture^| ^50|2 octets^0|| ==== Sprites Infos zone 4 ==== ^0|2 octets^0|| ^2|2 octets|**Position cible X**|| ^4|2 octets|**Position cible Y**|| ^6|2 octets^0|| ^8|2 octets^0|| ^10|2 octets|**Position source X**^| ^12|2 octets|**Position source Y**^| ^14|2 octets|**Position source X (2)** (pour les effectPages)^| ^16|2 octets|**Position source Y (2)** (pour les effectPages)^| ^18|2 octets|Largeur bloc^32| ^20|2 octets|Hauteur bloc^32| ^22|2 octets|**Numéro palette**^Commence à la palette n°0| ^24|2 octets|**Id**^0| ^26|1 octet|**Paramètre**^| ^27|1 octet|**État**^| ^28|1 octet|Transparence par addition^Booléen| ^29|1 octet|Transparence par addition ?^Booléen| ^30|2 octets|Transparence par addition ?^0, 1 ou 3| ^32|2 octets|**Page**^| ^34|2 octets|**effectPage**^| ^36|2 octets|Type de palette^0 (peu de couleurs) ou 1 (palette normale)| ^38|4 octets|Coordonnée Z^0 ou 999| ^42|4 octets|Coordonnée X texture^| ^46|4 octets|Coordonnée Y texture^| ^50|2 octets^0|| ==== Paramètres ==== Dans la deuxième et troisième zone, il y a les deux octets que j'appelle "paramètre" et "états". Ceux-ci permettent de donner un numéro à un petit bout de l'image qui sera sous plusieurs états différents. Sur Final Fantasy VII, le plus grand numéro de paramètre observé est 51, on peut aller en théorie jusqu'au numéro 256 (soit 255 paramètres). == États == Les états sont rangés dans un octet où chaque bit correspond à un état (il y a donc 8 états). Si un bit est à 1, l'état correspondant existe. Par exemple si l'octet des états est à 00000010, l'état 2 est activé. Parfois les numéros de certains paramètres ne se suivent pas. ===== Les données de l'image ===== [{{ :ff7:technique:field:page1.jpg|Voila la première page du fichier anfrst_1 affichée en brut, et je me suis servi de la première palette.}}] Elles sont toujours précédées par le mot-clé "TEXTURE". Les données de l'image sont séparées en 42 **pages**. Si le premier mot de la page est différent de zéro, c'est qu'il y a des données dans la page, dans le cas contraire la page ne fait que deux octets de longueur. === Shéma d'une page : === ^Position^Taille^Description^| ^0|2 octets^Si =0, il n'y a pas de page.|| ^Header^^^^ ^2|2 octets^**0** (sprites 16*16) ou **1** (sprites 32*32)|| ^4|2 octets|coulPix^Si =**1** : un octet = un pixel (utilisation d'une palette) ;\\ Si =**2** : deux octets = un pixel| ^Données de la page^^^^ ^6|65536 * coulPix|Données de la page^| Si vous voulez afficher directement ces pages, vous devez afficher des images de 256*256 pixels (utilisez les [[pal|palettes]]). Comme dans l'illustration, vous verrez des lignes de 16 pixels de hauteur. Je vous conseille vivement de collecter tous les points de départ des pages dans un tableau bien rangé, par exemple : [0] => 0 [1] => 65542 [15] => 131110 Par la suite je vais appeler ce tableau "$pages". === Groupement des pages (supposition) === * 0 -> 14 : * 15 -> 23 : ~effectPages * 24 -> 26 : * 27 -> 28 : pages sans palettes * 29 -> 84 : inused ===== Construction d'une image ===== ==== Avant la construction : collecter les informations ==== Pour correctement construire l'image, nous avons besoins des **véritables dimensions**, et de la **liste des premiers états de chaque paramètre**. Pour cela nous allons parcourir toutes les zones Sprites Infos, et à chaque Sprite Info récupérer les position cibles. Je vous laisse comprendre mon code (qui est en PHP...). $largeurMax=0;$hauteurMax=0; $largeurMin=0;$hauteurMin=0; for($zone = 0 ; $zone < $nbZones ; $zone++) { for($numSpriteInfo = 0 ; $numSpriteInfo < $nbSpritesInfo[$zone] ; $numSpriteInfo++){ $spriteInfo = substr($spriteData[$zone], 52*$numSpriteInfo, 52*$numSpriteInfo+52); $page = bin2dec_2($Block,32); if(($page2 = bin2dec_2($Block,34)) != 0) $page = $page2; if(empty($pages[$page])) continue;//Si référence à une page inexistante (fix trnad_3) $X = bin2dec_2($spriteInfo, 2); $Y = bin2dec_2($spriteInfo, 4); //Unsigned int 2 signed int, ça c'est si vous ne pouvez pas déclarer une variable signed int ^^ if($X > 32768) $X-=65536; if($Y > 32768) $Y-=65536; if($X==10000 || $X==-3184) continue;//fix if($X > $largeurMax && $X > 0) $largeurMax = $X; elseif($X < 0 && -$X > $largeurMin) $largeurMin = -$X; if($Y > $hauteurMax && $Y > 0) $hauteurMax = $Y; elseif($Y < 0 && -$Y > $hauteurMin) $hauteurMin = -$Y; //Listing des paramètres $param = bin2dec_2($spriteInfo, 26); if($param && ($paramList[$param % 256] > $param || !$paramList[$param % 256])) $paramList[$param % 256] = $param; } } $largeur = $largeurMax + $largeurMin + 16; $hauteur = $hauteurMax + $hauteurMin + 16; ==== Sprites zone 1 ==== [{{ :ff7:technique:field:ancnt3-couche1.png?200|Juste la première zone du fichier ancnt3}}] Pour construire une image, on utilise les Infos sprites. Dans la zone 1, un sprite est une image de 16*16 pixels. On construit cette image grâce aux Infos sprites (positions et autres infos), aux données de l'image (pour créer les pixels) et aux palettes (pour les couleurs). Regardez plus haut pour savoir où trouver la zone 1 des Infos sprites, et comment elle est faite. C'est la plus simple des zones. Elle est scindée en nbSpritesInfos parties de 52 octets chacune. Ces 52 octets vous donnent les infos pour pouvoir construire le sprite. === Chercher les pixels du sprite === $SrcX = bin2dec_2($spriteInfo, 10); $SrcY = bin2dec_2($spriteInfo, 12); $page = bin2dec_2($spriteInfo, 32); $uneCoul = bin2dec_2($imageData, $pages[$Page]+4); //les deux derniers octets du header de la page (qui disent si 1 octet = 1 pixel ou si 2 octets = 1 pixel) $pos = $pages[$page] + 6 + ($srcY * 256 + $srcX) * $uneCoul; //Position de départ du sprite dans les données de l'image Ce code nous donne le **point de départ** du sprite dans la partie //données de l'image//. Elle utilise les variables extraites des infos du sprite. Explications : * le tableau $pages[] donne les points de départ des pages * + 6 : c'est la taille du header de la page. * 'SrcY' est la position Y dans l'image de 256*256 pixels. * la largeur de l'image d'une page = 256. Pour aller d'un ligne à l'autre dans les données, il faut faire des bonds de 256 octets. * 'SrcX' est la postion X dans l'image de 256*256 pixels. * $uneCoul = 1 ou 2. Quand c'est égal à deux, on a pas besoin de palettes. Il vous faut extraire à partir de StartOffset un **carré de 16*16 pixels**. Mais [[#les_donnees_de_l_image|remontez un peu]] et regardez l'illustration. Prendre 16*16 pixels, c'est pas si simple. Au début on prend l'octet StartOffset, puis l'octet StartOffset + 1, etc, jusqu'à l'octet StartOffset + 15. On a une ligne ! Mais on est bien embêté pour passer à la ligne suivante ! Il faut aller à StartOffset + 256, donc en gros faire un bond de 240 octets... jusqu'à ce qu'on ait finalement 16*16 octets, pour construire le sprite. == Mini récapitulatif == * On regarde un info Sprite, celui-ci permet de placer un petit carré de 16*16 pixels sur l'image finale ; * donc dans l'info Sprite, on prend le numéro de la page utilisée et les position sources pour savoir où dans les données on trouve le petit carré à reproduire sur l'image finale. === Chercher les couleurs du sprite === $Palette = substr($PaletteData, 512*$Pal, 512); //Partie données de la section palette Pour chaque octets du sprite de 16*16 pixels, il faut aller chercher la couleur dans la palette (le numéro de palette est donné dans les données du sprites). Un exemple : vous avez l'octet 0x5d, alors il faut aller chercher la **0x5d-ième couleur de la palette**. Comme il y a deux octets par couleur dans une palette, la position dans la palette est **0x5d*2**. Et pour savoir quelle palette utiliser, prenez l'info dans les sprites data (ça va de 0 à nbPalette - 1). J'ai développé dans l'article [[pal|palette]] la manière de traduire les deux octets de la couleur en une couleur RVB. Si il n'y a pas de palettes, les couleurs sont données directement dans les données de l'image, un pixel = 2 octets. Couleurs sur deux octets : **rrrrrvvv vvmbbbbb** (avec r=rouge, v=vert, b=bleu, m=inconnu).\\ Par contre ne tracez pas les pixels noirs (r=0,v=0,b=0) ! == Complications sur les palettes == * Dans l'en-tête (celle au tout début de l'article :-p ), vous avez extrait l'activité des premiers pixels des palettes (que j'ai nommé **actPixPal**). Celui-ci est une suite de vingt-quatre 0 et 1. En fait, si par exemple le premier octet est 0, cela signifie que toutes les couleurs de la palette n°0 doivent être utilisées, si le premier octet est 1, cela signifie que la première couleur de la palette n°0 ne doit pas être utilisée.\\ Autre exemple : si le quatrième octet est sur 1, cela signifie qu'on peut utiliser toutes les couleurs de la palette n°3, si il est sur 0, cela signifie qu'on ne peut pas utiliser la première couleur de la palette n°3. * Si vous rencontrez un pixel noir (r=0,v=0,b=0,m=0), remplacez-le par la première couleur de la palette (peu importe la valeur de **actPixPal**). == Mini récapitulatif == * On se demande si on doit utiliser une palette pour construire notre petit carré ; * Si oui, on utilise le sprite data pour connaitre le numéro de la palette ; * Sinon, on passe à la suite, en retenant qu'il faut utiliser la méthode sans palette. === Chercher la position cible === Les infos du sprite vous donnent des positions cibles. Mais l'origine se trouve bien souvent (pas tout le temps) au milieu de l'écran, on se retrouve donc avec des coordonnées parfois négatives. Voila comment retrouver des coordonnées positives (**xCible** et **yCible** sont deux signed int extraits du Sprite infos en cours, **largeurMin** et **hauteurMin** sont les plus grandes valeurs cible en dessous de 0, en valeur absolue) : xCible = xCible + largeurMin; yCible = yCible + hauteurMin; Voila, vous pouvez tracer le petit carré. ==== Sprites zone 2 ==== [{{ :ff7:technique:field:ancnt3-couche2a.png?200|Première et deuxième zone (sans les effectPages) du fichier ancnt3}}] Dans la zone 2, on utilise le même procédé que dans la zone 1, sauf pour les infos sprites qui ont un **effectPage** supérieur à 0. En tout cas en traçant la zone 1 et la zone 2 sauf les effectPage, vous aurez déjà un beau background. Allez faire un tour [[#l_ordre_des_couches|en bas de l'article]] pour prendre conscience de la séparation page/effectPage de la zone 2. === Les effectPage === [{{:ff7:technique:field:ancnt3-couche2b.png?200 |Première et deuxième zone (avec les effectPages) du fichier ancnt3}}] Vous devez utiliser les positions source X (2) et Y (2) : $srcX2 = bin2dec_2($spriteInfo, 14); $srcY2 = bin2dec_2($spriteInfo, 16); $id = bin2dec_2($spriteInfo, 24); $effectPage = bin2dec_2($spriteInfo, 34); if($effectPage && $id!=4095) { //Quand id==4095, cela signifie qu'on est dans la zone 1, pour éviter les problème j'évite d'utiliser les effectPage si je suis dans la zone 1 $srcX = $srcX2; $srcY = $srcY2; $page = $effectPage; } == "Transparence" == Dans le cas d'un effectPage, la plupart des couleurs sont indiquées comme transparentes. En fait quand on trace un pixel transparent, il ne faut pas utiliser le canal alpha, mais regarder quelles sont les couleurs du pixel qui était déjà tracé là où on veut tracer notre pixel transparent, et **additionner** ces couleurs avec les couleurs du pixel transparent pour obtenir les véritables couleurs !\\ Exemple : vous voulez tracer un pixel transparent, et là où vous voulez le tracer il y a déjà un pixel de couleur r=56 v=64 b=28, et votre pixel est de couleur r=8 v=16 b=8 ; la nouvelle couleur sera donc r=56+8 v=64+16 b=28+8. == Les paramètres == J'ai réussi à trouver les bonnes conditions pour n'afficher que le premier état de chaque paramètre. Quand on a collecté des informations précédemment, on a créé le liste $paramList qui contient les numéros des premiers états de chaque paramètre. Si vous avez suivit la construction de paramList, les conditions suivantes devraient fonctionner, on ne trace que si le paramètre = 0 ou bien si le paramètre = premier état. $param == $paramList[$param % 256] ==== Sprites zone 3 ==== Changement majeur : on trace des sprites de 32*32 pixels. Cette zone est une sorte de background répété au centre de l'écran (comme la propriété ''background: repeat;'' en css). ==== Sprites zone 4 ==== Sprites de 32*32. Cette zone est une sorte de background fixé là où se trouve la caméra (comme la propriété ''background: fixed;'' en css). ===== L'ordre des couches ===== L'ordre des couches est donné par l'Id des infos Sprites. Cet id est compris entre 0 et 4096 (inclus), avec 0 le plus près et 4096 le plus éloigné. Dans les scripts, on peut changer cette valeur entre -32768 et +32767 (signed short). Il est donc judicieux de trier les tiles par leur Id. Par défaut, les couches ont des id prédéfinis : * Zone 1 : 4095 * Zone 2 : variable * Zone 3 : 4096 * Zone 4 : 0 La zone 4 est toujours devant, la zone 3 derrière, la zone 1 juste devant la 3 et la 2 ça dépend. Ces valeurs peuvent changer par les scripts, si vous voulez optimiser l'affichage, il faut savoir lire les scripts :-) .