aboutsummaryrefslogtreecommitdiff
path: root/tools/smxlink/main.cpp
diff options
context:
space:
mode:
authorJohn Wilbert M. Villamor <lameguy64@gmail.com>2019-04-06 10:11:07 +0800
committerJohn Wilbert M. Villamor <lameguy64@gmail.com>2019-04-06 10:11:07 +0800
commitf3e040230772f978540a71aea43dfde200992922 (patch)
treebd8ca31b72dd01e24980b073854e263589530f56 /tools/smxlink/main.cpp
downloadpsn00bsdk-f3e040230772f978540a71aea43dfde200992922.tar.gz
First commit
Diffstat (limited to 'tools/smxlink/main.cpp')
-rw-r--r--tools/smxlink/main.cpp1003
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;
+
+}