mirror of
https://github.com/simtactics/mysimulation.git
synced 2025-03-15 14:51:21 +00:00
Removed changes by Nicholas. These will need to be re-submitted through Trac and manually validated.
Added BMP (24-bit uncompressed, 8-bit uncompressed, and RLE8) and PNG support to File::ReadImageFile(). So far everything in FileHandler is presumed to be safe with any input file except UTK decompression. Also started making use of the static keyword in various places to aid the compiler in optimization.
This commit is contained in:
parent
7442579090
commit
cb751c0bb8
29 changed files with 692 additions and 1291 deletions
|
@ -18,18 +18,14 @@ set(FILEHANDLER_MINOR 0)
|
|||
set(FILEHANDLER_SOURCES
|
||||
File.cpp
|
||||
Image.cpp
|
||||
bmp/read_bmp.c
|
||||
cst/cst.c
|
||||
iff/stbl.c
|
||||
iff/bhav.c
|
||||
iff/sprite.c
|
||||
iff/chunks.c
|
||||
iff/iff.c
|
||||
)
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/Libraries/FileHandler)
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/Libraries/FileHandler/libpng)
|
||||
|
||||
add_library(FileHandler_static STATIC ${FILEHANDLER_SOURCES})
|
||||
set_target_properties(FileHandler_static PROPERTIES
|
||||
OUTPUT_NAME "FileHandler${FILEHANDLER_SERIES}"
|
||||
|
@ -44,4 +40,4 @@ set_target_properties(FileHandler_shared PROPERTIES
|
|||
PREFIX ""
|
||||
IMPORT_PREFIX ""
|
||||
CLEAN_DIRECT_OUTPUT 1)
|
||||
target_link_libraries(FileHandler_shared kernel32 jpegturbo_static zlib_shared libpng_static)
|
||||
target_link_libraries(FileHandler_shared kernel32 jpegturbo_static libpng_static zlib_static)
|
|
@ -21,13 +21,6 @@ namespace File {
|
|||
int Error = 0;
|
||||
unsigned FileSize = 0;
|
||||
|
||||
const uint8_t Signature[][4] = {
|
||||
{0xFF,0xD8,0xFF,0xE0} //JPEG
|
||||
};
|
||||
const uint8_t SignatureSize[] = {
|
||||
4 //JPEG
|
||||
};
|
||||
|
||||
uint8_t * ReadFile(const char * Filename){
|
||||
HANDLE hFile = CreateFile(Filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
||||
if(hFile == INVALID_HANDLE_VALUE){
|
||||
|
|
|
@ -37,7 +37,8 @@ enum FErr {
|
|||
FERR_BLANK,
|
||||
FERR_MEMORY,
|
||||
FERR_READ,
|
||||
FERR_UNRECOGNIZED
|
||||
FERR_UNRECOGNIZED,
|
||||
FERR_INVALIDDATA
|
||||
};
|
||||
|
||||
enum ImageFormat_t {
|
||||
|
|
|
@ -14,36 +14,101 @@
|
|||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <memory.h>
|
||||
#include <stdio.h>
|
||||
#include <setjmp.h> //Used by libpng
|
||||
#include "bmp/read_bmp.h"
|
||||
#include "libjpeg-turbo/jpeglib.h"
|
||||
#include "libpng/png.h"
|
||||
#define NOWINDOWS
|
||||
#include "FileHandler.hpp"
|
||||
|
||||
namespace File {
|
||||
|
||||
enum ImageType {
|
||||
FIMG_BMP,
|
||||
FIMG_JPEG,
|
||||
FIMG_PNG,
|
||||
FIMG_TGA,
|
||||
FIMG_COUNT
|
||||
};
|
||||
|
||||
uint8_t * ReadJPG(Image_t * Image, const uint8_t * InData, size_t FileSize);
|
||||
uint8_t * ReadBMP(Image_t * Image, const uint8_t * InData, size_t FileSize);
|
||||
uint8_t * ReadPNG(Image_t * Image, const uint8_t * InData, size_t FileSize);
|
||||
uint8_t * ReadTGA(Image_t * Image, const uint8_t * InData, size_t FileSize);
|
||||
|
||||
static const uint8_t Signature[] = {
|
||||
'B', //BMP
|
||||
0xFF, //JPEG
|
||||
0x89, //PNG
|
||||
0x00 //TGA
|
||||
};
|
||||
static uint8_t* (* const ImageFunction[])(Image_t*, const uint8_t*, size_t) = {
|
||||
ReadBMP,
|
||||
ReadJPG,
|
||||
ReadPNG,
|
||||
ReadTGA
|
||||
};
|
||||
|
||||
Image_t * ReadImageFile(const char * Filename){
|
||||
uint8_t * InData = File::ReadFile(Filename);
|
||||
if(InData == NULL) return NULL;
|
||||
|
||||
if(File::FileSize < 4){
|
||||
free(InData);
|
||||
File::Error = FERR_INVALIDDATA;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Image_t * Image = (Image_t*) malloc(sizeof(Image_t));
|
||||
if(Image == NULL){
|
||||
free(InData);
|
||||
File::Error = FERR_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t * OutData = ReadJPG(Image, InData, File::FileSize);
|
||||
|
||||
free(InData);
|
||||
if(OutData != NULL){
|
||||
return Image;
|
||||
uint8_t * OutData = NULL;
|
||||
for(int i=0; i<FIMG_COUNT; i++){
|
||||
if(InData[0] == Signature[i]){
|
||||
OutData = ImageFunction[i](Image, InData, File::FileSize);
|
||||
free(InData);
|
||||
if(OutData == NULL){
|
||||
File::Error = FERR_INVALIDDATA;
|
||||
return NULL;
|
||||
}
|
||||
return Image;
|
||||
}
|
||||
}
|
||||
|
||||
free(InData);
|
||||
File::Error = FERR_UNRECOGNIZED;
|
||||
free(Image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t * ReadBMP(Image_t * Image, const uint8_t * InData, size_t FileSize){
|
||||
bmpheader_t BMPHeader;
|
||||
if(!bmp_read_header(&BMPHeader, InData, FileSize)){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t * OutData = (uint8_t*) malloc(BMPHeader.DecompressedSize);
|
||||
if(OutData == NULL){
|
||||
return NULL;
|
||||
}
|
||||
if(!bmp_read_data(&BMPHeader, InData, OutData)){
|
||||
free(OutData);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Image->Width = BMPHeader.biWidth;
|
||||
Image->Height = BMPHeader.biHeight;
|
||||
Image->Format = FIMG_BGR24;
|
||||
Image->Data = OutData;
|
||||
return OutData;
|
||||
}
|
||||
|
||||
uint8_t * ReadJPG(Image_t * Image, const uint8_t * InData, size_t FileSize){
|
||||
//Initialize
|
||||
jpeg_decompress_struct cinfo;
|
||||
|
@ -55,6 +120,7 @@ uint8_t * ReadJPG(Image_t * Image, const uint8_t * InData, size_t FileSize){
|
|||
jpeg_destroy_decompress(&cinfo);
|
||||
return NULL;
|
||||
}
|
||||
cinfo.out_color_space = JCS_EXT_BGR;
|
||||
if(!jpeg_start_decompress(&cinfo)){
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
return NULL;
|
||||
|
@ -68,10 +134,11 @@ uint8_t * ReadJPG(Image_t * Image, const uint8_t * InData, size_t FileSize){
|
|||
jpeg_destroy_decompress(&cinfo);
|
||||
return NULL;
|
||||
}
|
||||
for(unsigned i=0; cinfo.output_scanline < cinfo.output_height; i++){
|
||||
for(unsigned i=cinfo.output_height; i; i--){
|
||||
//According to the libjpeg documentation,
|
||||
//jpeg_read_scanlines can only really read 1 scanline at a time.
|
||||
uint8_t * Location = OutData + i*row_stride;
|
||||
//We need to convert to bottom-up format anyway.
|
||||
uint8_t * Location = OutData + (i-1)*row_stride;
|
||||
if(!jpeg_read_scanlines(&cinfo, &Location, 1)){
|
||||
free(OutData);
|
||||
jpeg_finish_decompress(&cinfo);
|
||||
|
@ -92,4 +159,64 @@ uint8_t * ReadJPG(Image_t * Image, const uint8_t * InData, size_t FileSize){
|
|||
return OutData;
|
||||
}
|
||||
|
||||
struct pngdata_t {
|
||||
const uint8_t * buffer;
|
||||
size_t size;
|
||||
};
|
||||
static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length){
|
||||
pngdata_t *pngdata = (pngdata_t *) png_get_io_ptr(png_ptr);
|
||||
if(length > pngdata->size) png_error(png_ptr, "");
|
||||
memcpy(data, pngdata->buffer, length);
|
||||
pngdata->buffer += length;
|
||||
pngdata->size -= length;
|
||||
}
|
||||
uint8_t * ReadPNG(Image_t * Image, const uint8_t * InData, size_t FileSize){
|
||||
pngdata_t pngdata;
|
||||
|
||||
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if(png_ptr == NULL) return 0;
|
||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||
if(info_ptr == NULL){
|
||||
png_destroy_read_struct(&png_ptr, NULL, NULL);
|
||||
return NULL;
|
||||
}
|
||||
if(setjmp(png_jmpbuf(png_ptr))){
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pngdata.buffer = InData;
|
||||
pngdata.size = FileSize;
|
||||
png_set_read_fn(png_ptr, &pngdata, user_read_data);
|
||||
png_set_user_limits(png_ptr, 4096, 4096);
|
||||
png_read_png(png_ptr, info_ptr,
|
||||
PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_STRIP_ALPHA |
|
||||
PNG_TRANSFORM_PACKING | PNG_TRANSFORM_GRAY_TO_RGB | PNG_TRANSFORM_BGR, NULL);
|
||||
|
||||
//png_get_IHDR does not work in high-level mode.
|
||||
unsigned width = png_get_image_width(png_ptr, info_ptr);
|
||||
unsigned height = png_get_image_height(png_ptr, info_ptr);
|
||||
uint8_t * OutData = (uint8_t *) malloc(width*height*3);
|
||||
if(OutData == NULL){
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t **Scanlines = png_get_rows(png_ptr, info_ptr);
|
||||
printf("png:Now. %ux%u\n", width, height);
|
||||
for(unsigned i=0; i<height; i++)
|
||||
memcpy(OutData + i*width*3, Scanlines[height-i-1], width*3);
|
||||
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
Image->Width = width;
|
||||
Image->Height = height;
|
||||
Image->Format = FIMG_BGR24;
|
||||
Image->Data = OutData;
|
||||
return OutData;
|
||||
}
|
||||
|
||||
uint8_t * ReadTGA(Image_t * Image, const uint8_t * InData, size_t FileSize){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
read_bmp.c - Copyright (c) 2011-2012 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 <stdint.h>
|
||||
#include <string.h>
|
||||
#include "read_bmp.h"
|
||||
|
||||
#define BI_RGB 0
|
||||
#define BI_RLE8 1
|
||||
|
||||
#ifndef read_int32
|
||||
#define read_uint32(x) (unsigned)(((x)[0]<<(8*0)) | ((x)[1]<<(8*1)) | ((x)[2]<<(8*2)) | ((x)[3]<<(8*3)))
|
||||
#define read_uint16(x) (unsigned)(((x)[0]<<(8*0)) | ((x)[1]<<(8*1)))
|
||||
#endif
|
||||
|
||||
#ifndef __restrict
|
||||
#define __restrict
|
||||
#endif
|
||||
|
||||
int bmp_read_header(bmpheader_t * BMPHeader, const uint8_t * Buffer, size_t FileSize){
|
||||
if(FileSize < 54) return 0;
|
||||
BMPHeader->bfType = read_uint16(Buffer);
|
||||
BMPHeader->bfSize = read_uint32(Buffer+2);
|
||||
BMPHeader->bfReserved1 = read_uint16(Buffer+6);
|
||||
BMPHeader->bfReserved2 = read_uint16(Buffer+8);
|
||||
BMPHeader->bfOffBits = read_uint32(Buffer+10);
|
||||
|
||||
BMPHeader->biSize = read_uint32(Buffer+14);
|
||||
BMPHeader->biWidth = read_uint32(Buffer+18);
|
||||
BMPHeader->biHeight = read_uint32(Buffer+22);
|
||||
BMPHeader->biPlanes = read_uint16(Buffer+26);
|
||||
BMPHeader->biBitCount = read_uint16(Buffer+28);
|
||||
BMPHeader->biCompression = read_uint32(Buffer+30);
|
||||
BMPHeader->biSizeImage = read_uint32(Buffer+34);
|
||||
BMPHeader->biXPelsPerMeter = read_uint32(Buffer+38);
|
||||
BMPHeader->biYPelsPerMeter = read_uint32(Buffer+42);
|
||||
BMPHeader->biClrUsed = read_uint32(Buffer+46);
|
||||
BMPHeader->biClrImportant = read_uint32(Buffer+50);
|
||||
|
||||
BMPHeader->CompressedSize = FileSize - BMPHeader->bfOffBits;
|
||||
BMPHeader->DecompressedSize = BMPHeader->biWidth * BMPHeader->biHeight * 3;
|
||||
|
||||
if(BMPHeader->bfType != 0x4D42 ||
|
||||
BMPHeader->bfSize != FileSize ||
|
||||
BMPHeader->bfReserved1 != 0 || BMPHeader->bfReserved2 != 0 ||
|
||||
BMPHeader->biSize != 40 ||
|
||||
BMPHeader->biWidth == 0 || BMPHeader->biWidth > 4096 || /*< Includes negative check */
|
||||
BMPHeader->biHeight == 0 || BMPHeader->biHeight > 4096 || /*< by treating as unsigned */
|
||||
BMPHeader->biPlanes != 1 ||
|
||||
(BMPHeader->biBitCount != 24 &&
|
||||
(BMPHeader->biBitCount != 8 || FileSize < 1078 /* We need room for the color palette */)) ||
|
||||
(BMPHeader->biCompression != BI_RGB &&
|
||||
(BMPHeader->biCompression != BI_RLE8 || BMPHeader->biBitCount > 8)) ||
|
||||
BMPHeader->bfOffBits >= FileSize ||
|
||||
(BMPHeader->biCompression == BI_RGB &&
|
||||
((BMPHeader->biBitCount == 24 && BMPHeader->CompressedSize < BMPHeader->DecompressedSize) ||
|
||||
(BMPHeader->biBitCount == 8 && BMPHeader->CompressedSize < BMPHeader->DecompressedSize/3 +
|
||||
BMPHeader->biHeight*(BMPHeader->biWidth%4) /* Account for padding in 8-bit BMPs */)))
|
||||
) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int bmp_read_data(bmpheader_t * BMPHeader, const uint8_t *__restrict InBuffer, uint8_t *__restrict OutBuffer){
|
||||
if(BMPHeader->biBitCount == 24 && BMPHeader->biCompression == BI_RGB){
|
||||
memcpy(OutBuffer, InBuffer+BMPHeader->bfOffBits, BMPHeader->DecompressedSize);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(BMPHeader->biBitCount == 8){
|
||||
const uint8_t *__restrict Palette = InBuffer + 54;
|
||||
InBuffer += BMPHeader->bfOffBits;
|
||||
|
||||
if(BMPHeader->biCompression == BI_RGB){
|
||||
unsigned y, x;
|
||||
unsigned padding = BMPHeader->biWidth % 4;
|
||||
for(y=0; y<BMPHeader->biHeight; y++){
|
||||
for(x=0; x<BMPHeader->biWidth; x++){
|
||||
unsigned index = 4*(*InBuffer++);
|
||||
*OutBuffer++ = Palette[index];
|
||||
*OutBuffer++ = Palette[index+1];
|
||||
*OutBuffer++ = Palette[index+2];
|
||||
}
|
||||
InBuffer += padding;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(BMPHeader->biCompression == BI_RLE8){
|
||||
const uint8_t *__restrict const srcend = InBuffer+BMPHeader->CompressedSize;
|
||||
uint8_t *__restrict const destend = OutBuffer+BMPHeader->DecompressedSize;
|
||||
|
||||
while((unsigned)(srcend-InBuffer) >= 2){
|
||||
unsigned i;
|
||||
const unsigned command = *InBuffer++;
|
||||
const unsigned value = *InBuffer++;
|
||||
|
||||
if(command == 0){
|
||||
if(value == 0) continue; /* End of scanline reminder */
|
||||
if(value == 1) return 1; /* End of bitmap reminder */
|
||||
if(value == 2) return 0; /* Delta, used for ICO/CUR masks; wrong kind of bitmap */
|
||||
|
||||
/* Absolute copy */
|
||||
if(value > (unsigned)(srcend-InBuffer) || value*3 > (unsigned)(destend-OutBuffer)) break;
|
||||
for(i=0; i<value; i++){
|
||||
unsigned index = 4*(*InBuffer++);
|
||||
*OutBuffer++ = Palette[index];
|
||||
*OutBuffer++ = Palette[index+1];
|
||||
*OutBuffer++ = Palette[index+2];
|
||||
}
|
||||
if(value%2 && InBuffer != srcend) InBuffer++; /* Padding */
|
||||
}else{
|
||||
/* Run */
|
||||
unsigned index = 4*value;
|
||||
if(command > (unsigned)(destend-OutBuffer)) break;
|
||||
for(i=0; i<command; i++){
|
||||
*OutBuffer++ = Palette[index];
|
||||
*OutBuffer++ = Palette[index+1];
|
||||
*OutBuffer++ = Palette[index+2];
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
51
Libraries/FileHandler/bmp/read_bmp.h
Normal file
51
Libraries/FileHandler/bmp/read_bmp.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
read_bmp.h - Copyright (c) 2011-2012 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.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* BITMAPFILEHEADER */
|
||||
uint16_t bfType;
|
||||
uint32_t bfSize;
|
||||
uint16_t bfReserved1;
|
||||
uint16_t bfReserved2;
|
||||
uint32_t bfOffBits;
|
||||
/* BITMAPINFOHEADER */
|
||||
uint32_t biSize;
|
||||
uint32_t biWidth;
|
||||
uint32_t biHeight;
|
||||
uint16_t biPlanes;
|
||||
uint16_t biBitCount;
|
||||
uint32_t biCompression;
|
||||
uint32_t biSizeImage;
|
||||
uint32_t biXPelsPerMeter;
|
||||
uint32_t biYPelsPerMeter;
|
||||
uint32_t biClrUsed;
|
||||
uint32_t biClrImportant;
|
||||
|
||||
size_t CompressedSize;
|
||||
size_t DecompressedSize;
|
||||
} bmpheader_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int bmp_read_header(bmpheader_t * BMPHeader, const uint8_t * Buffer, size_t FileSize);
|
||||
int bmp_read_data(bmpheader_t * BMPHeader, const uint8_t * InData, uint8_t * OutData);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -18,7 +18,7 @@
|
|||
#include <string.h>
|
||||
#include "cst.h"
|
||||
|
||||
unsigned cst_count_strings(const char * Buffer, size_t FileSize){
|
||||
static unsigned cst_count_strings(const char * Buffer, size_t FileSize){
|
||||
unsigned count = 0;
|
||||
int instring = 0;
|
||||
while(FileSize--){
|
||||
|
|
|
@ -2,13 +2,8 @@ cmake_minimum_required(VERSION 2.6)
|
|||
project(iff)
|
||||
|
||||
set(IFF_SOURCES
|
||||
bhav.c
|
||||
stbl.c
|
||||
sprite.c
|
||||
chunks.c
|
||||
iff.c
|
||||
)
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/Libraries/FileHandler/libpng)
|
||||
|
||||
add_executable(iffexport iffexport.c ${IFF_SOURCES})
|
|
@ -1,53 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "iff.h"
|
||||
|
||||
int iff_parse_bhav(IFFChunk * ChunkInfo, const uint8_t * Buffer)
|
||||
{
|
||||
IFF_TREETABLE * TreeTableData;
|
||||
if(ChunkInfo->Size < 12)
|
||||
return 0;
|
||||
ChunkInfo->FormattedData = malloc(17);
|
||||
if(ChunkInfo->FormattedData == NULL)
|
||||
return 0;
|
||||
memset(ChunkInfo->FormattedData, 0, 17);
|
||||
TreeTableData = (IFF_TREETABLE *)ChunkInfo->FormattedData;
|
||||
|
||||
memcpy (TreeTableData, Buffer, 2);
|
||||
|
||||
int nodeCount = 0;
|
||||
if (TreeTableData->StreamVersion == 0x8003)
|
||||
{
|
||||
memcpy (((char *)TreeTableData)+2, Buffer+2, 7);
|
||||
memcpy (&nodeCount, Buffer+9, 4);
|
||||
}
|
||||
else if ((TreeTableData->StreamVersion == 0x8000) || (TreeTableData->StreamVersion == 0x8001) || (TreeTableData->StreamVersion == 0x8002))
|
||||
{
|
||||
memcpy (&nodeCount, Buffer+2, 2);
|
||||
memcpy (((char *)TreeTableData)+2, Buffer+4, 3);
|
||||
memcpy (((char *)TreeTableData)+5, Buffer+8, 4);
|
||||
switch (TreeTableData->StreamVersion)
|
||||
{
|
||||
case 0x8002:
|
||||
break;
|
||||
case 0x8001:
|
||||
if (TreeTableData->NumParams > 4) { TreeTableData->NumParams = 4; }
|
||||
if (TreeTableData->NumLocals > 4) { TreeTableData->NumLocals = 4; }
|
||||
break;
|
||||
case 0x8000:
|
||||
TreeTableData->NumParams = 4;
|
||||
TreeTableData->NumLocals = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Node Count: %d", nodeCount);
|
||||
TreeTableData->NodesBegin = (IFF_TREETABLENODE *)malloc(12 * nodeCount);
|
||||
TreeTableData->NodesEnd = TreeTableData->NodesBegin + nodeCount;
|
||||
memcpy(TreeTableData->NodesBegin, Buffer+((TreeTableData->StreamVersion == 0x8003) ? 13 : 12), 12 * nodeCount);
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/* BHAV chunk */
|
||||
|
||||
typedef struct TreeNodeParams
|
||||
{
|
||||
uint16_t Param0;
|
||||
uint16_t Param1;
|
||||
uint16_t Param2;
|
||||
uint16_t Param3;
|
||||
} IFF_TRETABLENODEPARAMS;
|
||||
|
||||
typedef struct TreeTableNode
|
||||
{
|
||||
uint16_t PrimitiveNumber;
|
||||
uint8_t TransitionTrue;
|
||||
uint8_t TransitionFalse;
|
||||
IFF_TRETABLENODEPARAMS Parameters;
|
||||
} IFF_TREETABLENODE;
|
||||
|
||||
typedef struct TreeTable
|
||||
{
|
||||
uint16_t StreamVersion;
|
||||
uint8_t Type;
|
||||
uint8_t NumParams;
|
||||
uint8_t NumLocals;
|
||||
uint32_t TreeVersion;
|
||||
|
||||
IFF_TREETABLENODE *NodesBegin;
|
||||
IFF_TREETABLENODE *NodesEnd;
|
||||
} IFF_TREETABLE;
|
|
@ -19,19 +19,242 @@
|
|||
#include <stdint.h>
|
||||
#include "iff.h"
|
||||
|
||||
int iff_parse_chunk(IFFChunk * ChunkInfo, const uint8_t * Buffer, IFFFile *SourceFile){
|
||||
int iff_parse_chunk(IFFChunk * ChunkInfo, const uint8_t * Buffer){
|
||||
if( !strcmp(ChunkInfo->Type, "STR#") ||
|
||||
!strcmp(ChunkInfo->Type, "CTSS") ||
|
||||
!strcmp(ChunkInfo->Type, "FAMs") ||
|
||||
!strcmp(ChunkInfo->Type, "TTAs") )
|
||||
!strcmp(ChunkInfo->Type, "TTAs") )
|
||||
return iff_parse_str(ChunkInfo, Buffer);
|
||||
else if (!strcmp(ChunkInfo->Type, "BHAV"))
|
||||
return iff_parse_bhav(ChunkInfo, Buffer);
|
||||
else if (!strcmp(ChunkInfo->Type, "SPR#") || !strcmp(ChunkInfo->Type, "SPR2"))
|
||||
return iff_parse_sprite(ChunkInfo, Buffer, SourceFile);
|
||||
else if (!strcmp(ChunkInfo->Type, "PALT"))
|
||||
return iff_parse_pmap(ChunkInfo, Buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iff_parse_str(IFFChunk * ChunkInfo, const uint8_t * Buffer){
|
||||
/* No bounds checking yet */
|
||||
IFF_STR * StringData;
|
||||
unsigned Size = ChunkInfo->Size - 76;
|
||||
if(Size < 2)
|
||||
return 0;
|
||||
ChunkInfo->FormattedData = malloc(sizeof(IFF_STR));
|
||||
if(ChunkInfo->FormattedData == NULL)
|
||||
return 0;
|
||||
memset(ChunkInfo->FormattedData, 0, sizeof(IFF_STR));
|
||||
StringData = (IFF_STR*) ChunkInfo->FormattedData;
|
||||
StringData->Format = read_int16le(Buffer);
|
||||
Buffer += 2;
|
||||
if(Size-2 < 2) /* TSO allows this; as seen in the animations chunk in personglobals.iff */
|
||||
return 1;
|
||||
|
||||
switch(StringData->Format){
|
||||
|
||||
case 0: {
|
||||
unsigned i;
|
||||
IFFStringPairNode * PrevPair = NULL;
|
||||
|
||||
StringData->LanguageSets[0].PairCount = read_uint16le(Buffer);
|
||||
Buffer += 2;
|
||||
if(StringData->LanguageSets[0].PairCount == 0)
|
||||
return 1;
|
||||
|
||||
for(i=0; i<StringData->LanguageSets[0].PairCount; i++){
|
||||
IFFStringPairNode * CurrentPair;
|
||||
unsigned length;
|
||||
CurrentPair = malloc(sizeof(IFFStringPairNode));
|
||||
memset(CurrentPair, 0, sizeof(IFFStringPairNode));
|
||||
|
||||
if(i == 0) StringData->LanguageSets[0].FirstPair = CurrentPair;
|
||||
else PrevPair->NextPair = CurrentPair;
|
||||
CurrentPair->PrevPair = PrevPair;
|
||||
|
||||
/* Key */
|
||||
length = read_uint8le(Buffer);
|
||||
if(length != 0){
|
||||
CurrentPair->Pair.Key = malloc(length+1);
|
||||
memcpy(CurrentPair->Pair.Key, Buffer+1, length);
|
||||
CurrentPair->Pair.Key[length] = 0x00;
|
||||
}
|
||||
Buffer += length+1;
|
||||
|
||||
PrevPair = CurrentPair;
|
||||
}
|
||||
StringData->LanguageSets[0].LastPair = PrevPair;
|
||||
} return 1;
|
||||
|
||||
case -1: {
|
||||
unsigned i;
|
||||
IFFStringPairNode * PrevPair = NULL;
|
||||
|
||||
StringData->LanguageSets[0].PairCount = read_uint16le(Buffer);
|
||||
Buffer += 2;
|
||||
if(StringData->LanguageSets[0].PairCount == 0)
|
||||
return 1;
|
||||
|
||||
for(i=0; i<StringData->LanguageSets[0].PairCount; i++){
|
||||
IFFStringPairNode * CurrentPair;
|
||||
unsigned length;
|
||||
CurrentPair = malloc(sizeof(IFFStringPairNode));
|
||||
memset(CurrentPair, 0, sizeof(IFFStringPairNode));
|
||||
|
||||
if(i == 0) StringData->LanguageSets[0].FirstPair = CurrentPair;
|
||||
else PrevPair->NextPair = CurrentPair;
|
||||
CurrentPair->PrevPair = PrevPair;
|
||||
|
||||
/* Key */
|
||||
length = strlen((char*)Buffer);
|
||||
if(length != 0){
|
||||
CurrentPair->Pair.Key = malloc(length+1);
|
||||
strcpy(CurrentPair->Pair.Key, (char*)Buffer);
|
||||
}
|
||||
Buffer += length+1;
|
||||
|
||||
PrevPair = CurrentPair;
|
||||
}
|
||||
StringData->LanguageSets[0].LastPair = PrevPair;
|
||||
} return 1;
|
||||
|
||||
case -2: {
|
||||
unsigned i;
|
||||
IFFStringPairNode * PrevPair = NULL;
|
||||
|
||||
StringData->LanguageSets[0].PairCount = read_uint16le(Buffer);
|
||||
Buffer += 2;
|
||||
if(StringData->LanguageSets[0].PairCount == 0)
|
||||
return 1;
|
||||
|
||||
for(i=0; i<StringData->LanguageSets[0].PairCount; i++){
|
||||
IFFStringPairNode * CurrentPair;
|
||||
unsigned length;
|
||||
CurrentPair = malloc(sizeof(IFFStringPairNode));
|
||||
memset(CurrentPair, 0, sizeof(IFFStringPairNode));
|
||||
|
||||
if(i == 0) StringData->LanguageSets[0].FirstPair = CurrentPair;
|
||||
else PrevPair->NextPair = CurrentPair;
|
||||
CurrentPair->PrevPair = PrevPair;
|
||||
|
||||
/* Key */
|
||||
length = strlen((char*)Buffer);
|
||||
if(length != 0){
|
||||
CurrentPair->Pair.Key = malloc(length+1);
|
||||
strcpy(CurrentPair->Pair.Key, (char*)Buffer);
|
||||
}
|
||||
Buffer += length+1;
|
||||
|
||||
/* Value */
|
||||
length = strlen((char*)Buffer);
|
||||
if(length != 0){
|
||||
CurrentPair->Pair.Value = malloc(length+1);
|
||||
strcpy(CurrentPair->Pair.Value, (char*)Buffer);
|
||||
}
|
||||
Buffer += length+1;
|
||||
|
||||
PrevPair = CurrentPair;
|
||||
}
|
||||
StringData->LanguageSets[0].LastPair = PrevPair;
|
||||
} return 1;
|
||||
|
||||
case -3: {
|
||||
unsigned i, TotalPairCount;
|
||||
|
||||
TotalPairCount = read_uint16le(Buffer);
|
||||
Buffer += 2;
|
||||
if(TotalPairCount == 0)
|
||||
return 1;
|
||||
|
||||
for(i=0; i<TotalPairCount; i++){
|
||||
IFFStringPairNode * Pair;
|
||||
unsigned length;
|
||||
Pair = malloc(sizeof(IFFStringPairNode));
|
||||
memset(Pair, 0, sizeof(IFFStringPairNode));
|
||||
Pair->Pair.LanguageSet = read_uint8le(Buffer) - 1;
|
||||
Buffer++;
|
||||
|
||||
/* Key */
|
||||
length = strlen((char*)Buffer);
|
||||
if(length != 0){
|
||||
Pair->Pair.Key = malloc(length+1);
|
||||
strcpy(Pair->Pair.Key, (char*)Buffer);
|
||||
}
|
||||
Buffer += length+1;
|
||||
|
||||
/* Value */
|
||||
length = strlen((char*)Buffer);
|
||||
if(length != 0){
|
||||
Pair->Pair.Value = malloc(length+1);
|
||||
strcpy(Pair->Pair.Value, (char*)Buffer);
|
||||
}
|
||||
Buffer += length+1;
|
||||
|
||||
/* Add the pair to the end of the associated language set */
|
||||
Pair->PrevPair = StringData->LanguageSets[0].LastPair;
|
||||
if(StringData->LanguageSets[0].PairCount == 0)
|
||||
StringData->LanguageSets[0].FirstPair = Pair;
|
||||
else
|
||||
StringData->LanguageSets[0].LastPair->NextPair = Pair;
|
||||
StringData->LanguageSets[0].PairCount++;
|
||||
StringData->LanguageSets[0].LastPair = Pair;
|
||||
}
|
||||
} return 1;
|
||||
|
||||
case -4: {
|
||||
unsigned LanguageSet;
|
||||
unsigned LanguageSetCount = read_uint8le(Buffer);
|
||||
Buffer++;
|
||||
if(LanguageSetCount > 20) LanguageSetCount = 20;
|
||||
|
||||
for(LanguageSet=0; LanguageSet<LanguageSetCount; LanguageSet++){
|
||||
unsigned i;
|
||||
IFFStringPairNode * PrevPair = NULL;
|
||||
|
||||
StringData->LanguageSets[LanguageSet].PairCount = read_uint16le(Buffer);
|
||||
Buffer += 2;
|
||||
if(StringData->LanguageSets[LanguageSet].PairCount == 0)
|
||||
continue;
|
||||
|
||||
for(i=0; i<StringData->LanguageSets[LanguageSet].PairCount; i++){
|
||||
IFFStringPairNode * CurrentPair;
|
||||
unsigned length;
|
||||
CurrentPair = malloc(sizeof(IFFStringPairNode));
|
||||
memset(CurrentPair, 0, sizeof(IFFStringPairNode));
|
||||
|
||||
if(i == 0) StringData->LanguageSets[LanguageSet].FirstPair = CurrentPair;
|
||||
else PrevPair->NextPair = CurrentPair;
|
||||
CurrentPair->PrevPair = PrevPair;
|
||||
|
||||
Buffer++; /* Skip over LanguageSet */
|
||||
|
||||
/* Key */
|
||||
length = read_uint8le(Buffer);
|
||||
if(length > 127){
|
||||
length = (length & 127) | (read_uint8le(Buffer+1) << 7);
|
||||
Buffer++;
|
||||
}
|
||||
if(length != 0){
|
||||
CurrentPair->Pair.Key = malloc(length+1);
|
||||
memcpy(CurrentPair->Pair.Key, Buffer+1, length);
|
||||
CurrentPair->Pair.Key[length] = 0x00;
|
||||
}
|
||||
Buffer += length + 1;
|
||||
|
||||
/* Value */
|
||||
length = read_uint8le(Buffer);
|
||||
if(length > 127){
|
||||
length = (length & 127) | (read_uint8le(Buffer+1) << 7);
|
||||
Buffer++;
|
||||
}
|
||||
if(length != 0){
|
||||
CurrentPair->Pair.Value = malloc(length+1);
|
||||
memcpy(CurrentPair->Pair.Value, Buffer+1, length);
|
||||
CurrentPair->Pair.Value[length] = 0x00;
|
||||
}
|
||||
Buffer += length + 1;
|
||||
|
||||
PrevPair = CurrentPair;
|
||||
}
|
||||
StringData->LanguageSets[LanguageSet].LastPair = PrevPair;
|
||||
}
|
||||
} return 1;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iff_parse_rsmp(IFFChunk * ChunkInfo, const uint8_t * Buffer, unsigned IFFSize){
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "iff.h"
|
||||
|
||||
#ifndef __inline
|
||||
|
@ -37,11 +36,10 @@ IFFFile * iff_create()
|
|||
return ptr;
|
||||
}
|
||||
|
||||
int iff_read_header(IFFFile * IFFFileInfo, const uint8_t * Buffer, unsigned FileSize, char *FileName)
|
||||
int iff_read_header(IFFFile * IFFFileInfo, const uint8_t * Buffer, unsigned FileSize)
|
||||
{
|
||||
unsigned offset;
|
||||
|
||||
|
||||
if(!FileSize) FileSize = ~0;
|
||||
else if(FileSize < 64)
|
||||
return 0;
|
||||
|
@ -49,8 +47,6 @@ int iff_read_header(IFFFile * IFFFileInfo, const uint8_t * Buffer, unsigned File
|
|||
if(memcmp(Buffer, Header_IFF, 60))
|
||||
return 0;
|
||||
memcpy(IFFFileInfo->Header, Buffer, 60);
|
||||
|
||||
IFFFileInfo->FileName = FileName;
|
||||
|
||||
offset = read_uint32be(Buffer+60);
|
||||
if(offset > FileSize - 28)
|
||||
|
@ -105,8 +101,7 @@ IFFChunkNode * iff_add_chunk(IFFFile * IFFFileInfo, int Position)
|
|||
node->NextChunk = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
IFFFileInfo->ChunkCount++;
|
||||
return ptr;
|
||||
}
|
||||
|
@ -152,20 +147,4 @@ int iff_enumerate_chunks(IFFFile * IFFFileInfo, const uint8_t * Buffer, unsigned
|
|||
BufferSize -= chunk->Chunk.Size;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
IFFChunk *iff_find_first_chunk(IFFFile *IFFFileInfo, const char *type, uint16_t id)
|
||||
{
|
||||
IFFChunkNode *currentNode = IFFFileInfo->FirstChunk;
|
||||
do
|
||||
{
|
||||
if (type == NULL || !memcmp(type, currentNode->Chunk.Type, 4) &&
|
||||
(id == 0 || id == currentNode->Chunk.ChunkID))
|
||||
return ¤tNode->Chunk;
|
||||
|
||||
currentNode = currentNode->NextChunk;
|
||||
}
|
||||
while (currentNode != IFFFileInfo->LastChunk && currentNode != NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
|
@ -13,9 +13,6 @@
|
|||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include "stbl.h"
|
||||
#include "bhav.h"
|
||||
#include "sprite.h"
|
||||
|
||||
#ifndef read_uint32be
|
||||
#define read_int32be(x) (signed)(((x)[0]<<(8*3)) | ((x)[1]<<(8*2)) | ((x)[2]<<(8*1)) | ((x)[3]<<(8*0)))
|
||||
|
@ -61,8 +58,6 @@ typedef struct IFFChunkNode_struct
|
|||
typedef struct IFFFile_struct
|
||||
{
|
||||
uint8_t Header[64];
|
||||
|
||||
char *FileName;
|
||||
|
||||
uint32_t ChunkCount;
|
||||
IFFChunkNode * FirstChunk;
|
||||
|
@ -76,6 +71,59 @@ static const uint8_t Header_IFF[] = "IFF FILE 2.5:TYPE FOLLOWED BY SIZE\0 JAMIE
|
|||
** IFF chunk structs
|
||||
*/
|
||||
|
||||
/* STR# chunk */
|
||||
|
||||
enum IFFLanguage {
|
||||
IFFLANG_DEFAULT = 0,
|
||||
IFFLANG_EN_US = 1,
|
||||
IFFLANG_EN_INTERNATIONAL = 2,
|
||||
IFFLANG_FRENCH = 3,
|
||||
IFFLANG_GERMAN = 4,
|
||||
IFFLANG_ITALIAN = 5,
|
||||
IFFLANG_SPANISH = 6,
|
||||
IFFLANG_DUTCH = 7,
|
||||
IFFLANG_DANISH = 8,
|
||||
IFFLANG_SWEDISH = 9,
|
||||
IFFLANG_NORWEGIAN = 10,
|
||||
IFFLANG_FINNISH = 11,
|
||||
IFFLANG_HEBREW = 12,
|
||||
IFFLANG_RUSSIAN = 13,
|
||||
IFFLANG_PORTUGUESE = 14,
|
||||
IFFLANG_JAPANESE = 15,
|
||||
IFFLANG_POLISH = 16,
|
||||
IFFLANG_CHINESE_SIMPLIFIED = 17,
|
||||
IFFLANG_CHINESE_TRADITIONAL = 18,
|
||||
IFFLANG_THAI = 19,
|
||||
IFFLANG_KOREAN = 20
|
||||
};
|
||||
|
||||
typedef struct IFFStringPair_struct
|
||||
{
|
||||
uint8_t LanguageSet;
|
||||
char * Key;
|
||||
char * Value;
|
||||
} IFFStringPair;
|
||||
|
||||
typedef struct IFFStringPairNode_struct
|
||||
{
|
||||
IFFStringPair Pair;
|
||||
struct IFFStringPairNode_struct * PrevPair;
|
||||
struct IFFStringPairNode_struct * NextPair;
|
||||
} IFFStringPairNode;
|
||||
|
||||
typedef struct IFFLanguageSet_struct
|
||||
{
|
||||
uint16_t PairCount;
|
||||
IFFStringPairNode * FirstPair;
|
||||
IFFStringPairNode * LastPair;
|
||||
} IFFLanguageSet;
|
||||
|
||||
typedef struct IFF_STR_struct
|
||||
{
|
||||
int16_t Format;
|
||||
IFFLanguageSet LanguageSets[20];
|
||||
} IFF_STR;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -85,7 +133,7 @@ extern "C" {
|
|||
*/
|
||||
|
||||
IFFFile * iff_create();
|
||||
int iff_read_header(IFFFile * IFFFileInfo, const uint8_t * Buffer, unsigned FileSize, char *FileName);
|
||||
int iff_read_header(IFFFile * IFFFileInfo, const uint8_t * Buffer, unsigned FileSize);
|
||||
|
||||
IFFChunkNode * iff_add_chunk(IFFFile * IFFFileInfo, int Position);
|
||||
int iff_read_chunk(IFFChunk * ChunkInfo, const uint8_t * Buffer, unsigned MaxChunkSize);
|
||||
|
@ -99,12 +147,9 @@ void iff_delete(IFFFile * IFFFileInfo);
|
|||
** IFF chunk functions
|
||||
*/
|
||||
|
||||
IFFChunk *iff_find_first_chunk(IFFFile *IFFFileInfo, const char *type, uint16_t id);
|
||||
int iff_parse_rsmp(IFFChunk * ChunkInfo, const uint8_t * Buffer, unsigned IFFSize);
|
||||
int iff_parse_chunk(IFFChunk * ChunkInfo, const uint8_t * Buffer, IFFFile *SourceFile);
|
||||
int iff_parse_chunk(IFFChunk * ChunkInfo, const uint8_t * Buffer);
|
||||
int iff_parse_str(IFFChunk * ChunkInfo, const uint8_t * Buffer);
|
||||
int iff_parse_bhav(IFFChunk * ChunkInfo, const uint8_t * Buffer);
|
||||
int iff_parse_sprite(IFFChunk * ChunkInfo, const uint8_t * Buffer, IFFFile *SourceFile);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ int main(int argc, char *argv[]){
|
|||
printf("%sMemory for this file could not be allocated.", "iffexport: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(!iff_read_header(IFFFileInfo, IFFData, FileSize, InFile)){
|
||||
if(!iff_read_header(IFFFileInfo, IFFData, FileSize)){
|
||||
printf("%sNot a valid IFF file.", "iffexport: error: ");
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -1,571 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <png.h>
|
||||
#include "iff.h"
|
||||
|
||||
|
||||
int sprite_frame_set_texel(IFFSpriteFrame *frame, uint32_t column, uint32_t row, IFFSpriteColor color);
|
||||
int sprite_frame_set_texel_alpha(IFFSpriteFrame *frame, uint32_t column, uint32_t row, IFFSpriteColor color, uint8_t alpha);
|
||||
int sprite_frame_export_as_targa(IFFSpriteFrame *frame, const char *filename);
|
||||
int sprite_frame_export_as_png(IFFSpriteFrame *frame, const char *filename);
|
||||
|
||||
int iff_parse_sprite(IFFChunk * ChunkInfo, const uint8_t * pBuffer, IFFFile *SourceFile)
|
||||
{
|
||||
uint32_t frameCount = 0;
|
||||
uint32_t paletteID = 0;
|
||||
|
||||
uint32_t *offsets;
|
||||
|
||||
IFFChunk *PaletteMap;
|
||||
IFFPMap *PMap;
|
||||
|
||||
IFFSprite *Sprite;
|
||||
IFFSpriteFrame *Frame;
|
||||
|
||||
uint32_t i = 0;
|
||||
uint32_t l = 0;
|
||||
uint32_t j = 0;
|
||||
|
||||
uint32_t iRow = 0;
|
||||
uint32_t cPixelsSet = 0;
|
||||
uint8_t bQuit = 0;
|
||||
|
||||
uint32_t cBytesReadInitial = 0;
|
||||
|
||||
uint32_t cBytesRead = 0;
|
||||
uint16_t mRowHeader = 0;
|
||||
uint16_t mColumnHeader = 0;
|
||||
uint16_t eRowControlCode = 0;
|
||||
uint16_t eColumnControlCode = 0;
|
||||
uint16_t cBytesInThisRow = 0;
|
||||
uint16_t cPixelCount = 0; /* Per-control-code pixel count*/
|
||||
|
||||
uint8_t Z;
|
||||
|
||||
|
||||
#ifdef IFF2HTML
|
||||
char *outputPath;
|
||||
char *dummyName;
|
||||
char *folderName;
|
||||
#endif
|
||||
|
||||
uint32_t version = read_uint32le(pBuffer);
|
||||
pBuffer += 4;
|
||||
|
||||
if (version == 1001)
|
||||
{
|
||||
paletteID = read_uint32le(pBuffer);
|
||||
pBuffer += 4;
|
||||
frameCount = read_uint32le(pBuffer);
|
||||
pBuffer += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
frameCount = read_uint32le(pBuffer);
|
||||
pBuffer += 4;
|
||||
paletteID = read_uint32le(pBuffer);
|
||||
pBuffer += 4;
|
||||
}
|
||||
|
||||
|
||||
/* Try to load the appropriate palette */
|
||||
PaletteMap = iff_find_first_chunk(SourceFile, "PALT", paletteID);
|
||||
/* If that didn't work, try loading any palette from the IFF file */
|
||||
/* Some sprites in IFFs containing only one PALT don't bother to specify a correct PALT ID */
|
||||
if (PaletteMap == NULL)
|
||||
{
|
||||
printf("ERR");
|
||||
fflush(stdout);
|
||||
|
||||
PaletteMap = iff_find_first_chunk(SourceFile, "PALT", 0);
|
||||
/* If there is no existing palette data, there can be no coherent image. */
|
||||
if (PaletteMap == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (PaletteMap->FormattedData == NULL)
|
||||
{
|
||||
printf("HERE");
|
||||
fflush(stdout);
|
||||
iff_parse_pmap(PaletteMap, PaletteMap->Data);
|
||||
}
|
||||
PMap = (IFFPMap *)PaletteMap->FormattedData;
|
||||
|
||||
offsets = (uint32_t *)malloc(sizeof(uint32_t) * frameCount);
|
||||
memset(offsets, 0, sizeof(uint32_t) * frameCount);
|
||||
|
||||
if (version == 1000)
|
||||
{
|
||||
for (i = 0; i < frameCount; i++)
|
||||
{
|
||||
offsets[i] = read_uint32le(pBuffer);
|
||||
pBuffer += 4;
|
||||
}
|
||||
}
|
||||
|
||||
Sprite = (IFFSprite *)malloc(sizeof(IFFSprite));
|
||||
Sprite->FrameCount = frameCount;
|
||||
Sprite->Frames = (IFFSpriteFrame **)malloc(sizeof (IFFSpriteFrame *) * frameCount);
|
||||
|
||||
#ifdef IFF2HTML
|
||||
Sprite->Version = version;
|
||||
#endif
|
||||
|
||||
for (l = 0; l < frameCount; l++)
|
||||
{
|
||||
Frame = (IFFSpriteFrame *)malloc(sizeof(IFFSpriteFrame));
|
||||
|
||||
/* Version 1000 specifies offsets for each frame of image data */
|
||||
if (version == 1000)
|
||||
pBuffer = ChunkInfo->Data + offsets[l];
|
||||
|
||||
/* There are two "+=" statements here for clarity. That is optimized away by a decent compiler */
|
||||
if (version == 1001)
|
||||
{
|
||||
pBuffer += 4; /* Version */
|
||||
pBuffer += 4; /* Size */
|
||||
}
|
||||
if (version != 1000 && version != 1001) /* for SPR# resources */
|
||||
{
|
||||
Frame->YLocation = read_uint16le(pBuffer);
|
||||
pBuffer += 2;
|
||||
Frame->YLocation = read_uint16le(pBuffer);
|
||||
pBuffer += 2;
|
||||
Frame->Height = read_uint16le(pBuffer);
|
||||
pBuffer += 2;
|
||||
Frame->Width = read_uint16le(pBuffer);
|
||||
pBuffer += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
Frame->Width = read_uint16le(pBuffer);
|
||||
pBuffer += 2;
|
||||
Frame->Height = read_uint16le(pBuffer);
|
||||
pBuffer += 2;
|
||||
}
|
||||
|
||||
Frame->Flag = read_uint16le(pBuffer);
|
||||
pBuffer += 2;
|
||||
|
||||
if (version == 1000 || version == 1001)
|
||||
{
|
||||
pBuffer += 2;
|
||||
Frame->PaletteID = read_uint16le(pBuffer); /* This is unused or the same as the master PALT ID */
|
||||
pBuffer += 2;
|
||||
Frame->TransparentPixel = PMap->Colors[read_uint16le(pBuffer)];
|
||||
pBuffer += 2;
|
||||
Frame->YLocation = read_uint16le(pBuffer);
|
||||
pBuffer += 2;
|
||||
Frame->XLocation = read_uint16le(pBuffer);
|
||||
pBuffer += 2;
|
||||
}
|
||||
|
||||
|
||||
if (Frame->PaletteID != 0xA3A3)
|
||||
{
|
||||
/* Try to load the appropriate palette */
|
||||
PaletteMap = iff_find_first_chunk(SourceFile, "PALT", Frame->PaletteID);
|
||||
/* If that didn't work, try loading any palette from the IFF file */
|
||||
/* Some sprites in IFFs containing only one PALT don't bother to specify a correct PALT ID */
|
||||
if (PaletteMap == NULL)
|
||||
{
|
||||
PaletteMap = iff_find_first_chunk(SourceFile, "PALT", 0);
|
||||
/* If there is no existing palette data, there can be no coherent image. */
|
||||
if (PaletteMap == NULL)
|
||||
return 0;
|
||||
}
|
||||
PMap = (IFFPMap *)PaletteMap->FormattedData;
|
||||
}
|
||||
|
||||
/* Now that we know the frame size, allocate the buffer to hold its texels */
|
||||
Frame->Texels = (IFFSpriteColor *)malloc(sizeof(IFFSpriteColor) * Frame->Width * Frame->Height);
|
||||
|
||||
|
||||
iRow = 0;
|
||||
cPixelsSet = 0;
|
||||
bQuit = 0;
|
||||
|
||||
cBytesReadInitial = 0;
|
||||
|
||||
cBytesRead = 0;
|
||||
mRowHeader = 0;
|
||||
mColumnHeader = 0;
|
||||
eRowControlCode = 0;
|
||||
eColumnControlCode = 0;
|
||||
cBytesInThisRow = 0;
|
||||
cPixelCount = 0;
|
||||
if (version == 1000 || version == 1001)
|
||||
{
|
||||
while (!bQuit)
|
||||
{
|
||||
mRowHeader = read_uint16le(pBuffer);
|
||||
eRowControlCode = mRowHeader>>13;
|
||||
cBytesInThisRow = mRowHeader&0x1FFF;
|
||||
pBuffer += 2;
|
||||
cBytesRead = 2; /* We just read the row header, which is included in cBytesInThisRow */
|
||||
cPixelsSet = 0;
|
||||
switch (eRowControlCode)
|
||||
{
|
||||
case 0:
|
||||
while (cBytesRead < cBytesInThisRow)
|
||||
{
|
||||
mColumnHeader = read_uint16le(pBuffer);
|
||||
eColumnControlCode = mColumnHeader>>13;
|
||||
cPixelCount = mColumnHeader&0x1FFF;
|
||||
pBuffer += 2;
|
||||
cBytesRead += 2;
|
||||
|
||||
|
||||
switch (eColumnControlCode)
|
||||
{
|
||||
case 1: /* Add cPixelCount ZRGB pixels */
|
||||
|
||||
for (i = 0; i < cPixelCount; i++)
|
||||
{
|
||||
Z = *pBuffer++; /* TODO: Use the z-buffer */
|
||||
sprite_frame_set_texel(Frame, cPixelsSet++, iRow, PMap->Colors[*pBuffer++]);
|
||||
cBytesRead += 2;
|
||||
}
|
||||
break;
|
||||
case 2: /* Add cPixelCount ZRGBA pixels */
|
||||
i = 0;
|
||||
for (i = 0; i < cPixelCount; i++)
|
||||
{
|
||||
Z = *pBuffer++; /* TODO: Use the z-buffer */
|
||||
sprite_frame_set_texel_alpha(Frame, cPixelsSet++, iRow, PMap->Colors[*pBuffer++], (uint8_t)*pBuffer++);/* Read and set the alpha channel's value */
|
||||
cBytesRead += 3;
|
||||
}
|
||||
/* Read EA's padding byte if the current position is not a multiple of 2 */
|
||||
if ((pBuffer - ChunkInfo->Data) % 2 == 1)
|
||||
{
|
||||
pBuffer++;
|
||||
cBytesRead++;
|
||||
}
|
||||
break;
|
||||
case 3: /* Add cPixelCount transparent pixels */
|
||||
for (i = 0; i < cPixelCount; i++)
|
||||
{
|
||||
sprite_frame_set_texel(Frame, cPixelsSet++, iRow, Frame->TransparentPixel);
|
||||
}
|
||||
break;
|
||||
case 6: /* Add cPixelCount RGB pixels */
|
||||
i = 0;
|
||||
for (i = 0; i < cPixelCount; i++)
|
||||
{
|
||||
sprite_frame_set_texel(Frame, cPixelsSet++, iRow, PMap->Colors[*pBuffer++]);
|
||||
cBytesRead++;
|
||||
}
|
||||
/* Read EA's padding byte if the current position is not a multiple of 2 */
|
||||
if ((pBuffer - ChunkInfo->Data) % 2 == 1)
|
||||
{
|
||||
pBuffer++;
|
||||
cBytesRead++;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
/* Error reading column code */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Set any extra (unread) texels in the current row to transparent */
|
||||
while (cPixelsSet < Frame->Width) { sprite_frame_set_texel(Frame, cPixelsSet++, iRow, Frame->TransparentPixel); }
|
||||
iRow++;
|
||||
|
||||
break;
|
||||
|
||||
case 4:
|
||||
for (i = 0; i < cBytesInThisRow; i++) /* cBytesInThisRow is used as the count of rows to fill with the transparent color in this case */
|
||||
{
|
||||
for (cPixelsSet = 0; cPixelsSet < Frame->Width; cPixelsSet++)
|
||||
{
|
||||
sprite_frame_set_texel(Frame, cPixelsSet++, iRow, Frame->TransparentPixel);
|
||||
}
|
||||
iRow++;
|
||||
}
|
||||
break;
|
||||
case 5: /* This means to stop reading */
|
||||
bQuit = 1;
|
||||
break;
|
||||
default:
|
||||
/* Error reading row code */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((uint32_t)(pBuffer - ChunkInfo->Data) == ChunkInfo->Size)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (bQuit == 0)
|
||||
{
|
||||
eRowControlCode = *pBuffer++;
|
||||
cBytesInThisRow = *pBuffer++;
|
||||
cBytesRead = 2;
|
||||
cPixelsSet = 0;
|
||||
switch (eRowControlCode)
|
||||
{
|
||||
case 4:
|
||||
for (cBytesInThisRow = 0; cBytesInThisRow < cBytesInThisRow;)
|
||||
{
|
||||
eColumnControlCode = *pBuffer++;
|
||||
cPixelCount = *pBuffer++;
|
||||
cBytesRead += 2;
|
||||
|
||||
switch (eColumnControlCode)
|
||||
{
|
||||
case 3:
|
||||
for (i = 0; i < cPixelCount; i++)
|
||||
{
|
||||
sprite_frame_set_texel(Frame, cPixelsSet++, iRow, PMap->Colors[*pBuffer++]);
|
||||
cBytesRead++;
|
||||
}
|
||||
|
||||
if ((pBuffer - ChunkInfo->Data) % 2 == 1)
|
||||
{
|
||||
pBuffer++;
|
||||
cBytesRead++;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (i = 0; i < cPixelCount; i++)
|
||||
{
|
||||
sprite_frame_set_texel(Frame, cPixelsSet++, iRow, PMap->Colors[*pBuffer++]);
|
||||
pBuffer++; /* Unused value */
|
||||
cBytesRead += 2;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
for (i = 0; i < cPixelCount; i++)
|
||||
{
|
||||
sprite_frame_set_texel(Frame, cPixelsSet++, iRow, Frame->TransparentPixel);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Error reading column code */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Set any extra (unread) texels in the current row to transparent */
|
||||
while (cPixelsSet < Frame->Width) { sprite_frame_set_texel(Frame, cPixelsSet++, iRow, Frame->TransparentPixel); }
|
||||
iRow++;
|
||||
break;
|
||||
case 9:
|
||||
for (i = 0; i < cBytesInThisRow; i++) /* cBytesInThisRow is used as the count of rows to fill with the transparent color in this case */
|
||||
{
|
||||
for (cPixelsSet = 0; cPixelsSet < Frame->Width; cPixelsSet++)
|
||||
{
|
||||
sprite_frame_set_texel(Frame, cPixelsSet++, iRow, Frame->TransparentPixel);
|
||||
}
|
||||
iRow++;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
bQuit = 1;
|
||||
printf("END");
|
||||
fflush(stdout);
|
||||
break;
|
||||
default:
|
||||
/* Error reading row code */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*if ((uint32_t)(pBuffer - ChunkInfo->Data) == ChunkInfo->Size)
|
||||
break; */
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < Frame->Height; i++) /* cBytesInThisRow is used as the count of rows to fill with the transparent color in this case */
|
||||
{
|
||||
for (j = 0; j < Frame->Width; j++)
|
||||
{
|
||||
if (sprite_are_colors_equal_rgb(Frame->Texels[i*Frame->Width+j], Frame->TransparentPixel))
|
||||
Frame->Texels[i*Frame->Width+j].A = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef IFF2HTML
|
||||
outputPath = (char *)malloc(sizeof(char) * 255);
|
||||
|
||||
folderName = (char *)malloc(sizeof(char) * 255);
|
||||
dummyName = (char *)malloc(sizeof(char) * 255);
|
||||
strcpy(folderName, SourceFile->FileName);
|
||||
*strchr(folderName, (int)'.') = '\0';
|
||||
sprintf(outputPath, "./%s/%s (%d) Frame %d.png", folderName, ChunkInfo->Label, ChunkInfo->ChunkID, l);
|
||||
/*printf(outputPath);
|
||||
fflush(stdout);*/
|
||||
sprite_frame_export_as_png (Frame, outputPath); /* The images export faster and look better as targa. This tells me I'm doing something wrong in the PNG exporter code */
|
||||
Sprite->Frames[l] = Frame;
|
||||
Sprite->Frames[l]->filePath = outputPath;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* By adding this to the ChunkInfo at the success point, we ensure that no corrupt or partial sprite appears ingame */
|
||||
ChunkInfo->FormattedData = Sprite;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* This function never returns zero because it is capable of producing logical output independent of the input's validity. */
|
||||
int sprite_are_colors_equal_rgb(IFFSpriteColor clr1, IFFSpriteColor clr2)
|
||||
{
|
||||
return clr1.R == clr2.R && clr1.G == clr2.G && clr1.B == clr2.B;
|
||||
}
|
||||
|
||||
/* This function never returns zero because it is capable of producing logical output independent of the input's validity. */
|
||||
int iff_parse_pmap(IFFChunk * ChunkInfo, uint8_t * pBuffer)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t indicator;
|
||||
|
||||
IFFPMap *PMap = malloc(sizeof(IFFPMap));
|
||||
pBuffer = ChunkInfo->Data;
|
||||
|
||||
PMap->Colors = (IFFSpriteColor *)malloc(sizeof(IFFSpriteColor) * 256);
|
||||
|
||||
indicator = read_uint32le(pBuffer);
|
||||
if (indicator != 1)
|
||||
pBuffer += (indicator>>24) - 8;
|
||||
else
|
||||
pBuffer += 12;
|
||||
|
||||
/* In every single one of EA's PALT resources, there have been 256 colors. */
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
if ((uint32_t)(pBuffer - ChunkInfo->Data) < ChunkInfo->Size + 3) /* Are there 3 more bytes left to read? */
|
||||
{
|
||||
PMap->Colors[i].R = *(pBuffer++);
|
||||
PMap->Colors[i].G = *(pBuffer++);
|
||||
PMap->Colors[i].B = *(pBuffer++);
|
||||
PMap->Colors[i].A = 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
PMap->Colors[i].R = 128;
|
||||
PMap->Colors[i].G = 128;
|
||||
PMap->Colors[i].B = 128;
|
||||
PMap->Colors[i].A = 255;
|
||||
}
|
||||
}
|
||||
|
||||
ChunkInfo->FormattedData = PMap;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sprite_frame_set_texel(IFFSpriteFrame *frame, uint32_t column, uint32_t row, IFFSpriteColor color)
|
||||
{
|
||||
/*printf("Index: %d out of %d", frame->Width * row + column, frame->Width*frame->Height);*/
|
||||
|
||||
memcpy(&frame->Texels[frame->Width * row + column], &color, sizeof(IFFSpriteColor));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sprite_frame_set_texel_alpha(IFFSpriteFrame *frame, uint32_t column, uint32_t row, IFFSpriteColor color, uint8_t alpha)
|
||||
{
|
||||
/*printf("Index: %d out of %d", frame->Width * row + column, frame->Width*frame->Height);*/
|
||||
|
||||
memcpy(&frame->Texels[frame->Width * row + column], &color, sizeof(IFFSpriteColor));
|
||||
frame->Texels[frame->Width * row + column].A = alpha;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sprite_frame_export_as_targa(IFFSpriteFrame *frame, const char *filename)
|
||||
{
|
||||
int i;
|
||||
|
||||
FILE *targaFile = fopen(filename, "w");
|
||||
putc(0, targaFile);
|
||||
putc(0, targaFile);
|
||||
putc(2, targaFile);
|
||||
putc(0, targaFile); putc(0, targaFile);
|
||||
putc(0, targaFile); putc(0, targaFile);
|
||||
putc(0, targaFile);
|
||||
fwrite(&frame->XLocation, 2, 1, targaFile);
|
||||
fwrite(&frame->YLocation, 2, 1, targaFile);
|
||||
fwrite(&frame->Width, 2, 1, targaFile);
|
||||
fwrite(&frame->Height, 2, 1, targaFile);
|
||||
putc(32, targaFile);
|
||||
putc(0, targaFile);
|
||||
|
||||
for (i = 0; i < frame->Width * frame->Height; i++)
|
||||
{
|
||||
putc(frame->Texels[i].B, targaFile);
|
||||
putc(frame->Texels[i].G, targaFile);
|
||||
putc(frame->Texels[i].R, targaFile);
|
||||
putc(frame->Texels[i].A, targaFile);
|
||||
}
|
||||
|
||||
fclose(targaFile);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sprite_frame_export_as_png(IFFSpriteFrame *frame, const char *filename)
|
||||
{
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
png_bytepp row_pointers;
|
||||
int h;
|
||||
int w;
|
||||
FILE *pngFile = fopen(filename, "wb");
|
||||
|
||||
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
|
||||
setjmp(png_jmpbuf(png_ptr));
|
||||
|
||||
png_init_io(png_ptr, pngFile);
|
||||
|
||||
setjmp(png_jmpbuf(png_ptr));
|
||||
|
||||
png_set_IHDR(png_ptr, info_ptr, frame->Width, frame->Height,
|
||||
8, 6, PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
|
||||
setjmp(png_jmpbuf(png_ptr));
|
||||
|
||||
|
||||
|
||||
row_pointers = (png_bytepp) malloc (frame->Height * sizeof (png_bytep));
|
||||
for (h = 0; h < frame->Height; h++) {
|
||||
row_pointers[h] = (png_bytep) malloc (frame->Width*4);
|
||||
for (w = 0; w < frame->Width; w++) {
|
||||
row_pointers[h][w*4] = frame->Texels[frame->Width*h + w].R;
|
||||
row_pointers[h][w*4+1] = frame->Texels[frame->Width*h + w].G;
|
||||
row_pointers[h][w*4+2] = frame->Texels[frame->Width*h + w].B;
|
||||
row_pointers[h][w*4+3] = frame->Texels[frame->Width*h + w].A;
|
||||
}
|
||||
}
|
||||
|
||||
png_write_image(png_ptr, row_pointers);
|
||||
|
||||
setjmp(png_jmpbuf(png_ptr));
|
||||
|
||||
png_write_end(png_ptr, NULL);
|
||||
|
||||
for (h = 0; h < frame->Height; h++) {
|
||||
free((row_pointers)[h]);
|
||||
}
|
||||
free(row_pointers);
|
||||
|
||||
fclose(pngFile);
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
#define IFF2HTML
|
||||
|
||||
typedef struct IFFSpriteColor_struct
|
||||
{
|
||||
uint8_t A;
|
||||
uint8_t R;
|
||||
uint8_t G;
|
||||
uint8_t B;
|
||||
} IFFSpriteColor;
|
||||
|
||||
typedef struct IFFPixelMap_struct
|
||||
{
|
||||
IFFSpriteColor *Colors; /* This is 255 b/c sometimes SPR2 and SPR resource go out of bounds (safety first!) */
|
||||
} IFFPMap;
|
||||
|
||||
typedef struct IFFSpriteFrame_struct
|
||||
{
|
||||
uint16_t XLocation;
|
||||
uint16_t YLocation;
|
||||
uint16_t Width;
|
||||
uint16_t Height;
|
||||
uint16_t Flag;
|
||||
uint16_t PaletteID;
|
||||
IFFSpriteColor TransparentPixel;
|
||||
|
||||
IFFSpriteColor *Texels;
|
||||
|
||||
#ifdef IFF2HTML
|
||||
char *filePath;
|
||||
#endif
|
||||
|
||||
} IFFSpriteFrame;
|
||||
|
||||
typedef struct IFFSprite_struct
|
||||
{
|
||||
IFFSpriteFrame **Frames;
|
||||
uint16_t FrameCount;
|
||||
#ifdef IFF2HTML
|
||||
uint32_t Version;
|
||||
#endif
|
||||
} IFFSprite;
|
|
@ -1,233 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "iff.h"
|
||||
|
||||
int iff_parse_str(IFFChunk * ChunkInfo, const uint8_t * Buffer){
|
||||
/* No bounds checking yet */
|
||||
IFF_STR * StringData;
|
||||
unsigned Size = ChunkInfo->Size - 76;
|
||||
if(Size < 2)
|
||||
return 0;
|
||||
ChunkInfo->FormattedData = malloc(sizeof(IFF_STR));
|
||||
if(ChunkInfo->FormattedData == NULL)
|
||||
return 0;
|
||||
memset(ChunkInfo->FormattedData, 0, sizeof(IFF_STR));
|
||||
StringData = (IFF_STR*) ChunkInfo->FormattedData;
|
||||
StringData->Format = read_int16le(Buffer);
|
||||
Buffer += 2;
|
||||
if(Size-2 < 2) /* TSO allows this; as seen in the animations chunk in personglobals.iff */
|
||||
return 1;
|
||||
|
||||
switch(StringData->Format){
|
||||
|
||||
case 0: {
|
||||
unsigned i;
|
||||
IFFStringPairNode * PrevPair = NULL;
|
||||
|
||||
StringData->LanguageSets[0].PairCount = read_uint16le(Buffer);
|
||||
Buffer += 2;
|
||||
if(StringData->LanguageSets[0].PairCount == 0)
|
||||
return 1;
|
||||
|
||||
for(i=0; i<StringData->LanguageSets[0].PairCount; i++){
|
||||
IFFStringPairNode * CurrentPair;
|
||||
unsigned length;
|
||||
CurrentPair = malloc(sizeof(IFFStringPairNode));
|
||||
memset(CurrentPair, 0, sizeof(IFFStringPairNode));
|
||||
|
||||
if(i == 0) StringData->LanguageSets[0].FirstPair = CurrentPair;
|
||||
else PrevPair->NextPair = CurrentPair;
|
||||
CurrentPair->PrevPair = PrevPair;
|
||||
|
||||
/* Key */
|
||||
length = read_uint8le(Buffer);
|
||||
if(length != 0){
|
||||
CurrentPair->Pair.Key = malloc(length+1);
|
||||
memcpy(CurrentPair->Pair.Key, Buffer+1, length);
|
||||
CurrentPair->Pair.Key[length] = 0x00;
|
||||
}
|
||||
Buffer += length+1;
|
||||
|
||||
PrevPair = CurrentPair;
|
||||
}
|
||||
StringData->LanguageSets[0].LastPair = PrevPair;
|
||||
} return 1;
|
||||
|
||||
case -1: {
|
||||
unsigned i;
|
||||
IFFStringPairNode * PrevPair = NULL;
|
||||
|
||||
StringData->LanguageSets[0].PairCount = read_uint16le(Buffer);
|
||||
Buffer += 2;
|
||||
if(StringData->LanguageSets[0].PairCount == 0)
|
||||
return 1;
|
||||
|
||||
for(i=0; i<StringData->LanguageSets[0].PairCount; i++){
|
||||
IFFStringPairNode * CurrentPair;
|
||||
unsigned length;
|
||||
CurrentPair = malloc(sizeof(IFFStringPairNode));
|
||||
memset(CurrentPair, 0, sizeof(IFFStringPairNode));
|
||||
|
||||
if(i == 0) StringData->LanguageSets[0].FirstPair = CurrentPair;
|
||||
else PrevPair->NextPair = CurrentPair;
|
||||
CurrentPair->PrevPair = PrevPair;
|
||||
|
||||
/* Key */
|
||||
length = strlen((char*)Buffer);
|
||||
if(length != 0){
|
||||
CurrentPair->Pair.Key = malloc(length+1);
|
||||
strcpy(CurrentPair->Pair.Key, (char*)Buffer);
|
||||
}
|
||||
Buffer += length+1;
|
||||
|
||||
PrevPair = CurrentPair;
|
||||
}
|
||||
StringData->LanguageSets[0].LastPair = PrevPair;
|
||||
} return 1;
|
||||
|
||||
case -2: {
|
||||
unsigned i;
|
||||
IFFStringPairNode * PrevPair = NULL;
|
||||
|
||||
StringData->LanguageSets[0].PairCount = read_uint16le(Buffer);
|
||||
Buffer += 2;
|
||||
if(StringData->LanguageSets[0].PairCount == 0)
|
||||
return 1;
|
||||
|
||||
for(i=0; i<StringData->LanguageSets[0].PairCount; i++){
|
||||
IFFStringPairNode * CurrentPair;
|
||||
unsigned length;
|
||||
CurrentPair = malloc(sizeof(IFFStringPairNode));
|
||||
memset(CurrentPair, 0, sizeof(IFFStringPairNode));
|
||||
|
||||
if(i == 0) StringData->LanguageSets[0].FirstPair = CurrentPair;
|
||||
else PrevPair->NextPair = CurrentPair;
|
||||
CurrentPair->PrevPair = PrevPair;
|
||||
|
||||
/* Key */
|
||||
length = strlen((char*)Buffer);
|
||||
if(length != 0){
|
||||
CurrentPair->Pair.Key = malloc(length+1);
|
||||
strcpy(CurrentPair->Pair.Key, (char*)Buffer);
|
||||
}
|
||||
Buffer += length+1;
|
||||
|
||||
/* Value */
|
||||
length = strlen((char*)Buffer);
|
||||
if(length != 0){
|
||||
CurrentPair->Pair.Value = malloc(length+1);
|
||||
strcpy(CurrentPair->Pair.Value, (char*)Buffer);
|
||||
}
|
||||
Buffer += length+1;
|
||||
|
||||
PrevPair = CurrentPair;
|
||||
}
|
||||
StringData->LanguageSets[0].LastPair = PrevPair;
|
||||
} return 1;
|
||||
|
||||
case -3: {
|
||||
unsigned i, TotalPairCount;
|
||||
|
||||
TotalPairCount = read_uint16le(Buffer);
|
||||
Buffer += 2;
|
||||
if(TotalPairCount == 0)
|
||||
return 1;
|
||||
|
||||
for(i=0; i<TotalPairCount; i++){
|
||||
IFFStringPairNode * Pair;
|
||||
unsigned length;
|
||||
Pair = malloc(sizeof(IFFStringPairNode));
|
||||
memset(Pair, 0, sizeof(IFFStringPairNode));
|
||||
Pair->Pair.LanguageSet = read_uint8le(Buffer) - 1;
|
||||
Buffer++;
|
||||
|
||||
/* Key */
|
||||
length = strlen((char*)Buffer);
|
||||
if(length != 0){
|
||||
Pair->Pair.Key = malloc(length+1);
|
||||
strcpy(Pair->Pair.Key, (char*)Buffer);
|
||||
}
|
||||
Buffer += length+1;
|
||||
|
||||
/* Value */
|
||||
length = strlen((char*)Buffer);
|
||||
if(length != 0){
|
||||
Pair->Pair.Value = malloc(length+1);
|
||||
strcpy(Pair->Pair.Value, (char*)Buffer);
|
||||
}
|
||||
Buffer += length+1;
|
||||
|
||||
/* Add the pair to the end of the associated language set */
|
||||
Pair->PrevPair = StringData->LanguageSets[0].LastPair;
|
||||
if(StringData->LanguageSets[0].PairCount == 0)
|
||||
StringData->LanguageSets[0].FirstPair = Pair;
|
||||
else
|
||||
StringData->LanguageSets[0].LastPair->NextPair = Pair;
|
||||
StringData->LanguageSets[0].PairCount++;
|
||||
StringData->LanguageSets[0].LastPair = Pair;
|
||||
}
|
||||
} return 1;
|
||||
|
||||
case -4: {
|
||||
unsigned LanguageSet;
|
||||
unsigned LanguageSetCount = read_uint8le(Buffer);
|
||||
Buffer++;
|
||||
if(LanguageSetCount > 20) LanguageSetCount = 20;
|
||||
|
||||
for(LanguageSet=0; LanguageSet<LanguageSetCount; LanguageSet++){
|
||||
unsigned i;
|
||||
IFFStringPairNode * PrevPair = NULL;
|
||||
|
||||
StringData->LanguageSets[LanguageSet].PairCount = read_uint16le(Buffer);
|
||||
Buffer += 2;
|
||||
if(StringData->LanguageSets[LanguageSet].PairCount == 0)
|
||||
continue;
|
||||
|
||||
for(i=0; i<StringData->LanguageSets[LanguageSet].PairCount; i++){
|
||||
IFFStringPairNode * CurrentPair;
|
||||
unsigned length;
|
||||
CurrentPair = malloc(sizeof(IFFStringPairNode));
|
||||
memset(CurrentPair, 0, sizeof(IFFStringPairNode));
|
||||
|
||||
if(i == 0) StringData->LanguageSets[LanguageSet].FirstPair = CurrentPair;
|
||||
else PrevPair->NextPair = CurrentPair;
|
||||
CurrentPair->PrevPair = PrevPair;
|
||||
|
||||
Buffer++; /* Skip over LanguageSet */
|
||||
|
||||
/* Key */
|
||||
length = read_uint8le(Buffer);
|
||||
if(length > 127){
|
||||
length = (length & 127) | (read_uint8le(Buffer+1) << 7);
|
||||
Buffer++;
|
||||
}
|
||||
if(length != 0){
|
||||
CurrentPair->Pair.Key = malloc(length+1);
|
||||
memcpy(CurrentPair->Pair.Key, Buffer+1, length);
|
||||
CurrentPair->Pair.Key[length] = 0x00;
|
||||
}
|
||||
Buffer += length + 1;
|
||||
|
||||
/* Value */
|
||||
length = read_uint8le(Buffer);
|
||||
if(length > 127){
|
||||
length = (length & 127) | (read_uint8le(Buffer+1) << 7);
|
||||
Buffer++;
|
||||
}
|
||||
if(length != 0){
|
||||
CurrentPair->Pair.Value = malloc(length+1);
|
||||
memcpy(CurrentPair->Pair.Value, Buffer+1, length);
|
||||
CurrentPair->Pair.Value[length] = 0x00;
|
||||
}
|
||||
Buffer += length + 1;
|
||||
|
||||
PrevPair = CurrentPair;
|
||||
}
|
||||
StringData->LanguageSets[LanguageSet].LastPair = PrevPair;
|
||||
}
|
||||
} return 1;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/* STR# chunk */
|
||||
|
||||
enum IFFLanguage {
|
||||
IFFLANG_DEFAULT = 0,
|
||||
IFFLANG_EN_US = 1,
|
||||
IFFLANG_EN_INTERNATIONAL = 2,
|
||||
IFFLANG_FRENCH = 3,
|
||||
IFFLANG_GERMAN = 4,
|
||||
IFFLANG_ITALIAN = 5,
|
||||
IFFLANG_SPANISH = 6,
|
||||
IFFLANG_DUTCH = 7,
|
||||
IFFLANG_DANISH = 8,
|
||||
IFFLANG_SWEDISH = 9,
|
||||
IFFLANG_NORWEGIAN = 10,
|
||||
IFFLANG_FINNISH = 11,
|
||||
IFFLANG_HEBREW = 12,
|
||||
IFFLANG_RUSSIAN = 13,
|
||||
IFFLANG_PORTUGUESE = 14,
|
||||
IFFLANG_JAPANESE = 15,
|
||||
IFFLANG_POLISH = 16,
|
||||
IFFLANG_CHINESE_SIMPLIFIED = 17,
|
||||
IFFLANG_CHINESE_TRADITIONAL = 18,
|
||||
IFFLANG_THAI = 19,
|
||||
IFFLANG_KOREAN = 20
|
||||
};
|
||||
|
||||
typedef struct IFFStringPair_struct
|
||||
{
|
||||
uint8_t LanguageSet;
|
||||
char * Key;
|
||||
char * Value;
|
||||
} IFFStringPair;
|
||||
|
||||
typedef struct IFFStringPairNode_struct
|
||||
{
|
||||
IFFStringPair Pair;
|
||||
struct IFFStringPairNode_struct * PrevPair;
|
||||
struct IFFStringPairNode_struct * NextPair;
|
||||
} IFFStringPairNode;
|
||||
|
||||
typedef struct IFFLanguageSet_struct
|
||||
{
|
||||
uint16_t PairCount;
|
||||
IFFStringPairNode * FirstPair;
|
||||
IFFStringPairNode * LastPair;
|
||||
} IFFLanguageSet;
|
||||
|
||||
typedef struct IFF_STR_struct
|
||||
{
|
||||
int16_t Format;
|
||||
IFFLanguageSet LanguageSets[20];
|
||||
} IFF_STR;
|
|
@ -17,7 +17,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
#include "read_utk.h"
|
||||
|
||||
#ifndef read_int32
|
||||
|
@ -44,6 +43,13 @@
|
|||
#define __restrict
|
||||
#endif
|
||||
|
||||
static uint8_t ReadBits(utkparams_t *p, uint8_t bits);
|
||||
static void SetUTKParameters(utkparams_t *p);
|
||||
static void DecompressBlock(utkparams_t *p);
|
||||
static void LatticeFilter(utkparams_t *p, int Voiced, float * Window, int Interval);
|
||||
static void Synthesize(utkparams_t *p, unsigned Sample, unsigned Blocks);
|
||||
static void PredictionFilter(const float *__restrict ImpulseTrain, float *__restrict Residual);
|
||||
|
||||
float UTKTable1[64];
|
||||
uint8_t UTKTable2[512];
|
||||
const uint8_t UTKTable3[29] = {8,7,8,7,2,2,2,3,3,4,4,3,3,5,5,4,4,6,6,5,5,7,7,6,6,8,8,7,7};
|
||||
|
@ -126,9 +132,9 @@ void UTKGenerateTables(void){
|
|||
case 1: UTKTable2[i] = (i<256) ? 6 : (11 + (i%8 > 4)); break;
|
||||
case 2: UTKTable2[i] = (i<256) ? 5 : (7 + (i%8 > 4)); break;
|
||||
case 3: {
|
||||
uint8_t l1[] = {9,15,13,19,10,16};
|
||||
uint8_t l2[] = {17,21,18,25,17,22,18,00,17,21,18,26,17,22,18,02,
|
||||
23,27,24,01,23,28,24,03,23,27,24,01,23,28,24,03};
|
||||
const uint8_t l1[] = {9,15,13,19,10,16},
|
||||
l2[] = {17,21,18,25,17,22,18,00,17,21,18,26,17,22,18,02,
|
||||
23,27,24,01,23,28,24,03,23,27,24,01,23,28,24,03};
|
||||
if(i%16 < 4) UTKTable2[i] = l1[0 + (i>256)];
|
||||
else if(i%16 < 8) UTKTable2[i] = l1[2 + (i>256)] + (i%32 > 16);
|
||||
else if(i%16 < 12) UTKTable2[i] = l1[4 + (i>256)];
|
||||
|
@ -147,7 +153,7 @@ void UTKGenerateTables(void){
|
|||
}
|
||||
}
|
||||
|
||||
uint8_t ReadBits(utkparams_t *p, uint8_t bits){
|
||||
static uint8_t ReadBits(utkparams_t *p, uint8_t bits){
|
||||
unsigned value = p->UnreadBitsValue & (255>>(8-bits));
|
||||
p->UnreadBitsValue >>= bits;
|
||||
p->UnreadBitsCount -= bits;
|
||||
|
@ -159,7 +165,7 @@ uint8_t ReadBits(utkparams_t *p, uint8_t bits){
|
|||
return value;
|
||||
}
|
||||
|
||||
void SetUTKParameters(utkparams_t *p){
|
||||
static void SetUTKParameters(utkparams_t *p){
|
||||
/* Call once per file */
|
||||
int i;
|
||||
float s;
|
||||
|
@ -178,7 +184,7 @@ void SetUTKParameters(utkparams_t *p){
|
|||
memset(p->Delay, 0, 324*sizeof(float));
|
||||
}
|
||||
|
||||
void DecompressBlock(utkparams_t *p){
|
||||
static void DecompressBlock(utkparams_t *p){
|
||||
int i,j;
|
||||
float Window[118];
|
||||
float Matrix[12];
|
||||
|
@ -237,7 +243,7 @@ void DecompressBlock(utkparams_t *p){
|
|||
}
|
||||
}
|
||||
|
||||
void LatticeFilter(utkparams_t *p, int Voiced, float * Window, int Interval){
|
||||
static void LatticeFilter(utkparams_t *p, int Voiced, float * Window, int Interval){
|
||||
if(Voiced){
|
||||
int t = 0;
|
||||
int i = 0;
|
||||
|
@ -295,7 +301,7 @@ void LatticeFilter(utkparams_t *p, int Voiced, float * Window, int Interval){
|
|||
}
|
||||
}
|
||||
|
||||
void Synthesize(utkparams_t *p, unsigned Sample, unsigned Blocks){
|
||||
static void Synthesize(utkparams_t *p, unsigned Sample, unsigned Blocks){
|
||||
float Residual[12];
|
||||
unsigned Samples = Blocks*12;
|
||||
int offset = -1;
|
||||
|
@ -313,7 +319,7 @@ void Synthesize(utkparams_t *p, unsigned Sample, unsigned Blocks){
|
|||
}
|
||||
}
|
||||
|
||||
void PredictionFilter(const float *__restrict ImpulseTrain, float *__restrict Residual){
|
||||
static void PredictionFilter(const float *__restrict ImpulseTrain, float *__restrict Residual){
|
||||
int i,j;
|
||||
float ResidualGain[12];
|
||||
float ImpulseGain[12];
|
||||
|
|
|
@ -16,17 +16,17 @@
|
|||
|
||||
typedef struct
|
||||
{
|
||||
char sID[4];
|
||||
DWORD dwOutSize;
|
||||
DWORD dwWfxSize;
|
||||
char sID[4];
|
||||
uint32_t dwOutSize;
|
||||
uint32_t dwWfxSize;
|
||||
/* WAVEFORMATEX */
|
||||
WORD wFormatTag;
|
||||
WORD nChannels;
|
||||
DWORD nSamplesPerSec;
|
||||
DWORD nAvgBytesPerSec;
|
||||
WORD nBlockAlign;
|
||||
WORD wBitsPerSample;
|
||||
DWORD cbSize;
|
||||
uint16_t wFormatTag;
|
||||
uint16_t nChannels;
|
||||
uint32_t nSamplesPerSec;
|
||||
uint32_t nAvgBytesPerSec;
|
||||
uint16_t nBlockAlign;
|
||||
uint16_t wBitsPerSample;
|
||||
uint32_t cbSize;
|
||||
|
||||
unsigned Frames;
|
||||
unsigned UTKDataSize;
|
||||
|
@ -51,12 +51,6 @@ extern "C" {
|
|||
int utk_read_header(utkheader_t * UTKHeader, const uint8_t * Buffer, unsigned FileSize);
|
||||
int utk_decode(const uint8_t *__restrict InBuffer, uint8_t *__restrict OutBuffer, unsigned Frames);
|
||||
void UTKGenerateTables(void);
|
||||
uint8_t ReadBits(utkparams_t *p, uint8_t bits);
|
||||
void SetUTKParameters(utkparams_t *p);
|
||||
void DecompressBlock(utkparams_t *p);
|
||||
void LatticeFilter(utkparams_t *p, int Voiced, float * Window, int Interval);
|
||||
void Synthesize(utkparams_t *p, unsigned Sample, unsigned Blocks);
|
||||
void PredictionFilter(const float *__restrict ImpulseTrain, float *__restrict Residual);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
#include "read_xa.h"
|
||||
|
||||
#define HINIBBLE(byte) ((byte) >> 4)
|
||||
|
@ -56,7 +55,7 @@ unsigned xa_compressed_size(unsigned Frames, unsigned Channels)
|
|||
return Channels*SingleChannelData;
|
||||
}
|
||||
|
||||
int xa_read_header(xaheader_t * XAHeader, const uint8_t * Buffer, unsigned FileSize)
|
||||
int xa_read_header(xaheader_t * XAHeader, const uint8_t * Buffer, size_t FileSize)
|
||||
{
|
||||
if(FileSize < 24) return 0;
|
||||
memcpy(&XAHeader->szID, Buffer, 4);
|
||||
|
|
|
@ -16,15 +16,15 @@
|
|||
|
||||
typedef struct
|
||||
{
|
||||
char szID[4];
|
||||
DWORD dwOutSize;
|
||||
char szID[4];
|
||||
uint32_t dwOutSize;
|
||||
/* WAVEFORMATEX */
|
||||
WORD wFormatTag;
|
||||
WORD nChannels;
|
||||
DWORD nSamplesPerSec;
|
||||
DWORD nAvgBytesPerSec;
|
||||
WORD nBlockAlign;
|
||||
WORD wBitsPerSample;
|
||||
uint16_t wFormatTag;
|
||||
uint16_t nChannels;
|
||||
uint32_t nSamplesPerSec;
|
||||
uint32_t nAvgBytesPerSec;
|
||||
uint16_t nBlockAlign;
|
||||
uint16_t wBitsPerSample;
|
||||
|
||||
unsigned Frames;
|
||||
unsigned XADataSize;
|
||||
|
|
|
@ -106,6 +106,7 @@ void DisplayFileError(const char * Filename){
|
|||
break;
|
||||
case FERR_BLANK:
|
||||
case FERR_UNRECOGNIZED:
|
||||
case FERR_INVALIDDATA:
|
||||
Message = "%s is corrupt or invalid.";
|
||||
break;
|
||||
case FERR_MEMORY:
|
||||
|
@ -132,7 +133,7 @@ bool LoadTextures()
|
|||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture[i]);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, Image->Width, Image->Height, 0, GL_RGB, GL_UNSIGNED_BYTE, Image->Data);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, Image->Width, Image->Height, 0, GL_BGR, GL_UNSIGNED_BYTE, Image->Data);
|
||||
free(Image->Data);
|
||||
free(Image);
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ void ReadMesh(Mesh_t& Mesh){
|
|||
TextureVertex_t * TextureVertexData = (TextureVertex_t*) malloc(Mesh.RealVertexCount * sizeof(TextureVertex_t));
|
||||
for(unsigned i=0; i<Mesh.RealVertexCount; i++){
|
||||
TextureVertexData[i].u = VBFile.readfloat();
|
||||
TextureVertexData[i].v = VBFile.readfloat();
|
||||
TextureVertexData[i].v = -VBFile.readfloat();
|
||||
}
|
||||
|
||||
Mesh.BlendVertexCount = VBFile.readint32();
|
||||
|
|
|
@ -16,7 +16,7 @@ void SetType(HWND hDlg, int type){
|
|||
}
|
||||
|
||||
INT_PTR CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){
|
||||
switch (message){
|
||||
switch (message){
|
||||
case WM_INITDIALOG: {
|
||||
CenterDialog(hDlg);
|
||||
|
||||
|
@ -43,15 +43,15 @@ INT_PTR CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){
|
|||
|
||||
//Create the tooltips
|
||||
HWND FARInfo = CreateWindowEx(0, TOOLTIPS_CLASS, NULL,
|
||||
WS_POPUP | TTS_NOPREFIX | 0x40 | TTS_ALWAYSTIP,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
hDlg, NULL, hInst, NULL),
|
||||
DBPFInfo = CreateWindowEx(0, TOOLTIPS_CLASS, NULL,
|
||||
WS_POPUP | TTS_NOPREFIX | 0x40 | TTS_ALWAYSTIP,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
hDlg, NULL, hInst, NULL);
|
||||
WS_POPUP | TTS_NOPREFIX | TTS_BALLOON | TTS_ALWAYSTIP,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
hDlg, NULL, hInst, NULL),
|
||||
DBPFInfo = CreateWindowEx(0, TOOLTIPS_CLASS, NULL,
|
||||
WS_POPUP | TTS_NOPREFIX | TTS_BALLOON | TTS_ALWAYSTIP,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
hDlg, NULL, hInst, NULL);
|
||||
|
||||
TOOLINFO tinfo = {
|
||||
sizeof(TOOLINFO), //cbSize
|
||||
|
@ -67,9 +67,9 @@ INT_PTR CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){
|
|||
L"FAR version 1a is found in The Sims 1.\r\n\r\n"
|
||||
L"Version 1b appears to be a mistake, in which it was intended to take on the version number 2.\r\n\r\n"
|
||||
L"1b and 3 are both found exclusively in The Sims Online.";
|
||||
SendMessage(FARInfo, (WM_USER + 24), 2000, 200);
|
||||
SendMessage(FARInfo, (WM_USER + 32), TTI_INFO_LARGE, (LPARAM) L"FAR version");
|
||||
SendMessage(FARInfo, TTM_ADDTOOL, 0, (LPARAM) &tinfo);
|
||||
SendMessage(FARInfo, TTM_SETMAXTIPWIDTH, 2000, 200);
|
||||
SendMessage(FARInfo, TTM_SETTITLE, TTI_INFO_LARGE, (LPARAM) L"FAR version");
|
||||
SendMessage(FARInfo, TTM_ADDTOOL, 0, (LPARAM) &tinfo);
|
||||
SendMessage(FARInfo, TTM_SETDELAYTIME, TTDT_AUTOPOP, 12000);
|
||||
tinfo.uId = (UINT_PTR) GetDlgItem(hDlg, IDC_NA_DBPFINFO);
|
||||
tinfo.lpszText = (wchar_t*)
|
||||
|
@ -78,21 +78,21 @@ INT_PTR CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){
|
|||
L"DBPF 1.0;i7.0 is found in The Sims Online and SimCity 4.\r\n\r\n"
|
||||
L"1.0;i7.0 and 1.1;i7.1 are found in The Sims 2.\r\n\r\n"
|
||||
L"2.0;i3.0 is found in Spore.";
|
||||
SendMessage(DBPFInfo, (WM_USER + 24), 2000, 200);
|
||||
SendMessage(DBPFInfo, (WM_USER + 32), TTI_INFO_LARGE, (LPARAM) L"DBPF version");
|
||||
SendMessage(DBPFInfo, TTM_ADDTOOL, 0, (LPARAM) &tinfo);
|
||||
SendMessage(DBPFInfo, TTM_SETMAXTIPWIDTH, 2000, 200);
|
||||
SendMessage(DBPFInfo, TTM_SETTITLE, TTI_INFO_LARGE, (LPARAM) L"DBPF version");
|
||||
SendMessage(DBPFInfo, TTM_ADDTOOL, 0, (LPARAM) &tinfo);
|
||||
SendMessage(DBPFInfo, TTM_SETDELAYTIME, TTDT_AUTOPOP, 20000);
|
||||
|
||||
SetType(hDlg, TYPE_FAR);
|
||||
} return TRUE;
|
||||
case WM_CTLCOLORSTATIC:
|
||||
if((HWND) lParam == GetDlgItem(hDlg, IDC_NA_TYPETEXT)){
|
||||
SetBkColor((HDC) wParam, GetSysColor(COLOR_WINDOW));
|
||||
return (INT_PTR) GetSysColorBrush(COLOR_WINDOW);
|
||||
}
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
switch(LOWORD(wParam)){
|
||||
if((HWND) lParam == GetDlgItem(hDlg, IDC_NA_TYPETEXT)){
|
||||
SetBkColor((HDC) wParam, GetSysColor(COLOR_WINDOW));
|
||||
return (INT_PTR) GetSysColorBrush(COLOR_WINDOW);
|
||||
}
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
switch(LOWORD(wParam)){
|
||||
case IDC_NA_TYPE:
|
||||
if(HIWORD(wParam) == CBN_SELCHANGE)
|
||||
SetType(hDlg, SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0));
|
||||
|
@ -110,7 +110,7 @@ INT_PTR CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){
|
|||
EndDialog(hDlg, 0);
|
||||
} break;
|
||||
case WM_CLOSE:
|
||||
EndDialog(hDlg, 0);
|
||||
EndDialog(hDlg, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -30,8 +30,8 @@ bool Close(){
|
|||
|
||||
Archive::IsOpen = false;
|
||||
|
||||
SetWindowText(hWnd, L"FARDive");
|
||||
SendMessage(statusbar, SB_SETTEXT, 0, (LPARAM) L"");
|
||||
SetWindowText(hWnd, L"FARDive");
|
||||
SendMessage(statusbar, SB_SETTEXT, 0, (LPARAM) L"");
|
||||
|
||||
MENUITEMINFO mii;
|
||||
mii.cbSize = sizeof(MENUITEMINFO);
|
||||
|
@ -86,7 +86,7 @@ bool PopulateEntries(){
|
|||
item.mask = LVIF_TEXT;
|
||||
item.iItem = 0;
|
||||
item.pszText = (LPTSTR) L"Test";
|
||||
SendMessage(hList, LVM_SETITEMCOUNT, EntryCount, 0x00000002);
|
||||
SendMessage(hList, LVM_SETITEMCOUNT, EntryCount, LVSICF_NOSCROLL);
|
||||
SendMessage(hList, LVM_INSERTITEM, 0, (LPARAM) &item);
|
||||
|
||||
wchar_t buffer[17];
|
||||
|
@ -162,7 +162,7 @@ bool SetWorkspace(){
|
|||
|
||||
RECT ClientRect;
|
||||
GetClientRect(hWnd, &ClientRect);
|
||||
hList = CreateWindowEx(WS_EX_CLIENTEDGE | 0x00010000 | WS_EX_COMPOSITED, WC_LISTVIEW, NULL, LVS_LIST | LVS_SHOWSELALWAYS | WS_CHILD | WS_VISIBLE,
|
||||
hList = CreateWindowEx(WS_EX_CLIENTEDGE | LVS_EX_DOUBLEBUFFER | WS_EX_COMPOSITED, WC_LISTVIEW, NULL, LVS_LIST | LVS_SHOWSELALWAYS | WS_CHILD | WS_VISIBLE,
|
||||
5, 5, 192, ClientRect.bottom-statusbarheight-10, hWnd, NULL, NULL, NULL);
|
||||
SetWindowTheme(hList, L"Explorer", NULL);
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#define IFF2HTML
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
@ -59,9 +58,6 @@ int main(int argc, char *argv[]){
|
|||
unsigned chunk = 0;
|
||||
IFFFile * IFFFileInfo;
|
||||
IFFChunkNode * ChunkNode;
|
||||
IFF_TREETABLENODE *currentNode; /* for iterating through BHAVs */
|
||||
char *dummyValue;
|
||||
char *resourceDir;
|
||||
|
||||
if(argc == 1 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){
|
||||
printf("Usage: iff2html [-f] infile (outfile)\n"
|
||||
|
@ -98,15 +94,7 @@ int main(int argc, char *argv[]){
|
|||
/****
|
||||
** Open the file and read in entire contents to memory
|
||||
*/
|
||||
|
||||
resourceDir = (char *)malloc(sizeof(char) * 255);
|
||||
dummyValue = (char *)malloc(sizeof(char) * 255);
|
||||
strcpy(resourceDir+2, InFile);
|
||||
*strchr(resourceDir+2, (int)'.') = '\0';
|
||||
resourceDir[0] = '.';
|
||||
resourceDir[1] = '/';
|
||||
CreateDirectory(resourceDir, NULL);
|
||||
|
||||
|
||||
hFile = CreateFile(InFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
||||
hFile = fopen(InFile, "rb");
|
||||
if(hFile == NULL){
|
||||
|
@ -131,9 +119,6 @@ int main(int argc, char *argv[]){
|
|||
return -1;
|
||||
}
|
||||
fclose(hFile);
|
||||
|
||||
|
||||
|
||||
|
||||
/****
|
||||
** Load header information
|
||||
|
@ -144,7 +129,7 @@ int main(int argc, char *argv[]){
|
|||
printf("%sMemory for this file could not be allocated.", "iff2html: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(!iff_read_header(IFFFileInfo, IFFData, FileSize, InFile)){
|
||||
if(!iff_read_header(IFFFileInfo, IFFData, FileSize)){
|
||||
printf("%sNot a valid IFF file.", "iff2html: error: ");
|
||||
return -1;
|
||||
}
|
||||
|
@ -165,7 +150,7 @@ int main(int argc, char *argv[]){
|
|||
free(IFFData);
|
||||
|
||||
for(chunk = 1, ChunkNode = IFFFileInfo->FirstChunk; ChunkNode; ChunkNode = ChunkNode->NextChunk, chunk++)
|
||||
iff_parse_chunk(&ChunkNode->Chunk, ChunkNode->Chunk.Data, IFFFileInfo);
|
||||
iff_parse_chunk(&ChunkNode->Chunk, ChunkNode->Chunk.Data);
|
||||
|
||||
|
||||
/****
|
||||
|
@ -287,7 +272,7 @@ int main(int argc, char *argv[]){
|
|||
fprintf(hFile, "\n");
|
||||
|
||||
for(i=1, ChunkNode = IFFFileInfo->FirstChunk; ChunkNode; ChunkNode = ChunkNode->NextChunk, i++){
|
||||
|
||||
IFF_STR * StringData = (IFF_STR*) ChunkNode->Chunk.FormattedData;
|
||||
fprintf(hFile, "<h2 id=\"chunk%u_%.4x\">%u [%s] (%.4X)%s%s <a href=\"#chunk%u_%.4x\">(Jump)</a></h2>\n",
|
||||
i, ChunkNode->Chunk.ChunkID, i, ChunkNode->Chunk.Type, ChunkNode->Chunk.ChunkID,
|
||||
(ChunkNode->Chunk.Label[0] != 0x00) ? " – " : "", ChunkNode->Chunk.Label,
|
||||
|
@ -301,8 +286,6 @@ int main(int argc, char *argv[]){
|
|||
!strcmp(ChunkNode->Chunk.Type, "FAMs") ||
|
||||
!strcmp(ChunkNode->Chunk.Type, "TTAs") ){
|
||||
|
||||
IFF_STR * StringData = (IFF_STR*) ChunkNode->Chunk.FormattedData;
|
||||
|
||||
/****
|
||||
** STR# parsing
|
||||
*/
|
||||
|
@ -367,114 +350,6 @@ int main(int argc, char *argv[]){
|
|||
fprintf(hFile, "</table>\n");
|
||||
}
|
||||
}
|
||||
else if (!strcmp(ChunkNode->Chunk.Type, "BHAV") )
|
||||
{
|
||||
IFF_TREETABLE * TreeTableData = (IFF_TREETABLE*) ChunkNode->Chunk.FormattedData;
|
||||
|
||||
fprintf(hFile, "<table>\n");
|
||||
fprintf(hFile, "<tr><td>Stream Version:</td><td>");
|
||||
switch(TreeTableData->StreamVersion){
|
||||
case 0x8000: fprintf(hFile, "<tt>0x8000</tt> (0)"); break;
|
||||
case 0x8001: fprintf(hFile, "<tt>0x8001</tt> (1)"); break;
|
||||
case 0x8002: fprintf(hFile, "<tt>0x8002</tt> (2)"); break;
|
||||
case 0x8003: fprintf(hFile, "<tt>0x8003</tt> (3)"); break;
|
||||
default: fprintf(hFile, "Unrecognized"); break;
|
||||
}
|
||||
fprintf(hFile, "</td></tr>\n");
|
||||
|
||||
fprintf(hFile, "<tr><td>Tree Version:</td><td>");
|
||||
fprintf(hFile, "<tt>%-#10X</tt> (%u)", TreeTableData->TreeVersion, TreeTableData->TreeVersion);
|
||||
fprintf(hFile, "</td></tr>\n");
|
||||
|
||||
fprintf(hFile, "<tr><td>Tree Type:</td><td>");
|
||||
fprintf(hFile, "<tt>%-#4X</tt> (%u)", TreeTableData->Type, TreeTableData->Type);
|
||||
fprintf(hFile, "</td></tr>\n");
|
||||
|
||||
fprintf(hFile, "<tr><td>Number of Parameters:</td><td>");
|
||||
fprintf(hFile, "<tt>%u</tt>", TreeTableData->NumParams);
|
||||
fprintf(hFile, "</td></tr>\n");
|
||||
|
||||
fprintf(hFile, "<tr><td>Number of Local Variables:</td><td>");
|
||||
fprintf(hFile, "<tt>%u</tt>", TreeTableData->NumLocals);
|
||||
fprintf(hFile, "</td></tr>\n");
|
||||
|
||||
fprintf(hFile, "<tr><td>Number of Tree Nodes:</td><td>");
|
||||
fprintf(hFile, "<tt>%u</tt>", (TreeTableData->NodesEnd - TreeTableData->NodesBegin));
|
||||
fprintf(hFile, "</td></tr>\n");
|
||||
|
||||
fprintf(hFile, "</table>\n");
|
||||
if(TreeTableData->StreamVersion >= 0x8000 && TreeTableData->StreamVersion <= 0x8003)
|
||||
{
|
||||
fprintf(hFile, "<br />\n");
|
||||
fprintf(hFile, "<table class=\"center\">\n");
|
||||
fprintf(hFile, "<tr><th>Node ID</th><th>Primitive #</th><th>Transition True</th><th>Transition False</th><th>Parameter 0</th><th>Parameter 1</th><th>Parameter 2</th><th>Parameter 3</th></tr>\n");
|
||||
|
||||
for (currentNode = TreeTableData->NodesBegin; currentNode != TreeTableData->NodesEnd; currentNode++)
|
||||
{
|
||||
fprintf(hFile, "<tr><td>%d</td>\n", (currentNode-TreeTableData->NodesBegin));
|
||||
fprintf(hFile, "<td>%d (%-#6X)</td>\n", currentNode->PrimitiveNumber, currentNode->PrimitiveNumber);
|
||||
if (currentNode->TransitionTrue < 253)
|
||||
fprintf(hFile, "<td>%d (%-#4X)</td>\n", currentNode->TransitionTrue, currentNode->TransitionTrue);
|
||||
else
|
||||
fprintf(hFile, "<td>%s</td>\n", currentNode->TransitionTrue == 253 ? "error" : currentNode->TransitionTrue == 254 ? "true" : "false");
|
||||
|
||||
|
||||
if (currentNode->TransitionFalse < 253)
|
||||
fprintf(hFile, "<td>%d (%-#4X)</td>\n", currentNode->TransitionFalse, currentNode->TransitionFalse);
|
||||
else
|
||||
fprintf(hFile, "<td>%s</td>\n", currentNode->TransitionFalse == 253 ? "error" : currentNode->TransitionFalse == 254 ? "true" : "false");
|
||||
fprintf(hFile, "<td>%d (%-#6X)</td>\n", currentNode->Parameters.Param0, currentNode->Parameters.Param0);
|
||||
fprintf(hFile, "<td>%d (%-#6X)</td>\n", currentNode->Parameters.Param1, currentNode->Parameters.Param1);
|
||||
fprintf(hFile, "<td>%d (%-#6X)</td>\n", currentNode->Parameters.Param2, currentNode->Parameters.Param2);
|
||||
fprintf(hFile, "<td>%d (%-#6X)</td>\n", currentNode->Parameters.Param3, currentNode->Parameters.Param3);
|
||||
}
|
||||
|
||||
fprintf(hFile, "</table>\n");
|
||||
}
|
||||
}
|
||||
else if (!strcmp(ChunkNode->Chunk.Type, "SPR#") || !strcmp(ChunkNode->Chunk.Type, "SPR2"))
|
||||
{
|
||||
IFFSprite * Sprite = (IFFSprite*) ChunkNode->Chunk.FormattedData;
|
||||
|
||||
fprintf(hFile, "<table>\n");
|
||||
fprintf(hFile, "<tr><td>Sprite Version:</td><td>");
|
||||
fprintf(hFile, "<tt>%-#6X</tt>", Sprite->Version);
|
||||
fprintf(hFile, "</td></tr>\n");
|
||||
|
||||
fprintf(hFile, "<tr><td>Sprite Type:</td><td>");
|
||||
fprintf(hFile, "<tt>%s</tt>", ChunkNode->Chunk.Type);
|
||||
fprintf(hFile, "</td></tr>\n");
|
||||
|
||||
fprintf(hFile, "<tr><td>Number of Frames:</td><td>");
|
||||
fprintf(hFile, "<tt>%u</tt>", Sprite->FrameCount);
|
||||
fprintf(hFile, "</td></tr>\n");
|
||||
|
||||
fprintf(hFile, "</table>\n");
|
||||
if(Sprite->Version >= 500 && Sprite->Version <= 1001)
|
||||
{
|
||||
fprintf(hFile, "<br />\n");
|
||||
fprintf(hFile, "<table class=\"center\">\n");
|
||||
fprintf(hFile, "<tr><th>Image</th><th>X Location</th><th>Y Location</th><th>Width</th><th>Height</th><th>Flag</th><th>Palette ID</th><th>Transparent Pixel</th></tr>\n");
|
||||
|
||||
for (i = 0; i < Sprite->FrameCount; i++)
|
||||
{
|
||||
fprintf(hFile, "<tr><td><img src=\"%s\" /></td>\n", Sprite->Frames[i]->filePath);
|
||||
fprintf(hFile, "<td>%d</td>\n", Sprite->Frames[i]->XLocation);
|
||||
fprintf(hFile, "<td>%d</td>\n", Sprite->Frames[i]->YLocation);
|
||||
fprintf(hFile, "<td>%d</td>\n", Sprite->Frames[i]->Width);
|
||||
fprintf(hFile, "<td>%d</td>\n", Sprite->Frames[i]->Height);
|
||||
fprintf(hFile, "<td>%d</td>\n", Sprite->Frames[i]->Flag);
|
||||
fprintf(hFile, "<td>%d</td>\n", Sprite->Frames[i]->PaletteID);
|
||||
fprintf(hFile, "<td style=\"background-color:rgb(%d, %d, %d);\"></td>\n", Sprite->Frames[i]->TransparentPixel.R, Sprite->Frames[i]->TransparentPixel.G, Sprite->Frames[i]->TransparentPixel.B);
|
||||
}
|
||||
|
||||
fprintf(hFile, "</table>\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(hFile, "The contents of this chunk could not be parsed.\n");
|
||||
}
|
||||
|
||||
fprintf(hFile, "</div>\n\n");
|
||||
}
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
int dummy = 0;
|
||||
char *someString = &dummy;
|
||||
|
||||
someString += '(';
|
||||
int currentParamIdx = 0;
|
||||
unsigned short currentParam;
|
||||
unsigned short param0;
|
||||
do
|
||||
{
|
||||
currentParam = *(¶m0 + currentParamIdx);
|
||||
if (currentParamIdx > 0)
|
||||
someString += ' ';
|
||||
|
||||
// Now, we iterate through the nibbles, starting at the high nibble and working our way down
|
||||
int shiftingAmountForCurrentNibble = 12;
|
||||
do
|
||||
{
|
||||
char nibbleType = 0;
|
||||
int currentNibble = (currentParam >> shiftingAmountForCurrentNibble) & 0xF;
|
||||
if (currentNibble > 9)
|
||||
{
|
||||
if (currentNibble > 15) //((currentNibble - 10) > 5)
|
||||
nibbleType = 120;
|
||||
else
|
||||
nibbleType = currentNibble + 55;
|
||||
}
|
||||
else
|
||||
nibbleType = currentNibble + 48;
|
||||
|
||||
char *unk = &nibbleType;
|
||||
char oldVal;
|
||||
do
|
||||
{
|
||||
oldVal = *unk;
|
||||
}
|
||||
while (*unk)
|
||||
|
||||
|
||||
bool outOfBounds = shiftingAmountForCurrentNibble - 4 < 0;
|
||||
shiftingAmountForCurrentNibble -= 4;
|
||||
}
|
||||
while (!outOfBounds);
|
||||
|
||||
}
|
||||
while (currentParamIdx < 4);
|
||||
someString += ')';
|
Loading…
Add table
Reference in a new issue