If I could remember the syntax for the program itself I could write you one in a minute, but alas I haven't had to convert anything in months.
I kept this from a thread some time ago now, with the hope of 1 day maybe making a convertdata to work for the newer .xsi layout. But I suck at code and don't know what I am doing. Some time, when I get time, I'd like to learn it more, It would certainly be handy for plugins and the like.
EDit; Ha! smiley face's are just how happy this code is, ..... or just the web page.
// ConvertXSI.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <map>
#include "Engine/DataStructures/AlgorithmLibrary.h"
#include "Engine/Render/Mesh/MeshSystem.h"
#include "Engine/String/StringConvert.h"
#include "XSIParser.h"
#include "dotXSITemplate.h"
#include "dotXSIParam.h"
#include "dotXSIParams.h"
#include "SIBCUtil.h"
#include "Scene.h"
#include "Model.h"
#include "Mesh.h"
#include "MaterialLibrary.h"
#include "Shape.h"
#include "Shape_35.h"
#include "Material.h"
#include "Texture2D.h"
#include "VariantParameter.h"
#include "CustomPSet.h"
#include "ShaderInstanceData.h"
#include "ShaderConnectionPoint.h"
#include "PolygonList.h"
#include "Transform.h"
#include "UVCoordArray.h"
#include "XSIMaterial.h"
#include "XSIShader.h"
struct SceneInfo
{
Iron::Mesh:
ata meshData;
Iron:
ynamicVector<Iron::StdFixedString, true> materialNames;
SceneInfo() : materialNames(makeFileLocation()) {}
};
Iron::UVCoord ConvertUVCoord(const CSIBCVector2D& uvCoordIn)
{
Iron::UVCoord uvCoordOut;
uvCoordOut.m_U = uvCoordIn.m_fX;
uvCoordOut.m_V = 1.f - uvCoordIn.m_fY;
return uvCoordOut;
}
Iron::Vector3 ConvertCoordSystem(const CSIBCVector3D& vectorIn)
{
Iron::Vector3 vectorOut;
vectorOut.x = vectorIn.m_fX;
vectorOut.y = vectorIn.m_fY;
vectorOut.z = -vectorIn.m_fZ; // invert z (see directx docs for converting between left and right handed coordinate systems)
// rotate 180 degrees around y axis.
vectorOut.Transform(Iron::Matrix33().BuildRotationY(Iron::MathConst:
i()));
return vectorOut;
}
Iron::Mesh::Vertex DumpMeshVertex(CSLShape_35* shape, CSLPolygonList* polygonList, int index)
{
Iron::Mesh::Vertex meshVertex;
int vertexIndex = polygonList->GetVertexIndicesPtr()[index];
CSIBCVector3D position = (*shape->GetVertexList())[vertexIndex];
meshVertex.m_Position = ConvertCoordSystem(position);
int normalIndex = polygonList->GetNormalIndicesPtr()[index];
CSIBCVector3D normal = (*shape->GetNormalList())[normalIndex];
meshVertex.m_Normal = ConvertCoordSystem(normal);
int colorIndex = -1;
if (polygonList->GetColorIndicesPtr() != NULL)
{
colorIndex = polygonList->GetColorIndicesPtr()[index];
CSIBCColorf color = (*shape->GetColorList())[colorIndex];
meshVertex.m_Tangent = ConvertCoordSystem(CSIBCVector3D(color.m_fR, color.m_fG, color.m_fB));
}
if (polygonList->GetUVArrayCount() > 0)
{
int uvCoordIndex = polygonList->GetUVIndicesPtr(0)[index];
CSLUVCoordArray* uvCoordArray = shape->UVCoordArrays()[0];
CSIBCVector2D uvCoord = (*uvCoordArray->GetUVCoordList())[uvCoordIndex];
meshVertex.m_TextureCoord0 = ConvertUVCoord(uvCoord);
}
if (polygonList->GetUVArrayCount() > 1)
{
int uvCoordIndex = polygonList->GetUVIndicesPtr(1)[index];
CSLUVCoordArray* uvCoordArray = shape->UVCoordArrays()[1];
CSIBCVector2D uvCoord = (*uvCoordArray->GetUVCoordList())[uvCoordIndex];
meshVertex.m_TextureCoord1 = ConvertUVCoord(uvCoord);
}
return meshVertex;
}
void FixupWindingOrder(Iron::Mesh::Triangle* triangle, const Iron:
ynamicVector<Iron::Mesh::Vertex, true>& vertices)
{
Iron::Vector3 v0 = vertices.At(triangle->m_iVertex0).m_Position - vertices.At(triangle->m_iVertex1).m_Position;
Iron::Vector3 v1 = vertices.At(triangle->m_iVertex0).m_Position - vertices.At(triangle->m_iVertex2).m_Position;
Iron::Vector3 cross = Iron::Vector3::Normalize(Iron::Vector3::Cross(v0, v1));
float dot = Iron::Vector3:
ot(cross, vertices.At(triangle->m_iVertex0).m_Normal);
if (dot <= 0.f)
{
//bad winding order!
Iron::Algorithm::Swap(&triangle->m_iVertex1, &triangle->m_iVertex2);
}
}
void DumpPolygonListWithMaterial(SceneInfo* sceneInfo, CSLShape_35* shape, CSLPolygonList* polygonList, int materialIndex)
{
if (polygonList->GetUVArrayCount() > 2)
{
printf("Ignoring extra uv channels.\n");
}
Iron:
ynamicVector<Iron::Mesh::Vertex, true> meshVertices(makeFileLocation());
Iron:
ynamicVector<Iron::Mesh::Triangle, true> meshTriangles(makeFileLocation());
int baseIndex = 0;
for (int i = 0; i < polygonList->GetPolygonCount(); ++i)
{
int polygonVertexCount = polygonList->GetPolygonVertexCountListPtr()[i];
int polygonTriCount = polygonVertexCount - 2;
if ((polygonTriCount < 1) || (polygonTriCount > 2))
{
printf("Invalid Polygon Vertex Count: %d\n", polygonVertexCount);
}
for (int t = 0; t < polygonTriCount; ++t)
{
meshVertices.PushBack(DumpMeshVertex(shape, polygonList, baseIndex));
meshVertices.PushBack(DumpMeshVertex(shape, polygonList, baseIndex + t + 1));
meshVertices.PushBack(DumpMeshVertex(shape, polygonList, baseIndex + t + 2));
Iron::Mesh::Triangle meshTriangle;
meshTriangle.m_iVertex0 = meshVertices.Size() - 3;
meshTriangle.m_iVertex1 = meshVertices.Size() - 2;
meshTriangle.m_iVertex2 = meshVertices.Size() - 1;
meshTriangle.m_iMaterial = materialIndex;
FixupWindingOrder(&meshTriangle, meshVertices);
meshTriangles.PushBack(meshTriangle);
}
baseIndex += polygonVertexCount;
}
int oldVertexCount = sceneInfo->meshData.m_Vertices.Size();
sceneInfo->meshData.m_Vertices.SetSizePreserve(oldVertexCount + meshVertices.Size());
for (int i = 0; i < meshVertices.Size(); ++i)
{
sceneInfo->meshData.m_Vertices.At(oldVertexCount + i) = meshVertices.At(i);
}
int oldTriangleCount = sceneInfo->meshData.m_Triangles.Size();
sceneInfo->meshData.m_Triangles.SetSizePreserve(oldTriangleCount + meshTriangles.Size());
for (int i = 0; i < meshTriangles.Size(); ++i)
{
meshTriangles.At(i).m_iVertex0 += oldVertexCount;
meshTriangles.At(i).m_iVertex1 += oldVertexCount;
meshTriangles.At(i).m_iVertex2 += oldVertexCount;
sceneInfo->meshData.m_Triangles.At(oldTriangleCount + i) = meshTriangles.At(i);
}
}
void DumpPolygonList(SceneInfo* sceneInfo, CSLShape_35* shape, CSLPolygonList* polygonList)
{
if (polygonList->GetMaterial() == NULL)
{
printf("PolygonList has no material.\n");
}
else
{
int materialIndex = -1;
for (int i = 0; i < sceneInfo->materialNames.Size(); ++i)
{
if (Iron::String::IsEqual(sceneInfo->materialNames.At(i), polygonList->GetMaterial()->GetName()))
{
materialIndex = i;
break;
}
}
if (materialIndex == -1)
{
printf("Valid Material not found for PolygonList: %s\n", polygonList->GetMaterial()->GetName());
}
else
{
DumpPolygonListWithMaterial(sceneInfo, shape, polygonList, materialIndex);
}
}
}
void DumpMesh(SceneInfo* sceneInfo, CSLModel* model)
{
CSLMesh* mesh = (CSLMesh*)model->Primitive();
CSLShape_35* shape = (CSLShape_35*)mesh->Shape();
for (int i = 0; i < mesh->GetPolygonListCount(); ++i)
{
CSLPolygonList* polygonList = mesh->PolygonLists()[i];
DumpPolygonList(sceneInfo, shape, polygonList);
}
}
void DumpPoints(SceneInfo* sceneInfo, CSLModel* rootModel)
{
for (int i = 0; i < rootModel->GetChildrenCount(); ++i)
{
CSLModel* childModel = rootModel->GetChildrenList()[i];
if (childModel->GetPrimitiveType() != CSLTemplate::SI_NULL_OBJECT)
{
printf("Ignoring '%s' underneath root point. Must be a Null Object!\n", childModel->GetName());
}
else
{
if (strlen(childModel->GetName()) < 6)
{
printf("Invalid Point Name: %s\n", childModel->GetName());
}
else
{
//chop off first 5 characters (just used to uniquly identify points)
const char* pointName = childModel->GetName() + 5;
printf("Point found: '%s'\n", pointName);
childModel->Transform()->ComputeGlobalMatrix();
CSIBCMatrix4x4 transform = childModel->Transform()->GetGlobalMatrix();
int oldPointCount = sceneInfo->meshData.m_Points.Size();
sceneInfo->meshData.m_Points.SetSizePreserve(oldPointCount + 1);
sceneInfo->meshData.m_Points.At(oldPointCount).m_DataString = pointName;
CSIBCVector3D translation;
transform.GetTranslation(translation);
sceneInfo->meshData.m_Points.At(oldPointCount).m_Position = ConvertCoordSystem(translation);
/*
CSIBCVector3D rotation;
transform.GetRotation(rotation);
//convert to left-handed
//http://www.inframez.com/papers/dotxsi_dev.htm
rotation.m_fX = -rotation.m_fX;
rotation.m_fY = -rotation.m_fY;
printf(_T("%.2f, %.2f, %.2f\n"), rotation.m_fX, rotation.m_fY, rotation.m_fZ);
Iron::Matrix33* o = &sceneInfo->meshData.m_Points.At(oldPointCount).m_Orientation;
o->BuildIdentity();
(*o) *= Iron::Matrix33().BuildRotationX(rotation.m_fX);
(*o) *= Iron::Matrix33().BuildRotationZ(rotation.m_fY);
(*o) *= Iron::Matrix33().BuildRotationY(rotation.m_fZ);
*/
/*
CSIBCVector3D orientationXAxis;
CSIBCVector3D orientationYAxis;
CSIBCVector3D orientationZAxis;
transform.GetOrientation(orientationXAxis, orientationYAxis, orientationZAxis);
Iron::Vector3 xAxis = Iron::Vector3(orientationXAxis.m_fX, orientationXAxis.m_fY, orientationXAxis.m_fZ).Normalize();
Iron::Vector3 yAxis = Iron::Vector3(orientationYAxis.m_fX, orientationYAxis.m_fY, orientationYAxis.m_fZ).Normalize();
Iron::Vector3 zAxis = Iron::Vector3(orientationZAxis.m_fX, orientationZAxis.m_fY, orientationZAxis.m_fZ).Normalize();
//xAxis = ConvertCoordSystem(CSIBCVector3D(xAxis.x, xAxis.y, xAxis.z));
//yAxis = ConvertCoordSystem(CSIBCVector3D(yAxis.x, yAxis.y, yAxis.z));
//zAxis = ConvertCoordSystem(CSIBCVector3D(zAxis.x, zAxis.y, zAxis.z));
Iron::Matrix33* o = &sceneInfo->meshData.m_Points.At(oldPointCount).m_Orientation;
o->m00 = xAxis.x;
o->m01 = xAxis.y;
o->m02 = xAxis.z;
o->m10 = yAxis.x;
o->m11 = yAxis.y;
o->m12 = yAxis.z;
o->m20 = zAxis.x;
o->m21 = zAxis.y;
o->m22 = zAxis.z;
*/
CSIBCVector3D eulerRot;// = childModel->Transform()->GetEulerRotation();
transform.GetRotation(eulerRot);
float ex = eulerRot.GetX();
float ey = eulerRot.GetY();
float ez = eulerRot.GetZ();
Iron::Matrix33* o = &sceneInfo->meshData.m_Points.At(oldPointCount).m_Orientation;
(*o) = Iron::Matrix33().BuildEulerRotation(
ey,
ex,
ez);
}
}
}
}
void DumpNullObject(SceneInfo* sceneInfo, CSLModel* model)
{
if (strcmp(model->GetName(), "rootpoint") == 0)
{
DumpPoints(sceneInfo, model);
}
}
void DumpModelRecursive(SceneInfo* sceneInfo, CSLModel* model)
{
if (model != NULL)
{
switch (model->GetPrimitiveType())
{
case CSLTemplate::SI_MODEL:
case CSLTemplate::SI_CAMERA:
case CSLTemplate::SI_DIRECTIONAL_LIGHT:
break;
case CSLTemplate::SI_MESH:
DumpMesh(sceneInfo, model);
break;
case CSLTemplate::SI_NULL_OBJECT:
DumpNullObject(sceneInfo, model);
break;
default:
printf("Ignoring unknown node type (%d): %s\n", model->GetPrimitiveType(), model->GetName());
break;
}
CSLModel** children = model->GetChildrenList();
for (int i = 0; i < model->GetChildrenCount(); ++i)
{
DumpModelRecursive(sceneInfo, children[i]);
}
}
}
CSLXSIShader* FindPhongShader(CSLXSIMaterial* material)
{
CSLXSIShader* phongShader = NULL;
for (int i = 0; i < material->GetShaderCount(); ++i)
{
CSLXSIShader* shader = material->GetShaderList()[i];
if (strcmp(shader->GetProgID(), "Softimage.material-phong.1") == 0)
{
phongShader = shader;
break;
}
}
return phongShader;
}
void DumpTextureFileName(Iron::StdFixedString* fileName, CSLXSIMaterial* material, CSLXSIShader* phongShader, char* searchName, char* mapName)
{
CSLShaderConnectionPoint* searchConnectionPoint = NULL;
for (int i = 0; i < phongShader->GetConnectionPointCount(); ++i)
{
CSLShaderConnectionPoint* connectionPoint = phongShader->GetConnectionPointList()[i];
if (strcmp(connectionPoint->GetName(), searchName) == 0)
{
searchConnectionPoint = connectionPoint;
break;
}
}
if ((searchConnectionPoint == NULL) || (searchConnectionPoint->GetShader() == NULL))
{
//printf("Shader connection '%s' not found in matrial:'%s' - shader:'%s'\n", searchName, material->GetName(), phongShader->GetName());
}
else
{
CSLShaderConnectionPoint* texConnectionPoint = NULL;
for (int i = 0; i < searchConnectionPoint->GetShader()->GetConnectionPointCount(); ++i)
{
CSLShaderConnectionPoint* connectionPoint = searchConnectionPoint->GetShader()->GetConnectionPointList()[i];
if (strcmp(connectionPoint->GetName(), "tex") == 0)
{
texConnectionPoint = connectionPoint;
break;
}
}
if (texConnectionPoint == NULL)
{
printf("'tex' not found in shader:'%s'\n", searchConnectionPoint->GetShader()->GetName());
}
else
{
(*fileName) = texConnectionPoint->GetImage();
// for some reason the extension is changed from ".dds" to "_dds" in .xsi export, not to sure why, hack it back ...
int fileNameLength = Iron::String::GetLength(*fileName);
if ((fileNameLength > 4) && fileName->GetBuffer()[fileNameLength - 4] == _T('_'))
{
fileName->GetBuffer()[fileNameLength - 4] = _T('.');
}
else
{
printf("Unexpected texture file name: %s\n", fileName->GetBuffer());
(*fileName) = _T("");
}
}
}
}
CSLVariantParameter* FindParam(CSLXSIShader* shader, const char* name)
{
CSLVariantParameter* foundParam = NULL;
for (int i = 0; i < shader->GetParameterCount(); ++i)
{
CSLVariantParameter* param = shader->GetParameterList()[i];
if (strcmp(param->GetName(), name) == 0)
{
foundParam = param;
break;
}
}
return foundParam;
}
void DumpMaterials(SceneInfo* sceneInfo, CSLMaterialLibrary* materialLibrary)
{
if (materialLibrary == NULL)
{
printf("No material library exists!\n");
}
else
{
int materialCount = materialLibrary->GetMaterialCount();
for (int i = 0; i < materialCount; ++i)
{
CSLBaseMaterial* baseMaterial = materialLibrary->GetMaterialList()[i];
if (baseMaterial->Type() != CSLTemplate::XSI_MATERIAL)
{
printf("Ignoring unknown material type (%d): %s\n", baseMaterial->Type(), baseMaterial->GetName());
}
else
{
CSLXSIMaterial* material = (CSLXSIMaterial*)baseMaterial;
CSLXSIShader* phongShader = FindPhongShader(material);
if (phongShader == NULL)
{
printf("Phong shader not found in material: %s\n", material->GetName());
}
else
{
Iron::Mesh::Material meshMaterial;
DumpTextureFileName(&meshMaterial.m_DiffuseTextureFileName, material, phongShader, "diffuse", "DiffuseMap");
DumpTextureFileName(&meshMaterial.m_NormalTextureFileName, material, phongShader, "ambient", "NormalMap");
DumpTextureFileName(&meshMaterial.m_SelfIlluminationTextureFileName, material, phongShader, "specular", "DataMap");
meshMaterial.m_Ambient = Iron::Color::WHITE;
meshMaterial.m_Diffuse = Iron::Color::WHITE;
meshMaterial.m_Specular = Iron::Color::WHITE;
meshMaterial.m_Emissive = Iron::Color::WHITE;
float glossiness = 1.f;
CSLVariantParameter* glossinessParam = FindParam(phongShader, "shiny");
if (glossinessParam != NULL)
{
glossiness = glossinessParam->GetFloatValue();
}
meshMaterial.m_Glossiness = glossiness;
sceneInfo->meshData.m_Materials.SetSizePreserve(sceneInfo->meshData.m_Materials.Size() + 1);
sceneInfo->meshData.m_Materials.At(sceneInfo->meshData.m_Materials.Size() - 1) = meshMaterial;
sceneInfo->materialNames.PushBack(material->GetName());
printf("Material found: '%s'\n", material->GetName());
printf(" cl = '%s'\n", meshMaterial.m_DiffuseTextureFileName.GetBuffer());
printf(" nm = '%s'\n", meshMaterial.m_NormalTextureFileName.GetBuffer());
printf(" da = '%s'\n", meshMaterial.m_SelfIlluminationTextureFileName.GetBuffer());
}
}
}
}
}
void CalculateBoundingInformation(SceneInfo* sceneInfo)
{
sceneInfo->meshData.CalculateBoundingInformation();
printf("Bounding Information Calculated - Radius:%.2f\n", sceneInfo->meshData.m_BoundingRadius);
}
class SortDupVertexMapValues
{
public:
bool operator()(std::vector<int>& a, std::vector<int>& 
{
return (a[0] < b[0]);
}
};
void OptimizeMesh(SceneInfo* sceneInfo)
{
printf("Optimizing...\n");
printf("Pre-Optimization Vertex Count = %d\n", sceneInfo->meshData.m_Vertices.Size());
typedef std::map< int, std::vector<int> > DupVertexMap;
// first - build a map to remember every vertex-index of duplicate vertices (checksum -> vertex indices).
DupVertexMap dupVertexMap;
for (int i = 0; i < sceneInfo->meshData.m_Vertices.Size(); ++i)
{
const Iron::Mesh::Vertex& vertex = sceneInfo->meshData.m_Vertices.At(i);
int vertexCheckSum = vertex.GetCheckSum();
dupVertexMap[vertexCheckSum].push_back(i);
int otherVertexIndex = *dupVertexMap[vertexCheckSum].begin();
const Iron::Mesh::Vertex& otherVertex = sceneInfo->meshData.m_Vertices.At(otherVertexIndex);
if(vertex != otherVertex)
{
printf("FAILED VERTEX CHECKSUM\n");
}
}
// second - build a vector of vertex-index-vectors, we just needed the map to create this more useful data structure.
typedef std::vector< std::vector<int> > DupVertexMapValues;
DupVertexMapValues dupVertexMapValues;
for (DupVertexMap::const_iterator i = dupVertexMap.begin(); i != dupVertexMap.end(); ++i)
{
dupVertexMapValues.push_back(i->second);
}
std::sort(dupVertexMapValues.begin(), dupVertexMapValues.end(), SortDupVertexMapValues());
// third - build up a vertex index remap dictionary, then update all triangles with it.
typedef std::map< int, int > VertexIndexRemap;
VertexIndexRemap vertexIndexRemap;
for (int i = 0; i < dupVertexMapValues.size(); ++i)
{
const std::vector<int>& vertexIndices = dupVertexMapValues.at(i);
for (int j = 0; j < vertexIndices.size(); ++j)
{
vertexIndexRemap[ vertexIndices.at(j) ] = i;
}
}
for (int i = 0; i < sceneInfo->meshData.m_Triangles.Size(); ++i)
{
Iron::Mesh::Triangle* triangle = &sceneInfo->meshData.m_Triangles.At(i);
triangle->m_iVertex0 = vertexIndexRemap[triangle->m_iVertex0];
triangle->m_iVertex1 = vertexIndexRemap[triangle->m_iVertex1];
triangle->m_iVertex2 = vertexIndexRemap[triangle->m_iVertex2];
}
// fourth - create a new smaller set of vertices.
Iron:
ynamicArray<Iron::Mesh::Vertex> newVertices(makeFileLocation());
newVertices.SetSizeNoPreserve((int)dupVertexMapValues.size());
for (int i = 0; i < dupVertexMapValues.size(); ++i)
{
newVertices.At(i) = sceneInfo->meshData.m_Vertices.At(dupVertexMapValues.at(i).at(0));
}
sceneInfo->meshData.m_Vertices = newVertices;
printf("Post-Optimization Vertex Count = %d\n", sceneInfo->meshData.m_Vertices.Size());
}
void ValidateMesh(SceneInfo* sceneInfo)
{
for (int i = 0; i < sceneInfo->meshData.m_Triangles.Size(); ++i)
{
const Iron::Mesh::Triangle& triangle = sceneInfo->meshData.m_Triangles.At(i);
int duplicateVertexIndex = -1;
if (triangle.m_iVertex0 == triangle.m_iVertex1)
{
duplicateVertexIndex = triangle.m_iVertex1;
}
else if (triangle.m_iVertex0 == triangle.m_iVertex2)
{
duplicateVertexIndex = triangle.m_iVertex2;
}
else if (triangle.m_iVertex1 == triangle.m_iVertex2)
{
duplicateVertexIndex = triangle.m_iVertex2;
}
if (duplicateVertexIndex != -1)
{
const Iron::Mesh::Vertex& vertex = sceneInfo->meshData.m_Vertices.At(duplicateVertexIndex);
printf("Error *** Found duplicate vertex at [%.1f , %.1f , %.1f]\n", vertex.m_Position.x, vertex.m_Position.y, vertex.m_Position.z);
}
}
}
void DumpScene(SceneInfo* sceneInfo, CSLScene* scene)
{
DumpMaterials(sceneInfo, scene->GetMaterialLibrary());
DumpModelRecursive(sceneInfo, scene->Root());
CalculateBoundingInformation(sceneInfo);
}
int _tmain(int argc, _TCHAR* argv[])
{
SI_Error siError = SI_SUCCESS;
if (argc < 3)
{
printf("%s expects at least 2 arguments: <in.xsi> <out.mesh> <--nooptimize>\n", argv[0]);
siError = SI_FILE_NOT_FOUND;
}
else
{
char* inFileName = argv[1];
char* outFileName = argv[2];
bool optimize = true;
if (argc > 3)
{
const TCHAR* option = argv[3];
if (Iron::String::IsEqual(option, _T("--nooptimize")))
{
optimize = false;
}
else
{
printf("unknown option found: %s\n", option);
}
}
CSLScene scene;
siError = scene.Open(inFileName);
if (siError != SI_SUCCESS)
{
printf("Failed to Open %s.\n", inFileName);
}
else
{
siError = scene.Read();
if (siError != SI_SUCCESS)
{
printf("Failed to Read %s.\n", inFileName);
}
else
{
SceneInfo info;
DumpScene(&info, &scene);
if (optimize)
{
OptimizeMesh(&info);
}
ValidateMesh(&info);
info.meshData.m_hasValidTangents = true;
if(!g_MeshSystem.SaveMeshData(outFileName, info.meshData, Iron::FileTranslation::Text))
{
printf("Failed to Save %s.\n", outFileName);
}
}
scene.Close();
}
}
return siError;
}