diff options
| author | John Wilbert M. Villamor <lameguy64@gmail.com> | 2019-04-06 10:11:07 +0800 |
|---|---|---|
| committer | John Wilbert M. Villamor <lameguy64@gmail.com> | 2019-04-06 10:11:07 +0800 |
| commit | f3e040230772f978540a71aea43dfde200992922 (patch) | |
| tree | bd8ca31b72dd01e24980b073854e263589530f56 /tools/smxlink/main.cpp | |
| download | psn00bsdk-f3e040230772f978540a71aea43dfde200992922.tar.gz | |
First commit
Diffstat (limited to 'tools/smxlink/main.cpp')
| -rw-r--r-- | tools/smxlink/main.cpp | 1003 |
1 files changed, 1003 insertions, 0 deletions
diff --git a/tools/smxlink/main.cpp b/tools/smxlink/main.cpp new file mode 100644 index 0000000..ec6f707 --- /dev/null +++ b/tools/smxlink/main.cpp @@ -0,0 +1,1003 @@ +/* This tool was originally developed for Scarlet Engine + * (formerly Project Scarlet) + * + * This utility is still a work in progress and the SMX and SMD specification + * is subject to change without notice. It is included as part of the + * PSn00bSDK project as an example utility for the n00bdemo example which + * uses SMD format model data files. + * + */ + +#include <stdio.h> +#include <math.h> +#include <tinyxml2.h> +#include <string> +//#include <windef.h> +#include "timreader.h" + +#define VERSION "0.25b" + +namespace param +{ + std::string smxFileName; + std::string smdFileName; + std::string texDir; + + float scaleFactor = 1.f; +} + +typedef struct { + char id[3]; // File ID (SMD) + unsigned char version; // Version number (0x01) + unsigned short flags; + unsigned short numverts; + unsigned short numnorms; + unsigned short numprims; + unsigned long vtxAddr; + unsigned long nrmAddr; + unsigned long priAddr; +} SMD_HEADER; + +typedef struct { + short vx,vy,vz,vp; +} SVECTOR; + + +#define PRIM_TYPE_LINE 0 +#define PRIM_TYPE_TRI 1 +#define PRIM_TYPE_QUAD 2 + +#define PRIM_LIGHTING_NONE 0 // No shading (no normals) +#define PRIM_LIGHTING_FLAT 1 // Flat shading (1 normal) +#define PRIM_LIGHTING_SMOOTH 2 // Smooth shading (3 normals per vertex) + +typedef struct { + + unsigned char type:2; // Primitive type + unsigned char l_type:2; // Lighting type (0 - none, 1 - flat shading, 2 - smooth shading) + unsigned char c_type:1; // Coloring type (0 - solid color, 1 - gouraud) + unsigned char texture:1; // Texture mapped + unsigned char blend:2; // Blend mode setting (actual blend enable is determined by primitive code) + // byte boundary + unsigned char zoff:4; + unsigned char nocull:1; // Double sided (no cull) + unsigned char mask:1; // Force mask bit setting + unsigned char texwin:2; + // byte boundary + unsigned char texoff:2; + unsigned char reserved:6; + // byte boundary + unsigned char len; +} PRIM_ID; + +typedef struct { + unsigned short v0,v1,v2,v3; +} PRIM_V; + +typedef struct { + unsigned char r,g,b,c; +} PRIM_RGBC; + +typedef struct { + unsigned short tpage,clut; +} PRIM_TC; + +typedef struct { + unsigned char u,v; +} PRIM_UV; + + +int main(int argc, const char* argv[]) { + + printf("SMXLINK " VERSION " - Scarlet SMX to SMD Model Converter " + "(part of Scarlet Engine)\n"); + printf("Note: Outputs in *NEW* revision 1 format!\n"); + printf("2017-2019 Meido-Tek Productions\n\n"); + + if (argc <= 1) { + + printf("Parameters:\n"); + printf(" smxlink [-o <filename>] [-s <scale>] <smxfile>\n\n"); + printf(" -o <filename> - Specify output filename (default: first file specified)\n"); + printf(" -s <scale> - Scale factor to apply to model on conversion (default: 1.0)\n"); + printf(" -tp <path> - Specify directory path to TIM texture files\n"); + printf(" <smxfile> - SMX file to convert to SMD\n"); + + return EXIT_SUCCESS; + + } + + for(int i=1; i<argc; i++) { + + if (strcasecmp(argv[i], "-o") == 0) { + + i++; + param::smdFileName = argv[i]; + + } else if (strcasecmp(argv[i], "-s") == 0) { + + i++; + param::scaleFactor = atof(argv[i]); + + } else if (strcasecmp(argv[i], "-tp") == 0) { + + i++; + param::texDir = argv[i]; + + if( ( param::texDir[param::texDir.size()-1] != '\\' ) && + ( param::texDir[param::texDir.size()-1] != '/') ) { + + param::texDir += "/"; + + } + + } else { + + param::smxFileName = argv[i]; + + } + + } + + if (param::smdFileName.empty()) { + + param::smdFileName = param::smxFileName; + param::smdFileName.erase(param::smdFileName.rfind(".")); + param::smdFileName += ".smd"; + + } + + printf("Input : %s\n", param::smxFileName.c_str()); + printf("Output : %s\n", param::smdFileName.c_str()); + + if (!param::texDir.empty()) + printf("TexDir : %s\n", param::texDir.c_str()); + + printf("\n"); + + tinyxml2::XMLDocument smxFile; + + if (smxFile.LoadFile(param::smxFileName.c_str()) != tinyxml2::XML_SUCCESS) { + printf("ERROR: Unable to load SMX file:\n"); + smxFile.PrintError(); + return EXIT_FAILURE; + } + + tinyxml2::XMLElement* smxModel = smxFile.FirstChildElement("model"); + + // Parse textures + TIM_COORDS *texCoords = NULL; + int numTextures = 0; + + if (smxModel->FirstChildElement("textures") != NULL) { + + tinyxml2::XMLElement *texFileElement = smxModel->FirstChildElement("textures"); + + if (texFileElement != NULL) { + + numTextures = atoi(texFileElement->Attribute("count")); + texFileElement = texFileElement->FirstChildElement("texture"); + + texCoords = (TIM_COORDS*)malloc(sizeof(TIM_COORDS)*numTextures); + + int index = 0; + + while(texFileElement != NULL) { + + std::string timFileName = texFileElement->Attribute("file"); + + if (timFileName.rfind(".") == std::string::npos) + { + timFileName.append(".tim"); + } + + timFileName = param::texDir + timFileName; + + if (!GetTimCoords(timFileName.c_str(), &texCoords[index])) { + printf("ERROR: Unable to open texture file: %s\n", timFileName.c_str()); + free(texCoords); + return EXIT_FAILURE; + } + + switch(texCoords[index].flag.pmode) { + case 0: // 4-bit + texCoords[index].pixdata.pw *= 4; + break; + case 1: // 8-bit + texCoords[index].pixdata.pw *= 2; + break; + } + + texFileElement = texFileElement->NextSiblingElement("texture"); + index++; + + } + + } + + } + + + FILE* smdFile = fopen(param::smdFileName.c_str(), "wb"); + + // Create temporary header + SMD_HEADER smdHeader; + + memset(&smdHeader, 0x00, sizeof(SMD_HEADER)); + fwrite(&smdHeader, sizeof(SMD_HEADER), 1, smdFile); + + + // Convert vertices + if (smxModel->FirstChildElement("vertices") != NULL) { + + smdHeader.vtxAddr = ftell(smdFile); + + tinyxml2::XMLElement* smxVertices = smxModel->FirstChildElement("vertices"); + smxVertices = smxVertices->FirstChildElement("v"); + + while(smxVertices != NULL) { + + SVECTOR vertex; + + vertex.vx = round(param::scaleFactor * atof(smxVertices->Attribute("x"))); + vertex.vy = round(param::scaleFactor * atof(smxVertices->Attribute("y"))); + vertex.vz = round(param::scaleFactor * atof(smxVertices->Attribute("z"))); + vertex.vp = 0; + + fwrite(&vertex, sizeof(SVECTOR), 1, smdFile); + smdHeader.numverts++; + + smxVertices = smxVertices->NextSiblingElement("v"); + + } + + smdHeader.flags |= 0x1; + + } + + + // Convert normals + if (smxModel->FirstChildElement("normals") != NULL) { + + smdHeader.nrmAddr = ftell(smdFile); + + tinyxml2::XMLElement* smxVertices = smxModel->FirstChildElement("normals"); + + smxVertices = smxVertices->FirstChildElement("v"); + + while(smxVertices != NULL) { + + SVECTOR vertex; + + vertex.vx = round(4096 * atof(smxVertices->Attribute("x"))); + vertex.vy = round(4096 * atof(smxVertices->Attribute("y"))); + vertex.vz = round(4096 * atof(smxVertices->Attribute("z"))); + vertex.vp = 0; + + fwrite(&vertex, sizeof(SVECTOR), 1, smdFile); + smdHeader.numnorms++; + + smxVertices = smxVertices->NextSiblingElement("v"); + + } + + smdHeader.flags |= 0x2; + + } else { + + smdHeader.numnorms = 0; + + } + + + if (smxModel->FirstChildElement("primitives") != NULL) { + + smdHeader.priAddr = ftell(smdFile); + + tinyxml2::XMLElement* smxPrimitive = smxModel->FirstChildElement("primitives"); + smxPrimitive = smxPrimitive->FirstChildElement("poly"); + + PRIM_ID *prim; + char pribuff[40]; + char* priptr; + while(smxPrimitive != NULL) { + + const char* primType = smxPrimitive->Attribute("type"); + + if( primType == NULL ) { + smxPrimitive = smxPrimitive->NextSiblingElement("poly"); + continue; + } + + memset( pribuff, 0x0, 32 ); + priptr = pribuff; + + prim = (PRIM_ID*)priptr; + + if( smxPrimitive->IntAttribute( "double", 0 ) ) + prim->nocull = true; + + if( ( strcasecmp( "F3", primType ) == 0 ) || + ( strcasecmp( "FT3", primType ) == 0 ) ) { + + prim->type = PRIM_TYPE_TRI; + prim->len = 4; + + priptr += sizeof(PRIM_ID); + + // Write vertex indices + ((PRIM_V*)priptr)->v0 = atoi( smxPrimitive->Attribute( "v0" ) ); + ((PRIM_V*)priptr)->v1 = atoi( smxPrimitive->Attribute( "v1" ) ); + ((PRIM_V*)priptr)->v2 = atoi( smxPrimitive->Attribute( "v2" ) ); + ((PRIM_V*)priptr)->v3 = 0; + + priptr += 8; + prim->len += 8; + + if( strcasecmp( "F", smxPrimitive->Attribute( "shading" ) ) == 0 ) { + + prim->l_type = PRIM_LIGHTING_FLAT; + + ((PRIM_V*)priptr)->v0 = atoi( smxPrimitive->Attribute( "n0" ) ); + ((PRIM_V*)priptr)->v1 = 0; + priptr += 4; + prim->len += 4; + + } else if( strcasecmp( "S", smxPrimitive->Attribute( "shading" ) ) == 0 ) { + + prim->l_type = PRIM_LIGHTING_SMOOTH; + + ((PRIM_V*)priptr)->v0 = atoi( smxPrimitive->Attribute( "n0" ) ); + ((PRIM_V*)priptr)->v1 = atoi( smxPrimitive->Attribute( "n1" ) ); + ((PRIM_V*)priptr)->v2 = atoi( smxPrimitive->Attribute( "n2" ) ); + ((PRIM_V*)priptr)->v3 = 0; + + priptr += 8; + prim->len += 8; + + } + + ((PRIM_RGBC*)priptr)->r = atoi( smxPrimitive->Attribute( "r0" ) ); + ((PRIM_RGBC*)priptr)->g = atoi( smxPrimitive->Attribute( "g0" ) ); + ((PRIM_RGBC*)priptr)->b = atoi( smxPrimitive->Attribute( "b0" ) ); + + if( smxPrimitive->IntAttribute( "blend" ) > 0 ) { + ((PRIM_RGBC*)priptr)->c = 0x2; + prim->blend = smxPrimitive->IntAttribute( "blend" )-1; + } + + priptr += 4; + prim->len += 4; + + if( strcasecmp( "FT3", primType ) == 0 ) { // Textured + + TIM_COORDS *tex; + int uoffs,voffs; + int texNum = atoi( smxPrimitive->Attribute( "texture" ) ); + + if( texNum < 0 ) { + + printf( "ERROR: Primitive with negative texture index encountered.\n" ); + + fclose( smdFile ); + + if( texCoords != NULL ) { + free( texCoords ); + } + + return EXIT_FAILURE; + + } else if( texNum > numTextures-1 ) { + + printf( "ERROR: Primitive with texture index greater than specified encountered.\n" ); + + fclose( smdFile ); + + if( texCoords != NULL ) { + free( texCoords ); + } + + return EXIT_FAILURE; + + } + + tex = &texCoords[texNum]; + + uoffs = tex->pixdata.px; + voffs = tex->pixdata.py&0xff; + + switch(tex->flag.pmode) { + case 0: // 4-bit + uoffs = (uoffs*4)%256; + break; + case 1: // 8-bit + uoffs = (uoffs*2)%128; + break; + case 2: // 16-bit + uoffs = uoffs%64; + break; + } + + ((PRIM_UV*)priptr)[0].u = smxPrimitive->IntAttribute( "tu0" )+uoffs; + ((PRIM_UV*)priptr)[0].v = smxPrimitive->IntAttribute( "tv0" )+voffs; + ((PRIM_UV*)priptr)[1].u = smxPrimitive->IntAttribute( "tu1" )+uoffs; + ((PRIM_UV*)priptr)[1].v = smxPrimitive->IntAttribute( "tv1" )+voffs; + ((PRIM_UV*)priptr)[2].u = smxPrimitive->IntAttribute( "tu2" )+uoffs; + ((PRIM_UV*)priptr)[2].v = smxPrimitive->IntAttribute( "tv2" )+voffs; + ((PRIM_UV*)priptr)[3].u = 0; + ((PRIM_UV*)priptr)[3].v = 0; + + priptr += 8; + prim->len += 8; + + ((PRIM_TC*)priptr)->tpage = GetTPage( tex->flag.pmode, + prim->blend, tex->pixdata.px, tex->pixdata.py ); + ((PRIM_TC*)priptr)->clut = GetClut( tex->clutdata.px, tex->clutdata.py ); + + priptr += 4; + prim->len += 4; + + prim->texture = true; + + } + + fwrite( pribuff, 1, prim->len, smdFile ); + smdHeader.numprims++; + + } else if( strcasecmp( "G3", primType ) == 0 ) { + + prim->type = PRIM_TYPE_TRI; + prim->len = 4; + prim->c_type = 1; // Gouraud + + priptr += sizeof(PRIM_ID); + + // Write vertex indices + ((PRIM_V*)priptr)->v0 = atoi( smxPrimitive->Attribute( "v0" ) ); + ((PRIM_V*)priptr)->v1 = atoi( smxPrimitive->Attribute( "v1" ) ); + ((PRIM_V*)priptr)->v2 = atoi( smxPrimitive->Attribute( "v2" ) ); + ((PRIM_V*)priptr)->v3 = 0; + + priptr += 8; + prim->len += 8; + + if( strcasecmp( "F", smxPrimitive->Attribute( "shading" ) ) == 0 ) { + + prim->l_type = PRIM_LIGHTING_FLAT; + + ((PRIM_V*)priptr)->v0 = atoi( smxPrimitive->Attribute( "n0" ) ); + ((PRIM_V*)priptr)->v1 = 0; + priptr += 4; + prim->len += 4; + + } else if( strcasecmp( "S", smxPrimitive->Attribute( "shading" ) ) == 0 ) { + + prim->l_type = PRIM_LIGHTING_SMOOTH; + + ((PRIM_V*)priptr)->v0 = atoi( smxPrimitive->Attribute( "n0" ) ); + ((PRIM_V*)priptr)->v1 = atoi( smxPrimitive->Attribute( "n1" ) ); + ((PRIM_V*)priptr)->v2 = atoi( smxPrimitive->Attribute( "n2" ) ); + ((PRIM_V*)priptr)->v3 = 0; + + priptr += 8; + prim->len += 8; + + } + + ((PRIM_RGBC*)priptr)->r = atoi( smxPrimitive->Attribute( "r0" ) ); + ((PRIM_RGBC*)priptr)->g = atoi( smxPrimitive->Attribute( "g0" ) ); + ((PRIM_RGBC*)priptr)->b = atoi( smxPrimitive->Attribute( "b0" ) ); + if( smxPrimitive->IntAttribute( "blend" ) > 0 ) { + ((PRIM_RGBC*)priptr)->c = 0x2; + prim->blend = smxPrimitive->IntAttribute( "blend" )-1; + } + priptr += 4; + prim->len += 4; + + // Color 1 + ((PRIM_RGBC*)priptr)->r = atoi( smxPrimitive->Attribute( "r1" ) ); + ((PRIM_RGBC*)priptr)->g = atoi( smxPrimitive->Attribute( "g1" ) ); + ((PRIM_RGBC*)priptr)->b = atoi( smxPrimitive->Attribute( "b1" ) ); + priptr += 4; + prim->len += 4; + + // Color 2 + ((PRIM_RGBC*)priptr)->r = atoi( smxPrimitive->Attribute( "r2" ) ); + ((PRIM_RGBC*)priptr)->g = atoi( smxPrimitive->Attribute( "g2" ) ); + ((PRIM_RGBC*)priptr)->b = atoi( smxPrimitive->Attribute( "b2" ) ); + priptr += 4; + prim->len += 4; + + fwrite( pribuff, 1, prim->len, smdFile ); + smdHeader.numprims++; + + } else if( ( strcasecmp( "F4", primType ) == 0 ) || + ( strcasecmp( "FT4", primType ) == 0 ) ) { + + prim->type = PRIM_TYPE_QUAD; + prim->len = 4; + + priptr += sizeof(PRIM_ID); + + // Write vertex indices + ((PRIM_V*)priptr)->v0 = atoi( smxPrimitive->Attribute( "v0" ) ); + ((PRIM_V*)priptr)->v1 = atoi( smxPrimitive->Attribute( "v1" ) ); + ((PRIM_V*)priptr)->v2 = atoi( smxPrimitive->Attribute( "v2" ) ); + ((PRIM_V*)priptr)->v3 = atoi( smxPrimitive->Attribute( "v3" ) ); + + priptr += 8; + prim->len += 8; + + if( strcasecmp( "F", smxPrimitive->Attribute( "shading" ) ) == 0 ) { + + prim->l_type = PRIM_LIGHTING_FLAT; + + ((PRIM_V*)priptr)->v0 = atoi( smxPrimitive->Attribute( "n0" ) ); + ((PRIM_V*)priptr)->v1 = 0; + priptr += 4; + prim->len += 4; + + } else if( strcasecmp( "S", smxPrimitive->Attribute( "shading" ) ) == 0 ) { + + prim->l_type = PRIM_LIGHTING_SMOOTH; + + ((PRIM_V*)priptr)->v0 = atoi( smxPrimitive->Attribute( "n0" ) ); + ((PRIM_V*)priptr)->v1 = atoi( smxPrimitive->Attribute( "n1" ) ); + ((PRIM_V*)priptr)->v2 = atoi( smxPrimitive->Attribute( "n2" ) ); + ((PRIM_V*)priptr)->v3 = atoi( smxPrimitive->Attribute( "n3" ) ); + + priptr += 8; + prim->len += 8; + + } + + ((PRIM_RGBC*)priptr)->r = atoi( smxPrimitive->Attribute( "r0" ) ); + ((PRIM_RGBC*)priptr)->g = atoi( smxPrimitive->Attribute( "g0" ) ); + ((PRIM_RGBC*)priptr)->b = atoi( smxPrimitive->Attribute( "b0" ) ); + + if( smxPrimitive->IntAttribute( "blend" ) > 0 ) { + ((PRIM_RGBC*)priptr)->c = 0x2; + prim->blend = smxPrimitive->IntAttribute( "blend" )-1; + } + + priptr += 4; + prim->len += 4; + + if( strcasecmp( "FT4", primType ) == 0 ) { // Textured + + TIM_COORDS *tex; + int uoffs,voffs; + int texNum = atoi( smxPrimitive->Attribute( "texture" ) ); + + if( texNum < 0 ) { + + printf( "ERROR: Primitive with negative texture index encountered.\n" ); + + fclose( smdFile ); + + if( texCoords != NULL ) { + free( texCoords ); + } + + return EXIT_FAILURE; + + } else if( texNum > numTextures-1 ) { + + printf( "ERROR: Primitive with texture index greater than specified encountered.\n" ); + + fclose( smdFile ); + + if( texCoords != NULL ) { + free( texCoords ); + } + + return EXIT_FAILURE; + + } + + tex = &texCoords[texNum]; + + uoffs = tex->pixdata.px; + voffs = tex->pixdata.py&0xff; + + switch(tex->flag.pmode) { + case 0: // 4-bit + uoffs = (uoffs*4)%256; + break; + case 1: // 8-bit + uoffs = (uoffs*2)%128; + break; + case 2: // 16-bit + uoffs = uoffs%64; + break; + } + + ((PRIM_UV*)priptr)[0].u = smxPrimitive->IntAttribute( "tu0" )+uoffs; + ((PRIM_UV*)priptr)[0].v = smxPrimitive->IntAttribute( "tv0" )+voffs; + ((PRIM_UV*)priptr)[1].u = smxPrimitive->IntAttribute( "tu1" )+uoffs; + ((PRIM_UV*)priptr)[1].v = smxPrimitive->IntAttribute( "tv1" )+voffs; + ((PRIM_UV*)priptr)[2].u = smxPrimitive->IntAttribute( "tu2" )+uoffs; + ((PRIM_UV*)priptr)[2].v = smxPrimitive->IntAttribute( "tv2" )+voffs; + ((PRIM_UV*)priptr)[3].u = smxPrimitive->IntAttribute( "tu3" )+uoffs; + ((PRIM_UV*)priptr)[3].v = smxPrimitive->IntAttribute( "tv3" )+voffs; + + priptr += 8; + prim->len += 8; + + ((PRIM_TC*)priptr)->tpage = GetTPage( tex->flag.pmode, + prim->blend, tex->pixdata.px, tex->pixdata.py ); + ((PRIM_TC*)priptr)->clut = GetClut( tex->clutdata.px, tex->clutdata.py ); + + priptr += 4; + prim->len += 4; + + prim->texture = true; + + } + + fwrite( pribuff, 1, prim->len, smdFile ); + smdHeader.numprims++; + + } else if( strcasecmp( "G4", primType ) == 0 ) { + + prim->type = PRIM_TYPE_QUAD; + prim->len = 4; + prim->c_type = 1; // Gouraud + + priptr += sizeof(PRIM_ID); + + // Write vertex indices + ((PRIM_V*)priptr)->v0 = atoi( smxPrimitive->Attribute( "v0" ) ); + ((PRIM_V*)priptr)->v1 = atoi( smxPrimitive->Attribute( "v1" ) ); + ((PRIM_V*)priptr)->v2 = atoi( smxPrimitive->Attribute( "v2" ) ); + ((PRIM_V*)priptr)->v3 = atoi( smxPrimitive->Attribute( "v3" ) ); + + priptr += 8; + prim->len += 8; + + if( strcasecmp( "F", smxPrimitive->Attribute( "shading" ) ) == 0 ) { + + prim->l_type = PRIM_LIGHTING_FLAT; + + ((PRIM_V*)priptr)->v0 = atoi( smxPrimitive->Attribute( "n0" ) ); + ((PRIM_V*)priptr)->v1 = 0; + priptr += 4; + prim->len += 4; + + } else if( strcasecmp( "S", smxPrimitive->Attribute( "shading" ) ) == 0 ) { + + prim->l_type = PRIM_LIGHTING_SMOOTH; + + ((PRIM_V*)priptr)->v0 = atoi( smxPrimitive->Attribute( "n0" ) ); + ((PRIM_V*)priptr)->v1 = atoi( smxPrimitive->Attribute( "n1" ) ); + ((PRIM_V*)priptr)->v2 = atoi( smxPrimitive->Attribute( "n2" ) ); + ((PRIM_V*)priptr)->v3 = atoi( smxPrimitive->Attribute( "n3" ) ); + + priptr += 8; + prim->len += 8; + + } + + // Color 0 + ((PRIM_RGBC*)priptr)->r = atoi( smxPrimitive->Attribute( "r0" ) ); + ((PRIM_RGBC*)priptr)->g = atoi( smxPrimitive->Attribute( "g0" ) ); + ((PRIM_RGBC*)priptr)->b = atoi( smxPrimitive->Attribute( "b0" ) ); + + if( smxPrimitive->IntAttribute( "blend" ) > 0 ) { + ((PRIM_RGBC*)priptr)->c = 0x2; + prim->blend = smxPrimitive->IntAttribute( "blend" )-1; + } + + priptr += 4; + prim->len += 4; + + // Color 1 + ((PRIM_RGBC*)priptr)->r = atoi( smxPrimitive->Attribute( "r1" ) ); + ((PRIM_RGBC*)priptr)->g = atoi( smxPrimitive->Attribute( "g1" ) ); + ((PRIM_RGBC*)priptr)->b = atoi( smxPrimitive->Attribute( "b1" ) ); + ((PRIM_RGBC*)priptr)->c = 0; + priptr += 4; + prim->len += 4; + + // Color 2 + ((PRIM_RGBC*)priptr)->r = atoi( smxPrimitive->Attribute( "r2" ) ); + ((PRIM_RGBC*)priptr)->g = atoi( smxPrimitive->Attribute( "g2" ) ); + ((PRIM_RGBC*)priptr)->b = atoi( smxPrimitive->Attribute( "b2" ) ); + ((PRIM_RGBC*)priptr)->c = 0; + priptr += 4; + prim->len += 4; + + // Color 3 + ((PRIM_RGBC*)priptr)->r = atoi( smxPrimitive->Attribute( "r3" ) ); + ((PRIM_RGBC*)priptr)->g = atoi( smxPrimitive->Attribute( "g3" ) ); + ((PRIM_RGBC*)priptr)->b = atoi( smxPrimitive->Attribute( "b3" ) ); + ((PRIM_RGBC*)priptr)->c = 0; + priptr += 4; + prim->len += 4; + + fwrite( pribuff, 1, prim->len, smdFile ); + smdHeader.numprims++; + + } else { + + printf( "ERROR: Unknown or unsupported primitive type: %s\n", + primType ); + + fclose( smdFile ); + + if( texCoords != NULL ) { + free( texCoords ); + } + + return EXIT_FAILURE; + + } + + smxPrimitive = smxPrimitive->NextSiblingElement("poly"); + + } + + { + int term = 0; + fwrite( &term, 1, 4, smdFile ); + } + + /* + while(smxPrimitive != NULL) { + + bool polyBlended = false; + const char* primType = smxPrimitive->Attribute("type"); + + memset(&prim, 0x00, sizeof(PRIM_ID)); + + if (strcasecmp("F", smxPrimitive->Attribute("shading")) == 0) { + + prim.lighting = PRIM_LIGHTING_FLAT; + + } else if (strcasecmp("S", smxPrimitive->Attribute("shading")) == 0) { + + prim.lighting = PRIM_LIGHTING_SMOOTH; + + } + + // 3-point polygons + if ((strcasecmp("F3", primType) == 0) || + (strcasecmp("G3", primType) == 0) || + (strcasecmp("FT3", primType) == 0) || + (strcasecmp("GT3", primType) == 0)) { + + if (strcasecmp("F3", primType) == 0) { + + prim.type = PRIM_TYPE_TRI; + prim.len = 20; + + } else if (strcasecmp("G3", primType) == 0) { + + prim.type = PRIM_TYPE_TRI; + prim.gouraud = true; + prim.len = 28; + + } else if (strcasecmp("FT3", primType) == 0) { + + prim.type = PRIM_TYPE_TRI; + prim.textured = true; + prim.len = 32; + + } else if (strcasecmp("GT3", primType) == 0) { + + prim.type = PRIM_TYPE_TRI; + prim.gouraud = true; + prim.textured = true; + prim.len = 42; + + } + + if ( smxPrimitive->IntAttribute("blendmode") > 0 ) { + + polyBlended = true; + prim.blendmode = smxPrimitive->IntAttribute("blendmode")-1; + + } + + if ( smxPrimitive->IntAttribute("doublesided") ) { + + prim.noculling = true; + + } + + PRIM_V3 vert; + + vert.v0 = atoi(smxPrimitive->Attribute("v0")); + vert.v1 = atoi(smxPrimitive->Attribute("v1")); + vert.v2 = atoi(smxPrimitive->Attribute("v2")); + + if ((vert.v0 < 0) || (vert.v1 < 0) || (vert.v2 < 0)) { + + printf("ERROR: Primitive with negative vertex index encountered.\n"); + + fclose(smdFile); + + if (texCoords != NULL) + free(texCoords); + + return EXIT_FAILURE; + + } + + PRIM_V3 norm = { 0 }; + + if (prim.lighting == PRIM_LIGHTING_FLAT) { + + norm.v0 = atoi(smxPrimitive->Attribute("n0")); + prim.len += 4; + + } else if (prim.lighting == PRIM_LIGHTING_SMOOTH) { + + norm.v0 = atoi(smxPrimitive->Attribute("n0")); + norm.v1 = atoi(smxPrimitive->Attribute("n1")); + norm.v2 = atoi(smxPrimitive->Attribute("n2")); + prim.len += 12; + + } + + if ((norm.v0 < 0) || (norm.v1 < 0) || (norm.v2 < 0)) { + + printf("ERROR: Primitive with negative normal index encountered.\n"); + + fclose(smdFile); + + if (texCoords != NULL) + free(texCoords); + + return EXIT_FAILURE; + + } + + fwrite(&prim, sizeof(PRIM_ID), 1, smdFile); + fwrite(&vert, sizeof(PRIM_V3), 1, smdFile); + + if (prim.lighting == PRIM_LIGHTING_FLAT) { + fwrite(&norm, 4, 1, smdFile); + } else if (prim.lighting == PRIM_LIGHTING_SMOOTH) { + fwrite(&norm, sizeof(PRIM_V3), 1, smdFile); + } + + PRIM_RGBC col; + + col.r = atoi(smxPrimitive->Attribute("r0")); + col.g = atoi(smxPrimitive->Attribute("g0")); + col.b = atoi(smxPrimitive->Attribute("b0")); + col.c = 0x00; + + if (polyBlended) { + col.c |= 0x2; + } + + fwrite(&col, sizeof(PRIM_RGBC), 1, smdFile); + + if ((strcasecmp("G3", primType) == 0) || + (strcasecmp("GT3", primType) == 0)) { + + col.r = atoi(smxPrimitive->Attribute("r1")); + col.g = atoi(smxPrimitive->Attribute("g1")); + col.b = atoi(smxPrimitive->Attribute("b1")); + col.c = 0x00; + + fwrite(&col, sizeof(PRIM_RGBC), 1, smdFile); + + col.r = atoi(smxPrimitive->Attribute("r2")); + col.g = atoi(smxPrimitive->Attribute("g2")); + col.b = atoi(smxPrimitive->Attribute("b2")); + col.c = 0x00; + + fwrite(&col, sizeof(PRIM_RGBC), 1, smdFile); + + } + + if ((strcasecmp("FT3", primType) == 0) || (strcasecmp("GT3", primType) == 0)) { + + PRIM_TC tc; + PRIM_UV uvcd; + + int texNum = atoi(smxPrimitive->Attribute("texture")); + + if (texNum < 0) { + + printf("ERROR: Primitive with negative texture index encountered.\n"); + + fclose(smdFile); + + if (texCoords != NULL) + free(texCoords); + + return EXIT_FAILURE; + + } else if (texNum > numTextures-1) { + + printf("ERROR: Primitive with texture index greater than specified encountered.\n"); + + fclose(smdFile); + + if (texCoords != NULL) + free(texCoords); + + return EXIT_FAILURE; + + } + + TIM_COORDS *tex = &texCoords[texNum]; + + int uoffs = tex->pixdata.px; + int voffs = tex->pixdata.py&0xff; + + switch(tex->flag.pmode) { + case 0: // 4-bit + uoffs = (uoffs*4)%256; + break; + case 1: // 8-bit + uoffs = (uoffs*2)%128; + break; + case 2: // 16-bit + uoffs = uoffs%64; + break; + } + + // TPAGE and CLUT + tc.tpage = GetTPage( tex->flag.pmode, prim.blendmode, + tex->pixdata.px, tex->pixdata.py ); + tc.clut = GetClut( tex->clutdata.px, tex->clutdata.py ); + fwrite(&tc, sizeof(PRIM_TC), 1, smdFile); + + // Texcoords + uvcd.u = smxPrimitive->IntAttribute("tu0")+uoffs; + uvcd.v = smxPrimitive->IntAttribute("tv0")+voffs; + fwrite(&uvcd, sizeof(PRIM_UV), 1, smdFile); + + uvcd.u = smxPrimitive->IntAttribute("tu1")+uoffs; + uvcd.v = smxPrimitive->IntAttribute("tv1")+voffs; + fwrite(&uvcd, sizeof(PRIM_UV), 1, smdFile); + + uvcd.u = smxPrimitive->IntAttribute("tu2")+uoffs; + uvcd.v = smxPrimitive->IntAttribute("tv2")+voffs; + fwrite(&uvcd, sizeof(PRIM_UV), 1, smdFile); + + // Padding + uvcd.u = uvcd.v = 0; + fwrite(&uvcd, sizeof(PRIM_UV), 1, smdFile); + + } + + } else { + + printf("Unsupported primitive %s, ignoring...\n", primType); + + } + + smxPrimitive = smxPrimitive->NextSiblingElement("poly"); + + } + + // Write terminator + memset(&prim, 0x00, sizeof(PRIM_ID)); + fwrite(&prim, sizeof(PRIM_ID), 1, smdFile); + */ + + } + + + strcpy(smdHeader.id, "SMD"); + smdHeader.version = 1; + + fseek(smdFile, 0, SEEK_SET); + fwrite(&smdHeader, sizeof(SMD_HEADER), 1, smdFile); + + fclose(smdFile); + + if (texCoords != NULL) + free(texCoords); + + printf("Converted successfully.\n"); + + return EXIT_SUCCESS; + +} |
