diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3fdc511 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ + +.vs/ +Debug/ +Release/ diff --git a/NitroPaint/NitroPaint.vcxproj b/NitroPaint/NitroPaint.vcxproj index fc4b1bd..420bc96 100644 --- a/NitroPaint/NitroPaint.vcxproj +++ b/NitroPaint/NitroPaint.vcxproj @@ -191,6 +191,7 @@ + @@ -230,6 +231,7 @@ + diff --git a/NitroPaint/filecommon.c b/NitroPaint/filecommon.c index b6a1db9..ccd887d 100644 --- a/NitroPaint/filecommon.c +++ b/NitroPaint/filecommon.c @@ -336,6 +336,7 @@ int ObjIdentify(char *file, int size, LPCWSTR path) { else if (CellIsValidHudson(buffer, bufferSize)) type = FILE_TYPE_CELL; else if (CellIsValidGhostTrick(buffer, bufferSize)) type = FILE_TYPE_CELL; else if (AnmIsValidGhostTrick(buffer, bufferSize)) type = FILE_TYPE_NANR; + else if (TdsIsValid(buffer, bufferSize)) type = FILE_TYPE_TDS; //test for bin format files else { diff --git a/NitroPaint/filecommon.h b/NitroPaint/filecommon.h index 07a97d7..506a992 100644 --- a/NitroPaint/filecommon.h +++ b/NitroPaint/filecommon.h @@ -15,6 +15,7 @@ #define FILE_TYPE_COMBO2D 10 #define FILE_TYPE_NMCR 11 #define FILE_TYPE_NMAR 12 +#define FILE_TYPE_TDS 13 typedef struct OBJECT_HEADER_ { int size; diff --git a/NitroPaint/nitropaint.c b/NitroPaint/nitropaint.c index bfe0bff..e402449 100644 --- a/NitroPaint/nitropaint.c +++ b/NitroPaint/nitropaint.c @@ -20,6 +20,7 @@ #include "tileeditor.h" #include "textureeditor.h" #include "nsbtx.h" +#include "tds.h" #include "nmcrviewer.h" #include "colorchooser.h" #include "ui.h" @@ -658,6 +659,9 @@ VOID OpenFileByName(HWND hWnd, LPCWSTR path) { case FILE_TYPE_IMAGE: CreateImageDialog(hWnd, path); break; + case FILE_TYPE_TDS: + CreateTdsViewer(data->hWndMdi, path); + break; case FILE_TYPE_COMBO2D: { //since we're kind of stepping around things a bit, we need to decompress here if applicable diff --git a/NitroPaint/tds.c b/NitroPaint/tds.c new file mode 100644 index 0000000..0bd2027 --- /dev/null +++ b/NitroPaint/tds.c @@ -0,0 +1,112 @@ +#include "tds.h" +#include "texture.h" +#include "textureeditor.h" + +#include +#include + +HWND CreateTdsViewer(HWND hWndParent, LPCWSTR path) { + TdsFile tds; + int n = TdsReadFile(&tds, path); + if (n) { + MessageBox(hWndParent, L"Invalid file.", L"Invalid file", MB_ICONERROR); + return NULL; + } + + return CreateTextureEditorImmediate(CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hWndParent, &tds.texture); +} + +void TdsFree(OBJECT_HEADER* header) { + TdsFile* tds = (TdsFile*)header; + if (tds->texture.texels.texel != NULL) free(tds->texture.texels.texel); + if (tds->texture.texels.cmp != NULL) free(tds->texture.texels.cmp); + if (tds->texture.palette.pal != NULL) free(tds->texture.palette.pal); + +} + +void TdsInit(TdsFile* tds) { + tds->header.size = sizeof(TdsFile); + ObjInit((OBJECT_HEADER*)tds, FILE_TYPE_TDS, 0); + tds->header.dispose = TdsFree; +} + +int TdsIsValid(char* buffer, unsigned int size) { + if (size < 0x24 || (size & 3)) return 0; + + uint32_t magic = *(uint32_t*)(buffer + 0); + if (magic != '.tds') return 0; + + uint32_t texCount = *(uint32_t*)(buffer + 0x04); + if (texCount != 1) { + printf("!!!TexCount not 1!!!\n"); + return 0; + } + + uint32_t texFormat = *(uint8_t*)(buffer + 0x08); + uint32_t texSizeS = *(uint8_t*)(buffer + 0x09); + uint32_t texSizeT = *(uint8_t*)(buffer + 0x0A); + uint32_t textureOffset = *(uint32_t*)(buffer + 0x0C); + uint32_t paletteOffset = *(uint32_t*)(buffer + 0x14); + uint32_t width = *(uint32_t*)(buffer + 0x1C); + uint32_t height = *(uint32_t*)(buffer + 0x20); + if (textureOffset < 0x24 || textureOffset >= size) + return 0; + if (paletteOffset < 0x24 || paletteOffset >= size) + return 0; + if (width > (8 << texSizeS) || height > (8 << texSizeT) || texFormat == 0) + return 0; + + if (texFormat == CT_4x4) { + printf("!!!TexFormat is 4x4!?!?\n"); + return 0; + } + + return 1; + +} + +int TdsRead(TdsFile* tds, char* buffer, int size) { + //is it valid? + if (!TdsIsValid(buffer, size)) return 1; + + TdsInit(tds); + + uint32_t texFormat = *(uint8_t*)(buffer + 0x08); + uint32_t texSizeS = *(uint8_t*)(buffer + 0x09); + uint32_t texSizeT = *(uint8_t*)(buffer + 0x0A); + uint32_t textureOffset = *(uint32_t*)(buffer + 0x0C); + uint32_t textureLength = *(uint32_t*)(buffer + 0x10); + uint32_t paletteOffset = *(uint32_t*)(buffer + 0x14); + uint32_t paletteLength = *(uint32_t*)(buffer + 0x18); + uint32_t width = *(uint32_t*)(buffer + 0x1C); + uint32_t height = *(uint32_t*)(buffer + 0x20); + + uint32_t texImageParam = 0; + texImageParam |= (texSizeS & 0x7) << 20; + texImageParam |= (texSizeT & 0x7) << 23; + texImageParam |= (texFormat & 0x7) << 26; + + tds->texture.texels.texImageParam = texImageParam; + tds->texture.texels.height = height; + tds->texture.texels.cmp = NULL; + tds->texture.texels.texel = calloc(textureLength, 1); + memcpy(tds->texture.texels.texel, buffer + textureOffset, textureLength); + + tds->texture.palette.nColors = paletteLength / 2; + tds->texture.palette.pal = calloc(paletteLength, 1); + memcpy(tds->texture.palette.pal, buffer + paletteOffset, paletteLength); + + return 0; +} + +int TdsReadFile(TdsFile* tds, LPCWSTR path) { + return ObjReadFile(path, (OBJECT_HEADER*)tds, (OBJECT_READER)TdsRead); +} + +int TdsWrite(TdsFile* tds, BSTREAM* stream) { + return 0; +} + +int TdsWriteFile(TdsFile* tds, LPWSTR name) { + return ObjWriteFile(name, (OBJECT_HEADER*)tds, (OBJECT_WRITER)TdsWrite); +} diff --git a/NitroPaint/tds.h b/NitroPaint/tds.h new file mode 100644 index 0000000..76fffbb --- /dev/null +++ b/NitroPaint/tds.h @@ -0,0 +1,26 @@ +#pragma once +#include +#include "texture.h" +#include "filecommon.h" + + +typedef struct TdsFile_ { + + OBJECT_HEADER header; + TEXTURE texture; + +} TdsFile; + +HWND CreateTdsViewer(HWND hWndParent, LPCWSTR path); + +void TdsInit(TdsFile* tds); + +int TdsRead(TdsFile* tds, char* buffer, int size); + +int TdsIsValid(char* buffer, unsigned int size); + +int TdsReadFile(TdsFile* tds, LPCWSTR path); + +int TdsWriteFile(TdsFile* tds, LPWSTR filename); + +int TdsWrite(TdsFile* tds, BSTREAM* stream);