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, &parameter->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;
}
Exemple #3
0
	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;
	}
Exemple #4
0
// 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;
}
Exemple #5
0
	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;
	}
Exemple #6
0
	/**
	 * 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");
		}

	}
Exemple #7
0
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;
}
Exemple #8
0
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();
}