Added support for SPR2, DGRP, and OBJf in the iff library and in iff2html.

This commit is contained in:
Fatbag 2012-06-15 10:18:12 -05:00
parent bc978bfa0b
commit e51ce26db9
11 changed files with 647 additions and 90 deletions

View file

@ -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; y<BMPHeader->biHeight; y++){
for(x=0; x<BMPHeader->biWidth; x++){
unsigned index = 4*(*InBuffer++);

View file

@ -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

View file

@ -0,0 +1,108 @@
/*
FileHandler - General-purpose file handling library for Niotso
dgrp.c - Copyright (c) 2012 Niotso Project <http://niotso.org/>
Author(s): Fatbag <X-Fi6@phppoll.org>
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; j<Angle->SpriteCount; 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);
}
}

View file

@ -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 */

View file

@ -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 */

View file

@ -0,0 +1,60 @@
/*
FileHandler - General-purpose file handling library for Niotso
objf.c - Copyright (c) 2012 Niotso Project <http://niotso.org/>
Author(s): Ahmed El-Mahdawy <aa.mahdawy.10@gmail.com>
Fatbag <X-Fi6@phppoll.org>
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; i<Table->FunctionCount; 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);
}

View file

@ -16,42 +16,41 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdio.h>
#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; i<SpriteList->SpriteCount; 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);
}

View file

@ -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.
*/
*/
#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; i<SpriteList->SpriteCount; 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; j<Sprite->Width*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;
}

View file

@ -302,26 +302,27 @@ int main(int argc, char *argv[]){
fprintf(hFile, "</div>\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, "<h2 id=\"chunk%u_%.4x\">%u [%s] (%.4X)%s%s <a href=\"#chunk%u_%.4x\">(Jump)</a></h2>\n",
c, ChunkData->ChunkID, c, ChunkData->Type, ChunkData->ChunkID,
c+1, ChunkData->ChunkID, c+1, ChunkData->Type, ChunkData->ChunkID,
(ChunkData->Label[0] != 0x00) ? " &ndash; " : "", ChunkData->Label,
c, ChunkData->ChunkID);
c+1, ChunkData->ChunkID);
fprintf(hFile, "<div>\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, "<table class=\"center centerall\">\n");
fprintf(hFile, "<tr><th>Image</th></tr>\n");
fprintf(hFile, "<tr><td><img src=\"bmp_%u_%.4x.png\" width=\"%u\" height=\"%u\" alt=\"\" /></td></tr>\n",
c+1, ChunkData->ChunkID, Width, Height);
fprintf(hFile, "<tr><td><img src=\"%s_%u_%.4x.png\" width=\"%u\" height=\"%u\" alt=\"\" /></td></tr>\n",
bmp ? "bmp" : "fbmp", c+1, ChunkData->ChunkID, Width, Height);
fprintf(hFile, "</table>\n");
success++;
}
@ -536,11 +537,12 @@ int main(int argc, char *argv[]){
fprintf(hFile, "</tr>\n");
}
fprintf(hFile, "</table>\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, "<table class=\"center centerall\">\n");
fprintf(hFile, "<tr><th colspan=\"2\">Sprite</th></tr>\n");
fprintf(hFile, "<tr><th colspan=\"2\">Sprite</th>");
if(!spr1) fprintf(hFile, "<th>Z-Buffer</th>");
fprintf(hFile, "</tr>\n");
for(i=0; i<SpriteList->SpriteCount; 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, "<tr><td>%u</td><td>", i+1);
if(Sprite->IndexData && iff_depalette(Sprite, PaletteData) && WritePNG(filename, NULL, Sprite, NULL, NULL))
fprintf(hFile, "<img src=\"spr1_%u_%.4x_%u.png\" width=\"%u\" height=\"%u\" alt=\"\" />",
c+1, ChunkData->ChunkID, i+1, Sprite->Width, Sprite->Height);
else
fprintf(hFile, Sprite->InvalidDimensions ? "Blank sprite" : "This sprite cannot be displayed.");
fprintf(hFile, "<tr><td>%u</td><td", i+1);
if(Sprite->IndexData && iff_depalette(Sprite, PaletteData)){
WritePNG(filename, NULL, 0, Sprite, NULL, NULL);
fprintf(hFile, "><img src=\"%s_%u_%.4x_%u.png\" width=\"%u\" height=\"%u\" alt=\"\" />",
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, "</td><td><img src=\"spr2_%u_%.4x_%u_z.png\" width=\"%u\" height=\"%u\" alt=\"\" />",
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, "</td></tr>\n");
}
fprintf(hFile, "</table>\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, "<table>\n");
fprintf(hFile, "<tr><td>Version:</td><td>%u</td></tr>\n", Group->Version);
fprintf(hFile, "</table>\n");
fprintf(hFile, "<br />\n");
fprintf(hFile, "<table class=\"center\">\n");
fprintf(hFile, "<tr><th>Direction</th><th>Zoom</th><th colspan=\"6\">Sprite</th></tr>\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,
"<tr><td rowspan=\"%u\">%s</td><td rowspan=\"%u\">%s</td>"
"<th>#</th><th>Type</th><th>Chunk ID</th><th>Sprite index</th>"
"<th>Flags</th><th>Sprite offset</th><th>Object offset</th></tr>\n",
1+Angle->SpriteCount, Direction, 1+Angle->SpriteCount, Zooms[Angle->Zoom-1]);
for(j=0, Sprite = Angle->SpriteInfo; j<Angle->SpriteCount; j++, Sprite++)
fprintf(hFile, "<tr><td>%u</td><td>%u</td><td>%.4X</td><td>%u</td><td>%u</td>"
"<td>(%+d,%+d)</td><td>(%+g,%+g,%+g)</td></tr>",
j+1, Sprite->Type, Sprite->ChunkID, Sprite->SpriteIndex, Sprite->Flags,
Sprite->SpriteX, Sprite->SpriteY, Sprite->ObjectX, Sprite->ObjectY, Sprite->ObjectZ);
}else{
fprintf(hFile, "<tr><td>%s</td><td>%s</td><td>None specified</td></tr>", Direction, Zooms[Angle->Zoom-1]);
}
}
fprintf(hFile, "</table>\n");
}else if(!strcmp(ChunkData->Type, "OBJf")){
/****
** OBJf parsing
*/
IFFFunctionTable * Table = ChunkData->FormattedData;
fprintf(hFile, "<table>\n");
fprintf(hFile, "<tr><td>Version:</td><td>%u</td></tr>\n", Table->Version);
fprintf(hFile, "</table>\n");
if(Table->FunctionCount > 0){
unsigned i;
fprintf(hFile, "<br />\n");
fprintf(hFile, "<table class=\"center\">\n");
fprintf(hFile, "<tr><th colspan=\"2\">Condition function</th><th>Action function</th></tr>\n");
for(i=0; i<Table->FunctionCount; i++)
fprintf(hFile,
"<tr><td>%u</td><td>%.4X</td><td>%.4X</td></tr>\n",
i+1, Table->Functions[i].ConditionID, Table->Functions[i].ActionID);
fprintf(hFile, "</table>\n");
}
}else{
fprintf(hFile, "The contents of this chunk cannot be shown on this page.\n");
}

View file

@ -23,7 +23,8 @@
#include <libpng/png.h>
#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<Image.Width*Image.Height; i++){
uint8_t temp = Image.Data[i*4 + 0];
Image.Data[i*4 + 0] = Image.Data[i*4 + 2];
Image.Data[i*4 + 2] = temp;
if(!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<Image.Width*Image.Height; i++){
uint8_t temp = Image.Data[i*4 + 0];
Image.Data[i*4 + 0] = Image.Data[i*4 + 2];
Image.Data[i*4 + 2] = temp;
}
}
}
@ -74,7 +77,7 @@ int WritePNG(const char * OutName, const IFFChunk * ChunkData, const IFFSprite *
return 0;
}
for(i=0; i<Image.Height; i++)
row_pointers[i] = Image.Data + Image.Width*((ChunkData) ? 3*(Image.Height-i-1) : 4*i);
row_pointers[i] = Image.Data + Image.Width*((ChunkData) ? 3*(Image.Height-i-1) : ((!ZBuffer)?4:1)*i);
/****
** PNG handling
@ -118,7 +121,8 @@ int WritePNG(const char * OutName, const IFFChunk * ChunkData, const IFFSprite *
png_set_compression_window_bits(png_ptr, 15);
png_set_compression_buffer_size(png_ptr, 32768);
png_set_IHDR(png_ptr, info_ptr, Image.Width, Image.Height, 8, ChunkData ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA,
png_set_IHDR(png_ptr, info_ptr, Image.Width, Image.Height, 8,
ChunkData ? PNG_COLOR_TYPE_RGB : (!ZBuffer) ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_GRAY,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_set_rows(png_ptr, info_ptr, row_pointers);

View file

@ -16,4 +16,5 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
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);