/* 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 #include #include #include //#include #include "timreader.h" #ifdef WIN32 #define strcasecmp _stricmp #endif #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 ] [-s ] \n\n"); printf(" -o - Specify output filename (default: first file specified)\n"); printf(" -s - Scale factor to apply to model on conversion (default: 1.0)\n"); printf(" -tp - Specify directory path to TIM texture files\n"); printf(" - SMX file to convert to SMD\n"); return EXIT_SUCCESS; } for(int i=1; iFirstChildElement("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" ) ) 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; }