xmlNode* FArchiveXML::WriteGeometryMesh(FCDObject* object, xmlNode* parentNode) { FCDGeometryMesh* geometryMesh = (FCDGeometryMesh*)object; xmlNode* meshNode = NULL; if (geometryMesh->IsConvex() && !geometryMesh->GetConvexHullOf().empty()) { meshNode = AddChild(parentNode, DAE_CONVEX_MESH_ELEMENT); FUSStringBuilder convexHullOfName(geometryMesh->GetConvexHullOf()); AddAttribute(meshNode, DAE_CONVEX_HULL_OF_ATTRIBUTE, convexHullOfName); } else { meshNode = AddChild(parentNode, DAE_MESH_ELEMENT); // Write out the sources for (size_t i = 0; i < geometryMesh->GetSourceCount(); ++i) { FArchiveXML::LetWriteObject(geometryMesh->GetSource(i), meshNode); } // Write out the <vertices> element xmlNode* verticesNode = AddChild(meshNode, DAE_VERTICES_ELEMENT); xmlNode* verticesInputExtraNode = NULL,* verticesInputExtraTechniqueNode = NULL; for (size_t i = 0; i < geometryMesh->GetVertexSourceCount(); ++i) { FCDGeometrySource* source = geometryMesh->GetVertexSource(i); const char* semantic = FUDaeGeometryInput::ToString(source->GetType()); AddInput(verticesNode, source->GetDaeId(), semantic); if (geometryMesh->GetPolygonsCount() > 0) { FCDGeometryPolygons* firstPolys = geometryMesh->GetPolygons(0); FCDGeometryPolygonsInput* input = firstPolys->FindInput(source); FUAssert(input != NULL, continue); if (input->GetSet() != -1) { // We are interested in the set information, so if it is available, export it as an extra. if (verticesInputExtraNode == NULL) { verticesInputExtraNode = FUXmlWriter::CreateNode(DAE_EXTRA_ELEMENT); verticesInputExtraTechniqueNode = FUXmlWriter::AddChild(verticesInputExtraNode, DAE_TECHNIQUE_ELEMENT); FUXmlWriter::AddAttribute(verticesInputExtraTechniqueNode, DAE_PROFILE_ATTRIBUTE, DAE_FCOLLADA_PROFILE); } AddInput(verticesInputExtraTechniqueNode, source->GetDaeId(), semantic, -1, input->GetSet()); } } } if (verticesInputExtraNode != NULL) AddChild(verticesNode, verticesInputExtraNode); FUSStringBuilder verticesNodeId(geometryMesh->GetDaeId()); verticesNodeId.append("-vertices"); AddAttribute(verticesNode, DAE_ID_ATTRIBUTE, verticesNodeId); // Write out the polygons for (size_t i = 0; i < geometryMesh->GetPolygonsCount(); ++i) { FArchiveXML::LetWriteObject(geometryMesh->GetPolygons(i), meshNode); } }
bool FArchiveXML::LoadGeometryInstance(FCDObject* object, xmlNode* instanceNode) { if (!FArchiveXML::LoadEntityInstance(object, instanceNode)) return false; bool status = true; FCDGeometryInstance* geometryInstance = (FCDGeometryInstance*)object; // Look for the <bind_material> element. The others are discarded for now. xmlNode* bindMaterialNode = FindChildByType(instanceNode, DAE_BINDMATERIAL_ELEMENT); if (bindMaterialNode != NULL) { for (xmlNode* child = bindMaterialNode->children; child != NULL; child = child->next) { if (child->type != XML_ELEMENT_NODE) continue; if (IsEquivalent(child->name, DAE_PARAMETER_ELEMENT)) { FCDEffectParameter* parameter = geometryInstance->AddEffectParameter(FArchiveXML::GetEffectParameterType(child)); parameter->SetAnimator(); status &= FArchiveXML::LoadSwitch(parameter, ¶meter->GetObjectType(), child); } } // Retrieve the list of the <technique_common><instance_material> elements. xmlNode* techniqueNode = FindChildByType(bindMaterialNode, DAE_TECHNIQUE_COMMON_ELEMENT); xmlNodeList materialNodes; FindChildrenByType(techniqueNode, DAE_INSTANCE_MATERIAL_ELEMENT, materialNodes); for (xmlNodeList::iterator itM = materialNodes.begin(); itM != materialNodes.end(); ++itM) { FCDMaterialInstance* material = geometryInstance->AddMaterialInstance(); status &= (FArchiveXML::LoadMaterialInstance(material, *itM)); } } else { // Blinding attempt to use the material semantic from the polygons as a material id. FCDGeometry* geometry = (FCDGeometry*) geometryInstance->GetEntity(); if (geometry != NULL && geometry->HasType(FCDGeometry::GetClassType()) && geometry->IsMesh()) { FCDGeometryMesh* mesh = geometry->GetMesh(); size_t polyCount = mesh->GetPolygonsCount(); for (size_t i = 0; i < polyCount; ++i) { FCDGeometryPolygons* polys = mesh->GetPolygons(i); const fstring& semantic = polys->GetMaterialSemantic(); fm::string semanticUTF8 = TO_STRING(semantic); semanticUTF8 = FCDObjectWithId::CleanId(semanticUTF8.c_str()); FCDMaterial* material = geometry->GetDocument()->FindMaterial(semanticUTF8); if (material != NULL) { geometryInstance->AddMaterialInstance(material, polys); } } } } geometryInstance->SetDirtyFlag(); return status; }
bool CheckGeometryMesh(FULogFile& fileOut, FCDGeometryMesh* mesh) { // Verify the mesh and its sources PassIf(mesh->GetSourceCount() == 3); FCDGeometrySource* posSource = NULL,* colorSource = NULL,* dummySource = NULL; for (size_t i = 0; i < 3; ++i) { FCDGeometrySource* source = mesh->GetSource(i); FailIf(source == NULL); switch (source->GetType()) { case FUDaeGeometryInput::POSITION: posSource = source; PassIf(source->GetName() == FC("TestPositionSource")); break; case FUDaeGeometryInput::COLOR: colorSource = source; PassIf(source->GetName() == FC("TestColorSource")); break; case FUDaeGeometryInput::EXTRA: dummySource = source; PassIf(source->GetName() == FC("TestDummySource")); break; default: Fail; break; } } FailIf(posSource == NULL || colorSource == NULL || dummySource == NULL); PassIf(IsEquivalent(posSource->GetData(), posSource->GetDataCount(), positionData, 12)); PassIf(posSource->GetStride() == 3); PassIf(IsEquivalent(colorSource->GetData(), colorSource->GetDataCount(), colorData, 12)); PassIf(colorSource->GetStride() == 4); PassIf(IsEquivalent(dummySource->GetData(), dummySource->GetDataCount(), dummyData, 10)); PassIf(dummySource->GetStride() == 3); PassIf(CheckExtraTree(fileOut, dummySource->GetExtra(), false)); // Find the non-empty polygon set and verify that one of the polygon set is, in fact, empty. FCDGeometryPolygons* polys1 = NULL,* polysEmpty = NULL; for (size_t i = 0; i < mesh->GetPolygonsCount(); ++i) { FCDGeometryPolygons* p = mesh->GetPolygons(i); if (p->GetFaceCount() == 0) { PassIf(polysEmpty == NULL); polysEmpty = p; } else { PassIf(polys1 == NULL); polys1 = p; } CheckExtraTree(fileOut, p->GetExtra(), true); } PassIf(polys1 != NULL && polysEmpty != NULL); // Check that we have the wanted tetrahedron in the non-empty polygon set. PassIf(polys1->GetFaceCount() == 4); PassIf(polys1->GetHoleCount() == 0); PassIf(polys1->GetFaceVertexCount(0) == 3 && polys1->GetFaceVertexCount(1) == 3 && polys1->GetFaceVertexCount(2) == 3 && polys1->GetFaceVertexCount(3) == 3); FCDGeometryPolygonsInput* posInput = polys1->FindInput(posSource); FailIf(posInput == NULL || posInput->GetIndexCount() != 12); FCDGeometryPolygonsInput* colorInput = polys1->FindInput(colorSource); FailIf(colorInput == NULL || colorInput == posInput || colorInput->GetIndexCount() != 12); PassIf(IsEquivalent(posInput->GetIndices(), 12, positionIndices, 12)); PassIf(IsEquivalent(colorInput->GetIndices(), 12, colorIndices, 12)); return true; }
// Creates a new polygon group. FCDGeometryPolygons* FCDGeometryMesh::AddPolygons() { FCDGeometryPolygons* polys = new FCDGeometryPolygons(GetDocument(), this); polygons.push_back(polys); // Add to this new polygons all the per-vertex sources. size_t vertexSourceCount = vertexSources.size(); for (size_t v = 0; v < vertexSourceCount; ++v) { polys->AddInput(vertexSources[v], 0); } SetNewChildFlag(); if (parent != NULL) parent->SetNewChildFlag(); return polys; }
static FCDGeometryPolygons* GetPolysFromGeometry(FCDGeometry* geom) { REQUIRE(geom->IsMesh(), "geometry is mesh"); FCDGeometryMesh* mesh = geom->GetMesh(); if (! mesh->IsTriangles()) FCDGeometryPolygonsTools::Triangulate(mesh); REQUIRE(mesh->IsTriangles(), "mesh is made of triangles"); REQUIRE(mesh->GetPolygonsCount() == 1, "mesh has single set of polygons"); FCDGeometryPolygons* polys = mesh->GetPolygons(0); REQUIRE(polys->FindInput(FUDaeGeometryInput::POSITION) != NULL, "mesh has vertex positions"); REQUIRE(polys->FindInput(FUDaeGeometryInput::NORMAL) != NULL, "mesh has vertex normals"); REQUIRE(polys->FindInput(FUDaeGeometryInput::TEXCOORD) != NULL, "mesh has vertex tex coords"); return polys; }
/** * Converts a COLLADA XML document into the PMD mesh format. * * @param input XML document to parse * @param output callback for writing the PMD data; called lots of times * with small strings * @param xmlErrors output - errors reported by the XML parser * @throws ColladaException on failure */ static void ColladaToPMD(const char* input, OutputCB& output, std::string& xmlErrors) { CommonConvert converter(input, xmlErrors); if (converter.GetInstance().GetEntity()->GetType() == FCDEntity::GEOMETRY) { Log(LOG_INFO, "Found static geometry"); FCDGeometryPolygons* polys = GetPolysFromGeometry((FCDGeometry*)converter.GetInstance().GetEntity()); // Convert the geometry into a suitable form for the game ReindexGeometry(polys); std::vector<VertexBlend> boneWeights; // unused std::vector<BoneTransform> boneTransforms; // unused std::vector<PropPoint> propPoints; // Get the raw vertex data FCDGeometryPolygonsInput* inputPosition = polys->FindInput(FUDaeGeometryInput::POSITION); FCDGeometryPolygonsInput* inputNormal = polys->FindInput(FUDaeGeometryInput::NORMAL); FCDGeometryPolygonsInput* inputTexcoord = polys->FindInput(FUDaeGeometryInput::TEXCOORD); const uint32* indicesCombined = inputPosition->GetIndices(); size_t indicesCombinedCount = inputPosition->GetIndexCount(); // (ReindexGeometry guarantees position/normal/texcoord have the same indexes) FCDGeometrySource* sourcePosition = inputPosition->GetSource(); FCDGeometrySource* sourceNormal = inputNormal ->GetSource(); FCDGeometrySource* sourceTexcoord = inputTexcoord->GetSource(); float* dataPosition = sourcePosition->GetData(); float* dataNormal = sourceNormal ->GetData(); float* dataTexcoord = sourceTexcoord->GetData(); size_t vertexCount = sourcePosition->GetDataCount() / 3; assert(sourcePosition->GetDataCount() == vertexCount*3); assert(sourceNormal ->GetDataCount() == vertexCount*3); assert(sourceTexcoord->GetDataCount() == vertexCount*2); // Transform mesh coordinate system to game coordinates // (doesn't modify prop points) TransformStaticModel(dataPosition, dataNormal, vertexCount, converter.GetEntityTransform(), converter.IsYUp()); // Add static prop points // which are empty child nodes of the main parent // Default prop points are already given in game coordinates AddDefaultPropPoints(propPoints); // Calculate transform to convert from COLLADA-defined up_axis to Z-up because // it's relatively straightforward to convert that to game coordinates FMMatrix44 upAxisTransform = FMMatrix44_Identity; if (converter.IsYUp()) { // Prop points are rotated -90 degrees about the X-axis, reverse that rotation // (do this once now because it's easier than messing with quaternions later) upAxisTransform = FMMatrix44::XAxisRotationMatrix(1.57f); } AddStaticPropPoints(propPoints, upAxisTransform, converter.GetInstance().GetParent()); WritePMD(output, indicesCombined, indicesCombinedCount, dataPosition, dataNormal, dataTexcoord, vertexCount, boneWeights, boneTransforms, propPoints); } else if (converter.GetInstance().GetType() == FCDEntityInstance::CONTROLLER) { Log(LOG_INFO, "Found skinned geometry"); FCDControllerInstance& controllerInstance = static_cast<FCDControllerInstance&>(converter.GetInstance()); // (NB: GetType is deprecated and should be replaced with HasType, // except that has irritating linker errors when using a DLL, so don't // bother) assert(converter.GetInstance().GetEntity()->GetType() == FCDEntity::CONTROLLER); // assume this is always true? FCDController* controller = static_cast<FCDController*>(converter.GetInstance().GetEntity()); FCDSkinController* skin = controller->GetSkinController(); REQUIRE(skin != NULL, "is skin controller"); FixSkeletonRoots(controllerInstance); // Data for joints is stored in two places - avoid overflows by limiting // to the minimum of the two sizes, and warn if they're different (which // happens in practice for slightly-broken meshes) size_t jointCount = std::min(skin->GetJointCount(), controllerInstance.GetJointCount()); if (skin->GetJointCount() != controllerInstance.GetJointCount()) { Log(LOG_WARNING, "Mismatched bone counts (skin has %d, skeleton has %d)", skin->GetJointCount(), controllerInstance.GetJointCount()); for (size_t i = 0; i < skin->GetJointCount(); ++i) Log(LOG_INFO, "Skin joint %d: %s", i, skin->GetJoint(i)->GetId().c_str()); for (size_t i = 0; i < controllerInstance.GetJointCount(); ++i) Log(LOG_INFO, "Skeleton joint %d: %s", i, controllerInstance.GetJoint(i)->GetName().c_str()); } // Get the skinned mesh for this entity FCDGeometry* baseGeometry = controller->GetBaseGeometry(); REQUIRE(baseGeometry != NULL, "controller has base geometry"); FCDGeometryPolygons* polys = GetPolysFromGeometry(baseGeometry); // Make sure it doesn't use more bones per vertex than the game can handle SkinReduceInfluences(skin, maxInfluences, 0.001f); // Convert the geometry into a suitable form for the game ReindexGeometry(polys, skin); const Skeleton& skeleton = FindSkeleton(controllerInstance); // Convert the bone influences into VertexBlend structures for the PMD: bool hasComplainedAboutNonexistentJoints = false; // because we want to emit a warning only once std::vector<VertexBlend> boneWeights; // one per vertex const FCDSkinControllerVertex* vertexInfluences = skin->GetVertexInfluences(); for (size_t i = 0; i < skin->GetInfluenceCount(); ++i) { VertexBlend influences = defaultInfluences; assert(vertexInfluences[i].GetPairCount() <= maxInfluences); // guaranteed by ReduceInfluences; necessary for avoiding // out-of-bounds writes to the VertexBlend for (size_t j = 0; j < vertexInfluences[i].GetPairCount(); ++j) { uint32 jointIdx = vertexInfluences[i].GetPair(j)->jointIndex; REQUIRE(jointIdx <= 0xFF, "sensible number of joints (<256)"); // because we only have a u8 to store them in // Find the joint on the skeleton, after checking it really exists FCDSceneNode* joint = NULL; if (jointIdx < controllerInstance.GetJointCount()) joint = controllerInstance.GetJoint(jointIdx); // Complain on error if (! joint) { if (! hasComplainedAboutNonexistentJoints) { Log(LOG_WARNING, "Vertexes influenced by nonexistent joint"); hasComplainedAboutNonexistentJoints = true; } continue; } // Store into the VertexBlend int boneId = skeleton.GetBoneID(joint->GetName().c_str()); if (boneId < 0) { // The relevant joint does exist, but it's not a recognised // bone in our chosen skeleton structure Log(LOG_ERROR, "Vertex influenced by unrecognised bone '%s'", joint->GetName().c_str()); continue; } influences.bones[j] = (uint8)boneId; influences.weights[j] = vertexInfluences[i].GetPair(j)->weight; } boneWeights.push_back(influences); } // Convert the bind pose into BoneTransform structures for the PMD: BoneTransform boneDefault = { { 0, 0, 0 }, { 0, 0, 0, 1 } }; // identity transform std::vector<BoneTransform> boneTransforms (skeleton.GetBoneCount(), boneDefault); for (size_t i = 0; i < jointCount; ++i) { FCDSceneNode* joint = controllerInstance.GetJoint(i); int boneId = skeleton.GetRealBoneID(joint->GetName().c_str()); if (boneId < 0) { // unrecognised joint - it's probably just a prop point // or something, so ignore it continue; } FMMatrix44 bindPose = skin->GetJoint(i)->GetBindPoseInverse().Inverted(); HMatrix matrix; memcpy(matrix, bindPose.Transposed().m, sizeof(matrix)); // set matrix = bindPose^T, to match what decomp_affine wants AffineParts parts; decomp_affine(matrix, &parts); BoneTransform b = { { parts.t.x, parts.t.y, parts.t.z }, { parts.q.x, parts.q.y, parts.q.z, parts.q.w } }; boneTransforms[boneId] = b; } // Construct the list of prop points. // Currently takes all objects that are directly attached to a // standard bone, and whose name begins with "prop-" or "prop_". std::vector<PropPoint> propPoints; AddDefaultPropPoints(propPoints); for (size_t i = 0; i < jointCount; ++i) { FCDSceneNode* joint = controllerInstance.GetJoint(i); int boneId = skeleton.GetBoneID(joint->GetName().c_str()); if (boneId < 0) { // unrecognised joint name - ignore, same as before continue; } // Check all the objects attached to this bone for (size_t j = 0; j < joint->GetChildrenCount(); ++j) { FCDSceneNode* child = joint->GetChild(j); if (child->GetName().find("prop-") != 0 && child->GetName().find("prop_") != 0) { // doesn't begin with "prop-", so skip it continue; } // Strip off the "prop-" from the name std::string propPointName (child->GetName().substr(5)); Log(LOG_INFO, "Adding prop point %s", propPointName.c_str()); // Get translation and orientation of local transform FMMatrix44 localTransform = child->ToMatrix(); HMatrix matrix; memcpy(matrix, localTransform.Transposed().m, sizeof(matrix)); AffineParts parts; decomp_affine(matrix, &parts); // Add prop point to list PropPoint p = { propPointName, { parts.t.x, parts.t.y, parts.t.z }, { parts.q.x, parts.q.y, parts.q.z, parts.q.w }, (uint8)boneId }; propPoints.push_back(p); } } // Get the raw vertex data FCDGeometryPolygonsInput* inputPosition = polys->FindInput(FUDaeGeometryInput::POSITION); FCDGeometryPolygonsInput* inputNormal = polys->FindInput(FUDaeGeometryInput::NORMAL); FCDGeometryPolygonsInput* inputTexcoord = polys->FindInput(FUDaeGeometryInput::TEXCOORD); const uint32* indicesCombined = inputPosition->GetIndices(); size_t indicesCombinedCount = inputPosition->GetIndexCount(); // (ReindexGeometry guarantees position/normal/texcoord have the same indexes) FCDGeometrySource* sourcePosition = inputPosition->GetSource(); FCDGeometrySource* sourceNormal = inputNormal ->GetSource(); FCDGeometrySource* sourceTexcoord = inputTexcoord->GetSource(); float* dataPosition = sourcePosition->GetData(); float* dataNormal = sourceNormal ->GetData(); float* dataTexcoord = sourceTexcoord->GetData(); size_t vertexCount = sourcePosition->GetDataCount() / 3; assert(sourcePosition->GetDataCount() == vertexCount*3); assert(sourceNormal ->GetDataCount() == vertexCount*3); assert(sourceTexcoord->GetDataCount() == vertexCount*2); // Transform model coordinate system to game coordinates TransformSkinnedModel(dataPosition, dataNormal, vertexCount, boneTransforms, propPoints, converter.GetEntityTransform(), skin->GetBindShapeTransform(), converter.IsYUp(), converter.IsXSI()); WritePMD(output, indicesCombined, indicesCombinedCount, dataPosition, dataNormal, dataTexcoord, vertexCount, boneWeights, boneTransforms, propPoints); } else { throw ColladaException("Unrecognised object type"); } }
bool CModelConverter::ReadDAE(const tstring& sFilename) { if (m_pWorkListener) m_pWorkListener->BeginProgress(); FCollada::Initialize(); FCDocument* pDoc = FCollada::NewTopDocument(); if (m_pWorkListener) m_pWorkListener->SetAction("Reading file", 0); if (FCollada::LoadDocumentFromFile(pDoc, convert_to_fstring(sFilename))) { size_t i; FCDocumentTools::StandardizeUpAxisAndLength(pDoc, FMVector3(0, 1, 0)); FCDMaterialLibrary* pMatLib = pDoc->GetMaterialLibrary(); size_t iEntities = pMatLib->GetEntityCount(); if (m_pWorkListener) m_pWorkListener->SetAction("Reading materials", iEntities); for (i = 0; i < iEntities; ++i) { FCDMaterial* pColladaMaterial = pMatLib->GetEntity(i); FCDEffect* pEffect = pColladaMaterial->GetEffect(); size_t iMaterial = m_pScene->AddMaterial(convert_from_fstring(pColladaMaterial->GetName())); CConversionMaterial* pMaterial = m_pScene->GetMaterial(iMaterial); if (pEffect->GetProfileCount() < 1) continue; FCDEffectProfile* pEffectProfile = pEffect->GetProfile(0); FUDaeProfileType::Type eProfileType = pEffectProfile->GetType(); if (eProfileType == FUDaeProfileType::COMMON) { FCDEffectStandard* pStandardProfile = dynamic_cast<FCDEffectStandard*>(pEffectProfile); if (pStandardProfile) { pMaterial->m_vecAmbient = Vector((float*)pStandardProfile->GetAmbientColor()); pMaterial->m_vecDiffuse = Vector((float*)pStandardProfile->GetDiffuseColor()); pMaterial->m_vecSpecular = Vector((float*)pStandardProfile->GetSpecularColor()); pMaterial->m_vecEmissive = Vector((float*)pStandardProfile->GetEmissionColor()); pMaterial->m_flShininess = pStandardProfile->GetShininess(); } } for (size_t j = 0; j < pEffectProfile->GetEffectParameterCount(); j++) { FCDEffectParameter* pEffectParameter = pEffectProfile->GetEffectParameter(j); FCDEffectParameter::Type eType = pEffectParameter->GetType(); if (eType == FCDEffectParameter::SAMPLER) { FCDEffectParameterSampler* pSampler = dynamic_cast<FCDEffectParameterSampler*>(pEffectParameter); if (pSampler) { FCDEffectParameterSurface* pSurface = pSampler->GetSurface(); if (pSurface) { if (pSurface->GetImageCount()) { // Christ Collada why do you have to make things so damn complicated? FCDImage* pImage = pSurface->GetImage(0); pMaterial->m_sDiffuseTexture = convert_from_fstring(pImage->GetFilename()); // Fix up a bug in the Max Collada exporter if (pMaterial->m_sDiffuseTexture.startswith("\\\\C\\")) pMaterial->m_sDiffuseTexture = "C:\\" + pMaterial->m_sDiffuseTexture.substr(4); else if (pMaterial->m_sDiffuseTexture.startswith("\\\\D\\")) pMaterial->m_sDiffuseTexture = "D:\\" + pMaterial->m_sDiffuseTexture.substr(4); } } } } } if (m_pWorkListener) m_pWorkListener->WorkProgress(i+1); } FCDGeometryLibrary* pGeoLib = pDoc->GetGeometryLibrary(); iEntities = pGeoLib->GetEntityCount(); if (m_pWorkListener) m_pWorkListener->SetAction("Loading entities", iEntities); for (i = 0; i < iEntities; ++i) { FCDGeometry* pGeometry = pGeoLib->GetEntity(i); if (pGeometry->IsMesh()) { size_t j; size_t iMesh = m_pScene->AddMesh(convert_from_fstring(pGeometry->GetName())); CConversionMesh* pMesh = m_pScene->GetMesh(iMesh); pMesh->AddBone(convert_from_fstring(pGeometry->GetName())); FCDGeometryMesh* pGeoMesh = pGeometry->GetMesh(); FCDGeometrySource* pPositionSource = pGeoMesh->GetPositionSource(); size_t iVertexCount = pPositionSource->GetValueCount(); for (j = 0; j < iVertexCount; j++) { const float* pflValues = pPositionSource->GetValue(j); pMesh->AddVertex(pflValues[0], pflValues[1], pflValues[2]); } FCDGeometrySource* pNormalSource = pGeoMesh->FindSourceByType(FUDaeGeometryInput::NORMAL); if (pNormalSource) { iVertexCount = pNormalSource->GetValueCount(); for (j = 0; j < iVertexCount; j++) { const float* pflValues = pNormalSource->GetValue(j); pMesh->AddNormal(pflValues[0], pflValues[1], pflValues[2]); } } FCDGeometrySource* pUVSource = pGeoMesh->FindSourceByType(FUDaeGeometryInput::TEXCOORD); if (pUVSource) { iVertexCount = pUVSource->GetValueCount(); for (j = 0; j < iVertexCount; j++) { const float* pflValues = pUVSource->GetValue(j); pMesh->AddUV(pflValues[0], pflValues[1]); } } for (j = 0; j < pGeoMesh->GetPolygonsCount(); j++) { FCDGeometryPolygons* pPolygons = pGeoMesh->GetPolygons(j); FCDGeometryPolygonsInput* pPositionInput = pPolygons->FindInput(FUDaeGeometryInput::POSITION); FCDGeometryPolygonsInput* pNormalInput = pPolygons->FindInput(FUDaeGeometryInput::NORMAL); FCDGeometryPolygonsInput* pUVInput = pPolygons->FindInput(FUDaeGeometryInput::TEXCOORD); size_t iPositionCount = pPositionInput->GetIndexCount(); uint32* pPositions = pPositionInput->GetIndices(); size_t iNormalCount = 0; uint32* pNormals = NULL; if (pNormalInput) { iNormalCount = pNormalInput->GetIndexCount(); pNormals = pNormalInput->GetIndices(); } size_t iUVCount = 0; uint32* pUVs = NULL; if (pUVInput) { iUVCount = pUVInput->GetIndexCount(); pUVs = pUVInput->GetIndices(); } fm::stringT<fchar> sMaterial = pPolygons->GetMaterialSemantic(); size_t iCurrentMaterial = pMesh->AddMaterialStub(convert_from_fstring(sMaterial)); if (pPolygons->TestPolyType() == 3) { // All triangles! for (size_t k = 0; k < iPositionCount; k+=3) { size_t iFace = pMesh->AddFace(iCurrentMaterial); pMesh->AddVertexToFace(iFace, pPositions[k+0], pUVs?pUVs[k+0]:~0, pNormals?pNormals[k+0]:~0); pMesh->AddVertexToFace(iFace, pPositions[k+1], pUVs?pUVs[k+1]:~0, pNormals?pNormals[k+1]:~0); pMesh->AddVertexToFace(iFace, pPositions[k+2], pUVs?pUVs[k+2]:~0, pNormals?pNormals[k+2]:~0); } } else if (pPolygons->TestPolyType() == 4) { // All quads! for (size_t k = 0; k < iPositionCount; k+=4) { size_t iFace = pMesh->AddFace(iCurrentMaterial); pMesh->AddVertexToFace(iFace, pPositions[k+0], pUVs?pUVs[k+0]:~0, pNormals?pNormals[k+0]:~0); pMesh->AddVertexToFace(iFace, pPositions[k+1], pUVs?pUVs[k+1]:~0, pNormals?pNormals[k+1]:~0); pMesh->AddVertexToFace(iFace, pPositions[k+2], pUVs?pUVs[k+2]:~0, pNormals?pNormals[k+2]:~0); pMesh->AddVertexToFace(iFace, pPositions[k+3], pUVs?pUVs[k+3]:~0, pNormals?pNormals[k+3]:~0); } } else { size_t iFaces = pPolygons->GetFaceCount(); for (size_t k = 0; k < iFaces; k++) { size_t iFace = pMesh->AddFace(iCurrentMaterial); size_t o = pPolygons->GetFaceVertexOffset(k); size_t iFaceVertexCount = pPolygons->GetFaceVertexCount(k); for (size_t v = 0; v < iFaceVertexCount; v++) pMesh->AddVertexToFace(iFace, pPositions[o+v], pUVs?pUVs[o+v]:~0, pNormals?pNormals[o+v]:~0); } } } } if (m_pWorkListener) m_pWorkListener->WorkProgress(i+1); } FCDVisualSceneNodeLibrary* pVisualScenes = pDoc->GetVisualSceneLibrary(); iEntities = pVisualScenes->GetEntityCount(); for (i = 0; i < iEntities; ++i) { FCDSceneNode* pNode = pVisualScenes->GetEntity(i); size_t iScene = m_pScene->AddScene(convert_from_fstring(pNode->GetName())); ReadDAESceneTree(pNode, m_pScene->GetScene(iScene)); } } else { printf("Oops! Some kind of error happened!\n"); return false; } m_pScene->SetWorkListener(m_pWorkListener); m_pScene->CalculateExtends(); for (size_t i = 0; i < m_pScene->GetNumMeshes(); i++) { if (m_bWantEdges) m_pScene->GetMesh(i)->CalculateEdgeData(); if (m_pScene->GetMesh(i)->GetNumNormals() == 0) m_pScene->GetMesh(i)->CalculateVertexNormals(); m_pScene->GetMesh(i)->CalculateVertexTangents(); } pDoc->Release(); FCollada::Release(); if (m_pWorkListener) m_pWorkListener->EndProgress(); return true; }
void CModelConverter::SaveDAE(const tstring& sFilename) { if (m_pWorkListener) m_pWorkListener->BeginProgress(); FCollada::Initialize(); FCDocument* pDoc = FCollada::NewTopDocument(); FCDocumentTools::StandardizeUpAxisAndLength(pDoc, FMVector3(0, 1, 0)); FCDAsset* pAsset = pDoc->GetAsset(); FCDAssetContributor* pContributor = pAsset->AddContributor(); pContributor->SetAuthoringTool(fstring_literal("Created by SMAK using FCollada")); FCDMaterialLibrary* pMatLib = pDoc->GetMaterialLibrary(); if (m_pWorkListener) m_pWorkListener->SetAction("Saving materials", m_pScene->GetNumMaterials()); for (size_t iMaterial = 0; iMaterial < m_pScene->GetNumMaterials(); iMaterial++) { CConversionMaterial* pConversionMaterial = m_pScene->GetMaterial(iMaterial); FCDMaterial* pColladaMaterial = pMatLib->AddEntity(); pColladaMaterial->SetName(convert_to_fstring(pConversionMaterial->GetName())); FCDEffect* pEffect = pMatLib->GetDocument()->GetEffectLibrary()->AddEntity(); pColladaMaterial->SetEffect(pEffect); FCDEffectProfile* pEffectProfile = pEffect->AddProfile(FUDaeProfileType::COMMON); pEffect->SetName(convert_to_fstring(pConversionMaterial->GetName())); FCDEffectStandard* pStandardProfile = dynamic_cast<FCDEffectStandard*>(pEffectProfile); if (pStandardProfile) { pStandardProfile->SetLightingType(FCDEffectStandard::PHONG); pStandardProfile->SetAmbientColor(FMVector4(FMVector3((float*)pConversionMaterial->m_vecAmbient), 1)); pStandardProfile->SetDiffuseColor(FMVector4(FMVector3((float*)pConversionMaterial->m_vecDiffuse), 1)); pStandardProfile->SetSpecularColor(FMVector4(FMVector3((float*)pConversionMaterial->m_vecSpecular), 1)); pStandardProfile->SetEmissionColor(FMVector4(FMVector3((float*)pConversionMaterial->m_vecEmissive), 1)); pStandardProfile->SetShininess(pConversionMaterial->m_flShininess); } if (pConversionMaterial->GetDiffuseTexture().length()) { FCDEffectParameter* pEffectParameterSampler = pEffectProfile->AddEffectParameter(FCDEffectParameter::SAMPLER); FCDEffectParameter* pEffectParameterSurface = pEffectProfile->AddEffectParameter(FCDEffectParameter::SURFACE); FCDEffectParameterSampler* pSampler = dynamic_cast<FCDEffectParameterSampler*>(pEffectParameterSampler); FCDEffectParameterSurface* pSurface = dynamic_cast<FCDEffectParameterSurface*>(pEffectParameterSurface); FCDImage* pSurfaceImage = pMatLib->GetDocument()->GetImageLibrary()->AddEntity(); pSurfaceImage->SetFilename(convert_to_fstring(pConversionMaterial->GetDiffuseTexture())); pSurface->SetInitMethod(new FCDEffectParameterSurfaceInitFrom()); pSurface->AddImage(pSurfaceImage); pSurface->SetReference((pConversionMaterial->GetName() + "-surface").c_str()); pSampler->SetSurface(pSurface); } if (m_pWorkListener) m_pWorkListener->WorkProgress(iMaterial); } if (m_pWorkListener) m_pWorkListener->SetAction("Saving geometry", m_pScene->GetNumMeshes()); FCDGeometryLibrary* pGeoLib = pDoc->GetGeometryLibrary(); for (size_t i = 0; i < m_pScene->GetNumMeshes(); ++i) { CConversionMesh* pConversionMesh = m_pScene->GetMesh(i); FCDGeometry* pGeometry = pGeoLib->AddEntity(); pGeometry->SetName(convert_to_fstring(pConversionMesh->GetName())); pGeometry->CreateMesh(); FCDGeometryMesh* pMesh = pGeometry->GetMesh(); FCDGeometrySource* pPositionSource = pMesh->AddSource(FUDaeGeometryInput::POSITION); pPositionSource->SetName(convert_to_fstring(pConversionMesh->GetName() + "-position")); pPositionSource->SetStride(3); pPositionSource->SetValueCount(pConversionMesh->GetNumVertices()); for (size_t j = 0; j < pConversionMesh->GetNumVertices(); j++) pPositionSource->SetValue(j, pConversionMesh->GetVertex(j)); pMesh->AddVertexSource(pPositionSource); FCDGeometrySource* pNormalSource = pMesh->AddSource(FUDaeGeometryInput::NORMAL); pNormalSource->SetName(convert_to_fstring(pConversionMesh->GetName() + "-normal")); pNormalSource->SetStride(3); pNormalSource->SetValueCount(pConversionMesh->GetNumNormals()); for (size_t j = 0; j < pConversionMesh->GetNumNormals(); j++) pNormalSource->SetValue(j, pConversionMesh->GetNormal(j)); FCDGeometrySource* pUVSource = NULL; if (pConversionMesh->GetNumUVs()) { pUVSource = pMesh->AddSource(FUDaeGeometryInput::TEXCOORD); pUVSource->SetName(convert_to_fstring(pConversionMesh->GetName() + "-texcoord")); pUVSource->SetStride(2); pUVSource->SetValueCount(pConversionMesh->GetNumUVs()); for (size_t j = 0; j < pConversionMesh->GetNumUVs(); j++) pUVSource->SetValue(j, pConversionMesh->GetUV(j)); } for (size_t iMaterials = 0; iMaterials < pConversionMesh->GetNumMaterialStubs(); iMaterials++) { CConversionMaterialStub* pStub = pConversionMesh->GetMaterialStub(iMaterials); FCDGeometryPolygons* pPolygons = pMesh->AddPolygons(); pPolygons->SetMaterialSemantic(convert_to_fstring(pStub->GetName())); pPolygons->AddInput(pPositionSource, 0); pPolygons->AddInput(pNormalSource, 1); if (pConversionMesh->GetNumUVs()) pPolygons->AddInput(pUVSource, 2); FCDGeometryPolygonsInput* pPositionInput = pPolygons->FindInput(pPositionSource); FCDGeometryPolygonsInput* pNormalInput = pPolygons->FindInput(pNormalSource); FCDGeometryPolygonsInput* pUVInput = pPolygons->FindInput(pUVSource); for (size_t iFace = 0; iFace < pConversionMesh->GetNumFaces(); iFace++) { CConversionFace* pFace = pConversionMesh->GetFace(iFace); if (pFace->m != iMaterials) continue; pPolygons->AddFaceVertexCount(pFace->GetNumVertices()); for (size_t iVertex = 0; iVertex < pFace->GetNumVertices(); iVertex++) { pPositionInput->AddIndex(pFace->GetVertex(iVertex)->v); pNormalInput->AddIndex(pFace->GetVertex(iVertex)->vn); if (pConversionMesh->GetNumUVs()) pUVInput->AddIndex(pFace->GetVertex(iVertex)->vu); } } } if (m_pWorkListener) m_pWorkListener->WorkProgress(i); } if (m_pWorkListener) m_pWorkListener->SetAction("Saving scenes", m_pScene->GetNumScenes()); FCDVisualSceneNodeLibrary* pVisualScenes = pDoc->GetVisualSceneLibrary(); for (size_t i = 0; i < m_pScene->GetNumScenes(); ++i) { FCDSceneNode* pNode = pVisualScenes->AddEntity(); SaveDAEScene(pNode, m_pScene->GetScene(i)); if (m_pWorkListener) m_pWorkListener->WorkProgress(i); } if (m_pWorkListener) m_pWorkListener->SetAction("Writing to disk...", 0); FCollada::SaveDocument(pDoc, convert_to_fstring(sFilename)); pDoc->Release(); FCollada::Release(); if (m_pWorkListener) m_pWorkListener->EndProgress(); }