diff --git a/Engine/source/T3D/tsStatic.cpp b/Engine/source/T3D/tsStatic.cpp index 13964e632..9eaab881b 100644 --- a/Engine/source/T3D/tsStatic.cpp +++ b/Engine/source/T3D/tsStatic.cpp @@ -1073,6 +1073,97 @@ bool TSStatic::buildPolyList(PolyListContext context, AbstractPolyList* polyList return true; } +bool TSStatic::buildExportPolyList(PolyListContext context, ColladaUtils::ExportData* exportData, const Box3F &box, const SphereF &) +{ + if (!mShapeInstance) + return false; + + if (mCollisionType == Bounds) + { + ColladaUtils::ExportData::colMesh* colMesh; + exportData->colMeshes.increment(); + colMesh = &exportData->colMeshes.last(); + + colMesh->mesh.setTransform(&mObjToWorld, mObjScale); + colMesh->mesh.setObject(this); + + colMesh->mesh.addBox(mObjBox); + + colMesh->colMeshName = String::ToString("ColBox%d-1", exportData->colMeshes.size()); + } + else if (mCollisionType == VisibleMesh) + { + ColladaUtils::ExportData::colMesh* colMesh; + exportData->colMeshes.increment(); + colMesh = &exportData->colMeshes.last(); + + colMesh->mesh.setTransform(&mObjToWorld, mObjScale); + colMesh->mesh.setObject(this); + + mShapeInstance->buildPolyList(&colMesh->mesh, 0); + + colMesh->colMeshName = String::ToString("ColMesh%d-1", exportData->colMeshes.size()); + } + else if (mCollisionType == CollisionMesh) + { + // Everything else is done from the collision meshes + // which may be built from either the visual mesh or + // special collision geometry. + for (U32 i = 0; i < mCollisionDetails.size(); i++) + { + ColladaUtils::ExportData::colMesh* colMesh; + exportData->colMeshes.increment(); + colMesh = &exportData->colMeshes.last(); + + colMesh->mesh.setTransform(&mObjToWorld, mObjScale); + colMesh->mesh.setObject(this); + + mShapeInstance->buildPolyListOpcode(mCollisionDetails[i], &colMesh->mesh, box); + + colMesh->colMeshName = String::ToString("ColMesh%d-1", exportData->colMeshes.size()); + } + } + + //Next, process the LOD levels and materials. + if (isServerObject() && getClientObject()) + { + TSStatic* clientShape = dynamic_cast(getClientObject()); + U32 numDetails = clientShape->mShapeInstance->getNumDetails() - 1; + + exportData->meshData.increment(); + + //Prep a meshData for this shape in particular + ColladaUtils::ExportData::meshLODData* meshData = &exportData->meshData.last(); + + //Fill out the info we'll need later to actually append our mesh data for the detail levels during the processing phase + meshData->shapeInst = clientShape->mShapeInstance; + meshData->originatingObject = this; + meshData->meshTransform = mObjToWorld; + meshData->scale = mObjScale; + + //Iterate over all our detail levels + for (U32 i = 0; i < clientShape->mShapeInstance->getNumDetails(); i++) + { + TSShape::Detail detail = clientShape->mShapeInstance->getShape()->details[i]; + + String detailName = String::ToLower(clientShape->mShapeInstance->getShape()->getName(detail.nameIndex)); + + //Skip it if it's a collision or line of sight element + if (detailName.startsWith("col") || detailName.startsWith("los")) + continue; + + meshData->meshDetailLevels.increment(); + + ColladaUtils::ExportData::detailLevel* curDetail = &meshData->meshDetailLevels.last(); + + //Make sure we denote the size this detail level has + curDetail->size = detail.size; + } + } + + return true; +} + void TSStatic::buildConvex(const Box3F& box, Convex* convex) { if ( mCollisionType == None ) @@ -1279,6 +1370,16 @@ void TSStatic::onUnmount( SceneObject *obj, S32 node ) _updateShouldTick(); } +U32 TSStatic::getNumDetails() +{ + if (isServerObject() && getClientObject()) + { + TSStatic* clientShape = dynamic_cast(getClientObject()); + return clientShape->mShapeInstance->getNumDetails(); + } + return 0; +}; + //------------------------------------------------------------------------ //These functions are duplicated in tsStatic and shapeBase. //They each function a little differently; but achieve the same purpose of gathering diff --git a/Engine/source/T3D/tsStatic.h b/Engine/source/T3D/tsStatic.h index 224086c71..2df45a861 100644 --- a/Engine/source/T3D/tsStatic.h +++ b/Engine/source/T3D/tsStatic.h @@ -138,6 +138,7 @@ protected: bool castRay(const Point3F &start, const Point3F &end, RayInfo* info); bool castRayRendered(const Point3F &start, const Point3F &end, RayInfo* info); bool buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F &box, const SphereF& sphere); + bool buildExportPolyList(PolyListContext context, ColladaUtils::ExportData* exportData, const Box3F &box, const SphereF &); void buildConvex(const Box3F& box, Convex* convex); bool _createShape(); @@ -237,6 +238,8 @@ public: TSShapeInstance* getShapeInstance() const { return mShapeInstance; } + U32 getNumDetails(); + const Vector& getCollisionDetails() const { return mCollisionDetails; } const Vector& getLOSDetails() const { return mLOSDetails; } diff --git a/Engine/source/gui/worldEditor/worldEditor.cpp b/Engine/source/gui/worldEditor/worldEditor.cpp index 7846ec094..ca6c966ae 100644 --- a/Engine/source/gui/worldEditor/worldEditor.cpp +++ b/Engine/source/gui/worldEditor/worldEditor.cpp @@ -3927,15 +3927,38 @@ void WorldEditor::makeSelectionAMesh(const char *filename) OptimizedPolyList polyList; polyList.setBaseTransform(orientation); + ColladaUtils::ExportData exportData; + for (S32 i = 0; i < objectList.size(); i++) { SceneObject *pObj = objectList[i]; - if (!pObj->buildPolyList(PLC_Export, &polyList, pObj->getWorldBox(), pObj->getWorldSphere())) + if (!pObj->buildExportPolyList(PLC_Export, &exportData, pObj->getWorldBox(), pObj->getWorldSphere())) Con::warnf("colladaExportObjectList() - object %i returned no geometry.", pObj->getId()); } + //Now that we have all of our mesh data, process it so we can correctly collapse everything. + exportData.processData(); + + //recenter generated visual mesh results + for (U32 dl = 0; dl < exportData.colMeshes.size(); dl++) + { + for (U32 pnt = 0; pnt < exportData.colMeshes[dl].mesh.mPoints.size(); pnt++) + { + exportData.colMeshes[dl].mesh.mPoints[pnt] -= centroid; + } + } + + //recenter generated collision mesh results + for (U32 dl = 0; dl < exportData.detailLevels.size(); dl++) + { + for (U32 pnt = 0; pnt < exportData.detailLevels[dl].mesh.mPoints.size(); pnt++) + { + exportData.detailLevels[dl].mesh.mPoints[pnt] -= centroid; + } + } + // Use a ColladaUtils function to do the actual export to a Collada file - ColladaUtils::exportToCollada(filename, polyList); + ColladaUtils::exportToCollada(filename, exportData); // // Allocate TSStatic object and add to level. diff --git a/Engine/source/scene/sceneObject.h b/Engine/source/scene/sceneObject.h index 549246c9e..3e7fab355 100644 --- a/Engine/source/scene/sceneObject.h +++ b/Engine/source/scene/sceneObject.h @@ -60,6 +60,9 @@ #include "gfx/gfxDevice.h" #endif +#ifndef _COLLADA_UTILS_H_ +#include "ts/collada/colladaUtils.h" +#endif class SceneManager; class SceneRenderState; @@ -550,6 +553,24 @@ class SceneObject : public NetObject, private SceneContainer::Link, public Proce const Box3F& box, const SphereF& sphere ) { return false; } + /// Builds a list of polygons which intersect a bounding volume for exporting + /// + /// This will use either the sphere or the box, not both, the + /// SceneObject implementation ignores sphere. + /// + /// @see AbstractPolyList + /// @param context A contentual hint as to the type of polylist to build. + /// @param polyList Poly list build (out) + /// @param box Box bounding volume + /// @param sphere Sphere bounding volume + /// + virtual bool buildExportPolyList(PolyListContext context, + ColladaUtils::ExportData *exportData, + const Box3F& box, + const SphereF& sphere) { + return false; + } + /// Casts a ray and obtain collision information, returns true if RayInfo is modified. /// /// @param start Start point of ray diff --git a/Engine/source/ts/collada/colladaUtils.cpp b/Engine/source/ts/collada/colladaUtils.cpp index e88abe372..32c559077 100644 --- a/Engine/source/ts/collada/colladaUtils.cpp +++ b/Engine/source/ts/collada/colladaUtils.cpp @@ -1277,6 +1277,289 @@ void ColladaUtils::exportColladaMaterials(TiXmlElement* rootNode, const Optimize } +void ColladaUtils::exportColladaMaterials(TiXmlElement* rootNode, const ExportData& exportData, const Torque::Path& colladaFile) +{ + // First the image library + TiXmlElement* imgLibNode = new TiXmlElement("library_images"); + rootNode->LinkEndChild(imgLibNode); + + Vector matNames; + + for (U32 i = 0; i < exportData.materials.size(); i++) + { + BaseMatInstance* baseInst = exportData.materials[i]; + + matNames.push_back(String::ToString("Material%d", i)); + + Material* mat = dynamic_cast(baseInst->getMaterial()); + if (!mat) + continue; + + String diffuseMap; + + if (mat->getName() && mat->getName()[0]) + matNames.last() = mat->mMapTo; + + // Handle an auto-generated "Default Material" specially + if (mat->isAutoGenerated()) + { + Torque::Path diffusePath; + + if (mat->mDiffuseMapFilename[0].isNotEmpty()) + diffusePath = mat->mDiffuseMapFilename[0]; + else + diffusePath = String("warningMat"); + + matNames.last() = diffusePath.getFileName(); + diffuseMap += diffusePath.getFullFileName(); + } + else + { + if (mat->mDiffuseMapFilename[0].isNotEmpty()) + diffuseMap += mat->mDiffuseMapFilename[0]; + else + diffuseMap += "warningMat"; + } + + Torque::Path diffusePath = findTexture(colladaFile.getPath() + "/" + diffuseMap); + + // If we didn't get a path + if (diffusePath.getFullPath().isNotEmpty()) + diffuseMap = Torque::Path::MakeRelativePath(diffusePath, colladaFile); + + TiXmlElement* imageNode = new TiXmlElement("image"); + imgLibNode->LinkEndChild(imageNode); + imageNode->SetAttribute("id", avar("%s", matNames.last().c_str())); + imageNode->SetAttribute("name", avar("%s", matNames.last().c_str())); + + TiXmlElement* initNode = new TiXmlElement("init_from"); + imageNode->LinkEndChild(initNode); + TiXmlText* initText = new TiXmlText(avar("file://%s", diffuseMap.c_str())); // "the file://" is needed to load the texture in some old apps (ex: 3ds Max 2009) + initNode->LinkEndChild(initText); + } + + // Next the effects library + TiXmlElement* effectLibNode = new TiXmlElement("library_effects"); + rootNode->LinkEndChild(effectLibNode); + + for (U32 i = 0; i < exportData.materials.size(); i++) + { + BaseMatInstance* baseInst = exportData.materials[i]; + + Material* mat = dynamic_cast(baseInst->getMaterial()); + if (!mat) + continue; + + TiXmlElement* effectNode = new TiXmlElement("effect"); + effectLibNode->LinkEndChild(effectNode); + effectNode->SetAttribute("id", avar("%s-effect", matNames[i].c_str())); + effectNode->SetAttribute("name", avar("%s-effect", matNames[i].c_str())); + + TiXmlElement* profileNode = new TiXmlElement("profile_COMMON"); + effectNode->LinkEndChild(profileNode); + + // --------------------------- + TiXmlElement* newParamNode = new TiXmlElement("newparam"); + profileNode->LinkEndChild(newParamNode); + newParamNode->SetAttribute("sid", avar("%s-surface", matNames[i].c_str())); + + TiXmlElement* surfaceNode = new TiXmlElement("surface"); + newParamNode->LinkEndChild(surfaceNode); + surfaceNode->SetAttribute("type", "2D"); + + TiXmlElement* initNode2 = new TiXmlElement("init_from"); + surfaceNode->LinkEndChild(initNode2); + TiXmlText* init2Text = new TiXmlText(avar("%s", matNames[i].c_str())); + initNode2->LinkEndChild(init2Text); + + TiXmlElement* formatNode = new TiXmlElement("format"); + surfaceNode->LinkEndChild(formatNode); + TiXmlText* formatText = new TiXmlText("A8R8G8B8"); + formatNode->LinkEndChild(formatText); + + // --------------------------- + TiXmlElement* newParam2Node = new TiXmlElement("newparam"); + profileNode->LinkEndChild(newParam2Node); + newParam2Node->SetAttribute("sid", avar("%s-sampler", matNames[i].c_str())); + + TiXmlElement* sampler2DNode = new TiXmlElement("sampler2D"); + newParam2Node->LinkEndChild(sampler2DNode); + + TiXmlElement* sourceSampler2DNode = new TiXmlElement("source"); + sampler2DNode->LinkEndChild(sourceSampler2DNode); + TiXmlText* sourceSampler2DText = new TiXmlText(avar("%s-surface", matNames[i].c_str())); + sourceSampler2DNode->LinkEndChild(sourceSampler2DText); + + // --------------------------- + + TiXmlElement* techniqueNode = new TiXmlElement("technique"); + profileNode->LinkEndChild(techniqueNode); + techniqueNode->SetAttribute("sid", "common"); + + TiXmlElement* blinnNode = new TiXmlElement("blinn"); + techniqueNode->LinkEndChild(blinnNode); + + // --------------------------- + TiXmlElement* emissionNode = new TiXmlElement("emission"); + blinnNode->LinkEndChild(emissionNode); + + TiXmlElement* colorEmissionNode = new TiXmlElement("color"); + emissionNode->LinkEndChild(colorEmissionNode); + colorEmissionNode->SetAttribute("sid", "emission"); + + TiXmlText* colorEmissionNodeText = new TiXmlText("0.0 0.0 0.0 1.0"); + colorEmissionNode->LinkEndChild(colorEmissionNodeText); + + // --------------------------- + TiXmlElement* ambientNode = new TiXmlElement("ambient"); + blinnNode->LinkEndChild(ambientNode); + + TiXmlElement* colorAmbientNode = new TiXmlElement("color"); + ambientNode->LinkEndChild(colorAmbientNode); + colorAmbientNode->SetAttribute("sid", "ambient"); + + TiXmlText* colorAmbientNodeText = new TiXmlText("0.0 0.0 0.0 1.0"); + colorAmbientNode->LinkEndChild(colorAmbientNodeText); + + // --------------------------- + TiXmlElement* diffuseNode = new TiXmlElement("diffuse"); + blinnNode->LinkEndChild(diffuseNode); + TiXmlElement* textureDiffuseNode = new TiXmlElement("texture"); + diffuseNode->LinkEndChild(textureDiffuseNode); + textureDiffuseNode->SetAttribute("texture", avar("%s-sampler", matNames[i].c_str())); + textureDiffuseNode->SetAttribute("texcoord", "UVMap"); + + // Extra info useful for getting the texture to show up correctly in MAYA and 3DS Max + TiXmlElement* extraNode = new TiXmlElement("extra"); + textureDiffuseNode->LinkEndChild(extraNode); + + TiXmlElement* extraTechNode = new TiXmlElement("technique"); + extraNode->LinkEndChild(extraTechNode); + extraTechNode->SetAttribute("profile", "MAYA"); + + TiXmlElement* extraWrapUNode = new TiXmlElement("wrapU"); + extraTechNode->LinkEndChild(extraWrapUNode); + extraWrapUNode->SetAttribute("sid", "wrapU0"); + + TiXmlText* extraWrapUText = new TiXmlText("TRUE"); + extraWrapUNode->LinkEndChild(extraWrapUText); + + TiXmlElement* extraWrapVNode = new TiXmlElement("wrapV"); + extraTechNode->LinkEndChild(extraWrapVNode); + extraWrapVNode->SetAttribute("sid", "wrapV0"); + + TiXmlText* extraWrapVText = new TiXmlText("TRUE"); + extraWrapVNode->LinkEndChild(extraWrapVText); + + TiXmlElement* extraBlendNode = new TiXmlElement("blend_mode"); + extraTechNode->LinkEndChild(extraBlendNode); + + TiXmlText* extraBlendText = new TiXmlText("ADD"); + extraBlendNode->LinkEndChild(extraBlendText); + + // --------------------------- + TiXmlElement* specularNode = new TiXmlElement("specular"); + blinnNode->LinkEndChild(specularNode); + + TiXmlElement* colorSpecularNode = new TiXmlElement("color"); + specularNode->LinkEndChild(colorSpecularNode); + colorSpecularNode->SetAttribute("sid", "specular"); + + TiXmlText* colorSpecularNodeText = new TiXmlText("0.5 0.5 0.5 1.0"); + colorSpecularNode->LinkEndChild(colorSpecularNodeText); + + // --------------------------- + TiXmlElement* shininessNode = new TiXmlElement("shininess"); + blinnNode->LinkEndChild(shininessNode); + + TiXmlElement* colorShininessNode = new TiXmlElement("float"); + shininessNode->LinkEndChild(colorShininessNode); + colorShininessNode->SetAttribute("sid", "shininess"); + + TiXmlText* colorShininessNodeText = new TiXmlText("1.0"); + colorShininessNode->LinkEndChild(colorShininessNodeText); + + // --------------------------- + TiXmlElement* reflectiveNode = new TiXmlElement("reflective"); + blinnNode->LinkEndChild(reflectiveNode); + + TiXmlElement* colorReflectiveNode = new TiXmlElement("color"); + reflectiveNode->LinkEndChild(colorReflectiveNode); + colorReflectiveNode->SetAttribute("sid", "reflective"); + + TiXmlText* colorReflectiveNodeText = new TiXmlText("0.0 0.0 0.0 1.0"); + colorReflectiveNode->LinkEndChild(colorReflectiveNodeText); + + // --------------------------- + TiXmlElement* reflectivityNode = new TiXmlElement("reflectivity"); + blinnNode->LinkEndChild(reflectivityNode); + + TiXmlElement* floatReflectivityNode = new TiXmlElement("float"); + reflectivityNode->LinkEndChild(floatReflectivityNode); + floatReflectivityNode->SetAttribute("sid", "reflectivity"); + + TiXmlText* floatReflectivityText = new TiXmlText("0.5"); + floatReflectivityNode->LinkEndChild(floatReflectivityText); + + // --------------------------- + TiXmlElement* transparentNode = new TiXmlElement("transparent"); + blinnNode->LinkEndChild(transparentNode); + transparentNode->SetAttribute("opaque", "RGB_ZERO"); + + TiXmlElement* colorTransparentNode = new TiXmlElement("color"); + transparentNode->LinkEndChild(colorTransparentNode); + colorTransparentNode->SetAttribute("sid", "transparent"); + + TiXmlText* colorTransparentNodeText = new TiXmlText("0.0 0.0 0.0 1.0"); + colorTransparentNode->LinkEndChild(colorTransparentNodeText); + + // --------------------------- + TiXmlElement* transparencyNode = new TiXmlElement("transparency"); + blinnNode->LinkEndChild(transparencyNode); + + TiXmlElement* floatTransparencyNode = new TiXmlElement("float"); + transparencyNode->LinkEndChild(floatTransparencyNode); + floatTransparencyNode->SetAttribute("sid", "transparency"); + + TiXmlText* floatTransparencyText = new TiXmlText("0.0"); + floatTransparencyNode->LinkEndChild(floatTransparencyText); + + // --------------------------- + TiXmlElement* refractionNode = new TiXmlElement("index_of_refraction"); + blinnNode->LinkEndChild(refractionNode); + + TiXmlElement* colorRefractionNode = new TiXmlElement("float"); + refractionNode->LinkEndChild(colorRefractionNode); + colorRefractionNode->SetAttribute("sid", "index_of_refraction"); + + TiXmlText* colorRefractionNodeText = new TiXmlText("1"); + colorRefractionNode->LinkEndChild(colorRefractionNodeText); + } + + // Finally the material library + TiXmlElement* matLibNode = new TiXmlElement("library_materials"); + rootNode->LinkEndChild(matLibNode); + + for (U32 i = 0; i < exportData.materials.size(); i++) + { + BaseMatInstance* baseInst = exportData.materials[i]; + + Material* mat = dynamic_cast(baseInst->getMaterial()); + if (!mat) + continue; + + TiXmlElement* materialNode = new TiXmlElement("material"); + matLibNode->LinkEndChild(materialNode); + materialNode->SetAttribute("id", avar("%s-material", matNames[i].c_str())); + materialNode->SetAttribute("name", matNames[i].c_str()); + + TiXmlElement* instEffectNode = new TiXmlElement("instance_effect"); + materialNode->LinkEndChild(instEffectNode); + instEffectNode->SetAttribute("url", avar("#%s-effect", matNames[i].c_str())); + } + +} + void ColladaUtils::exportColladaTriangles(TiXmlElement* meshNode, const OptimizedPolyList& mesh, const String& meshName, const Vector& matNames) { // Start at -1 so we will export polygons that do not have a material. @@ -1396,6 +1679,252 @@ void ColladaUtils::exportColladaTriangles(TiXmlElement* meshNode, const Optimize } } +void ColladaUtils::exportColladaTriangles(TiXmlElement* meshNode, const ExportData& exportData, const U32 detailLevel, const String& meshName) +{ + // Calculate the number of triangles that uses this Material + U32 triangleCount = 0; + + const ExportData::detailLevel* dl = &exportData.detailLevels[detailLevel]; + + for (S32 i = 0; i < dl->materialRefList.size(); i++) + { + int matIdx; + dl->materialRefList.tryGetValue(i, matIdx); + BaseMatInstance* baseInst = exportData.materials[matIdx]; + + Material* mat = dynamic_cast(baseInst->getMaterial()); + if (!mat) + continue; + + String matName; + + if (mat->getName() && mat->getName()[0]) + matName = mat->mMapTo; + + for (U32 j = 0; j < dl->mesh.mPolyList.size(); j++) + { + const OptimizedPolyList::Poly& poly = dl->mesh.mPolyList[j]; + + if (poly.material != i) + continue; + + if (poly.vertexCount < 3) + continue; + + if (poly.type == OptimizedPolyList::TriangleList || + poly.type == OptimizedPolyList::TriangleFan || + poly.type == OptimizedPolyList::TriangleStrip) + { + triangleCount += poly.vertexCount - 2; + } + else + AssertISV(false, "ColladaUtils::exportColladaTriangles(): Unknown Poly type!"); + } + + // Make sure that we are actually using this Material + if (triangleCount == 0) + continue; + + TiXmlElement* trianglesNode = new TiXmlElement("triangles"); + meshNode->LinkEndChild(trianglesNode); + trianglesNode->SetAttribute("material", (i > -1) ? avar("%s-material", matName.c_str()) : ""); + trianglesNode->SetAttribute("count", avar("%d", triangleCount)); + + TiXmlElement* trianglesVertInputNode = new TiXmlElement("input"); + trianglesNode->LinkEndChild(trianglesVertInputNode); + trianglesVertInputNode->SetAttribute("semantic", "VERTEX"); + trianglesVertInputNode->SetAttribute("source", avar("#%s-mesh-vertices", meshName.c_str())); + trianglesVertInputNode->SetAttribute("offset", "0"); + + TiXmlElement* trianglesNormalInputNode = new TiXmlElement("input"); + trianglesNode->LinkEndChild(trianglesNormalInputNode); + trianglesNormalInputNode->SetAttribute("semantic", "NORMAL"); + trianglesNormalInputNode->SetAttribute("source", avar("#%s-mesh-normals", meshName.c_str())); + trianglesNormalInputNode->SetAttribute("offset", "1"); + + TiXmlElement* trianglesUV0InputNode = new TiXmlElement("input"); + trianglesNode->LinkEndChild(trianglesUV0InputNode); + trianglesUV0InputNode->SetAttribute("semantic", "TEXCOORD"); + trianglesUV0InputNode->SetAttribute("source", avar("#%s-mesh-map-0", meshName.c_str())); + trianglesUV0InputNode->SetAttribute("offset", "2"); + trianglesUV0InputNode->SetAttribute("set", "0"); + + TiXmlElement* polyNode = new TiXmlElement("p"); + trianglesNode->LinkEndChild(polyNode); + + Vector tempIndices; + tempIndices.reserve(4); + + for (U32 j = 0; j < dl->mesh.mPolyList.size(); j++) + { + const OptimizedPolyList::Poly& poly = dl->mesh.mPolyList[j]; + + if (poly.vertexCount < 3) + continue; + + if (poly.material != i) + continue; + + tempIndices.setSize(poly.vertexCount); + dMemset(tempIndices.address(), 0, poly.vertexCount); + + if (poly.type == OptimizedPolyList::TriangleStrip) + { + tempIndices[0] = 0; + U32 idx = 1; + + for (U32 k = 1; k < poly.vertexCount; k += 2) + tempIndices[idx++] = k; + + for (U32 k = ((poly.vertexCount - 1) & (~0x1)); k > 0; k -= 2) + tempIndices[idx++] = k; + } + else if (poly.type == OptimizedPolyList::TriangleList || + poly.type == OptimizedPolyList::TriangleFan) + { + for (U32 k = 0; k < poly.vertexCount; k++) + tempIndices[k] = k; + } + else + AssertISV(false, "ColladaUtils::exportColladaTriangles(): Unknown Poly type!"); + + const U32& firstIdx = dl->mesh.mIndexList[poly.vertexStart]; + const OptimizedPolyList::VertIndex& firstVertIdx = dl->mesh.mVertexList[firstIdx]; + + for (U32 k = 1; k < poly.vertexCount - 1; k++) + { + const U32& secondIdx = dl->mesh.mIndexList[poly.vertexStart + tempIndices[k]]; + const U32& thirdIdx = dl->mesh.mIndexList[poly.vertexStart + tempIndices[k + 1]]; + + const OptimizedPolyList::VertIndex& secondVertIdx = dl->mesh.mVertexList[secondIdx]; + const OptimizedPolyList::VertIndex& thirdVertIdx = dl->mesh.mVertexList[thirdIdx]; + + // Note the reversed winding on the triangles + const char* tri = avar("%d %d %d %d %d %d %d %d %d ", + thirdVertIdx.vertIdx, thirdVertIdx.normalIdx, thirdVertIdx.uv0Idx, + secondVertIdx.vertIdx, secondVertIdx.normalIdx, secondVertIdx.uv0Idx, + firstVertIdx.vertIdx, firstVertIdx.normalIdx, firstVertIdx.uv0Idx); + + TiXmlText* triangleText = new TiXmlText(tri); + polyNode->LinkEndChild(triangleText); + } + } + } +} + +void ColladaUtils::exportColladaCollisionTriangles(TiXmlElement* meshNode, const ExportData& exportData, const U32 collisionIdx) +{ + // Calculate the number of triangles that uses this Material + U32 triangleCount = 0; + + const ExportData::colMesh* col = &exportData.colMeshes[collisionIdx]; + + String meshName = col->colMeshName; + + for (U32 j = 0; j < col->mesh.mPolyList.size(); j++) + { + const OptimizedPolyList::Poly& poly = col->mesh.mPolyList[j]; + + if (poly.vertexCount < 3) + continue; + + if (poly.type == OptimizedPolyList::TriangleList || + poly.type == OptimizedPolyList::TriangleFan || + poly.type == OptimizedPolyList::TriangleStrip) + { + triangleCount += poly.vertexCount - 2; + } + else + AssertISV(false, "ColladaUtils::exportColladaCollisionTriangles(): Unknown Poly type!"); + } + + // Make sure that we are actually using this Material + if (triangleCount == 0) + return; + + TiXmlElement* trianglesNode = new TiXmlElement("triangles"); + meshNode->LinkEndChild(trianglesNode); + trianglesNode->SetAttribute("material", ""); + trianglesNode->SetAttribute("count", avar("%d", triangleCount)); + + TiXmlElement* trianglesVertInputNode = new TiXmlElement("input"); + trianglesNode->LinkEndChild(trianglesVertInputNode); + trianglesVertInputNode->SetAttribute("semantic", "VERTEX"); + trianglesVertInputNode->SetAttribute("source", avar("#%s-mesh-vertices", meshName.c_str())); + trianglesVertInputNode->SetAttribute("offset", "0"); + + TiXmlElement* trianglesNormalInputNode = new TiXmlElement("input"); + trianglesNode->LinkEndChild(trianglesNormalInputNode); + trianglesNormalInputNode->SetAttribute("semantic", "NORMAL"); + trianglesNormalInputNode->SetAttribute("source", avar("#%s-mesh-normals", meshName.c_str())); + trianglesNormalInputNode->SetAttribute("offset", "1"); + + TiXmlElement* trianglesUV0InputNode = new TiXmlElement("input"); + trianglesNode->LinkEndChild(trianglesUV0InputNode); + trianglesUV0InputNode->SetAttribute("semantic", "TEXCOORD"); + trianglesUV0InputNode->SetAttribute("source", avar("#%s-mesh-map-0", meshName.c_str())); + trianglesUV0InputNode->SetAttribute("offset", "2"); + trianglesUV0InputNode->SetAttribute("set", "0"); + + TiXmlElement* polyNode = new TiXmlElement("p"); + trianglesNode->LinkEndChild(polyNode); + + Vector tempIndices; + tempIndices.reserve(4); + + for (U32 j = 0; j < col->mesh.mPolyList.size(); j++) + { + const OptimizedPolyList::Poly& poly = col->mesh.mPolyList[j]; + + if (poly.vertexCount < 3) + continue; + + tempIndices.setSize(poly.vertexCount); + dMemset(tempIndices.address(), 0, poly.vertexCount); + + if (poly.type == OptimizedPolyList::TriangleStrip) + { + tempIndices[0] = 0; + U32 idx = 1; + + for (U32 k = 1; k < poly.vertexCount; k += 2) + tempIndices[idx++] = k; + + for (U32 k = ((poly.vertexCount - 1) & (~0x1)); k > 0; k -= 2) + tempIndices[idx++] = k; + } + else if (poly.type == OptimizedPolyList::TriangleList || + poly.type == OptimizedPolyList::TriangleFan) + { + for (U32 k = 0; k < poly.vertexCount; k++) + tempIndices[k] = k; + } + else + AssertISV(false, "ColladaUtils::exportColladaTriangles(): Unknown Poly type!"); + + const U32& firstIdx = col->mesh.mIndexList[poly.vertexStart]; + const OptimizedPolyList::VertIndex& firstVertIdx = col->mesh.mVertexList[firstIdx]; + + for (U32 k = 1; k < poly.vertexCount - 1; k++) + { + const U32& secondIdx = col->mesh.mIndexList[poly.vertexStart + tempIndices[k]]; + const U32& thirdIdx = col->mesh.mIndexList[poly.vertexStart + tempIndices[k + 1]]; + + const OptimizedPolyList::VertIndex& secondVertIdx = col->mesh.mVertexList[secondIdx]; + const OptimizedPolyList::VertIndex& thirdVertIdx = col->mesh.mVertexList[thirdIdx]; + + // Note the reversed winding on the triangles + const char* tri = avar("%d %d %d %d %d %d %d %d %d ", + thirdVertIdx.vertIdx, thirdVertIdx.normalIdx, thirdVertIdx.uv0Idx, + secondVertIdx.vertIdx, secondVertIdx.normalIdx, secondVertIdx.uv0Idx, + firstVertIdx.vertIdx, firstVertIdx.normalIdx, firstVertIdx.uv0Idx); + + TiXmlText* triangleText = new TiXmlText(tri); + polyNode->LinkEndChild(triangleText); + } + } +} + void ColladaUtils::exportColladaMesh(TiXmlElement* rootNode, const OptimizedPolyList& mesh, const String& meshName, const Vector& matNames) { TiXmlElement* libGeomsNode = new TiXmlElement("library_geometries"); @@ -1576,6 +2105,380 @@ void ColladaUtils::exportColladaMesh(TiXmlElement* rootNode, const OptimizedPoly } +void ColladaUtils::exportColladaMesh(TiXmlElement* rootNode, const ExportData& exportData, const String& meshName) +{ + TiXmlElement* libGeomsNode = new TiXmlElement("library_geometries"); + rootNode->LinkEndChild(libGeomsNode); + + for (U32 d = 0; d < exportData.detailLevels.size(); d++) + { + char lodMeshName[256]; + dSprintf(lodMeshName, 256, "%s%d", meshName.c_str(), exportData.detailLevels[d].size); + + char lodMeshID[256]; + dSprintf(lodMeshID, 256, "%s-mesh", lodMeshName); + + TiXmlElement* geometryNode = new TiXmlElement("geometry"); + libGeomsNode->LinkEndChild(geometryNode); + geometryNode->SetAttribute("id", lodMeshID); + geometryNode->SetAttribute("name", lodMeshName); + + TiXmlElement* meshNode = new TiXmlElement("mesh"); + geometryNode->LinkEndChild(meshNode); + + // Save out the vertices + TiXmlElement* vertsSourceNode = new TiXmlElement("source"); + meshNode->LinkEndChild(vertsSourceNode); + vertsSourceNode->SetAttribute("id", avar("%s-mesh-positions", lodMeshName)); + + TiXmlElement* vertsNode = new TiXmlElement("float_array"); + vertsSourceNode->LinkEndChild(vertsNode); + vertsNode->SetAttribute("id", avar("%s-mesh-positions-array", lodMeshName)); + vertsNode->SetAttribute("count", avar("%d", exportData.detailLevels[d].mesh.mPoints.size() * 3)); + + for (U32 i = 0; i < exportData.detailLevels[d].mesh.mPoints.size(); i++) + { + const Point3F& vert = exportData.detailLevels[d].mesh.mPoints[i]; + + TiXmlText* vertText = new TiXmlText(avar("%.4f %.4f %.4f ", vert.x, vert.y, vert.z)); + vertsNode->LinkEndChild(vertText); + } + + // Save the vertex accessor + TiXmlElement* vertsTechNode = new TiXmlElement("technique_common"); + vertsSourceNode->LinkEndChild(vertsTechNode); + + TiXmlElement* vertsAccNode = new TiXmlElement("accessor"); + vertsTechNode->LinkEndChild(vertsAccNode); + vertsAccNode->SetAttribute("source", avar("#%s-mesh-positions-array", lodMeshName)); + vertsAccNode->SetAttribute("count", avar("%d", exportData.detailLevels[d].mesh.mPoints.size())); + vertsAccNode->SetAttribute("stride", "3"); + + TiXmlElement* vertsAccXNode = new TiXmlElement("param"); + vertsAccNode->LinkEndChild(vertsAccXNode); + vertsAccXNode->SetAttribute("name", "X"); + vertsAccXNode->SetAttribute("type", "float"); + + TiXmlElement* vertsAccYNode = new TiXmlElement("param"); + vertsAccNode->LinkEndChild(vertsAccYNode); + vertsAccYNode->SetAttribute("name", "Y"); + vertsAccYNode->SetAttribute("type", "float"); + + TiXmlElement* vertsAccZNode = new TiXmlElement("param"); + vertsAccNode->LinkEndChild(vertsAccZNode); + vertsAccZNode->SetAttribute("name", "Z"); + vertsAccZNode->SetAttribute("type", "float"); + + // Save out the normals + TiXmlElement* normalsSourceNode = new TiXmlElement("source"); + meshNode->LinkEndChild(normalsSourceNode); + normalsSourceNode->SetAttribute("id", avar("%s-mesh-normals", lodMeshName)); + + TiXmlElement* normalsNode = new TiXmlElement("float_array"); + normalsSourceNode->LinkEndChild(normalsNode); + normalsNode->SetAttribute("id", avar("%s-mesh-normals-array", lodMeshName)); + normalsNode->SetAttribute("count", avar("%d", exportData.detailLevels[d].mesh.mNormals.size() * 3)); + + for (U32 i = 0; i < exportData.detailLevels[d].mesh.mNormals.size(); i++) + { + const Point3F& normal = exportData.detailLevels[d].mesh.mNormals[i]; + + TiXmlText* normalText = new TiXmlText(avar("%.4f %.4f %.4f ", normal.x, normal.y, normal.z)); + normalsNode->LinkEndChild(normalText); + } + + // Save the normals accessor + TiXmlElement* normalsTechNode = new TiXmlElement("technique_common"); + normalsSourceNode->LinkEndChild(normalsTechNode); + + TiXmlElement* normalsAccNode = new TiXmlElement("accessor"); + normalsTechNode->LinkEndChild(normalsAccNode); + normalsAccNode->SetAttribute("source", avar("#%s-mesh-normals-array", lodMeshName)); + normalsAccNode->SetAttribute("count", avar("%d", exportData.detailLevels[d].mesh.mNormals.size())); + normalsAccNode->SetAttribute("stride", "3"); + + TiXmlElement* normalsAccXNode = new TiXmlElement("param"); + normalsAccNode->LinkEndChild(normalsAccXNode); + normalsAccXNode->SetAttribute("name", "X"); + normalsAccXNode->SetAttribute("type", "float"); + + TiXmlElement* normalsAccYNode = new TiXmlElement("param"); + normalsAccNode->LinkEndChild(normalsAccYNode); + normalsAccYNode->SetAttribute("name", "Y"); + normalsAccYNode->SetAttribute("type", "float"); + + TiXmlElement* normalsAccZNode = new TiXmlElement("param"); + normalsAccNode->LinkEndChild(normalsAccZNode); + normalsAccZNode->SetAttribute("name", "Z"); + normalsAccZNode->SetAttribute("type", "float"); + + // Save out the uvs + TiXmlElement* uv0SourceNode = new TiXmlElement("source"); + meshNode->LinkEndChild(uv0SourceNode); + uv0SourceNode->SetAttribute("id", avar("%s-mesh-map-0", lodMeshName)); + + TiXmlElement* uv0Node = new TiXmlElement("float_array"); + uv0SourceNode->LinkEndChild(uv0Node); + uv0Node->SetAttribute("id", avar("%s-mesh-map-0-array", lodMeshName)); + uv0Node->SetAttribute("count", avar("%d", exportData.detailLevels[d].mesh.mUV0s.size() * 2)); + + for (U32 i = 0; i < exportData.detailLevels[d].mesh.mUV0s.size(); i++) + { + const Point2F& uv0 = exportData.detailLevels[d].mesh.mUV0s[i]; + + TiXmlText* uv0Text = new TiXmlText(avar("%.4f %.4f ", uv0.x, 1.0f - uv0.y)); // COLLADA uvs are upside down compared to Torque + uv0Node->LinkEndChild(uv0Text); + } + + // Save the uv0 accessor + TiXmlElement* uv0TechNode = new TiXmlElement("technique_common"); + uv0SourceNode->LinkEndChild(uv0TechNode); + + TiXmlElement* uv0AccNode = new TiXmlElement("accessor"); + uv0TechNode->LinkEndChild(uv0AccNode); + uv0AccNode->SetAttribute("source", avar("#%s-mesh-map-0-array", lodMeshName)); + uv0AccNode->SetAttribute("count", avar("%d", exportData.detailLevels[d].mesh.mUV0s.size())); + uv0AccNode->SetAttribute("stride", "2"); + + TiXmlElement* uv0AccSNode = new TiXmlElement("param"); + uv0AccNode->LinkEndChild(uv0AccSNode); + uv0AccSNode->SetAttribute("name", "S"); + uv0AccSNode->SetAttribute("type", "float"); + + TiXmlElement* uv0AccTNode = new TiXmlElement("param"); + uv0AccNode->LinkEndChild(uv0AccTNode); + uv0AccTNode->SetAttribute("name", "T"); + uv0AccTNode->SetAttribute("type", "float"); + + // Define the vertices position array + TiXmlElement* verticesNode = new TiXmlElement("vertices"); + meshNode->LinkEndChild(verticesNode); + verticesNode->SetAttribute("id", avar("%s-mesh-vertices", lodMeshName)); + + TiXmlElement* verticesInputNode = new TiXmlElement("input"); + verticesNode->LinkEndChild(verticesInputNode); + verticesInputNode->SetAttribute("semantic", "POSITION"); + verticesInputNode->SetAttribute("source", avar("#%s-mesh-positions", lodMeshName)); + + Vector mapNames; + + //exportColladaTriangles(meshNode, exportData.detailLevels[d].mesh, lodMeshName, mapNames); + exportColladaTriangles(meshNode, exportData, d, lodMeshName); + + // Extra info useful for COLLADAMaya importer (OpenCOLLADA) + TiXmlElement* extraGeoNode = new TiXmlElement("extra"); + libGeomsNode->LinkEndChild(extraGeoNode); + + TiXmlElement* extraGeoNodeTech = new TiXmlElement("technique"); + extraGeoNode->LinkEndChild(extraGeoNodeTech); + extraGeoNodeTech->SetAttribute("profile", "OpenCOLLADAMaya"); + + TiXmlElement* mayaNode2Id = new TiXmlElement("originalMayaNodeId"); + extraGeoNodeTech->LinkEndChild(mayaNode2Id); + mayaNode2Id->SetAttribute("sid", "originalMayaNodeId"); + TiXmlText* mayaIdMesh = new TiXmlText(avar("%s", lodMeshName)); + mayaNode2Id->LinkEndChild(mayaIdMesh); + + TiXmlElement* doubleSidedId = new TiXmlElement("double_sided"); + extraGeoNodeTech->LinkEndChild(doubleSidedId); + doubleSidedId->SetAttribute("sid", "double_sided"); + TiXmlText* doubleSideIdText = new TiXmlText("1"); + doubleSidedId->LinkEndChild(doubleSideIdText); + + TiXmlElement* paramExtraNode = new TiXmlElement("param"); + extraGeoNodeTech->LinkEndChild(paramExtraNode); + paramExtraNode->SetAttribute("sid", "colladaId"); + paramExtraNode->SetAttribute("type", "string"); + + TiXmlText* mayaParamMesh = new TiXmlText(avar("%s-mesh", lodMeshName)); + paramExtraNode->LinkEndChild(mayaParamMesh); + } + + //And now collisions + for (U32 d = 0; d < exportData.colMeshes.size(); d++) + { + const char* colMeshName = exportData.colMeshes[d].colMeshName; + + char colMeshId[256]; + dSprintf(colMeshId, 256, "%s-mesh", colMeshName); + + TiXmlElement* geometryNode = new TiXmlElement("geometry"); + libGeomsNode->LinkEndChild(geometryNode); + geometryNode->SetAttribute("id", colMeshId); + geometryNode->SetAttribute("name", colMeshName); + + TiXmlElement* meshNode = new TiXmlElement("mesh"); + geometryNode->LinkEndChild(meshNode); + + // Save out the vertices + TiXmlElement* vertsSourceNode = new TiXmlElement("source"); + meshNode->LinkEndChild(vertsSourceNode); + vertsSourceNode->SetAttribute("id", avar("%s-mesh-positions", colMeshName)); + + TiXmlElement* vertsNode = new TiXmlElement("float_array"); + vertsSourceNode->LinkEndChild(vertsNode); + vertsNode->SetAttribute("id", avar("%s-mesh-positions-array", colMeshName)); + vertsNode->SetAttribute("count", avar("%d", exportData.colMeshes[d].mesh.mPoints.size() * 3)); + + for (U32 i = 0; i < exportData.colMeshes[d].mesh.mPoints.size(); i++) + { + const Point3F& vert = exportData.colMeshes[d].mesh.mPoints[i]; + + TiXmlText* vertText = new TiXmlText(avar("%.4f %.4f %.4f ", vert.x, vert.y, vert.z)); + vertsNode->LinkEndChild(vertText); + } + + // Save the vertex accessor + TiXmlElement* vertsTechNode = new TiXmlElement("technique_common"); + vertsSourceNode->LinkEndChild(vertsTechNode); + + TiXmlElement* vertsAccNode = new TiXmlElement("accessor"); + vertsTechNode->LinkEndChild(vertsAccNode); + vertsAccNode->SetAttribute("source", avar("#%s-mesh-positions-array", colMeshName)); + vertsAccNode->SetAttribute("count", avar("%d", exportData.colMeshes[d].mesh.mPoints.size())); + vertsAccNode->SetAttribute("stride", "3"); + + TiXmlElement* vertsAccXNode = new TiXmlElement("param"); + vertsAccNode->LinkEndChild(vertsAccXNode); + vertsAccXNode->SetAttribute("name", "X"); + vertsAccXNode->SetAttribute("type", "float"); + + TiXmlElement* vertsAccYNode = new TiXmlElement("param"); + vertsAccNode->LinkEndChild(vertsAccYNode); + vertsAccYNode->SetAttribute("name", "Y"); + vertsAccYNode->SetAttribute("type", "float"); + + TiXmlElement* vertsAccZNode = new TiXmlElement("param"); + vertsAccNode->LinkEndChild(vertsAccZNode); + vertsAccZNode->SetAttribute("name", "Z"); + vertsAccZNode->SetAttribute("type", "float"); + + // Save out the normals + TiXmlElement* normalsSourceNode = new TiXmlElement("source"); + meshNode->LinkEndChild(normalsSourceNode); + normalsSourceNode->SetAttribute("id", avar("%s-mesh-normals", colMeshName)); + + TiXmlElement* normalsNode = new TiXmlElement("float_array"); + normalsSourceNode->LinkEndChild(normalsNode); + normalsNode->SetAttribute("id", avar("%s-mesh-normals-array", colMeshName)); + normalsNode->SetAttribute("count", avar("%d", exportData.colMeshes[d].mesh.mNormals.size() * 3)); + + for (U32 i = 0; i < exportData.colMeshes[d].mesh.mNormals.size(); i++) + { + const Point3F& normal = exportData.colMeshes[d].mesh.mNormals[i]; + + TiXmlText* normalText = new TiXmlText(avar("%.4f %.4f %.4f ", normal.x, normal.y, normal.z)); + normalsNode->LinkEndChild(normalText); + } + + // Save the normals accessor + TiXmlElement* normalsTechNode = new TiXmlElement("technique_common"); + normalsSourceNode->LinkEndChild(normalsTechNode); + + TiXmlElement* normalsAccNode = new TiXmlElement("accessor"); + normalsTechNode->LinkEndChild(normalsAccNode); + normalsAccNode->SetAttribute("source", avar("#%s-mesh-normals-array", colMeshName)); + normalsAccNode->SetAttribute("count", avar("%d", exportData.colMeshes[d].mesh.mNormals.size())); + normalsAccNode->SetAttribute("stride", "3"); + + TiXmlElement* normalsAccXNode = new TiXmlElement("param"); + normalsAccNode->LinkEndChild(normalsAccXNode); + normalsAccXNode->SetAttribute("name", "X"); + normalsAccXNode->SetAttribute("type", "float"); + + TiXmlElement* normalsAccYNode = new TiXmlElement("param"); + normalsAccNode->LinkEndChild(normalsAccYNode); + normalsAccYNode->SetAttribute("name", "Y"); + normalsAccYNode->SetAttribute("type", "float"); + + TiXmlElement* normalsAccZNode = new TiXmlElement("param"); + normalsAccNode->LinkEndChild(normalsAccZNode); + normalsAccZNode->SetAttribute("name", "Z"); + normalsAccZNode->SetAttribute("type", "float"); + + // Save out the uvs + TiXmlElement* uv0SourceNode = new TiXmlElement("source"); + meshNode->LinkEndChild(uv0SourceNode); + uv0SourceNode->SetAttribute("id", avar("%s-mesh-map-0", colMeshName)); + + TiXmlElement* uv0Node = new TiXmlElement("float_array"); + uv0SourceNode->LinkEndChild(uv0Node); + uv0Node->SetAttribute("id", avar("%s-mesh-map-0-array", colMeshName)); + uv0Node->SetAttribute("count", avar("%d", exportData.colMeshes[d].mesh.mUV0s.size() * 2)); + + for (U32 i = 0; i < exportData.colMeshes[d].mesh.mUV0s.size(); i++) + { + const Point2F& uv0 = exportData.colMeshes[d].mesh.mUV0s[i]; + + TiXmlText* uv0Text = new TiXmlText(avar("%.4f %.4f ", uv0.x, 1.0f - uv0.y)); // COLLADA uvs are upside down compared to Torque + uv0Node->LinkEndChild(uv0Text); + } + + // Save the uv0 accessor + TiXmlElement* uv0TechNode = new TiXmlElement("technique_common"); + uv0SourceNode->LinkEndChild(uv0TechNode); + + TiXmlElement* uv0AccNode = new TiXmlElement("accessor"); + uv0TechNode->LinkEndChild(uv0AccNode); + uv0AccNode->SetAttribute("source", avar("#%s-mesh-map-0-array", colMeshName)); + uv0AccNode->SetAttribute("count", avar("%d", exportData.colMeshes[d].mesh.mUV0s.size())); + uv0AccNode->SetAttribute("stride", "2"); + + TiXmlElement* uv0AccSNode = new TiXmlElement("param"); + uv0AccNode->LinkEndChild(uv0AccSNode); + uv0AccSNode->SetAttribute("name", "S"); + uv0AccSNode->SetAttribute("type", "float"); + + TiXmlElement* uv0AccTNode = new TiXmlElement("param"); + uv0AccNode->LinkEndChild(uv0AccTNode); + uv0AccTNode->SetAttribute("name", "T"); + uv0AccTNode->SetAttribute("type", "float"); + + // Define the vertices position array + TiXmlElement* verticesNode = new TiXmlElement("vertices"); + meshNode->LinkEndChild(verticesNode); + verticesNode->SetAttribute("id", avar("%s-mesh-vertices", colMeshName)); + + TiXmlElement* verticesInputNode = new TiXmlElement("input"); + verticesNode->LinkEndChild(verticesInputNode); + verticesInputNode->SetAttribute("semantic", "POSITION"); + verticesInputNode->SetAttribute("source", avar("#%s-mesh-positions", colMeshName)); + + Vector mapNames; + + //exportColladaTriangles(meshNode, exportData.detailLevels[d].mesh, lodMeshName, mapNames); + exportColladaCollisionTriangles(meshNode, exportData, d); + + // Extra info useful for COLLADAMaya importer (OpenCOLLADA) + TiXmlElement* extraGeoNode = new TiXmlElement("extra"); + libGeomsNode->LinkEndChild(extraGeoNode); + + TiXmlElement* extraGeoNodeTech = new TiXmlElement("technique"); + extraGeoNode->LinkEndChild(extraGeoNodeTech); + extraGeoNodeTech->SetAttribute("profile", "OpenCOLLADAMaya"); + + TiXmlElement* mayaNode2Id = new TiXmlElement("originalMayaNodeId"); + extraGeoNodeTech->LinkEndChild(mayaNode2Id); + mayaNode2Id->SetAttribute("sid", "originalMayaNodeId"); + TiXmlText* mayaIdMesh = new TiXmlText(avar("%s", colMeshName)); + mayaNode2Id->LinkEndChild(mayaIdMesh); + + TiXmlElement* doubleSidedId = new TiXmlElement("double_sided"); + extraGeoNodeTech->LinkEndChild(doubleSidedId); + doubleSidedId->SetAttribute("sid", "double_sided"); + TiXmlText* doubleSideIdText = new TiXmlText("1"); + doubleSidedId->LinkEndChild(doubleSideIdText); + + TiXmlElement* paramExtraNode = new TiXmlElement("param"); + extraGeoNodeTech->LinkEndChild(paramExtraNode); + paramExtraNode->SetAttribute("sid", "colladaId"); + paramExtraNode->SetAttribute("type", "string"); + + TiXmlText* mayaParamMesh = new TiXmlText(avar("%s-mesh", colMeshName)); + paramExtraNode->LinkEndChild(mayaParamMesh); + } +} + void ColladaUtils::exportColladaScene(TiXmlElement* rootNode, const String& meshName, const Vector& matNames) { TiXmlElement* libSceneNode = new TiXmlElement("library_visual_scenes"); @@ -1695,6 +2598,244 @@ void ColladaUtils::exportColladaScene(TiXmlElement* rootNode, const String& mesh instVisSceneNode->SetAttribute("url", "#RootNode"); } +void ColladaUtils::exportColladaScene(TiXmlElement* rootNode, const ExportData& exportData, const String& meshName) +{ + TiXmlElement* libSceneNode = new TiXmlElement("library_visual_scenes"); + rootNode->LinkEndChild(libSceneNode); + + TiXmlElement* visSceneNode = new TiXmlElement("visual_scene"); + libSceneNode->LinkEndChild(visSceneNode); + visSceneNode->SetAttribute("id", "RootNode"); + visSceneNode->SetAttribute("name", "RootNode"); + + for (U32 d = 0; d < exportData.detailLevels.size(); d++) + { + char lodMeshName[256]; + dSprintf(lodMeshName, 256, "%s%d", meshName.c_str(), exportData.detailLevels[d].size); + + TiXmlElement* nodeNode = new TiXmlElement("node"); + visSceneNode->LinkEndChild(nodeNode); + nodeNode->SetAttribute("id", lodMeshName); + nodeNode->SetAttribute("name", lodMeshName); + nodeNode->SetAttribute("type", "NODE"); + + TiXmlElement* instanceGeomNode = new TiXmlElement("instance_geometry"); + nodeNode->LinkEndChild(instanceGeomNode); + instanceGeomNode->SetAttribute("url", avar("#%s%d-mesh", meshName.c_str(), exportData.detailLevels[d].size)); + instanceGeomNode->SetAttribute("name", lodMeshName); + + TiXmlElement* bindMatNode = new TiXmlElement("bind_material"); + instanceGeomNode->LinkEndChild(bindMatNode); + + TiXmlElement* techniqueNode = new TiXmlElement("technique_common"); + bindMatNode->LinkEndChild(techniqueNode); + + // Bind the materials + for (U32 i = 0; i < exportData.detailLevels[d].materialRefList.size(); i++) + { + int matIdx; + exportData.detailLevels[d].materialRefList.tryGetValue(i, matIdx); + BaseMatInstance* baseInst = exportData.materials[matIdx]; + + Material* mat = dynamic_cast(baseInst->getMaterial()); + if (!mat) + continue; + + String matName; + + if (mat->getName() && mat->getName()[0]) + matName = mat->mMapTo; + + TiXmlElement* instMatNode = new TiXmlElement("instance_material"); + techniqueNode->LinkEndChild(instMatNode); + instMatNode->SetAttribute("symbol", avar("%s-material", matName.c_str())); + instMatNode->SetAttribute("target", avar("#%s-material", matName.c_str())); + TiXmlElement* bindVertexNode = new TiXmlElement("bind_vertex_input"); + instMatNode->LinkEndChild(bindVertexNode); + //bindVertexNode->SetAttribute("semantic", avar("%s-mesh-map-0", meshName.c_str())); + bindVertexNode->SetAttribute("semantic", "UVMap"); + bindVertexNode->SetAttribute("input_semantic", "TEXCOORD"); + bindVertexNode->SetAttribute("input_set", "0"); + } + + // Extra info useful for COLLADAMax importer (OpenCOLLADA) + TiXmlElement* extraInsGeoNode = new TiXmlElement("extra"); + nodeNode->LinkEndChild(extraInsGeoNode); + + TiXmlElement* extraInsGeoTechNode = new TiXmlElement("technique"); + extraInsGeoNode->LinkEndChild(extraInsGeoTechNode); + extraInsGeoTechNode->SetAttribute("profile", "OpenCOLLADA"); + + TiXmlElement* castShadowsNode = new TiXmlElement("cast_shadows"); + extraInsGeoTechNode->LinkEndChild(castShadowsNode); + castShadowsNode->SetAttribute("sid", "cast_shadows"); + castShadowsNode->SetAttribute("type", "bool"); + + TiXmlText* castShadowsText = new TiXmlText("1"); + castShadowsNode->LinkEndChild(castShadowsText); + + //----------------------------- + TiXmlElement* receiveShadowsNode = new TiXmlElement("receive_shadows"); + extraInsGeoTechNode->LinkEndChild(receiveShadowsNode); + receiveShadowsNode->SetAttribute("sid", "receive_shadows"); + receiveShadowsNode->SetAttribute("type", "bool"); + + TiXmlText* receiveShadowsText = new TiXmlText("1"); + receiveShadowsNode->LinkEndChild(receiveShadowsText); + + //----------------------------- + TiXmlElement* primaryVisibiltyNode = new TiXmlElement("primary_visibility"); + extraInsGeoTechNode->LinkEndChild(primaryVisibiltyNode); + primaryVisibiltyNode->SetAttribute("sid", "primary_visibility"); + primaryVisibiltyNode->SetAttribute("type", "int"); + + TiXmlText* primaryVisibiltyText = new TiXmlText("1"); + primaryVisibiltyNode->LinkEndChild(primaryVisibiltyText); + + //----------------------------- + TiXmlElement* secondaryVisibilityNode = new TiXmlElement("secondary_visibility"); + extraInsGeoTechNode->LinkEndChild(secondaryVisibilityNode); + secondaryVisibilityNode->SetAttribute("sid", "secondary_visibility"); + secondaryVisibilityNode->SetAttribute("type", "int"); + + TiXmlText* secondaryVisibilityText = new TiXmlText("1"); + secondaryVisibilityNode->LinkEndChild(secondaryVisibilityText); + + // Extra info useful for COLLADAMaya importer (OpenCOLLADA) + TiXmlElement* extra2InsGeoNode = new TiXmlElement("extra"); + nodeNode->LinkEndChild(extra2InsGeoNode); + + TiXmlElement* extra2InsGeoTechNode = new TiXmlElement("technique"); + extra2InsGeoNode->LinkEndChild(extra2InsGeoTechNode); + extra2InsGeoTechNode->SetAttribute("profile", "OpenCOLLADAMaya"); + + TiXmlElement* mayaNodeId = new TiXmlElement("originalMayaNodeId"); + extra2InsGeoTechNode->LinkEndChild(mayaNodeId); + mayaNodeId->SetAttribute("sid", "originalMayaNodeId"); + mayaNodeId->SetAttribute("type", "string"); + + TiXmlText* mayaNodeIdMesh = new TiXmlText(lodMeshName); + mayaNodeId->LinkEndChild(mayaNodeIdMesh); + + TiXmlElement* paramExtraNode = new TiXmlElement("param"); + extra2InsGeoTechNode->LinkEndChild(paramExtraNode); + paramExtraNode->SetAttribute("sid", "colladaId"); + paramExtraNode->SetAttribute("type", "string"); + + TiXmlText* mayaParamMesh = new TiXmlText(lodMeshName); + paramExtraNode->LinkEndChild(mayaParamMesh); + } + + //Collisions + for (U32 d = 0; d < exportData.colMeshes.size(); d++) + { + const char* colMeshName = exportData.colMeshes[d].colMeshName; + + TiXmlElement* nodeNode = new TiXmlElement("node"); + visSceneNode->LinkEndChild(nodeNode); + nodeNode->SetAttribute("id", colMeshName); + nodeNode->SetAttribute("name", colMeshName); + nodeNode->SetAttribute("type", "NODE"); + + TiXmlElement* instanceGeomNode = new TiXmlElement("instance_geometry"); + nodeNode->LinkEndChild(instanceGeomNode); + instanceGeomNode->SetAttribute("url", avar("#%s-mesh", colMeshName)); + instanceGeomNode->SetAttribute("name", colMeshName); + + TiXmlElement* bindMatNode = new TiXmlElement("bind_material"); + instanceGeomNode->LinkEndChild(bindMatNode); + + TiXmlElement* techniqueNode = new TiXmlElement("technique_common"); + bindMatNode->LinkEndChild(techniqueNode); + + TiXmlElement* instMatNode = new TiXmlElement("instance_material"); + techniqueNode->LinkEndChild(instMatNode); + instMatNode->SetAttribute("symbol", avar("%s-material", colMeshName)); + instMatNode->SetAttribute("target", avar("#%s-material", colMeshName)); + TiXmlElement* bindVertexNode = new TiXmlElement("bind_vertex_input"); + instMatNode->LinkEndChild(bindVertexNode); + //bindVertexNode->SetAttribute("semantic", avar("%s-mesh-map-0", meshName.c_str())); + bindVertexNode->SetAttribute("semantic", "UVMap"); + bindVertexNode->SetAttribute("input_semantic", "TEXCOORD"); + bindVertexNode->SetAttribute("input_set", "0"); + + // Extra info useful for COLLADAMax importer (OpenCOLLADA) + TiXmlElement* extraInsGeoNode = new TiXmlElement("extra"); + nodeNode->LinkEndChild(extraInsGeoNode); + + TiXmlElement* extraInsGeoTechNode = new TiXmlElement("technique"); + extraInsGeoNode->LinkEndChild(extraInsGeoTechNode); + extraInsGeoTechNode->SetAttribute("profile", "OpenCOLLADA"); + + TiXmlElement* castShadowsNode = new TiXmlElement("cast_shadows"); + extraInsGeoTechNode->LinkEndChild(castShadowsNode); + castShadowsNode->SetAttribute("sid", "cast_shadows"); + castShadowsNode->SetAttribute("type", "bool"); + + TiXmlText* castShadowsText = new TiXmlText("1"); + castShadowsNode->LinkEndChild(castShadowsText); + + //----------------------------- + TiXmlElement* receiveShadowsNode = new TiXmlElement("receive_shadows"); + extraInsGeoTechNode->LinkEndChild(receiveShadowsNode); + receiveShadowsNode->SetAttribute("sid", "receive_shadows"); + receiveShadowsNode->SetAttribute("type", "bool"); + + TiXmlText* receiveShadowsText = new TiXmlText("1"); + receiveShadowsNode->LinkEndChild(receiveShadowsText); + + //----------------------------- + TiXmlElement* primaryVisibiltyNode = new TiXmlElement("primary_visibility"); + extraInsGeoTechNode->LinkEndChild(primaryVisibiltyNode); + primaryVisibiltyNode->SetAttribute("sid", "primary_visibility"); + primaryVisibiltyNode->SetAttribute("type", "int"); + + TiXmlText* primaryVisibiltyText = new TiXmlText("1"); + primaryVisibiltyNode->LinkEndChild(primaryVisibiltyText); + + //----------------------------- + TiXmlElement* secondaryVisibilityNode = new TiXmlElement("secondary_visibility"); + extraInsGeoTechNode->LinkEndChild(secondaryVisibilityNode); + secondaryVisibilityNode->SetAttribute("sid", "secondary_visibility"); + secondaryVisibilityNode->SetAttribute("type", "int"); + + TiXmlText* secondaryVisibilityText = new TiXmlText("1"); + secondaryVisibilityNode->LinkEndChild(secondaryVisibilityText); + + // Extra info useful for COLLADAMaya importer (OpenCOLLADA) + TiXmlElement* extra2InsGeoNode = new TiXmlElement("extra"); + nodeNode->LinkEndChild(extra2InsGeoNode); + + TiXmlElement* extra2InsGeoTechNode = new TiXmlElement("technique"); + extra2InsGeoNode->LinkEndChild(extra2InsGeoTechNode); + extra2InsGeoTechNode->SetAttribute("profile", "OpenCOLLADAMaya"); + + TiXmlElement* mayaNodeId = new TiXmlElement("originalMayaNodeId"); + extra2InsGeoTechNode->LinkEndChild(mayaNodeId); + mayaNodeId->SetAttribute("sid", "originalMayaNodeId"); + mayaNodeId->SetAttribute("type", "string"); + + TiXmlText* mayaNodeIdMesh = new TiXmlText(colMeshName); + mayaNodeId->LinkEndChild(mayaNodeIdMesh); + + TiXmlElement* paramExtraNode = new TiXmlElement("param"); + extra2InsGeoTechNode->LinkEndChild(paramExtraNode); + paramExtraNode->SetAttribute("sid", "colladaId"); + paramExtraNode->SetAttribute("type", "string"); + + TiXmlText* mayaParamMesh = new TiXmlText(colMeshName); + paramExtraNode->LinkEndChild(mayaParamMesh); + } + //----------------------------- + + TiXmlElement* sceneNode = new TiXmlElement("scene"); + rootNode->LinkEndChild(sceneNode); + + TiXmlElement* instVisSceneNode = new TiXmlElement("instance_visual_scene"); + sceneNode->LinkEndChild(instVisSceneNode); + instVisSceneNode->SetAttribute("url", "#RootNode"); +} + void ColladaUtils::exportToCollada(const Torque::Path& colladaFile, const OptimizedPolyList& mesh, const String& meshName) { // Get the mesh name @@ -1728,11 +2869,14 @@ void ColladaUtils::exportToCollada(const Torque::Path& colladaFile, const Optimi exportColladaMaterials(rootNode, mesh, mapNames, colladaFile); + S32 suffix; + String baseMeshName = String::GetTrailingNumber(outMeshName, suffix); + // Save out our geometry - exportColladaMesh(rootNode, mesh, outMeshName, mapNames); + exportColladaMesh(rootNode, mesh, baseMeshName, mapNames); // Save out our scene nodes - exportColladaScene(rootNode, outMeshName, mapNames); + exportColladaScene(rootNode, baseMeshName, mapNames); // Write out the actual Collada file char fullPath[MAX_PATH_LENGTH]; @@ -1740,4 +2884,139 @@ void ColladaUtils::exportToCollada(const Torque::Path& colladaFile, const Optimi if (!doc.SaveFile(fullPath)) Con::errorf("ColladaUtils::exportToCollada(): Unable to export to %s", fullPath); +} + +void ColladaUtils::exportToCollada(const Torque::Path& colladaFile, const ExportData& exportData) +{ + // Get the mesh name + String outMeshName = colladaFile.getFileName(); + + // The XML document that will hold all of our data + TiXmlDocument doc; + + // Add a standard XML declaration to the top + TiXmlDeclaration* xmlDecl = new TiXmlDeclaration("1.0", "utf-8", ""); + doc.LinkEndChild(xmlDecl); + + // Create our Collada root node and populate a couple standard attributes + TiXmlElement* rootNode = new TiXmlElement("COLLADA"); + rootNode->SetAttribute("xmlns", "http://www.collada.org/2005/11/COLLADASchema"); + rootNode->SetAttribute("version", "1.4.1"); + //rootNode->SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); //T3D Collada loader complaint about this. + + + // Add the root node to the document + doc.LinkEndChild(rootNode); + + // Save out our header info + exportColladaHeader(rootNode); + + // Save out the materials + Vector mapNames; + + exportColladaMaterials(rootNode, exportData, colladaFile); + + S32 suffix; + String baseMeshName = String::GetTrailingNumber(outMeshName, suffix); + + // Save out our geometry + exportColladaMesh(rootNode, exportData, baseMeshName); + + // Save out our scene nodes + exportColladaScene(rootNode, exportData, baseMeshName); + + // Write out the actual Collada file + char fullPath[MAX_PATH_LENGTH]; + Platform::makeFullPathName(colladaFile.getFullPath(), fullPath, MAX_PATH_LENGTH); + + if (!doc.SaveFile(fullPath)) + Con::errorf("ColladaUtils::exportToCollada(): Unable to export to %s", fullPath); +} + +void ColladaUtils::ExportData::processData() +{ + //This pref dictates if we 'backfill' lower LODs with higher ones if any given mesh being exported lacks that level. + //For example, if there are 2 meshes, and one has 500, 200, 100 and the other has 500 and 200 - if this setting is on, the second mesh + //will backfill the 200 to the 100 so it has all levels filled. If it's off, the second mesh will not render at the 100 level + bool fillLowDetailLevels = dAtob(Con::getVariable("$exportMesh::fillLowDetailLevels", "1")); + + S32 numDetailLevels = numberOfDetailLevels(); + + detailLevels.clear(); + detailLevels.setSize(numDetailLevels); + + for (U32 m = 0; m < meshData.size(); ++m) + { + for (U32 i = 0; i < numDetailLevels; ++i) + { + //Get our target size + S32 targetDetailLevelSize = getDetailLevelSize(i); + + //alright, step through each meshdata and propagate the polyList info 'up' to fill + detailLevel* curDetail = &detailLevels[i]; + + curDetail->size = targetDetailLevelSize; + + //Do we have a detail level for this? + S32 detailLevelIdx = -1; + + for (S32 mdl = i; mdl >= 0; mdl--) + { + //walk backwards as needed to find our first valid detail level for this mesh. if we find none, just move on + S32 testDetailLevelSize = getDetailLevelSize(mdl); + detailLevelIdx = meshData[m].hasDetailLevel(testDetailLevelSize); + + if (detailLevelIdx != -1) + break; + } + + if (detailLevelIdx == -1) + { + //found nothing backwards, so lets check if we're configured to back-fill the first detail levels + if (fillLowDetailLevels) + { + //if so, search forward, find the first valid detail and fill it in + for (S32 mdl = 0; mdl < numDetailLevels; mdl++) + { + //walk backwards as needed to find our first valid detail level for this mesh. if we find none, just move on + S32 testDetailLevelSize = getDetailLevelSize(mdl); + detailLevelIdx = meshData[m].hasDetailLevel(testDetailLevelSize); + + if (detailLevelIdx != -1) + break; + } + } + } + + //If we found the detail level index, go ahead and build out the data for it + if (detailLevelIdx != -1) + { + curDetail->mesh.setTransform(&meshData[m].meshTransform, meshData[m].scale); + curDetail->mesh.setObject(meshData[m].originatingObject); + + if (!meshData[m].shapeInst->buildPolyList(&curDetail->mesh, detailLevelIdx)) + { + Con::errorf("TSStatic::buildExportPolyList - failed to build polylist for LOD %i", i); + continue; + } + + //lastly, get material + for (U32 m = 0; m < curDetail->mesh.mMaterialList.size(); m++) + { + S32 matIdx = hasMaterialInstance(curDetail->mesh.mMaterialList[m]); + + if (matIdx == -1) + { + //cool, haven't already got this material, so lets store it out + materials.push_back(curDetail->mesh.mMaterialList[m]); + curDetail->materialRefList.insert(m, materials.size() - 1); + } + else + { + curDetail->materialRefList.insert(m, matIdx); + } + } + } + } + } } \ No newline at end of file diff --git a/Engine/source/ts/collada/colladaUtils.h b/Engine/source/ts/collada/colladaUtils.h index 04592126e..4997a8803 100644 --- a/Engine/source/ts/collada/colladaUtils.h +++ b/Engine/source/ts/collada/colladaUtils.h @@ -50,6 +50,10 @@ #include "console/console.h" #endif +#ifndef _TSSHAPEINSTANCE_H_ +#include "ts/tsShapeInstance.h" +#endif + #include "platform/tmm_off.h" #include "dae.h" @@ -63,6 +67,7 @@ #include "dom/domCOLLADA.h" #include "platform/tmm_on.h" +#include "core/strings/findMatch.h" namespace ColladaUtils { @@ -100,7 +105,7 @@ namespace ColladaUtils { upAxis = UPAXISTYPE_COUNT; unit = -1.0f; - lodType = DetectDTS; + lodType = TrailingNumber; singleDetailSize = 2; matNamePrefix = ""; alwaysImport = ""; @@ -117,6 +122,123 @@ namespace ColladaUtils ImportOptions& getOptions(); + struct ExportData + { + struct detailLevel + { + OptimizedPolyList mesh; + S32 size; + Map materialRefList; + }; + + struct meshLODData + { + Vector meshDetailLevels; + TSShapeInstance* shapeInst; + MatrixF meshTransform; + SceneObject* originatingObject; + + Point3F scale; + + S32 hasDetailLevel(S32 size) + { + for (U32 i = 0; i < meshDetailLevels.size(); ++i) + { + U32 mdlSize = meshDetailLevels[i].size; + + if (mdlSize == size) + return i; + } + + return -1; + } + }; + + struct colMesh + { + OptimizedPolyList mesh; + String colMeshName; + }; + + Vector detailLevels; + Vector meshData; + Vector colMeshes; + Vector materials; + + void processData(); + + S32 hasDetailLevel(U32 dl) + { + for (U32 i = 0; i < detailLevels.size(); i++) + { + if (detailLevels[i].size == dl) + return i; + } + + return -1; + } + + S32 hasMaterialInstance(BaseMatInstance* matInst) + { + for (U32 i = 0; i < materials.size(); i++) + { + if (materials[i] == matInst) + return i; + } + + return -1; + } + + S32 numberOfDetailLevels() + { + Vector detailLevelIdxs; + + for (U32 i = 0; i < meshData.size(); ++i) + { + for (U32 d = 0; d < meshData[i].meshDetailLevels.size(); ++d) + { + detailLevelIdxs.push_back_unique(meshData[i].meshDetailLevels[d].size); + } + } + + return detailLevelIdxs.size(); + } + + static S32 _Sort(const S32 *p1, const S32 *p2) + { + S32 e1 = (*p1); + S32 e2 = (*p2); + + if (e1 > e2) + return 1; + else if (e1 < e2) + return -1; + + return 0; + } + + S32 getDetailLevelSize(U32 detailIdx) + { + Vector detailLevelIdxs; + + for (U32 i = 0; i < meshData.size(); ++i) + { + for (U32 d = 0; d < meshData[i].meshDetailLevels.size(); ++d) + { + S32 mdlSize = meshData[i].meshDetailLevels[d].size; + detailLevelIdxs.push_back_unique(mdlSize); + } + } + + if (detailIdx >= detailLevelIdxs.size()) + return -1; + + detailLevelIdxs.sort(&_Sort); + + return detailLevelIdxs[detailIdx]; + } + }; + void convertTransform(MatrixF& m); void collapsePath(std::string& path); @@ -139,8 +261,15 @@ namespace ColladaUtils void exportColladaMesh(TiXmlElement* rootNode, const OptimizedPolyList& mesh, const String& meshName, const Vector& matNames); void exportColladaScene(TiXmlElement* rootNode, const String& meshName, const Vector& matNames); + void exportColladaMaterials(TiXmlElement* rootNode, const ExportData& exportData, const Torque::Path& colladaFile); + void exportColladaMesh(TiXmlElement* rootNode, const ExportData& exportData, const String& meshName); + void exportColladaCollisionTriangles(TiXmlElement* meshNode, const ExportData& exportData, const U32 collisionIdx); + void exportColladaTriangles(TiXmlElement* meshNode, const ExportData& exportData, const U32 detailLevel, const String& meshName); + void exportColladaScene(TiXmlElement* rootNode, const ExportData& exportData, const String& meshName); + // Export an OptimizedPolyList to a simple Collada file void exportToCollada(const Torque::Path& colladaFile, const OptimizedPolyList& mesh, const String& meshName = String::EmptyString); + void exportToCollada(const Torque::Path& colladaFile, const ExportData& exportData); }; //----------------------------------------------------------------------------- @@ -535,7 +664,7 @@ template<> inline const domListOfUInts *ColladaPrimitive::getTrian continue; domUint* pSrcData = &(P->getValue()[0]); - S32 numTriangles = (P->getValue().getCount() / stride) - 2; + size_t numTriangles = (P->getValue().getCount() / stride) - 2; // Convert the strip back to a triangle list domUint* v0 = pSrcData; @@ -576,7 +705,7 @@ template<> inline const domListOfUInts *ColladaPrimitive::getTriangl continue; domUint* pSrcData = &(P->getValue()[0]); - S32 numTriangles = (P->getValue().getCount() / stride) - 2; + size_t numTriangles = (P->getValue().getCount() / stride) - 2; // Convert the fan back to a triangle list domUint* v0 = pSrcData + stride; @@ -608,7 +737,7 @@ template<> inline const domListOfUInts *ColladaPrimitive::getTriang continue; domUint* pSrcData = &(P->getValue()[0]); - S32 numPoints = P->getValue().getCount() / stride; + size_t numPoints = P->getValue().getCount() / stride; // Use a simple tri-fan (centered at the first point) method of // converting the polygon to triangles. diff --git a/Engine/source/ts/tsShapeConstruct.cpp b/Engine/source/ts/tsShapeConstruct.cpp index dd2a67644..fc5465401 100644 --- a/Engine/source/ts/tsShapeConstruct.cpp +++ b/Engine/source/ts/tsShapeConstruct.cpp @@ -135,6 +135,20 @@ IMPLEMENT_CONOBJECT(TSShapeConstructor); TSShapeConstructor::TSShapeConstructor() : mShapePath(""), mLoadingShape(false) { + mOptions.upAxis = UPAXISTYPE_COUNT; + mOptions.unit = -1.0f; + mOptions.lodType = ColladaUtils::ImportOptions::TrailingNumber; + mOptions.singleDetailSize = 2; + mOptions.matNamePrefix = ""; + mOptions.alwaysImport = ""; + mOptions.neverImport = String(Con::getVariable("$TSShapeConstructor::neverImport")); + mOptions.alwaysImportMesh = ""; + mOptions.neverImportMesh = String(Con::getVariable("$TSShapeConstructor::neverImportMesh")); + mOptions.ignoreNodeScale = false; + mOptions.adjustCenter = false; + mOptions.adjustFloor = false; + mOptions.forceUpdateMaterials = false; + mOptions.useDiffuseNames = false; mShape = NULL; }