コード例 #1
0
ファイル: FCDSceneNodeTools.cpp プロジェクト: Marlinc/0ad
	void ClearSampledAnimation()
	{
		sampleKeys.clear();
		sampleValues.clear();
	}
コード例 #2
0
ファイル: FCDSceneNodeTools.cpp プロジェクト: Marlinc/0ad
	void GenerateSampledAnimation(FCDSceneNode* node)
	{
		sampleKeys.clear();
		sampleValues.clear();

		FCDAnimatedList animateds;
		// Special case for rotation angles: need to check for changes that are greater than 180 degrees.
		Int32List angleIndices;
		
		// Collect all the animation curves
		size_t transformCount = node->GetTransformCount();
		for (size_t t = 0; t < transformCount; ++t)
		{
			FCDTransform* transform = node->GetTransform(t);
			FCDAnimated* animated = transform->GetAnimated();
			if (animated != NULL)
			{
				if (animated->HasCurve()) animateds.push_back(animated);

				// Figure out whether this is a rotation and then, which animated value contains the angle.
				if (!transform->HasType(FCDTRotation::GetClassType())) angleIndices.push_back(-1);
				else angleIndices.push_back((int32) animated->FindQualifier(".ANGLE"));
			}
		}
		if (animateds.empty()) return;

		// Make a list of the ordered key times to sample
		size_t animatedsCount = animateds.size();
		for (size_t i = 0; i < animatedsCount; ++i)
		{
			FCDAnimated* animated = animateds[i];
			int32 angleIndex = angleIndices[i];

			const FCDAnimationCurveListList& allCurves = animated->GetCurves();
			size_t valueCount = allCurves.size();
			for (size_t curveIndex = 0; curveIndex < valueCount; ++curveIndex)
			{
				const FCDAnimationCurveTrackList& curves = allCurves[curveIndex];
				if (curves.empty()) continue;

				size_t curveKeyCount = curves.front()->GetKeyCount();
				const FCDAnimationKey** curveKeys = curves.front()->GetKeys();
				size_t sampleKeyCount = sampleKeys.size();
				
				// Merge this curve's keys in with the sample keys
				// This assumes both key lists are in increasing order
				size_t s = 0, c = 0;
				while (s < sampleKeyCount && c < curveKeyCount)
				{
					float sampleKey = sampleKeys[s], curveKey = curveKeys[c]->input;
					if (IsEquivalent(sampleKey, curveKey)) { ++s; ++c; }
					else if (sampleKey < curveKey) { ++s; }
					else
					{
						// Add this curve key to the sampling key list
						sampleKeys.insert(sampleKeys.begin() + (s++), curveKeys[c++]->input);
						sampleKeyCount++;
					}
				}

				// Add all the left-over curve keys to the sampling key list
				while (c < curveKeyCount) sampleKeys.push_back(curveKeys[c++]->input);

				// Check for large angular rotations..
				if (angleIndex == (intptr_t) curveIndex)
				{
					for (size_t c = 1; c < curveKeyCount; ++c)
					{
						const FCDAnimationKey* previousKey = curveKeys[c - 1];
						const FCDAnimationKey* currentKey = curveKeys[c];
						float halfWrapAmount = (currentKey->output - previousKey->output) / 180.0f;
						halfWrapAmount *= FMath::Sign(halfWrapAmount);
						if (halfWrapAmount >= 1.0f)
						{
							// Need to add sample times.
							size_t addSampleCount = (size_t) floorf(halfWrapAmount);
							for (size_t d = 1; d <= addSampleCount; ++d)
							{
								float fd = (float) d;
								float fid = (float) (addSampleCount + 1 - d);
								float addSampleTime = (currentKey->input * fd + previousKey->input * fid) / (fd + fid);
								
								// Sorted insert.
								float* endIt = sampleKeys.end();
								for (float* sampleKeyTime = sampleKeys.begin(); sampleKeyTime != endIt; ++sampleKeyTime)
								{
									if (IsEquivalent(*sampleKeyTime, addSampleTime)) break;
									else if (*sampleKeyTime > addSampleTime)
									{
										sampleKeys.insert(sampleKeyTime, addSampleTime);
										break;
									}
								}
							}
						}
					}
				}
			}
		}
		size_t sampleKeyCount = sampleKeys.size();
		if (sampleKeyCount == 0) return;

		// Pre-allocate the value array;
		sampleValues.reserve(sampleKeyCount);
		
		// Sample the scene node transform
		for (size_t i = 0; i < sampleKeyCount; ++i)
		{
			float sampleTime = sampleKeys[i];
			for (FCDAnimatedList::iterator it = animateds.begin(); it != animateds.end(); ++it)
			{
				// Sample each animated, which changes the transform values directly
				(*it)->Evaluate(sampleTime);
			}

			// Retrieve the new transform matrix for the COLLADA scene node
			sampleValues.push_back(node->ToMatrix());
		}
	}
コード例 #3
0
ファイル: GeomReindex.cpp プロジェクト: 2asoft/0ad
void ReindexGeometry(FCDGeometryPolygons* polys, FCDSkinController* skin)
{
	// Given geometry with:
	//   positions, normals, texcoords, bone blends
	// each with their own data array and index array, change it to
	// have a single optimised index array shared by all vertexes.

	FCDGeometryPolygonsInput* inputPosition = polys->FindInput(FUDaeGeometryInput::POSITION);
	FCDGeometryPolygonsInput* inputNormal   = polys->FindInput(FUDaeGeometryInput::NORMAL);
	FCDGeometryPolygonsInput* inputTexcoord = polys->FindInput(FUDaeGeometryInput::TEXCOORD);

	size_t numVertices = polys->GetFaceVertexCount();

	assert(inputPosition->GetIndexCount() == numVertices);
	assert(inputNormal  ->GetIndexCount() == numVertices);
	assert(inputTexcoord->GetIndexCount() == numVertices);

	const uint32* indicesPosition = inputPosition->GetIndices();
	const uint32* indicesNormal   = inputNormal->GetIndices();
	const uint32* indicesTexcoord = inputTexcoord->GetIndices();

	assert(indicesPosition);
	assert(indicesNormal);
	assert(indicesTexcoord); // TODO - should be optional, because textureless meshes aren't unreasonable

	FCDGeometrySourceList texcoordSources;
	polys->GetParent()->FindSourcesByType(FUDaeGeometryInput::TEXCOORD, texcoordSources);

	FCDGeometrySource* sourcePosition = inputPosition->GetSource();
	FCDGeometrySource* sourceNormal   = inputNormal  ->GetSource();

	const float* dataPosition = sourcePosition->GetData();
	const float* dataNormal   = sourceNormal  ->GetData();

	if (skin)
	{
#ifndef NDEBUG
		size_t numVertexPositions = sourcePosition->GetDataCount() / sourcePosition->GetStride();
		assert(skin->GetInfluenceCount() == numVertexPositions);
#endif
	}

	uint32 stridePosition = sourcePosition->GetStride();
	uint32 strideNormal   = sourceNormal  ->GetStride();

	std::vector<uint32> indicesCombined;
	std::vector<VertexData> vertexes;
	InserterWithoutDuplicates<VertexData> inserter(vertexes);

	for (size_t i = 0; i < numVertices; ++i)
	{
		std::vector<FCDJointWeightPair> weights;
		if (skin)
		{
			FCDSkinControllerVertex* influences = skin->GetVertexInfluence(indicesPosition[i]);
			assert(influences != NULL);
			for (size_t j = 0; j < influences->GetPairCount(); ++j)
			{
				FCDJointWeightPair* pair = influences->GetPair(j);
				assert(pair != NULL);
				weights.push_back(*pair);
			}
			CanonicaliseWeights(weights);
		}

		std::vector<uv_pair_type> uvs;
		for (size_t set = 0; set < texcoordSources.size(); ++set)
		{
			const float* dataTexcoord = texcoordSources[set]->GetData();
			uint32 strideTexcoord = texcoordSources[set]->GetStride();

			uv_pair_type p;
			p.first = dataTexcoord[indicesTexcoord[i]*strideTexcoord];
			p.second = dataTexcoord[indicesTexcoord[i]*strideTexcoord + 1];
			uvs.push_back(p);
		}

		VertexData vtx (
			&dataPosition[indicesPosition[i]*stridePosition],
			&dataNormal  [indicesNormal  [i]*strideNormal],
			uvs,
			weights
		);
		size_t idx = inserter.add(vtx);
		indicesCombined.push_back((uint32)idx);
	}

	// TODO: rearrange indicesCombined (and rearrange vertexes to match) to use
	// the vertex cache efficiently
	// (<http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html> etc)

	FloatList newDataPosition;
	FloatList newDataNormal;
	FloatList newDataTexcoord;
	std::vector<std::vector<FCDJointWeightPair> > newWeightedMatches;

	for (size_t i = 0; i < vertexes.size(); ++i)
	{
		newDataPosition.push_back(vertexes[i].x);
		newDataPosition.push_back(vertexes[i].y);
		newDataPosition.push_back(vertexes[i].z);
		newDataNormal  .push_back(vertexes[i].nx);
		newDataNormal  .push_back(vertexes[i].ny);
		newDataNormal  .push_back(vertexes[i].nz);
		newWeightedMatches.push_back(vertexes[i].weights);
	}

	// (Slightly wasteful to duplicate this array so many times, but FCollada
	// doesn't seem to support multiple inputs with the same source data)
	inputPosition->SetIndices(&indicesCombined.front(), indicesCombined.size());
	inputNormal  ->SetIndices(&indicesCombined.front(), indicesCombined.size());
	inputTexcoord->SetIndices(&indicesCombined.front(), indicesCombined.size());

	for (size_t set = 0; set < texcoordSources.size(); ++set)
	{
		newDataTexcoord.clear();
		for (size_t i = 0; i < vertexes.size(); ++i)
		{
			newDataTexcoord.push_back(vertexes[i].uvs[set].first);
			newDataTexcoord.push_back(vertexes[i].uvs[set].second);
		}
		texcoordSources[set]->SetData(newDataTexcoord, 2);
	}

	sourcePosition->SetData(newDataPosition, 3);
	sourceNormal  ->SetData(newDataNormal,   3);

	if (skin)
	{
		skin->SetInfluenceCount(newWeightedMatches.size());
		for (size_t i = 0; i < newWeightedMatches.size(); ++i)
		{
			skin->GetVertexInfluence(i)->SetPairCount(0);
			for (size_t j = 0; j < newWeightedMatches[i].size(); ++j)
				skin->GetVertexInfluence(i)->AddPair(newWeightedMatches[i][j].jointIndex, newWeightedMatches[i][j].weight);
		}
	}
}