Added BHAV parsing and displaying, and started using the transparent color field in SPR2 chunks to remove the magenta background in some sprites.

This commit is contained in:
Fatbag 2012-06-15 20:45:11 -05:00
parent e51ce26db9
commit dd15e0d42a
7 changed files with 160 additions and 26 deletions

View file

@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 2.6)
project(iff) project(iff)
set(IFF_SOURCES set(IFF_SOURCES
bhav.c
cats.c cats.c
iff.c iff.c
bcon.c bcon.c

View file

@ -16,3 +16,76 @@
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "iffparser.h"
#define HEADER_SIZE (12 + (Behavior->Version == 0x8003))
int iff_parse_bhav(IFFChunk * ChunkInfo, const uint8_t * Buffer){
IFFBehavior *Behavior;
unsigned i;
if(ChunkInfo->Size < 12)
return 0;
ChunkInfo->FormattedData = calloc(1, sizeof(IFFBehavior));
if(ChunkInfo->FormattedData == NULL)
return 0;
Behavior = ChunkInfo->FormattedData;
Behavior->Version = read_uint16le(Buffer);
if(Behavior->Version < 0x8000 || Behavior->Version > 0x8003 || (Behavior->Version == 0x8003 && ChunkInfo->Size < 13))
return 0;
switch(Behavior->Version){
case 0x8000: {
Behavior->InstructionCount = read_uint16le(Buffer+2);
} break;
case 0x8001: {
Behavior->InstructionCount = read_uint16le(Buffer+2);
} break;
case 0x8002: {
Behavior->InstructionCount = read_uint16le(Buffer+2);
Behavior->Type = read_uint8le(Buffer+4);
Behavior->ArgumentCount = read_uint8le(Buffer+5);
Behavior->LocalCount = read_uint16le(Buffer+6);
Behavior->Flags = read_uint16le(Buffer+8);
} break;
default: {
Behavior->Type = read_uint8le(Buffer+2);
Behavior->ArgumentCount = read_uint8le(Buffer+3);
Behavior->LocalCount = read_uint8le(Buffer+4);
Behavior->Flags = read_uint16le(Buffer+7);
Behavior->InstructionCount = read_uint32le(Buffer+9);
} break;
}
if(Behavior->InstructionCount == 0)
return 1;
if(Behavior->InstructionCount > 255 || Behavior->InstructionCount*12 > ChunkInfo->Size - HEADER_SIZE)
return 0;
Behavior->Instructions = calloc(Behavior->InstructionCount, sizeof(IFFInstruction));
if(Behavior->Instructions == NULL)
return 0;
Buffer += HEADER_SIZE;
for(i=0; i<Behavior->InstructionCount; i++){
Behavior->Instructions[i].Opcode = read_uint16le(Buffer);
Behavior->Instructions[i].TDest = read_uint8le(Buffer+2);
Behavior->Instructions[i].FDest = read_uint8le(Buffer+3);
memcpy(Behavior->Instructions[i].Operands, Buffer+4, 8);
Buffer += 12;
}
return 1;
}
void iff_free_bhav(void * FormattedData){
IFFBehavior *Behavior = FormattedData;
free(Behavior->Instructions);
}

View file

@ -35,6 +35,7 @@ iff_register(c_string);
iff_register(glob); iff_register(glob);
iff_register(fcns); iff_register(fcns);
iff_register(palt); iff_register(palt);
iff_register(bhav);
iff_register(objf); iff_register(objf);
iff_register(spr); iff_register(spr);
iff_register(spr2); iff_register(spr2);
@ -56,6 +57,7 @@ const char chunktypes[] =
"DGRP" "DGRP"
"TMPL" "TMPL"
"TRCN" "TRCN"
"BHAV"
"OBJf" "OBJf"
"rsmp" "rsmp"
; ;
@ -72,6 +74,7 @@ int (* const iff_parse_function[])(IFFChunk*, const uint8_t*) = {
iff_parse_dgrp, iff_parse_dgrp,
iff_parse_tmpl, iff_parse_tmpl,
iff_parse_trcn, iff_parse_trcn,
iff_parse_bhav,
iff_parse_objf, iff_parse_objf,
iff_parse_rsmp iff_parse_rsmp
}; };
@ -88,6 +91,7 @@ void (* const iff_free_function[])(void*) = {
iff_free_dgrp, iff_free_dgrp,
iff_free_tmpl, iff_free_tmpl,
iff_free_trcn, iff_free_trcn,
iff_free_bhav,
iff_free_objf, iff_free_objf,
iff_free_rsmp iff_free_rsmp
}; };

View file

@ -83,6 +83,27 @@ typedef struct IFF_BCON_s
uint16_t * Constants; uint16_t * Constants;
} IFF_BCON; } IFF_BCON;
/* BHAV chunk */
typedef struct IFFInstruction_s
{
uint16_t Opcode;
uint8_t TDest;
uint8_t FDest;
uint8_t Operands[8];
} IFFInstruction;
typedef struct IFFBehavior_s
{
uint16_t Version;
uint32_t InstructionCount;
uint8_t Type;
uint8_t ArgumentCount;
uint16_t LocalCount;
uint16_t Flags;
IFFInstruction * Instructions;
} IFFBehavior;
/* DGRP chunk */ /* DGRP chunk */
typedef struct IFFSpriteInfo_s typedef struct IFFSpriteInfo_s

View file

@ -120,6 +120,7 @@ int iff_parse_spr(IFFChunk * ChunkInfo, const uint8_t * Buffer){
while(RowCount){ while(RowCount){
uint8_t PixelCommand, PixelCount; uint8_t PixelCommand, PixelCount;
uint8_t * IndexData;
if(RowCount < 2) if(RowCount < 2)
return 0; return 0;
@ -130,10 +131,11 @@ int iff_parse_spr(IFFChunk * ChunkInfo, const uint8_t * Buffer){
if(PixelCount > Sprite->Width - pixel) if(PixelCount > Sprite->Width - pixel)
return 0; return 0;
IndexData = Sprite->IndexData + (Sprite->Width*row + pixel)*2;
pixel += PixelCount;
if(PixelCommand == 1){ if(PixelCommand == 1){
/* Leave next n pixels as transparent */ /* Leave next n pixels as transparent */
pixel += PixelCount;
}else if(PixelCommand == 2){ }else if(PixelCommand == 2){
/* Set next n pixels to shared palette index */ /* Set next n pixels to shared palette index */
@ -146,9 +148,8 @@ int iff_parse_spr(IFFChunk * ChunkInfo, const uint8_t * Buffer){
RowCount -= 2; RowCount -= 2;
while(PixelCount--){ while(PixelCount--){
Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 0] = PaletteIndex; *IndexData++ = PaletteIndex;
Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 1] = 0xFF; *IndexData++ = 0xFF;
pixel++;
} }
}else if(PixelCommand == 3){ }else if(PixelCommand == 3){
/* Set next n pixels to n palette indices */ /* Set next n pixels to n palette indices */
@ -159,9 +160,8 @@ int iff_parse_spr(IFFChunk * ChunkInfo, const uint8_t * Buffer){
RowCount -= PixelCount + padding; RowCount -= PixelCount + padding;
while(PixelCount--){ while(PixelCount--){
Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 0] = *(b.Buffer++); *IndexData++ = *(b.Buffer++);
Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 1] = 0xFF; *IndexData++ = 0xFF;
pixel++;
} }
if(padding) b.Buffer++; /* Padding byte */ if(padding) b.Buffer++; /* Padding byte */
}else return 0; }else return 0;

View file

@ -144,6 +144,7 @@ int iff_parse_spr2(IFFChunk * ChunkInfo, const uint8_t * Buffer){
while(RowCount){ while(RowCount){
uint8_t PixelCommand; /* 3 bits */ uint8_t PixelCommand; /* 3 bits */
uint16_t PixelCount; /* 13 bits */ uint16_t PixelCount; /* 13 bits */
uint8_t * IndexData, * ZBuffer;
if(RowCount < 2) if(RowCount < 2)
return 0; return 0;
@ -157,6 +158,10 @@ int iff_parse_spr2(IFFChunk * ChunkInfo, const uint8_t * Buffer){
if(PixelCount > Sprite->Width - pixel) if(PixelCount > Sprite->Width - pixel)
return 0; return 0;
IndexData = Sprite->IndexData + (Sprite->Width*row + pixel)*2;
ZBuffer = Sprite->ZBuffer + (Sprite->Width*row + pixel)*1;
pixel += PixelCount;
if(PixelCommand == 1){ if(PixelCommand == 1){
/* color+z-buffer: Set next n pixels to n palette indices */ /* color+z-buffer: Set next n pixels to n palette indices */
@ -165,10 +170,10 @@ int iff_parse_spr2(IFFChunk * ChunkInfo, const uint8_t * Buffer){
RowCount -= PixelCount*2; RowCount -= PixelCount*2;
while(PixelCount--){ while(PixelCount--){
Sprite->ZBuffer[Sprite->Width*row + pixel] = *(b.Buffer++); *ZBuffer++ = *(b.Buffer++);
Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 0] = *(b.Buffer++); IndexData[0] = *(b.Buffer++);
Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 1] = 0xFF; IndexData[1] = (IndexData[0] != Sprite->TransparentColor) ? 0xFF : 0x00;
pixel++; IndexData += 2;
} }
}else if(PixelCommand == 2){ }else if(PixelCommand == 2){
/* color+z-buffer+alpha: Set next n pixels to n palette indices */ /* color+z-buffer+alpha: Set next n pixels to n palette indices */
@ -179,16 +184,13 @@ int iff_parse_spr2(IFFChunk * ChunkInfo, const uint8_t * Buffer){
RowCount -= PixelCount*3 + padding; RowCount -= PixelCount*3 + padding;
while(PixelCount--){ while(PixelCount--){
Sprite->ZBuffer[Sprite->Width*row + pixel] = *(b.Buffer++); *ZBuffer++ = *(b.Buffer++);
Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 0] = *(b.Buffer++); *IndexData++ = *(b.Buffer++);
Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 1] = *(b.Buffer++); *IndexData++ = *(b.Buffer++);
pixel++;
} }
if(padding) b.Buffer++; /* Padding byte */ if(padding) b.Buffer++; /* Padding byte */
}else if(PixelCommand == 3){ }else if(PixelCommand == 3){
/* Leave next n pixels as transparent */ /* Leave next n pixels as transparent */
pixel += PixelCount;
}else if(PixelCommand == 6){ }else if(PixelCommand == 6){
/* color: Set next n pixels to n palette indices */ /* color: Set next n pixels to n palette indices */
@ -198,10 +200,11 @@ int iff_parse_spr2(IFFChunk * ChunkInfo, const uint8_t * Buffer){
RowCount -= PixelCount + padding; RowCount -= PixelCount + padding;
while(PixelCount--){ while(PixelCount--){
Sprite->ZBuffer[Sprite->Width*row + pixel] = 0x00; IndexData[0] = *(b.Buffer++);
Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 0] = *(b.Buffer++); IndexData[1] = (IndexData[0] != Sprite->TransparentColor) ? 0xFF : 0x00;
Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 1] = 0xFF; if(Sprite->Flags >= 3)
pixel++; *ZBuffer++ = (IndexData[0] != Sprite->TransparentColor) ? 0x00 : 0xFF;
IndexData += 2;
} }
if(padding) b.Buffer++; /* Padding byte */ if(padding) b.Buffer++; /* Padding byte */
} else return 0; } else return 0;

View file

@ -578,20 +578,20 @@ int main(int argc, char *argv[]){
fprintf(hFile, "<tr><td>%u</td><td", i+1); fprintf(hFile, "<tr><td>%u</td><td", i+1);
if(Sprite->IndexData && iff_depalette(Sprite, PaletteData)){ if(Sprite->IndexData && iff_depalette(Sprite, PaletteData)){
WritePNG(filename, NULL, 0, Sprite, NULL, NULL); WritePNG(filename, NULL, 0, Sprite, NULL, NULL);
fprintf(hFile, "><img src=\"%s_%u_%.4x_%u.png\" width=\"%u\" height=\"%u\" alt=\"\" />", fprintf(hFile, "><img src=\"%s_%u_%.4x_%u.png\" width=\"%u\" height=\"%u\" alt=\"\" /></td><td>",
spr1 ? "spr1" : "spr2", c+1, ChunkData->ChunkID, i+1, Sprite->Width, Sprite->Height); spr1 ? "spr1" : "spr2", c+1, ChunkData->ChunkID, i+1, Sprite->Width, Sprite->Height);
if(!spr1){ if(!spr1){
sprintf(filename, "%sspr2_%u_%.4x_%u_z.png", OutDir, c+1, ChunkData->ChunkID, i+1); sprintf(filename, "%sspr2_%u_%.4x_%u_z.png", OutDir, c+1, ChunkData->ChunkID, i+1);
if(Sprite->ZBuffer){ if(Sprite->ZBuffer){
WritePNG(filename, NULL, 1, Sprite, NULL, NULL); WritePNG(filename, NULL, 1, Sprite, NULL, NULL);
fprintf(hFile, "</td><td><img src=\"spr2_%u_%.4x_%u_z.png\" width=\"%u\" height=\"%u\" alt=\"\" />", fprintf(hFile, "<img src=\"spr2_%u_%.4x_%u_z.png\" width=\"%u\" height=\"%u\" alt=\"\" />",
c+1, ChunkData->ChunkID, i+1, Sprite->Width, Sprite->Height); c+1, ChunkData->ChunkID, i+1, Sprite->Width, Sprite->Height);
}else }else
fprintf(hFile, "None provided"); fprintf(hFile, "None provided");
} }
}else }else
fprintf(hFile, Sprite->InvalidDimensions ? "%sBlank sprite" : "%sThis sprite cannot be displayed.", fprintf(hFile, Sprite->InvalidDimensions ? "%sBlank sprite" : "%sThis sprite cannot be displayed.",
!spr1 ? " colspan=\"2\">" : ""); !spr1 ? " colspan=\"2\">" : ">");
fprintf(hFile, "</td></tr>\n"); fprintf(hFile, "</td></tr>\n");
} }
fprintf(hFile, "</table>\n"); fprintf(hFile, "</table>\n");
@ -637,6 +637,38 @@ int main(int argc, char *argv[]){
} }
} }
fprintf(hFile, "</table>\n"); fprintf(hFile, "</table>\n");
}else if(!strcmp(ChunkData->Type, "BHAV")){
/****
** BHAV parsing
*/
IFFBehavior * Behavior = ChunkData->FormattedData;
IFFInstruction * Instruction;
fprintf(hFile, "<table>\n");
fprintf(hFile, "<tr><td>Version:</td><td>%u</td></tr>\n", Behavior->Version);
fprintf(hFile, "<tr><td>Type:</td><td>%u</td></tr>\n", Behavior->Type);
fprintf(hFile, "<tr><td>Arguments:</td><td>%u</td></tr>\n", Behavior->ArgumentCount);
fprintf(hFile, "<tr><td>Locals:</td><td>%u</td></tr>\n", Behavior->LocalCount);
fprintf(hFile, "<tr><td>Flags:</td><td>%.4X</td></tr>\n", Behavior->Flags);
fprintf(hFile, "</table>\n");
if(Behavior->InstructionCount > 0){
unsigned i;
fprintf(hFile, "<br />\n");
fprintf(hFile, "<table class=\"center\">\n");
fprintf(hFile, "<tr><th colspan=\"2\">Opcode</th><th>T-Dest</th><th>F-Dest</th><th>Operand data</th></tr>\n");
for(i=0, Instruction = Behavior->Instructions; i<Behavior->InstructionCount; i++, Instruction++)
fprintf(hFile, "<tr><td>%u</td><td><tt>%.4X</tt></td><td>%u</td><td>%u</td>"
"<td><tt>%.2X %.2X %.2X %.2X %.2X %.2X %.2X %.2X</tt></td></tr>\n",
i, Instruction->Opcode, Instruction->TDest, Instruction->FDest,
Instruction->Operands[0], Instruction->Operands[1],
Instruction->Operands[2], Instruction->Operands[3],
Instruction->Operands[4], Instruction->Operands[5],
Instruction->Operands[6], Instruction->Operands[7]);
fprintf(hFile, "</table>\n");
}
}else if(!strcmp(ChunkData->Type, "OBJf")){ }else if(!strcmp(ChunkData->Type, "OBJf")){
/**** /****
** OBJf parsing ** OBJf parsing