diff --git a/Makefile b/Makefile index bec6c8c..23ac41f 100644 --- a/Makefile +++ b/Makefile @@ -4,11 +4,14 @@ CFLAGS= -I"include" all: main -main: devil1pld.o +main: devil1pld.o devil1tex.o $(CC) $^ test/main.c $(CFLAGS) -o $(EX) devil1pld.o: src/devil1pld.c $(CC) -c $^ $(CFLAGS) +devil1tex.o: src/devil1tex.c + $(CC) -c $^ $(CFLAGS) + clean: rm *.o $(EX) diff --git a/include/devil1tex.h b/include/devil1tex.h new file mode 100644 index 0000000..db19345 --- /dev/null +++ b/include/devil1tex.h @@ -0,0 +1,71 @@ +#ifndef DEVIL1TEX_H +#define DEVIL1TEX_H + +#include +#include + +// disable struct padding +// to easily impose struct on plain data. +#pragma pack(push, 1) + +struct TexturePack { + char id[4]; + int32_t batchNumber; + uint32_t firstBatchOffset; // + uint32_t unknownA; +}; + +struct TextureBatchDescriptor{ + int32_t batchIdx; + uint32_t hash; // + uint32_t texNumber; + uint32_t unknownA[8]; // + uint32_t textureSize; // + uint32_t unknownB[30]; +}; + +struct Texture { + // size of array is defined by descriptor + // textureSize + unsigned char *data; +}; + +struct TextureBatch { + // quantity of textures are defined by descriptor + // texNumber + struct Texture *batch; +}; + +#pragma pack(pop) + +// -------------------------------------------------------+ +// Functions +// -------------------------------------------------------+ + +// Print Texture Pack Header. +void printtph(struct TexturePack*); + +// Print Texture Batch Descriptor. +void printtbd(struct TextureBatchDescriptor*); + +// Get Texture Batch Descriptor. +// ** = 'pass by reference' of a pointer to struct +bool gettexdescriptor(struct TextureBatchDescriptor**, + unsigned int, + const char *, + unsigned int); + +// Get Texture Batch. +// ** = 'pass by reference' of a pointer to struct +bool gettexbatch(struct TextureBatch**, + unsigned int, + const char*, + unsigned int); + +// Unpack Texture Batch +bool unpacktexbatch(struct Texture*, + unsigned int, + const char*, + const unsigned int); + +#endif diff --git a/src/devil1tex.c b/src/devil1tex.c new file mode 100644 index 0000000..486f068 --- /dev/null +++ b/src/devil1tex.c @@ -0,0 +1,93 @@ +#include "devil1tex.h" +#include +#include + +void printtph (struct TexturePack *tp) { + if (tp != NULL) { + printf("id: \t %c %c %c %c \n", tp -> id[3], + tp -> id[2], + tp -> id[1], + tp -> id[0]); + printf("batch#: \t %i \n", tp -> batchNumber); + printf("1st batch: \t %i \n", tp -> firstBatchOffset); + printf("unknownA: \t %i\n", tp -> unknownA); + } + return; +} + +void printtbd(struct TextureBatchDescriptor *bd) { + if (bd != NULL) { + printf("batch index: \t %i \n", bd -> batchIdx); + printf("hash: \t %u \n", bd -> hash); + printf("textures: \t %i\n", bd -> texNumber); + } +} + +bool gettexdescriptor(struct TextureBatchDescriptor **descriptor, + unsigned int i, + const char *filedata, + unsigned int filesize) { + // starts after the pack header. + bool done = false; + unsigned int offset = sizeof(struct TexturePack); + offset += sizeof(struct TextureBatchDescriptor) * i; + if (filedata != NULL) { + *descriptor = (struct TextureBatchDescriptor*)(filedata + offset); + done = true; + } + return done; +} + +bool gettexbatch(struct TextureBatch **batch, + unsigned int i, + const char *filedata, + unsigned int filesize) { + struct TexturePack *p = NULL; + if (filedata == NULL) { // no data to get batch from. + return false; + } + p = (struct TexturePack*)filedata; + if (i > p -> batchNumber) { // no such batch in texture pack + return false; + } + if (i == 0) { + *batch = (struct TextureBatch*)(filedata + (p -> firstBatchOffset)); + return true; + } + struct TextureBatchDescriptor *d = NULL; + // find how large are previous batches in total + // in order to jump to specified texture batch + unsigned int pastbatchsize = p -> firstBatchOffset; + unsigned int j; + for (j = 0; j < i; j++) { + gettexdescriptor(&d, j, filedata, filesize); + pastbatchsize += (d -> textureSize * d -> texNumber); + } + *batch = (struct TextureBatch*)(filedata + pastbatchsize); + return true; +} + +bool unpacktexbatch(struct Texture *t, + unsigned int i, + const char *filedata, + const unsigned int filesize) { + if (filedata == NULL) { + return false; + } + struct TextureBatch *b = NULL; + struct TextureBatchDescriptor *d = NULL; + gettexbatch(&b, i, filedata, filesize); + gettexdescriptor(&d, i, filedata, filesize); + + // first texture is at the start of the batch + // second texture is right after. + unsigned int j; + for (j = 0; j < d -> texNumber; j++) { + t[j].data = (unsigned char*)b + (d -> textureSize * j); + } + return true; +} + + + + diff --git a/test/main.c b/test/main.c index 1a6e312..c92f3ba 100644 --- a/test/main.c +++ b/test/main.c @@ -1,9 +1,11 @@ -#include "devil1pld.h" #include #include #include #include +#include "devil1pld.h" +#include "devil1tex.h" + bool writedata(const char *basename, unsigned int id, const char *data, @@ -98,11 +100,60 @@ bool unpackpld(const char *filedata, } } +void write(const char *filename, + const char* t, + unsigned int size) { + if (filename == NULL) { + return; + } + unsigned int written = 0; + FILE *out = fopen(filename, "wb"); + if (out != NULL) { + written = fwrite(t, sizeof(unsigned char), size, out); + fclose(out); + if (written == 0) { + perror("texture write error"); + } + } +} + +void exporttextures(const char *filedata, + unsigned int filesize, + const char *filename) { + struct TexturePack *p = NULL; + struct Texture *t = NULL; + struct TextureBatchDescriptor *d = NULL; + char * fmt = NULL; + if (filename == NULL || filesize == 0) { + return; + } + p = (struct TexturePack*)filedata; + fmt = (char*)malloc(strlen(filename) + 3 + 4); + unsigned int i; + unsigned int j; + unsigned int id = 0; + for (i = 0; i < p -> batchNumber; i++) { + gettexdescriptor(&d, i, filedata, filesize); + t = (struct Texture*) + malloc(sizeof(struct Texture) * (d -> texNumber)); + unpacktexbatch(t, i, filedata, filesize); + for (j = 0; j < d -> texNumber; j++) { + sprintf(fmt, "%s_%d.dds", filename, id); + write(fmt, t[j].data, d -> textureSize); + id++; + } + free(t); + } + free(fmt); + return; +} + int main(int argc, char ** argv) { char *f = argv[1]; unsigned int bufsize = 0; char *buffer = loadfile(f, &bufsize); - unpackpld(buffer, bufsize, f); +// unpackpld(buffer, bufsize, f); + exporttextures(buffer, bufsize, f); free(buffer); return 0; }