Les moddeurs se fichent bien des détails de l'implémentation des fichiers. Ils utilisent des outils comme BAMWorkshop ou autres pour travailler leurs fichiers. Ta problématique est celle du créateur d'outil. Tu te retrouves un peu seul, en tout cas dans l'environnement francophone. Les autres personnes qui s'intéressent aux formats sont les "découvreurs" des formats, prêts à farfouiller tous les fichiers pour comprendre comme le jeu exploite telle ou telle valeur, ainsi que les personnes qui écrivent l'émulateur GemRB.
Pour les portraits, j'ai une bonne nouvelle : ce ne sont pas des BAM mais de simples BMP.
Décodage du fichier BAM IMISC2J.BAM
J'ai utilisé un éditeur hexadécimal très puissant,
Hex Workshop, qui permet de définir des structures puis de le plaquer sur un fichier binaire. Bien évidemment, l'éditeur est payant. Mais dans un contexte de travail poussé sur des fichiers binaires, son prix n'est plus un frein face à l'énorme gain de temps que cette capacité apporte (quand je l'ai acheté il coûtait presque deux fois moins cher, à vrai dire). Il m'a rendu bien des services dans mon travail.
Le mainteneur d'IESDP avait écrit des définitions de structures pour certains formats (CRE, SPL, ...) mais pas le BAM. Je viens d'écrire rapidement les structures permettant de décoder au moins le début du fichier, jusqu'à la palette.
Je ne retrouve pas les mêmes résultats que toi et je m'interroge sur la façon dont tu as obtenu tes résultats dans les Frame Entries.
La première Frame Entry me semble bonne :
Frame width 25
Frame Height 24
Frame center X coordinate -4
Frame center Y coordinate -4
Offset frame Data / Compressed 1084 (compression RLE utilisée puisque valeur inférieure à 2 000 000 000)
Pour la seconde, j'obtiens :
Frame width 36
Frame Height 36
Frame center X coordinate 14
Frame center Y coordinate 18
Offset frame Data / Compressed 1577 (compression RLE utilisée puisque valeur inférieure à 2 000 000 000)
Je ne comprends pas comment tu as obtenu tes valeurs. Tu sembles avoir bon pour 25, 24 et -4. Mais je ne comprends pas d'où sort subitement ton -5 alors que le 1084 est bon. Ensuite, c'est tout faux pour la deuxième Frame entry. Les valeurs 28 et 11 n'apparaissent pas du tout dans le fichier dans cette zone entre les positions 24 et 56.
Ensuite, les valeurs pour Cycle Entries sont bonnes, mais mal rangées.
J'obtiens :
Cycle entry 1
count 1
index de début 0
Cycle entry 2
count 1
index de début 1
Palette
Elle fait forcément 256 couleurs (j'en avais déjà parlé, en tant que valeur implicite). Comme chaque couleur de pixel dans les Frame Data est sur 8 bits, il faut forcément 256 valeurs dans la palette pour les définir.
Lookup Table
Comme la donnée FrameCount est codée sur deux octets, on peut penser que chaque valeur dans la lookup table est codé sur deux octets. Sinon le lien indiqué dans la table ne permettrait pas d'accéder à plus de 256 images, donc FrameCount pourrait être limité à un seul octet.
Par ailleurs, la description de la table de correspondance indique
Pour trouver le nombre d'entrées de cette table de correspondance, cherchez la valeur maximale de la somme début (index) + nombre (count) dans la table des entrées de cycle.
Quand on regarde les deux cyles, on se rend compte que la somme index + count du premier vaut 1 et que celle du second vaut 2. Donc la table de correspondance a une taille de 2.
Compte tenu du contenu de la table, cela nous donne :
première position : 1
deuxième position : 0
Le cycle 1, qui utilise pour départ l'adresse 0 de la table de correspondance (index de début = 0), utilise 1 seule image (count = 1), donc la numéro 1.
Le cycle 2, qui utilise pour départ l'adresse 1 de la table de correspondance (index de début = 1), utilise 1 seule image (count = 1), donc la numéro 0.
Comme il n'y a pas de compression RLE dans aucune des images, le décodage des images est simple.
La première commence à l'adresse 1084 et comporte 24 lignes de 25 pixels, soit 600 octets. Grâce à la compression RLE, on constate que seulement 493 octets ont été nécessaires (1577 - 1084).
Le seconde commence à l'adresse 1577 et comporte 36 lignes de 36 pixels, soit 1296 octets. Grâce à la compression RLE, on constate que seulement 684 octets ont été nécessaires (taille du fichier, 2261, - 1577).
D'après ce que je comprends de la description des datas (il est écrit width * height), il faut considérer les pixels sur la première ligne, puis sur la suivante et ainsi de suite. Cela correspond à l'utilisation typique d'un FAX (il scanne par ligne, compresse en RLE ligne par ligne). Pour la première image, cela donnerait 25 pixels pour la première ligne, suivis de 25 pixels pour la deuxième ligne et ainsi de suite jusqu'à la 24ème ligne.
Il ne faut pas oublier que la décompression RLE vaut augmenter le nombre de pixels obtenus à partir des 493 ou 684 octets.
Chaque octet donne, pour son pixel, la position de la couleur dans la palette de couleur.
Pour décompresser le RLE, il faut s'appuyer sur la valeur de "The compressed colour index for RLE encoded bams" dans l'en-tête du fichier.
La description de ce champ donne, en français :
L'index de la couleur compressée pour les BAMs codés en RLE (c'est à dire la couleur qui est compressée).
L'index de transparence est fixé à la première occurence du code RGB(0,255,0). Si le code RGB(0,255,0) ne figure pas dans la palette, l'index de transparence est fixé à 0.
Dans le fichier qui nous intéresse, ce champ vaut 0. C'est donc la couleur à l'index 0 dans la palette qui sera compressé puisque le fichier utilise la compression RLE. Cela signifie que la valeur 0 dans la table de valeur de l'image indique que l'octet suivant est le nombre - 1 de pixels consécutifs dans la couleur compressée. Autrement dit une séquence 0 20 dans la table de pixel d'une image signifie 21 pixels consécutifs dans la couleur 0 de la palette.
Si le champ de l'en-tête avait valu 10, il aurait fallu repérer les séquences 10 suivi d'un nombre pour savoir combien de fois cette couleur 10 de la palette était répétée.
Dans la palette de notre BAM, l'index 0 a également la valeur RGB(0,255,0), plus le quatrième octet alpha toujours à 0. C'est à dire que ce sera notre couleur transparente. Ça tombe bien, c'est le code RGB du vert. Notre couleur compressé est donc la couleur transparente. C'est fréquemment le cas dans les BAMs. En effet, il y a souvent tout l'entourage autour de l'objet ou de l'icône de sort que l'on ne veut surtout pas faire apparaître à l'écran. Choisir cette couleur pour la couleur compressée est donc judicieux pour gagner sur le codage des pixels entourant la véritable image.
Pour décompresser la partie image, je te suggère de travailler sur une table de taille width * height. Tu lis octet par octet la zone affectée à l'image compressée.
- Si la valeur est différente de la couleur compressée, tu recopies dans la table décompressée et tu passes à la position suivante.
- Si la valeur est la couleur compressée, tu lis l'octet suivant (disons qu'il vaut N) et tu recopies N + 1 fois la couleur compressée dans la table décompressée.
Et ainsi de suite jusqu'à la fin de la zone affectée à l'image compressée. En principe, tu auras alors atteint la dernière position dans la table décompressée également.
Ensuite, tu peux découper cette table par bloc de witdh pixels pour les affecter à chaque ligne de l'image.
Pour connaître la véritable couleur d'un pixel, il te suffit de prendre la valeur RGB dans la palette à l'index indiqué par la valeur du pixel.
J'espère que je ne me suis pas trompé dans mon analyse de l'exploitation de l'image compressée. Je n'ai pas vraiment le temps d'écrire un programme pour réaliser ça et l'éditeur hexadécimal n'est d'aucun secours pour convertir ne serait-ce que 493 octets en 600 en appliquant même un algorithme aussi simple.
Si tu jettes un coup d'oeil au code WeiDU de BAM Batcher, tu retrouveras peut-être cet algorithme. Mais il risque d'être assez illisible, WeiDU n'étant pas un modèle de lisibilité pour écrire du code de ce type. Je suis d'ailleurs sidéré de voir que l'auteur ait utilisé WeiDU autant à contre emploi. C'est vraiment du codage de gourou de WeiDU, même si on arrive quand même à peu-près à le lire quand on sait ce qu'on cherche.