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);