From e51ce26db9d632b5d4f4fd4e886afde52d6dd454 Mon Sep 17 00:00:00 2001 From: Fatbag Date: Fri, 15 Jun 2012 10:18:12 -0500 Subject: [PATCH] Added support for SPR2, DGRP, and OBJf in the iff library and in iff2html. --- Libraries/FileHandler/bmp/read_bmp.c | 2 +- Libraries/FileHandler/iff/CMakeLists.txt | 3 + Libraries/FileHandler/iff/dgrp.c | 108 ++++++++++++ Libraries/FileHandler/iff/iff.c | 12 ++ Libraries/FileHandler/iff/iff.h | 74 +++++++- Libraries/FileHandler/iff/objf.c | 60 +++++++ Libraries/FileHandler/iff/spr.c | 127 +++++++------- Libraries/FileHandler/iff/spr2.c | 209 ++++++++++++++++++++++- Tools/iff2html/iff2html.c | 113 ++++++++++-- Tools/iff2html/image.c | 26 +-- Tools/iff2html/image.h | 3 +- 11 files changed, 647 insertions(+), 90 deletions(-) create mode 100644 Libraries/FileHandler/iff/dgrp.c create mode 100644 Libraries/FileHandler/iff/objf.c diff --git a/Libraries/FileHandler/bmp/read_bmp.c b/Libraries/FileHandler/bmp/read_bmp.c index 0c0ed3b..3785565 100644 --- a/Libraries/FileHandler/bmp/read_bmp.c +++ b/Libraries/FileHandler/bmp/read_bmp.c @@ -111,7 +111,7 @@ int bmp_read_data(bmpheader_t * BMPHeader, const uint8_t *__restrict InBuffer, u unsigned y, x; unsigned padding = BMPHeader->biWidth % 4; if(padding != 0) padding = 4-padding; - + for(y=0; ybiHeight; y++){ for(x=0; xbiWidth; x++){ unsigned index = 4*(*InBuffer++); diff --git a/Libraries/FileHandler/iff/CMakeLists.txt b/Libraries/FileHandler/iff/CMakeLists.txt index 21a6f20..ebd6d42 100644 --- a/Libraries/FileHandler/iff/CMakeLists.txt +++ b/Libraries/FileHandler/iff/CMakeLists.txt @@ -5,11 +5,14 @@ set(IFF_SOURCES cats.c iff.c bcon.c + dgrp.c fcns.c glob.c + objf.c palt.c rsmp.c spr.c + spr2.c str.c string.c tmpl.c diff --git a/Libraries/FileHandler/iff/dgrp.c b/Libraries/FileHandler/iff/dgrp.c new file mode 100644 index 0000000..33ac883 --- /dev/null +++ b/Libraries/FileHandler/iff/dgrp.c @@ -0,0 +1,108 @@ +/* + FileHandler - General-purpose file handling library for Niotso + dgrp.c - Copyright (c) 2012 Niotso Project + Author(s): Fatbag + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "iffparser.h" + +#define read_split(x, y, z) \ + (largefields ? read_uint##z(x) : read_uint##y(x)) + +int iff_parse_dgrp(IFFChunk * ChunkInfo, const uint8_t * Buffer){ + IFFDrawGroup *Group; + bytestream b; + int largefields; + unsigned i; + + if(ChunkInfo->Size < 52) + return 0; + set_bytestream(&b, Buffer, ChunkInfo->Size); + ChunkInfo->FormattedData = calloc(1, sizeof(IFFDrawGroup)); + if(ChunkInfo->FormattedData == NULL) + return 0; + + Group = ChunkInfo->FormattedData; + Group->Version = read_uint16(&b); + if(Group->Version < 20000 || Group->Version > 20004 || Group->Version == 20002) + return 0; + largefields = (Group->Version >= 20003); + Group->AngleCount = read_split(&b, 16, 32); + if(Group->AngleCount != 12) + return 0; + + for(i=0; i<12; i++){ + IFFDrawAngle * Angle = &Group->DrawAngles[i]; + unsigned j; + + if(b.Size < ((!largefields) ? 4 : 12)) + return 0; + + if(!largefields) + Angle->SpriteCount = read_uint16(&b); + Angle->Direction = read_split(&b, 8, 32); + Angle->Zoom = read_split(&b, 8, 32); + if(largefields) + Angle->SpriteCount = read_uint32(&b); + + if((Angle->Direction != 1 && Angle->Direction != 4 && Angle->Direction != 16 && Angle->Direction != 64) + || (!Angle->Zoom || Angle->Zoom > 3)) + return 0; + if(Angle->SpriteCount == 0) + continue; + + Angle->SpriteInfo = calloc(Angle->SpriteCount, sizeof(IFFSpriteInfo)); + if(Angle->SpriteInfo == NULL) + return 0; + + for(j=0; jSpriteCount; j++){ + IFFSpriteInfo * Sprite = &Angle->SpriteInfo[j]; + const uint8_t size[5] = {12, 16, 0, 24, 32}; + + if(b.Size < size[Group->Version - 20000]) + return 0; + + if(!largefields) + Sprite->Type = read_uint16(&b); + Sprite->ChunkID = read_split(&b, 16, 32); + Sprite->SpriteIndex = read_split(&b, 16, 32); + if(!largefields) + Sprite->Flags = read_uint16(&b); + Sprite->SpriteX = read_split(&b, 16, 32); + Sprite->SpriteY = read_split(&b, 16, 32); + if(Group->Version >= 20001){ + Sprite->ObjectZ = read_float(&b); + if(Group->Version >= 20003){ + Sprite->Flags = read_uint32(&b); + if(Group->Version == 20004){ + Sprite->ObjectX = read_float(&b); + Sprite->ObjectY = read_float(&b); + } + } + } + } + } + + return 1; +} + +void iff_free_dgrp(void * FormattedData){ + IFFDrawGroup *Group = FormattedData; + int i; + for(i=0; i<12; i++){ + IFFDrawAngle *Angle = &Group->DrawAngles[i]; + free(Angle->SpriteInfo); + } +} \ No newline at end of file diff --git a/Libraries/FileHandler/iff/iff.c b/Libraries/FileHandler/iff/iff.c index 4b311cd..94c9f5c 100644 --- a/Libraries/FileHandler/iff/iff.c +++ b/Libraries/FileHandler/iff/iff.c @@ -28,13 +28,16 @@ void iff_free_##x(void *) iff_register(bcon); +iff_register(dgrp); iff_register(str); iff_register(cats); iff_register(c_string); iff_register(glob); iff_register(fcns); iff_register(palt); +iff_register(objf); iff_register(spr); +iff_register(spr2); iff_register(tmpl); iff_register(trcn); iff_register(rsmp); @@ -49,8 +52,11 @@ const char chunktypes[] = "FCNS" "PALT" "SPR#" + "SPR2" + "DGRP" "TMPL" "TRCN" + "OBJf" "rsmp" ; int (* const iff_parse_function[])(IFFChunk*, const uint8_t*) = { @@ -62,8 +68,11 @@ int (* const iff_parse_function[])(IFFChunk*, const uint8_t*) = { iff_parse_fcns, iff_parse_palt, iff_parse_spr, + iff_parse_spr2, + iff_parse_dgrp, iff_parse_tmpl, iff_parse_trcn, + iff_parse_objf, iff_parse_rsmp }; void (* const iff_free_function[])(void*) = { @@ -75,8 +84,11 @@ void (* const iff_free_function[])(void*) = { iff_free_fcns, NULL, iff_free_spr, + iff_free_spr, + iff_free_dgrp, iff_free_tmpl, iff_free_trcn, + iff_free_objf, iff_free_rsmp }; /* End */ diff --git a/Libraries/FileHandler/iff/iff.h b/Libraries/FileHandler/iff/iff.h index 8a11ab2..1199c28 100644 --- a/Libraries/FileHandler/iff/iff.h +++ b/Libraries/FileHandler/iff/iff.h @@ -83,6 +83,49 @@ typedef struct IFF_BCON_s uint16_t * Constants; } IFF_BCON; +/* DGRP chunk */ + +typedef struct IFFSpriteInfo_s +{ + uint16_t Type; + uint32_t ChunkID; + uint32_t SpriteIndex; + uint16_t Flags; + int32_t SpriteX; + int32_t SpriteY; + float ObjectZ; + float ObjectX; + float ObjectY; +} IFFSpriteInfo; + +typedef struct IFFDrawAngle_s +{ + uint16_t SpriteCount; + uint32_t Direction; + uint32_t Zoom; + IFFSpriteInfo * SpriteInfo; +} IFFDrawAngle; + +typedef struct IFFDrawGroup_s +{ + uint16_t Version; + uint32_t AngleCount; + IFFDrawAngle DrawAngles[12]; +} IFFDrawGroup; + +enum IFFDrawDirection { + IFFDIRECTION_NORTHEAST = 1, + IFFDIRECTION_SOUTHEAST = 4, + IFFDIRECTION_NORTHWEST = 16, + IFFDIRECTION_SOUTHWEST = 64 +}; + +enum IFFDrawZoom { + IFFZOOM_FAR = 1, + IFFZOOM_MIDDLE, + IFFZOOM_CLOSE +}; + /* FCNS chunk */ typedef struct IFFConstant_s @@ -101,6 +144,23 @@ typedef struct IFFConstantList_s IFFConstant * Constants; } IFFConstantList; +/* OBJf chunk */ + +typedef struct IFFFunction_s +{ + uint16_t ConditionID; + uint16_t ActionID; +} IFFFunction; + +typedef struct IFFFunctionTable_s +{ + uint32_t Reserved; + uint32_t Version; + char MagicNumber[5]; + uint32_t FunctionCount; + IFFFunction * Functions; +} IFFFunctionTable; + /* PALT chunk */ typedef struct IFFPalette_s @@ -112,15 +172,21 @@ typedef struct IFFPalette_s uint8_t Data[256*3]; } IFFPalette; -/* SPR# chunk */ +/* SPR#/SPR2 chunk */ typedef struct IFFSprite_s { uint32_t Reserved; uint16_t Height; uint16_t Width; + uint32_t Flags; + uint16_t PaletteID; + uint16_t TransparentColor; + int16_t YLoc; + int16_t XLoc; uint8_t * IndexData; uint8_t * BGRA32Data; + uint8_t * ZBuffer; uint8_t InvalidDimensions; } IFFSprite; @@ -133,6 +199,12 @@ typedef struct IFFSpriteList_s IFFSprite * Sprites; } IFFSpriteList; +enum IFFSpriteFlags { + IFFSPRITE_FLAG_COLOR = 1, + IFFSPRITE_FLAG_ZBUFFER = 2, + IFFSPRITE_FLAG_ALPHA = 4 +}; + int iff_depalette(IFFSprite * Sprite, const IFFPalette * Palette); /* STR# chunk */ diff --git a/Libraries/FileHandler/iff/objf.c b/Libraries/FileHandler/iff/objf.c new file mode 100644 index 0000000..f039a5c --- /dev/null +++ b/Libraries/FileHandler/iff/objf.c @@ -0,0 +1,60 @@ +/* + FileHandler - General-purpose file handling library for Niotso + objf.c - Copyright (c) 2012 Niotso Project + Author(s): Ahmed El-Mahdawy + Fatbag + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "iffparser.h" + +int iff_parse_objf(IFFChunk * ChunkInfo, const uint8_t * Buffer){ + IFFFunctionTable *Table; + unsigned i; + + if(ChunkInfo->Size < 16) + return 0; + ChunkInfo->FormattedData = calloc(1, sizeof(IFFFunctionTable)); + if(ChunkInfo->FormattedData == NULL) + return 0; + + Table = ChunkInfo->FormattedData; + Table->Reserved = read_uint32le(Buffer); + Table->Version = read_uint32le(Buffer+4); + memcpy(Table->MagicNumber, Buffer+8, 4); + Table->MagicNumber[4] = 0x00; + Table->FunctionCount = read_uint32le(Buffer+12); + if(Table->Reserved != 0 || Table->Version != 0) + return 0; + if(Table->FunctionCount == 0) + return 1; + if(Table->FunctionCount > (ChunkInfo->Size - 16)/4) + return 0; + + Table->Functions = malloc(Table->FunctionCount * sizeof(IFFFunction)); + if(Table->Functions == NULL) + return 0; + + Buffer += 16; + for(i=0; iFunctionCount; i++, Buffer += 4){ + Table->Functions[i].ConditionID = read_uint16le(Buffer); + Table->Functions[i].ActionID = read_uint16le(Buffer+2); + } + return 1; +} + +void iff_free_objf(void * FormattedData){ + IFFFunctionTable *Table = FormattedData; + free(Table->Functions); +} \ No newline at end of file diff --git a/Libraries/FileHandler/iff/spr.c b/Libraries/FileHandler/iff/spr.c index dbf898b..04c32cb 100644 --- a/Libraries/FileHandler/iff/spr.c +++ b/Libraries/FileHandler/iff/spr.c @@ -16,42 +16,41 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include "iffparser.h" int iff_parse_spr(IFFChunk * ChunkInfo, const uint8_t * Buffer){ IFFSpriteList *SpriteList; - unsigned ChunkSize = ChunkInfo->Size; bytestream b; + unsigned NextSpriteOffset; /* Used for Version 1001 in place of the offset table */ unsigned i; - if(ChunkSize < 12) + if(ChunkInfo->Size < 12) return 0; - set_bytestream(&b, Buffer, ChunkSize); + set_bytestream(&b, Buffer, ChunkInfo->Size); + if((Buffer[0]|Buffer[1]) == 0) b.Endian++; /* Big endian */ ChunkInfo->FormattedData = calloc(1, sizeof(IFFSpriteList)); if(ChunkInfo->FormattedData == NULL) return 0; - SpriteList = ChunkInfo->FormattedData; - if((Buffer[0]|Buffer[1]) == 0) b.Endian++; /* Big endian */ + SpriteList = ChunkInfo->FormattedData; SpriteList->Version = read_uint32(&b); SpriteList->SpriteCount = read_uint32(&b); SpriteList->PaletteID = read_uint32(&b); if(SpriteList->Version < 502 || (SpriteList->Version > 505 && SpriteList->Version != 1001)) return 0; - if(SpriteList->Version == 1001){ + if(SpriteList->Version != 1001){ + if(SpriteList->SpriteCount > b.Size/4) + return 0; + }else{ /* Sprite count is blank in version 1001, so we must walk and count up the sprites ourselves; ** this is easy with the sprite size field */ - - /* At this point, we are looking at the first field of the first sprite */ - - for(SpriteList->SpriteCount = 0; b.Size >= 18; SpriteList->SpriteCount++){ + for(SpriteList->SpriteCount = 0; b.Size >= 16; SpriteList->SpriteCount++){ if(read_uint32(&b) != 1001 || !skipbytes(&b, read_uint32(&b))) - break; + return 0; } - seekto(&b, 12); + NextSpriteOffset = 16; } if(SpriteList->SpriteCount == 0) @@ -62,80 +61,89 @@ int iff_parse_spr(IFFChunk * ChunkInfo, const uint8_t * Buffer){ for(i=0; iSpriteCount; i++){ IFFSprite * Sprite = &SpriteList->Sprites[i]; - unsigned SpriteSize = 0; + unsigned SpriteSize; unsigned row = 0; if(SpriteList->Version != 1001){ /* Jump to the next sprite using the offset table; this is mandatory */ seekto(&b, 12 + 4*i); - if(!seekto(&b, read_uint32(&b))) + if(!seekto(&b, read_uint32(&b)) || b.Size < 8) return 0; - if((SpriteSize = b.Size) < 10) - return 0; - } - - if(SpriteList->Version == 1001){ - seekto(&b, b.Buffer - b.StartPos); /* Resynchronize b.Size with b.Buffer */ - if(b.Size < 18) - return 0; - read_uint32(&b); /* Sprite version; already checked to be equal to 1001 */ + SpriteSize = b.Size; + }else{ + /* Jump to the next sprite using the sprite size field; this is mandatory */ + seekto(&b, NextSpriteOffset); SpriteSize = read_uint32(&b); + NextSpriteOffset += SpriteSize + 8; } Sprite->Reserved = read_uint32(&b); Sprite->Height = read_uint16(&b); Sprite->Width = read_uint16(&b); - if(Sprite->Reserved != 0 || Sprite->Height == 0 || Sprite->Width == 0 || Sprite->Height > UINT_MAX/Sprite->Width/2){ + if(Sprite->Reserved != 0 || Sprite->Height == 0 || Sprite->Width == 0 || Sprite->Height > UINT_MAX/2/Sprite->Width){ /* This happens in the third sprite of every SPR# chunk in sprites.iff */ Sprite->InvalidDimensions = 1; continue; } - Sprite->IndexData = calloc(Sprite->Height*Sprite->Width, 2); + + SpriteSize -= 8; + + Sprite->IndexData = calloc(Sprite->Width*Sprite->Height, 2); if(Sprite->IndexData == NULL) - {printf("Error %u\n", 1);return 0;} + return 0; while(1){ - /* Row command: valid commands are 0, 4, 5, and 9 */ - uint8_t Command, Count; - if(SpriteSize < 2) - {printf("Error %u\n", 2);return 0;} + /**** + ** Row command: valid commands are 0, 4, 5, 9, and 16 + */ - Command = *(b.Buffer++); - Count = *(b.Buffer++); + uint8_t RowCommand, RowCount; + + if(SpriteSize < 2) + return 0; + RowCommand = *(b.Buffer++); + RowCount = *(b.Buffer++); SpriteSize -= 2; - if(Command == 0 || Command == 16){ + if(RowCommand == 0 || RowCommand == 16){ /* Start marker */ - }else if(Command == 4){ - /* Pixel command: valid commands are 1, 2, and 3 */ + }else if(RowCommand == 4){ + /**** + ** Pixel command: valid commands are 1, 2, and 3 + */ + unsigned pixel = 0; - if(row == Sprite->Height || Count < 2 || (Count -= 2) > SpriteSize || Count%2 != 0) - {printf("Error %u\n", 3);return 0;} - SpriteSize -= Count; - while(Count){ + if(row == Sprite->Height || RowCount < 2 || (RowCount -= 2) > SpriteSize || RowCount%2 != 0) + return 0; + SpriteSize -= RowCount; + + while(RowCount){ uint8_t PixelCommand, PixelCount; - if(Count < 2) - {printf("Error %u\n", 4);return 0;} + if(RowCount < 2) + return 0; PixelCommand = *(b.Buffer++); PixelCount = *(b.Buffer++); - Count -= 2; + RowCount -= 2; + + if(PixelCount > Sprite->Width - pixel) + return 0; if(PixelCommand == 1){ /* Leave next n pixels as transparent */ - if(PixelCount > Sprite->Width - pixel) - {printf("Error %u\n", 5);return 0;} + pixel += PixelCount; }else if(PixelCommand == 2){ /* Set next n pixels to shared palette index */ + uint8_t PaletteIndex; - if(PixelCount > Sprite->Width - pixel || Count < 2) - {printf("Error %u\n", 6);return 0;} + if(RowCount < 2) + return 0; PaletteIndex = *(b.Buffer++); b.Buffer++; /* Padding byte */ - Count -= 2; + RowCount -= 2; while(PixelCount--){ Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 0] = PaletteIndex; @@ -144,10 +152,11 @@ int iff_parse_spr(IFFChunk * ChunkInfo, const uint8_t * Buffer){ } }else if(PixelCommand == 3){ /* Set next n pixels to n palette indices */ + int padding = PixelCount%2; - if(PixelCount > Sprite->Width - pixel || PixelCount + padding > Count) - {printf("Error %u\n", 7);return 0;} - Count -= PixelCount + padding; + if(PixelCount + padding > RowCount) + return 0; + RowCount -= PixelCount + padding; while(PixelCount--){ Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 0] = *(b.Buffer++); @@ -155,18 +164,19 @@ int iff_parse_spr(IFFChunk * ChunkInfo, const uint8_t * Buffer){ pixel++; } if(padding) b.Buffer++; /* Padding byte */ - }else {printf("Error %u\n", 8);return 0;} + }else return 0; } row++; - }else if(Command == 5){ + }else if(RowCommand == 5){ /* End marker */ break; - }else if(Command == 9){ + }else if(RowCommand == 9){ /* Leave rows as transparent */ - if(Count > Sprite->Height - row) - {printf("Error %u\n", 9);return 0;} - row += Count; - }else {printf("Error %u\n", 10);return 0;} + + if(RowCount > Sprite->Height - row) + return 0; + row += RowCount; + }else return 0; } } @@ -181,6 +191,7 @@ void iff_free_spr(void * FormattedData){ IFFSprite *Sprite = &SpriteList->Sprites[s]; free(Sprite->IndexData); free(Sprite->BGRA32Data); + free(Sprite->ZBuffer); } free(SpriteList->Sprites); } diff --git a/Libraries/FileHandler/iff/spr2.c b/Libraries/FileHandler/iff/spr2.c index 4c35c04..436ab62 100644 --- a/Libraries/FileHandler/iff/spr2.c +++ b/Libraries/FileHandler/iff/spr2.c @@ -14,4 +14,211 @@ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ \ No newline at end of file +*/ + +#include "iffparser.h" + +int iff_parse_spr2(IFFChunk * ChunkInfo, const uint8_t * Buffer){ + IFFSpriteList *SpriteList; + bytestream b; + unsigned NextSpriteOffset; /* Used for Version 1001 in place of the offset table */ + unsigned i; + + if(ChunkInfo->Size < 12) + return 0; + set_bytestream(&b, Buffer, ChunkInfo->Size); + if((Buffer[0]|Buffer[1]) == 0) b.Endian++; /* Big endian */ + + ChunkInfo->FormattedData = calloc(1, sizeof(IFFSpriteList)); + if(ChunkInfo->FormattedData == NULL) + return 0; + + SpriteList = ChunkInfo->FormattedData; + SpriteList->Version = read_uint32(&b); + if(SpriteList->Version != 1000 && SpriteList->Version != 1001) + return 0; + + if(SpriteList->Version == 1000){ + SpriteList->SpriteCount = read_uint32(&b); + SpriteList->PaletteID = read_uint32(&b); + if(SpriteList->SpriteCount > b.Size/4) + return 0; + }else{ + SpriteList->PaletteID = read_uint32(&b); + skipbytes(&b, 4); + + /* Sprite count is blank in version 1001, so we must walk and count up the sprites ourselves; + ** this is easy with the sprite size field */ + for(SpriteList->SpriteCount = 0; b.Size >= 24; SpriteList->SpriteCount++){ + if(read_uint32(&b) != 1001 || !skipbytes(&b, read_uint32(&b))) + return 0; + } + NextSpriteOffset = 16; + } + + if(SpriteList->SpriteCount == 0) + return 1; + SpriteList->Sprites = calloc(SpriteList->SpriteCount, sizeof(IFFSprite)); + if(SpriteList->Sprites == NULL) + return 0; + + for(i=0; iSpriteCount; i++){ + IFFSprite * Sprite = &SpriteList->Sprites[i]; + unsigned SpriteSize; + unsigned row = 0; + int j; + + if(SpriteList->Version != 1001){ + /* Jump to the next sprite using the offset table; this is mandatory */ + seekto(&b, 12 + 4*i); + if(!seekto(&b, read_uint32(&b)) || b.Size < 16) + return 0; + SpriteSize = b.Size; + }else{ + /* Jump to the next sprite using the sprite size field; this is mandatory */ + seekto(&b, NextSpriteOffset); + SpriteSize = read_uint32(&b); + NextSpriteOffset += SpriteSize + 8; + } + + Sprite->Width = read_uint16(&b); + Sprite->Height = read_uint16(&b); + Sprite->Flags = read_uint32(&b); + Sprite->PaletteID = read_uint16(&b); + Sprite->TransparentColor = read_uint16(&b); + Sprite->YLoc = read_uint16(&b); + Sprite->XLoc = read_uint16(&b); + if((Sprite->Flags != 1 && Sprite->Flags != 3 && Sprite->Flags != 7) || Sprite->TransparentColor >= 256) + return 0; + if(Sprite->Height == 0 || Sprite->Width == 0 || Sprite->Height > UINT_MAX/2/Sprite->Width){ + /* This happens in the many chunks in 2personportal.spf */ + Sprite->InvalidDimensions = 1; + continue; + } + + SpriteSize -= 16; + + Sprite->IndexData = malloc(Sprite->Width*Sprite->Height*2); + if(Sprite->IndexData == NULL) + return 0; + for(j=0; jWidth*Sprite->Height; j++){ + Sprite->IndexData[2*j + 0] = Sprite->TransparentColor; + Sprite->IndexData[2*j + 1] = 0x00; + } + + if(Sprite->Flags >= 3){ /* Has the Z-Buffer flag */ + Sprite->ZBuffer = malloc(Sprite->Width*Sprite->Height); + if(Sprite->ZBuffer == NULL) + return 0; + memset(Sprite->ZBuffer, 0xFF, Sprite->Width*Sprite->Height); + } + + while(1){ + /**** + ** Row command: valid commands are 0, 4, and 5 + */ + + uint8_t RowCommand; /* 3 bits */ + uint16_t RowCount; /* 13 bits */ + + if(SpriteSize < 2) + return 0; + RowCount = read_uint16le(b.Buffer); + RowCommand = RowCount >> 13; + RowCount &= 0x1FFF; + + b.Buffer += 2; + SpriteSize -= 2; + + if(RowCommand == 0){ + /**** + ** Pixel command: valid commands are 1, 2, 3, and 6 + */ + + unsigned pixel = 0; + + if(row == Sprite->Height || RowCount < 2 || (RowCount -= 2) > SpriteSize || RowCount%2 != 0) + return 0; + SpriteSize -= RowCount; + + while(RowCount){ + uint8_t PixelCommand; /* 3 bits */ + uint16_t PixelCount; /* 13 bits */ + if(RowCount < 2) + return 0; + + PixelCount = read_uint16le(b.Buffer); + PixelCommand = PixelCount >> 13; + PixelCount &= 0x1FFF; + + b.Buffer += 2; + RowCount -= 2; + + if(PixelCount > Sprite->Width - pixel) + return 0; + + if(PixelCommand == 1){ + /* color+z-buffer: Set next n pixels to n palette indices */ + + if(Sprite->Flags < 3 || PixelCount*2 > RowCount) + return 0; + RowCount -= PixelCount*2; + + while(PixelCount--){ + Sprite->ZBuffer[Sprite->Width*row + pixel] = *(b.Buffer++); + Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 0] = *(b.Buffer++); + Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 1] = 0xFF; + pixel++; + } + }else if(PixelCommand == 2){ + /* color+z-buffer+alpha: Set next n pixels to n palette indices */ + + int padding = PixelCount%2; + if(Sprite->Flags < 7 || PixelCount*3 + padding > RowCount) + return 0; + RowCount -= PixelCount*3 + padding; + + while(PixelCount--){ + Sprite->ZBuffer[Sprite->Width*row + pixel] = *(b.Buffer++); + Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 0] = *(b.Buffer++); + Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 1] = *(b.Buffer++); + pixel++; + } + if(padding) b.Buffer++; /* Padding byte */ + }else if(PixelCommand == 3){ + /* Leave next n pixels as transparent */ + + pixel += PixelCount; + }else if(PixelCommand == 6){ + /* color: Set next n pixels to n palette indices */ + + int padding = PixelCount%2; + if(PixelCount + padding > RowCount) + return 0; + RowCount -= PixelCount + padding; + + while(PixelCount--){ + Sprite->ZBuffer[Sprite->Width*row + pixel] = 0x00; + Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 0] = *(b.Buffer++); + Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 1] = 0xFF; + pixel++; + } + if(padding) b.Buffer++; /* Padding byte */ + } else return 0; + } + row++; + }else if(RowCommand == 4){ + /* Leave rows as transparent */ + + if(RowCount > Sprite->Height - row) + return 0; + row += RowCount; + }else if(RowCommand == 5){ + /* End marker */ + break; + }else return 0; + } + } + + return 1; +} \ No newline at end of file diff --git a/Tools/iff2html/iff2html.c b/Tools/iff2html/iff2html.c index 2af7a90..9debdbd 100644 --- a/Tools/iff2html/iff2html.c +++ b/Tools/iff2html/iff2html.c @@ -302,26 +302,27 @@ int main(int argc, char *argv[]){ fprintf(hFile, "\n"); fprintf(hFile, "\n"); - for(c=1, ChunkData = IFFFileInfo->Chunks; c <= IFFFileInfo->ChunkCount; c++, ChunkData++){ + for(c=0, ChunkData = IFFFileInfo->Chunks; c < IFFFileInfo->ChunkCount; c++, ChunkData++){ fprintf(hFile, "

%u [%s] (%.4X)%s%s (Jump)

\n", - c, ChunkData->ChunkID, c, ChunkData->Type, ChunkData->ChunkID, + c+1, ChunkData->ChunkID, c+1, ChunkData->Type, ChunkData->ChunkID, (ChunkData->Label[0] != 0x00) ? " – " : "", ChunkData->Label, - c, ChunkData->ChunkID); + c+1, ChunkData->ChunkID); fprintf(hFile, "
\n"); if(ChunkData->FormattedData == NULL){ int success = 0; /* The iff library does not parse BMP_ or FBMP chunks */ if(!strcmp(ChunkData->Type, "BMP_") || !strcmp(ChunkData->Type, "FBMP")){ + int bmp = !strcmp(ChunkData->Type, "BMP_"); size_t Width, Height; char filename[32]; - sprintf(filename, "%sbmp_%u_%.4x.png", OutDir, c+1, ChunkData->ChunkID); + sprintf(filename, "%s%s_%u_%.4x.png", OutDir, bmp ? "bmp" : "fbmp", c+1, ChunkData->ChunkID); - if(WritePNG(filename, ChunkData, NULL, &Width, &Height)){ + if(WritePNG(filename, ChunkData, 0, NULL, &Width, &Height)){ fprintf(hFile, "\n"); fprintf(hFile, "\n"); - fprintf(hFile, "\n", - c+1, ChunkData->ChunkID, Width, Height); + fprintf(hFile, "\n", + bmp ? "bmp" : "fbmp", c+1, ChunkData->ChunkID, Width, Height); fprintf(hFile, "
Image
\"\"
\"\"
\n"); success++; } @@ -536,11 +537,12 @@ int main(int argc, char *argv[]){ fprintf(hFile, "\n"); } fprintf(hFile, "\n"); - }else if(!strcmp(ChunkData->Type, "SPR#")){ + }else if(!strcmp(ChunkData->Type, "SPR#") || !strcmp(ChunkData->Type, "SPR2")){ /**** - ** SPR# parsing + ** SPR# and SPR2 parsing */ + int spr1 = !strcmp(ChunkData->Type, "SPR#"); IFFSpriteList * SpriteList = ChunkData->FormattedData; IFFChunk * Palette = NULL; IFFPalette BlankPalette; @@ -565,21 +567,98 @@ int main(int argc, char *argv[]){ }else PaletteData = Palette->FormattedData; fprintf(hFile, "\n"); - fprintf(hFile, "\n"); + fprintf(hFile, ""); + if(!spr1) fprintf(hFile, ""); + fprintf(hFile, "\n"); for(i=0; iSpriteCount; i++){ IFFSprite * Sprite = &SpriteList->Sprites[i]; char filename[32]; - sprintf(filename, "%sspr1_%u_%.4x_%u.png", OutDir, c+1, ChunkData->ChunkID, i+1); + sprintf(filename, "%s%s_%u_%.4x_%u.png", OutDir, spr1 ? "spr1" : "spr2", c+1, ChunkData->ChunkID, i+1); - fprintf(hFile, "IndexData && iff_depalette(Sprite, PaletteData)){ + WritePNG(filename, NULL, 0, Sprite, NULL, NULL); + fprintf(hFile, ">\"\"", + spr1 ? "spr1" : "spr2", c+1, ChunkData->ChunkID, i+1, Sprite->Width, Sprite->Height); + if(!spr1){ + sprintf(filename, "%sspr2_%u_%.4x_%u_z.png", OutDir, c+1, ChunkData->ChunkID, i+1); + if(Sprite->ZBuffer){ + WritePNG(filename, NULL, 1, Sprite, NULL, NULL); + fprintf(hFile, "\n"); } fprintf(hFile, "
Sprite
SpriteZ-Buffer
%u", i+1); - if(Sprite->IndexData && iff_depalette(Sprite, PaletteData) && WritePNG(filename, NULL, Sprite, NULL, NULL)) - fprintf(hFile, "\"\"", - c+1, ChunkData->ChunkID, i+1, Sprite->Width, Sprite->Height); - else - fprintf(hFile, Sprite->InvalidDimensions ? "Blank sprite" : "This sprite cannot be displayed."); + fprintf(hFile, "
%u\"\"", + c+1, ChunkData->ChunkID, i+1, Sprite->Width, Sprite->Height); + }else + fprintf(hFile, "None provided"); + } + }else + fprintf(hFile, Sprite->InvalidDimensions ? "%sBlank sprite" : "%sThis sprite cannot be displayed.", + !spr1 ? " colspan=\"2\">" : ""); fprintf(hFile, "
\n"); + }else if(!strcmp(ChunkData->Type, "DGRP")){ + /**** + ** DGRP parsing + */ + + IFFDrawGroup * Group = ChunkData->FormattedData; + IFFDrawAngle * Angle; + IFFSpriteInfo * Sprite; + unsigned i,j; + const char * Zooms[] = {"Far", "Middle", "Close"}; + + fprintf(hFile, "\n"); + fprintf(hFile, "\n", Group->Version); + fprintf(hFile, "
Version:%u
\n"); + fprintf(hFile, "
\n"); + + fprintf(hFile, "\n"); + fprintf(hFile, "\n"); + for(i=0, Angle=Group->DrawAngles; i<12; i++, Angle++){ + const char * Direction = + (Angle->Direction == IFFDIRECTION_NORTHEAST) ? "North east" : + (Angle->Direction == IFFDIRECTION_SOUTHEAST) ? "South east" : + (Angle->Direction == IFFDIRECTION_NORTHWEST) ? "North west" : + "South west"; + + if(Angle->SpriteCount){ + fprintf(hFile, + "" + "" + "\n", + 1+Angle->SpriteCount, Direction, 1+Angle->SpriteCount, Zooms[Angle->Zoom-1]); + for(j=0, Sprite = Angle->SpriteInfo; jSpriteCount; j++, Sprite++) + fprintf(hFile, "" + "", + j+1, Sprite->Type, Sprite->ChunkID, Sprite->SpriteIndex, Sprite->Flags, + Sprite->SpriteX, Sprite->SpriteY, Sprite->ObjectX, Sprite->ObjectY, Sprite->ObjectZ); + + }else{ + fprintf(hFile, "", Direction, Zooms[Angle->Zoom-1]); + } + } + fprintf(hFile, "
DirectionZoomSprite
%s%s#TypeChunk IDSprite indexFlagsSprite offsetObject offset
%u%u%.4X%u%u(%+d,%+d)(%+g,%+g,%+g)
%s%sNone specified
\n"); + }else if(!strcmp(ChunkData->Type, "OBJf")){ + /**** + ** OBJf parsing + */ + + IFFFunctionTable * Table = ChunkData->FormattedData; + fprintf(hFile, "\n"); + fprintf(hFile, "\n", Table->Version); + fprintf(hFile, "
Version:%u
\n"); + + if(Table->FunctionCount > 0){ + unsigned i; + + fprintf(hFile, "
\n"); + fprintf(hFile, "\n"); + fprintf(hFile, "\n"); + for(i=0; iFunctionCount; i++) + fprintf(hFile, + "\n", + i+1, Table->Functions[i].ConditionID, Table->Functions[i].ActionID); + fprintf(hFile, "
Condition functionAction function
%u%.4X%.4X
\n"); + } }else{ fprintf(hFile, "The contents of this chunk cannot be shown on this page.\n"); } diff --git a/Tools/iff2html/image.c b/Tools/iff2html/image.c index 21ce7dc..12e4d58 100644 --- a/Tools/iff2html/image.c +++ b/Tools/iff2html/image.c @@ -23,7 +23,8 @@ #include #include "opngreduc.h" -int WritePNG(const char * OutName, const IFFChunk * ChunkData, const IFFSprite * Sprite, size_t * Width, size_t * Height){ +int WritePNG(const char * OutName, const IFFChunk * ChunkData, int ZBuffer, + const IFFSprite * Sprite, size_t * Width, size_t * Height){ FILE * hFile; png_structp png_ptr; png_infop info_ptr; @@ -40,7 +41,7 @@ int WritePNG(const char * OutName, const IFFChunk * ChunkData, const IFFSprite * /* BMP_ or FBMP chunk */ bmpheader_t BMPHeader; - if(!bmp_read_header(&BMPHeader, ChunkData->Data, ChunkData->Size - 76)) + if(!bmp_read_header(&BMPHeader, ChunkData->Data, ChunkData->Size)) return 0; Image.Data = malloc(BMPHeader.DecompressedSize); @@ -57,14 +58,16 @@ int WritePNG(const char * OutName, const IFFChunk * ChunkData, const IFFSprite * /* SPR# or SPR2 sprite */ Image.Width = Sprite->Width; Image.Height = Sprite->Height; - Image.Data = Sprite->BGRA32Data; + Image.Data = (!ZBuffer) ? Sprite->BGRA32Data : Sprite->ZBuffer; - /* Swap from BGR to RGB; this cannot be done with libpng when you use opng_reduce_image - ** due to the state that it leaves png_ptr in */ - for(i=0; i