2009-07-08 22:01:15 +00:00
|
|
|
/*
|
|
|
|
* OpenClonk, http://www.openclonk.org
|
|
|
|
*
|
2011-09-01 14:58:52 +00:00
|
|
|
* Copyright (c) 2009-2011 Armin Burgmeier
|
2010-12-23 00:01:24 +00:00
|
|
|
* Copyright (c) 2009 Mark Haßelbusch
|
|
|
|
* Copyright (c) 2010 Nicolas Hake
|
2009-07-08 22:01:15 +00:00
|
|
|
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
|
|
|
|
*
|
|
|
|
* Portions might be copyrighted by other authors who have contributed
|
|
|
|
* to OpenClonk.
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
* See isc_license.txt for full license and disclaimer.
|
|
|
|
*
|
|
|
|
* "Clonk" is a registered trademark of Matthes Bender.
|
|
|
|
* See clonk_trademark_license.txt for full license.
|
|
|
|
*/
|
|
|
|
|
2010-01-04 02:15:50 +00:00
|
|
|
#include "C4Include.h"
|
2009-07-08 22:01:15 +00:00
|
|
|
#include <StdMesh.h>
|
|
|
|
|
2009-07-28 11:58:19 +00:00
|
|
|
#ifdef _MSC_VER
|
2010-03-28 18:58:01 +00:00
|
|
|
# define _USE_MATH_DEFINES
|
|
|
|
# include <math.h>
|
2009-07-28 11:58:19 +00:00
|
|
|
#endif
|
|
|
|
|
2009-07-23 23:52:18 +00:00
|
|
|
#include <algorithm>
|
|
|
|
|
2010-04-01 21:00:05 +00:00
|
|
|
std::vector<StdMeshInstance::SerializableValueProvider::IDBase*>* StdMeshInstance::SerializableValueProvider::IDs = NULL;
|
|
|
|
|
2009-07-12 14:27:04 +00:00
|
|
|
namespace
|
|
|
|
{
|
2010-12-04 22:33:05 +00:00
|
|
|
// Helper to sort submeshes so that opaque ones appear before non-opaque ones
|
|
|
|
struct StdMeshSubMeshVisibilityCmpPred
|
|
|
|
{
|
|
|
|
bool operator()(const StdSubMesh& first, const StdSubMesh& second)
|
|
|
|
{
|
|
|
|
return first.GetMaterial().IsOpaque() > second.GetMaterial().IsOpaque();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-08-01 19:36:13 +00:00
|
|
|
// Helper to sort faces for FaceOrdering
|
|
|
|
struct StdMeshInstanceFaceOrderingCmpPred
|
|
|
|
{
|
|
|
|
const StdMeshInstance& m_inst;
|
2010-01-11 23:54:36 +00:00
|
|
|
const StdMeshVertex* m_vertices;
|
2010-06-08 22:55:34 +00:00
|
|
|
const StdMeshMatrix& m_global_trans;
|
2010-01-11 23:54:36 +00:00
|
|
|
|
2010-06-08 22:55:34 +00:00
|
|
|
StdMeshInstanceFaceOrderingCmpPred(const StdMeshInstance& inst, unsigned int submesh, const StdMeshMatrix& global_trans):
|
|
|
|
m_inst(inst), m_vertices(m_inst.GetSubMesh(submesh).GetVertices()), m_global_trans(global_trans) {}
|
2009-08-01 19:36:13 +00:00
|
|
|
|
2010-08-14 10:38:15 +00:00
|
|
|
inline float get_z(const StdMeshVertex& vtx) const
|
|
|
|
{
|
|
|
|
// We need to evaluate the Z coordinate of the transformed vertex
|
|
|
|
// (for all three vertices of the two faces), something like
|
|
|
|
// float z11 = (m_global_trans*m_vertices[face1.Vertices[0]]).z;
|
|
|
|
// However we don't do the full matrix multiplication as we are
|
|
|
|
// only interested in the Z coordinate of the result, also we are
|
|
|
|
// not interested in the resulting normals.
|
|
|
|
return m_global_trans(2,0)*vtx.x + m_global_trans(2,1)*vtx.y + m_global_trans(2,2)*vtx.z + m_global_trans(2,3);
|
|
|
|
}
|
|
|
|
|
2010-01-01 14:26:54 +00:00
|
|
|
bool operator()(const StdMeshFace& face1, const StdMeshFace& face2) const
|
2009-08-01 19:36:13 +00:00
|
|
|
{
|
2010-01-10 21:02:40 +00:00
|
|
|
// TODO: Need to apply attach matrix in case of attached meshes
|
2010-03-28 18:58:01 +00:00
|
|
|
switch (m_inst.GetFaceOrdering())
|
2009-08-01 19:36:13 +00:00
|
|
|
{
|
|
|
|
case StdMeshInstance::FO_Fixed:
|
2010-01-01 14:26:54 +00:00
|
|
|
assert(false);
|
|
|
|
return false;
|
2009-08-01 19:36:13 +00:00
|
|
|
case StdMeshInstance::FO_FarthestToNearest:
|
|
|
|
case StdMeshInstance::FO_NearestToFarthest:
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-08-14 10:38:15 +00:00
|
|
|
float z11 = get_z(m_vertices[face1.Vertices[0]]);
|
|
|
|
float z12 = get_z(m_vertices[face1.Vertices[1]]);
|
|
|
|
float z13 = get_z(m_vertices[face1.Vertices[2]]);
|
|
|
|
float z21 = get_z(m_vertices[face2.Vertices[0]]);
|
|
|
|
float z22 = get_z(m_vertices[face2.Vertices[1]]);
|
|
|
|
float z23 = get_z(m_vertices[face2.Vertices[2]]);
|
2010-06-26 19:20:10 +00:00
|
|
|
|
|
|
|
float z1 = std::max(std::max(z11, z12), z13);
|
|
|
|
float z2 = std::max(std::max(z21, z22), z23);
|
2010-06-08 22:55:34 +00:00
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
if (m_inst.GetFaceOrdering() == StdMeshInstance::FO_FarthestToNearest)
|
|
|
|
return z1 < z2;
|
|
|
|
else
|
|
|
|
return z2 < z1;
|
|
|
|
}
|
2009-08-01 19:36:13 +00:00
|
|
|
default:
|
|
|
|
assert(false);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2010-04-01 21:00:05 +00:00
|
|
|
// Seralize a ValueProvider with StdCompiler
|
|
|
|
struct ValueProviderAdapt
|
|
|
|
{
|
|
|
|
ValueProviderAdapt(StdMeshInstance::ValueProvider** Provider):
|
|
|
|
ValueProvider(Provider) {}
|
|
|
|
|
|
|
|
StdMeshInstance::ValueProvider** ValueProvider;
|
|
|
|
|
|
|
|
void CompileFunc(StdCompiler* pComp)
|
|
|
|
{
|
|
|
|
const StdMeshInstance::SerializableValueProvider::IDBase* id;
|
|
|
|
StdMeshInstance::SerializableValueProvider* svp = NULL;
|
|
|
|
|
|
|
|
if(pComp->isCompiler())
|
|
|
|
{
|
|
|
|
StdCopyStrBuf id_str;
|
|
|
|
pComp->Value(mkParAdapt(id_str, StdCompiler::RCT_Idtf));
|
|
|
|
|
|
|
|
id = StdMeshInstance::SerializableValueProvider::Lookup(id_str.getData());
|
|
|
|
if(!id) pComp->excCorrupt("No value provider for ID \"%s\"", id_str.getData());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
svp = dynamic_cast<StdMeshInstance::SerializableValueProvider*>(*ValueProvider);
|
|
|
|
if(!svp) pComp->excCorrupt("Value provider cannot be compiled");
|
|
|
|
id = StdMeshInstance::SerializableValueProvider::Lookup(typeid(*svp));
|
|
|
|
if(!id) pComp->excCorrupt("No ID for value provider registered");
|
|
|
|
|
|
|
|
StdCopyStrBuf id_str(id->name);
|
|
|
|
pComp->Value(mkParAdapt(id_str, StdCompiler::RCT_Idtf));
|
|
|
|
}
|
|
|
|
|
2010-04-01 21:08:06 +00:00
|
|
|
pComp->Separator(StdCompiler::SEP_START);
|
2010-04-01 21:00:05 +00:00
|
|
|
pComp->Value(mkContextPtrAdapt(svp, *id, false));
|
2010-04-01 21:08:06 +00:00
|
|
|
pComp->Separator(StdCompiler::SEP_END);
|
2010-04-01 21:00:05 +00:00
|
|
|
|
|
|
|
if(pComp->isCompiler())
|
|
|
|
*ValueProvider = svp;
|
|
|
|
}
|
2010-04-03 10:44:59 +00:00
|
|
|
|
|
|
|
ALLOW_TEMP_TO_REF(ValueProviderAdapt)
|
2010-04-01 21:00:05 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
ValueProviderAdapt mkValueProviderAdapt(StdMeshInstance::ValueProvider** ValueProvider) { return ValueProviderAdapt(ValueProvider); }
|
|
|
|
|
|
|
|
// Serialize a bone index by name with StdCompiler
|
|
|
|
struct TransformAdapt
|
|
|
|
{
|
|
|
|
StdMeshMatrix& Matrix;
|
|
|
|
TransformAdapt(StdMeshMatrix& matrix): Matrix(matrix) {}
|
|
|
|
|
|
|
|
void CompileFunc(StdCompiler* pComp)
|
|
|
|
{
|
2010-04-01 21:08:06 +00:00
|
|
|
pComp->Separator(StdCompiler::SEP_START);
|
2010-04-01 21:00:05 +00:00
|
|
|
for(unsigned int i = 0; i < 3; ++i)
|
|
|
|
{
|
|
|
|
for(unsigned int j = 0; j < 4; ++j)
|
|
|
|
{
|
2010-04-01 21:08:06 +00:00
|
|
|
if(i != 0 || j != 0) pComp->Separator();
|
2010-04-01 21:00:05 +00:00
|
|
|
// TODO: Teach StdCompiler how to handle float
|
|
|
|
// pComp->Value(Matrix(i, j));
|
|
|
|
|
|
|
|
if(pComp->isCompiler())
|
|
|
|
{
|
2010-05-04 15:35:18 +00:00
|
|
|
C4Real f;
|
2010-04-01 21:00:05 +00:00
|
|
|
pComp->Value(f);
|
|
|
|
Matrix(i,j) = fixtof(f);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-05-04 15:35:18 +00:00
|
|
|
C4Real f = ftofix(Matrix(i,j));
|
2010-04-01 21:00:05 +00:00
|
|
|
pComp->Value(f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-01 21:08:06 +00:00
|
|
|
pComp->Separator(StdCompiler::SEP_END);
|
2010-04-01 21:00:05 +00:00
|
|
|
}
|
2010-04-03 10:44:59 +00:00
|
|
|
|
|
|
|
ALLOW_TEMP_TO_REF(TransformAdapt)
|
2010-04-01 21:00:05 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
TransformAdapt mkTransformAdapt(StdMeshMatrix& Matrix) { return TransformAdapt(Matrix); }
|
|
|
|
|
2010-01-22 18:27:02 +00:00
|
|
|
// Reset all animation list entries corresponding to node or its children
|
|
|
|
void ClearAnimationListRecursively(std::vector<StdMeshInstance::AnimationNode*>& list, StdMeshInstance::AnimationNode* node)
|
|
|
|
{
|
|
|
|
list[node->GetNumber()] = NULL;
|
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
if (node->GetType() == StdMeshInstance::AnimationNode::LinearInterpolationNode)
|
2010-01-22 18:27:02 +00:00
|
|
|
{
|
|
|
|
ClearAnimationListRecursively(list, node->GetLeftChild());
|
|
|
|
ClearAnimationListRecursively(list, node->GetRightChild());
|
|
|
|
}
|
|
|
|
}
|
2010-09-09 20:40:07 +00:00
|
|
|
|
|
|
|
// Mirror is wrt X axis
|
2010-09-13 22:18:25 +00:00
|
|
|
void MirrorKeyFrame(StdMeshKeyFrame& frame, const StdMeshTransformation& old_bone_transformation, const StdMeshTransformation& new_inverse_bone_transformation)
|
2010-09-09 20:40:07 +00:00
|
|
|
{
|
|
|
|
// frame was a keyframe of a track for old_bone and was now transplanted to new_bone.
|
|
|
|
|
2010-09-13 22:18:25 +00:00
|
|
|
//frame.Transformation.rotate.x = -frame.Transformation.rotate.x;
|
2010-09-09 20:40:07 +00:00
|
|
|
frame.Transformation.rotate.y = -frame.Transformation.rotate.y;
|
|
|
|
frame.Transformation.rotate.z = -frame.Transformation.rotate.z;
|
|
|
|
|
|
|
|
// We might also want to do something like this... need to get feedback
|
|
|
|
// from modelers...
|
2010-09-13 22:18:25 +00:00
|
|
|
#if 0
|
|
|
|
StdMeshVector d = old_bone_transformation.scale * (old_bone_transformation.rotate * frame.Transformation.translate);
|
2010-09-09 20:40:07 +00:00
|
|
|
//d.x = -d.x;
|
2010-09-13 22:18:25 +00:00
|
|
|
frame.Transformation.translate = new_inverse_bone_transformation.rotate * (new_inverse_bone_transformation.scale * d);
|
|
|
|
#endif
|
2010-09-09 20:40:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool MirrorName(StdStrBuf& buf)
|
|
|
|
{
|
|
|
|
unsigned int len = buf.getLength();
|
|
|
|
|
|
|
|
if(buf.Compare_(".R", len-2) == 0)
|
|
|
|
buf.getMData()[len-1] = 'L';
|
|
|
|
else if(buf.Compare_(".L", len-2) == 0)
|
|
|
|
buf.getMData()[len-1] = 'R';
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2009-07-12 14:27:04 +00:00
|
|
|
}
|
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
/* Boring Math stuff begins here */
|
|
|
|
|
2010-01-05 21:35:30 +00:00
|
|
|
StdMeshVector StdMeshVector::Zero()
|
|
|
|
{
|
|
|
|
StdMeshVector v;
|
|
|
|
v.x = 0.0f;
|
|
|
|
v.y = 0.0f;
|
|
|
|
v.z = 0.0f;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshVector StdMeshVector::UnitScale()
|
|
|
|
{
|
|
|
|
StdMeshVector v;
|
|
|
|
v.x = 1.0f;
|
|
|
|
v.y = 1.0f;
|
|
|
|
v.z = 1.0f;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshVector StdMeshVector::Translate(float dx, float dy, float dz)
|
|
|
|
{
|
|
|
|
StdMeshVector v;
|
|
|
|
v.x = dx;
|
|
|
|
v.y = dy;
|
|
|
|
v.z = dz;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshVector StdMeshVector::Cross(const StdMeshVector& lhs, const StdMeshVector& rhs)
|
2009-07-08 22:01:15 +00:00
|
|
|
{
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshVector v;
|
|
|
|
v.x = lhs.y*rhs.z - lhs.z*rhs.y;
|
|
|
|
v.y = lhs.z*rhs.x - lhs.x*rhs.z;
|
|
|
|
v.z = lhs.x*rhs.y - lhs.y*rhs.x;
|
|
|
|
return v;
|
2009-07-08 22:01:15 +00:00
|
|
|
}
|
|
|
|
|
2010-01-05 21:35:30 +00:00
|
|
|
StdMeshQuaternion StdMeshQuaternion::Zero()
|
|
|
|
{
|
|
|
|
StdMeshQuaternion q;
|
|
|
|
q.w = 0.0f;
|
|
|
|
q.x = 0.0f;
|
|
|
|
q.y = 0.0f;
|
|
|
|
q.z = 0.0f;
|
|
|
|
return q;
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshQuaternion StdMeshQuaternion::AngleAxis(float theta, const StdMeshVector& axis)
|
|
|
|
{
|
|
|
|
StdMeshQuaternion q;
|
|
|
|
const float theta2 = theta/2.0f;
|
|
|
|
const float s = sin(theta2);
|
|
|
|
q.w = cos(theta2);
|
|
|
|
q.x = s*axis.x;
|
|
|
|
q.y = s*axis.y;
|
|
|
|
q.z = s*axis.z;
|
|
|
|
return q;
|
|
|
|
}
|
|
|
|
|
|
|
|
void StdMeshQuaternion::Normalize()
|
|
|
|
{
|
|
|
|
float length = sqrt(LenSqr());
|
|
|
|
w /= length;
|
|
|
|
x /= length;
|
|
|
|
y /= length;
|
|
|
|
z /= length;
|
|
|
|
}
|
|
|
|
|
2010-01-22 18:27:02 +00:00
|
|
|
StdMeshQuaternion StdMeshQuaternion::Nlerp(const StdMeshQuaternion& lhs, const StdMeshQuaternion& rhs, float w)
|
|
|
|
{
|
|
|
|
StdMeshQuaternion q;
|
|
|
|
float c = lhs.w * rhs.w + lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
|
2010-03-28 18:58:01 +00:00
|
|
|
if (c < 0.0f)
|
2010-01-22 18:27:02 +00:00
|
|
|
q = lhs + w * (-rhs - lhs);
|
|
|
|
else
|
|
|
|
q = lhs + w * ( rhs - lhs);
|
|
|
|
q.Normalize();
|
|
|
|
return q;
|
|
|
|
}
|
|
|
|
|
2010-01-05 21:35:30 +00:00
|
|
|
StdMeshTransformation StdMeshTransformation::Zero()
|
|
|
|
{
|
|
|
|
StdMeshTransformation t;
|
|
|
|
t.scale = StdMeshVector::Zero();
|
|
|
|
t.rotate = StdMeshQuaternion::Zero();
|
2010-03-28 18:58:01 +00:00
|
|
|
t.translate = StdMeshVector::Zero();
|
2010-01-05 21:35:30 +00:00
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshTransformation StdMeshTransformation::Identity()
|
|
|
|
{
|
|
|
|
StdMeshTransformation t;
|
|
|
|
t.scale = StdMeshVector::UnitScale();
|
|
|
|
t.rotate.w = 1.0f;
|
|
|
|
t.rotate.x = t.rotate.y = t.rotate.z = 0.0f;
|
2010-03-28 18:58:01 +00:00
|
|
|
t.translate = StdMeshVector::Zero();
|
2010-01-05 21:35:30 +00:00
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshTransformation StdMeshTransformation::Inverse(const StdMeshTransformation& transform)
|
|
|
|
{
|
2010-01-22 18:27:02 +00:00
|
|
|
StdMeshTransformation t;
|
|
|
|
t.scale = 1.0f/transform.scale;
|
2010-01-26 16:17:43 +00:00
|
|
|
t.rotate.w = transform.rotate.w;
|
|
|
|
//t.rotate.v = -transform.rotate.v; // Someone set us up the union!?!??
|
|
|
|
t.rotate.x = -transform.rotate.x;
|
|
|
|
t.rotate.y = -transform.rotate.y;
|
|
|
|
t.rotate.z = -transform.rotate.z;
|
2010-01-22 18:27:02 +00:00
|
|
|
t.translate = t.rotate * (t.scale * -transform.translate);
|
|
|
|
return t;
|
2010-01-05 21:35:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshTransformation StdMeshTransformation::Translate(float dx, float dy, float dz)
|
|
|
|
{
|
|
|
|
StdMeshTransformation t;
|
|
|
|
t.scale = StdMeshVector::UnitScale();
|
|
|
|
t.rotate.w = 1.0f;
|
|
|
|
t.rotate.x = t.rotate.y = t.rotate.z = 0.0f;
|
2010-03-28 18:58:01 +00:00
|
|
|
t.translate = StdMeshVector::Translate(dx, dy, dz);
|
2010-01-05 21:35:30 +00:00
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshTransformation StdMeshTransformation::Scale(float sx, float sy, float sz)
|
|
|
|
{
|
|
|
|
StdMeshTransformation t;
|
|
|
|
t.scale = StdMeshVector::Translate(sx, sy, sz);
|
|
|
|
t.rotate.w = 1.0f;
|
|
|
|
t.rotate.x = t.rotate.y = t.rotate.z = 0.0f;
|
2010-03-28 18:58:01 +00:00
|
|
|
t.translate = StdMeshVector::Zero();
|
2010-01-05 21:35:30 +00:00
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshTransformation StdMeshTransformation::Rotate(float angle, float rx, float ry, float rz)
|
|
|
|
{
|
|
|
|
StdMeshTransformation t;
|
|
|
|
t.scale = StdMeshVector::UnitScale();
|
|
|
|
t.rotate = StdMeshQuaternion::AngleAxis(angle, StdMeshVector::Translate(rx, ry, rz));
|
2010-03-28 18:58:01 +00:00
|
|
|
t.translate = StdMeshVector::Zero();
|
2010-01-05 21:35:30 +00:00
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
2010-01-22 18:27:02 +00:00
|
|
|
StdMeshTransformation StdMeshTransformation::Nlerp(const StdMeshTransformation& lhs, const StdMeshTransformation& rhs, float w)
|
|
|
|
{
|
|
|
|
StdMeshTransformation t;
|
|
|
|
t.translate = (1 - w) * lhs.translate + w * rhs.translate;
|
|
|
|
t.rotate = StdMeshQuaternion::Nlerp(lhs.rotate, rhs.rotate, w);
|
|
|
|
t.scale = (1 - w) * lhs.scale + w * rhs.scale;
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshMatrix StdMeshMatrix::Zero()
|
2009-12-31 17:18:58 +00:00
|
|
|
{
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshMatrix m;
|
|
|
|
m.a[0][0] = 0.0f; m.a[0][1] = 0.0f; m.a[0][2] = 0.0f; m.a[0][3] = 0.0f;
|
|
|
|
m.a[1][0] = 0.0f; m.a[1][1] = 0.0f; m.a[1][2] = 0.0f; m.a[1][3] = 0.0f;
|
|
|
|
m.a[2][0] = 0.0f; m.a[2][1] = 0.0f; m.a[2][2] = 0.0f; m.a[2][3] = 0.0f;
|
|
|
|
return m;
|
|
|
|
}
|
2009-12-31 17:18:58 +00:00
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshMatrix StdMeshMatrix::Identity()
|
|
|
|
{
|
|
|
|
StdMeshMatrix m;
|
|
|
|
m.a[0][0] = 1.0f; m.a[0][1] = 0.0f; m.a[0][2] = 0.0f; m.a[0][3] = 0.0f;
|
|
|
|
m.a[1][0] = 0.0f; m.a[1][1] = 1.0f; m.a[1][2] = 0.0f; m.a[1][3] = 0.0f;
|
|
|
|
m.a[2][0] = 0.0f; m.a[2][1] = 0.0f; m.a[2][2] = 1.0f; m.a[2][3] = 0.0f;
|
|
|
|
return m;
|
|
|
|
}
|
2009-12-31 17:18:58 +00:00
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshMatrix StdMeshMatrix::Inverse(const StdMeshMatrix& mat)
|
|
|
|
{
|
|
|
|
StdMeshMatrix m;
|
2009-12-31 17:18:58 +00:00
|
|
|
|
2010-01-29 14:58:33 +00:00
|
|
|
const float det = mat.Determinant();
|
2010-01-05 16:20:46 +00:00
|
|
|
assert(det != 0.0f);
|
2009-12-31 17:18:58 +00:00
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
m.a[0][0] = (mat.a[1][1]*mat.a[2][2] - mat.a[1][2]*mat.a[2][1]) / det;
|
|
|
|
m.a[1][0] = (mat.a[1][2]*mat.a[2][0] - mat.a[1][0]*mat.a[2][2]) / det;
|
|
|
|
m.a[2][0] = (mat.a[1][0]*mat.a[2][1] - mat.a[1][1]*mat.a[2][0]) / det;
|
|
|
|
|
|
|
|
m.a[0][1] = (mat.a[0][2]*mat.a[2][1] - mat.a[0][1]*mat.a[2][2]) / det;
|
|
|
|
m.a[1][1] = (mat.a[0][0]*mat.a[2][2] - mat.a[0][2]*mat.a[2][0]) / det;
|
|
|
|
m.a[2][1] = (mat.a[0][1]*mat.a[2][0] - mat.a[0][0]*mat.a[2][1]) / det;
|
|
|
|
|
|
|
|
m.a[0][2] = (mat.a[0][1]*mat.a[1][2] - mat.a[0][2]*mat.a[1][1]) / det;
|
|
|
|
m.a[1][2] = (mat.a[0][2]*mat.a[1][0] - mat.a[0][0]*mat.a[1][2]) / det;
|
|
|
|
m.a[2][2] = (mat.a[0][0]*mat.a[1][1] - mat.a[0][1]*mat.a[1][0]) / det;
|
|
|
|
|
|
|
|
m.a[0][3] = (mat.a[0][1]*mat.a[1][3]*mat.a[2][2]
|
2010-03-28 18:58:01 +00:00
|
|
|
+ mat.a[0][2]*mat.a[1][1]*mat.a[2][3]
|
|
|
|
+ mat.a[0][3]*mat.a[1][2]*mat.a[2][1]
|
|
|
|
- mat.a[0][1]*mat.a[1][2]*mat.a[2][3]
|
|
|
|
- mat.a[0][2]*mat.a[1][3]*mat.a[2][1]
|
|
|
|
- mat.a[0][3]*mat.a[1][1]*mat.a[2][2]) / det;
|
2010-01-05 16:20:46 +00:00
|
|
|
|
|
|
|
m.a[1][3] = (mat.a[0][0]*mat.a[1][2]*mat.a[2][3]
|
2010-03-28 18:58:01 +00:00
|
|
|
+ mat.a[0][2]*mat.a[1][3]*mat.a[2][0]
|
|
|
|
+ mat.a[0][3]*mat.a[1][0]*mat.a[2][2]
|
|
|
|
- mat.a[0][0]*mat.a[1][3]*mat.a[2][2]
|
|
|
|
- mat.a[0][2]*mat.a[1][0]*mat.a[2][3]
|
|
|
|
- mat.a[0][3]*mat.a[1][2]*mat.a[2][0]) / det;
|
2010-01-05 16:20:46 +00:00
|
|
|
|
|
|
|
m.a[2][3] = (mat.a[0][0]*mat.a[1][3]*mat.a[2][1]
|
2010-03-28 18:58:01 +00:00
|
|
|
+ mat.a[0][1]*mat.a[1][0]*mat.a[2][3]
|
|
|
|
+ mat.a[0][3]*mat.a[1][1]*mat.a[2][0]
|
|
|
|
- mat.a[0][0]*mat.a[1][1]*mat.a[2][3]
|
|
|
|
- mat.a[0][1]*mat.a[1][3]*mat.a[2][0]
|
|
|
|
- mat.a[0][3]*mat.a[1][0]*mat.a[2][1]) / det;
|
2010-01-05 16:20:46 +00:00
|
|
|
|
|
|
|
return m;
|
2009-12-31 17:18:58 +00:00
|
|
|
}
|
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshMatrix StdMeshMatrix::Translate(float dx, float dy, float dz)
|
2009-07-08 22:01:15 +00:00
|
|
|
{
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshMatrix m;
|
|
|
|
m.a[0][0] = 1.0f; m.a[0][1] = 0.0f; m.a[0][2] = 0.0f; m.a[0][3] = dx;
|
|
|
|
m.a[1][0] = 0.0f; m.a[1][1] = 1.0f; m.a[1][2] = 0.0f; m.a[1][3] = dy;
|
|
|
|
m.a[2][0] = 0.0f; m.a[2][1] = 0.0f; m.a[2][2] = 1.0f; m.a[2][3] = dz;
|
|
|
|
return m;
|
2009-07-08 22:01:15 +00:00
|
|
|
}
|
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshMatrix StdMeshMatrix::Scale(float sx, float sy, float sz)
|
2009-07-08 22:01:15 +00:00
|
|
|
{
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshMatrix m;
|
|
|
|
m.a[0][0] = sx; m.a[0][1] = 0.0f; m.a[0][2] = 0.0f; m.a[0][3] = 0.0f;
|
|
|
|
m.a[1][0] = 0.0f; m.a[1][1] = sy; m.a[1][2] = 0.0f; m.a[1][3] = 0.0f;
|
|
|
|
m.a[2][0] = 0.0f; m.a[2][1] = 0.0f; m.a[2][2] = sz; m.a[2][3] = 0.0f;
|
|
|
|
return m;
|
2009-07-08 22:01:15 +00:00
|
|
|
}
|
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshMatrix StdMeshMatrix::Rotate(float angle, float rx, float ry, float rz)
|
2009-07-08 22:01:15 +00:00
|
|
|
{
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshMatrix m;
|
|
|
|
|
2009-08-01 19:36:13 +00:00
|
|
|
// We do normalize the rx,ry,rz vector here: This is only required for
|
|
|
|
// precalculations anyway, thus not time-critical.
|
|
|
|
float abs = sqrt(rx*rx+ry*ry+rz*rz);
|
|
|
|
rx/=abs; ry/=abs; rz/=abs;
|
|
|
|
float c = cos(angle), s = sin(angle);
|
2009-07-08 22:01:15 +00:00
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
m.a[0][0] = rx*rx*(1-c)+c; m.a[0][1] = rx*ry*(1-c)-rz*s; m.a[0][2] = rx*rz*(1-c)+ry*s; m.a[0][3] = 0.0f;
|
|
|
|
m.a[1][0] = ry*rx*(1-c)+rz*s; m.a[1][1] = ry*ry*(1-c)+c; m.a[1][2] = ry*rz*(1-c)-rx*s; m.a[1][3] = 0.0f;
|
|
|
|
m.a[2][0] = rz*rx*(1-c)-ry*s; m.a[2][1] = ry*rz*(1-c)+rx*s; m.a[2][2] = rz*rz*(1-c)+c; m.a[2][3] = 0.0f;
|
2010-01-05 16:20:46 +00:00
|
|
|
return m;
|
2009-07-08 22:01:15 +00:00
|
|
|
}
|
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshMatrix StdMeshMatrix::Transform(const StdMeshTransformation& transform)
|
2009-07-08 22:01:15 +00:00
|
|
|
{
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshMatrix m;
|
|
|
|
|
|
|
|
float tx = 2*transform.rotate.x;
|
|
|
|
float ty = 2*transform.rotate.y;
|
|
|
|
float tz = 2*transform.rotate.z;
|
|
|
|
float twx = tx*transform.rotate.w;
|
|
|
|
float twy = ty*transform.rotate.w;
|
|
|
|
float twz = tz*transform.rotate.w;
|
|
|
|
float txx = tx*transform.rotate.x;
|
|
|
|
float txy = ty*transform.rotate.x;
|
|
|
|
float txz = tz*transform.rotate.x;
|
|
|
|
float tyy = ty*transform.rotate.y;
|
|
|
|
float tyz = tz*transform.rotate.y;
|
|
|
|
float tzz = tz*transform.rotate.z;
|
2010-03-28 18:58:01 +00:00
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
m.a[0][0] = (1.0f - (tyy + tzz) ) * transform.scale.x;
|
|
|
|
m.a[0][1] = (txy - twz) * transform.scale.y;
|
|
|
|
m.a[0][2] = (txz + twy) * transform.scale.z;
|
|
|
|
m.a[1][0] = (txy + twz) * transform.scale.x;
|
|
|
|
m.a[1][1] = (1.0f - (txx + tzz) ) * transform.scale.y;
|
|
|
|
m.a[1][2] = (tyz - twx) * transform.scale.z;
|
|
|
|
m.a[2][0] = (txz - twy) * transform.scale.x;
|
|
|
|
m.a[2][1] = (tyz + twx) * transform.scale.y;
|
|
|
|
m.a[2][2] = (1.0f - (txx + tyy) ) * transform.scale.z;
|
2010-03-28 18:58:01 +00:00
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
m.a[0][3] = transform.translate.x;
|
|
|
|
m.a[1][3] = transform.translate.y;
|
|
|
|
m.a[2][3] = transform.translate.z;
|
2010-03-28 18:58:01 +00:00
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshMatrix StdMeshMatrix::TransformInverse(const StdMeshTransformation& transform)
|
|
|
|
{
|
|
|
|
StdMeshMatrix m;
|
|
|
|
|
|
|
|
float tx = 2*transform.rotate.x;
|
|
|
|
float ty = 2*transform.rotate.y;
|
|
|
|
float tz = 2*transform.rotate.z;
|
|
|
|
float twx = -tx*transform.rotate.w;
|
|
|
|
float twy = -ty*transform.rotate.w;
|
|
|
|
float twz = -tz*transform.rotate.w;
|
|
|
|
float txx = tx*transform.rotate.x;
|
|
|
|
float txy = ty*transform.rotate.x;
|
|
|
|
float txz = tz*transform.rotate.x;
|
|
|
|
float tyy = ty*transform.rotate.y;
|
|
|
|
float tyz = tz*transform.rotate.y;
|
|
|
|
float tzz = tz*transform.rotate.z;
|
|
|
|
|
|
|
|
m.a[0][0] = (1.0f - (tyy + tzz) ) / transform.scale.x;
|
|
|
|
m.a[0][1] = (txy - twz) / transform.scale.x;
|
|
|
|
m.a[0][2] = (txz + twy) / transform.scale.x;
|
|
|
|
m.a[1][0] = (txy + twz) / transform.scale.y;
|
|
|
|
m.a[1][1] = (1.0f - (txx + tzz) ) / transform.scale.y;
|
|
|
|
m.a[1][2] = (tyz - twx) / transform.scale.y;
|
|
|
|
m.a[2][0] = (txz - twy) / transform.scale.z;
|
|
|
|
m.a[2][1] = (tyz + twx) / transform.scale.z;
|
|
|
|
m.a[2][2] = (1.0f - (txx + tyy) ) / transform.scale.z;
|
|
|
|
|
|
|
|
// Signs do not cancel!
|
|
|
|
StdMeshVector invtranslate = (-transform.rotate) * (-transform.translate/transform.scale);
|
|
|
|
|
|
|
|
m.a[0][3] = invtranslate.x;
|
|
|
|
m.a[1][3] = invtranslate.y;
|
|
|
|
m.a[2][3] = invtranslate.z;
|
2010-03-28 18:58:01 +00:00
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
2010-01-29 14:58:33 +00:00
|
|
|
float StdMeshMatrix::Determinant() const
|
|
|
|
{
|
|
|
|
return a[0][0]*a[1][1]*a[2][2] + a[0][1]*a[1][2]*a[2][0] + a[0][2]*a[1][0]*a[2][1]
|
2010-03-28 18:58:01 +00:00
|
|
|
- a[0][0]*a[1][2]*a[2][1] - a[0][1]*a[1][0]*a[2][2] - a[0][2]*a[1][1]*a[2][0];
|
2010-01-29 14:58:33 +00:00
|
|
|
}
|
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshMatrix operator*(const StdMeshMatrix& lhs, const StdMeshMatrix& rhs)
|
|
|
|
{
|
|
|
|
StdMeshMatrix m;
|
|
|
|
|
|
|
|
m(0,0) = lhs(0,0)*rhs(0,0) + lhs(0,1)*rhs(1,0) + lhs(0,2)*rhs(2,0);
|
|
|
|
m(1,0) = lhs(1,0)*rhs(0,0) + lhs(1,1)*rhs(1,0) + lhs(1,2)*rhs(2,0);
|
|
|
|
m(2,0) = lhs(2,0)*rhs(0,0) + lhs(2,1)*rhs(1,0) + lhs(2,2)*rhs(2,0);
|
2009-07-08 22:01:15 +00:00
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
m(0,1) = lhs(0,0)*rhs(0,1) + lhs(0,1)*rhs(1,1) + lhs(0,2)*rhs(2,1);
|
|
|
|
m(1,1) = lhs(1,0)*rhs(0,1) + lhs(1,1)*rhs(1,1) + lhs(1,2)*rhs(2,1);
|
|
|
|
m(2,1) = lhs(2,0)*rhs(0,1) + lhs(2,1)*rhs(1,1) + lhs(2,2)*rhs(2,1);
|
2009-07-08 22:01:15 +00:00
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
m(0,2) = lhs(0,0)*rhs(0,2) + lhs(0,1)*rhs(1,2) + lhs(0,2)*rhs(2,2);
|
|
|
|
m(1,2) = lhs(1,0)*rhs(0,2) + lhs(1,1)*rhs(1,2) + lhs(1,2)*rhs(2,2);
|
|
|
|
m(2,2) = lhs(2,0)*rhs(0,2) + lhs(2,1)*rhs(1,2) + lhs(2,2)*rhs(2,2);
|
2009-07-08 22:01:15 +00:00
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
m(0,3) = lhs(0,0)*rhs(0,3) + lhs(0,1)*rhs(1,3) + lhs(0,2)*rhs(2,3) + lhs(0,3);
|
|
|
|
m(1,3) = lhs(1,0)*rhs(0,3) + lhs(1,1)*rhs(1,3) + lhs(1,2)*rhs(2,3) + lhs(1,3);
|
|
|
|
m(2,3) = lhs(2,0)*rhs(0,3) + lhs(2,1)*rhs(1,3) + lhs(2,2)*rhs(2,3) + lhs(2,3);
|
2009-07-08 22:01:15 +00:00
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
return m;
|
2009-07-08 22:01:15 +00:00
|
|
|
}
|
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshMatrix operator*(float lhs, const StdMeshMatrix& rhs)
|
2009-07-08 22:01:15 +00:00
|
|
|
{
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshMatrix m;
|
|
|
|
m(0,0) = lhs * rhs(0,0);
|
|
|
|
m(1,0) = lhs * rhs(1,0);
|
|
|
|
m(2,0) = lhs * rhs(2,0);
|
|
|
|
m(0,1) = lhs * rhs(0,1);
|
|
|
|
m(1,1) = lhs * rhs(1,1);
|
|
|
|
m(2,1) = lhs * rhs(2,1);
|
|
|
|
m(0,2) = lhs * rhs(0,2);
|
|
|
|
m(1,2) = lhs * rhs(1,2);
|
|
|
|
m(2,2) = lhs * rhs(2,2);
|
|
|
|
m(0,3) = lhs * rhs(0,3);
|
|
|
|
m(1,3) = lhs * rhs(1,3);
|
|
|
|
m(2,3) = lhs * rhs(2,3);
|
|
|
|
return m;
|
2009-07-08 22:01:15 +00:00
|
|
|
}
|
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshMatrix operator*(const StdMeshMatrix& lhs, float rhs)
|
2009-07-08 22:01:15 +00:00
|
|
|
{
|
2010-01-05 16:20:46 +00:00
|
|
|
return rhs * lhs;
|
2009-07-08 22:01:15 +00:00
|
|
|
}
|
|
|
|
|
2010-06-08 22:55:34 +00:00
|
|
|
StdMeshMatrix& operator*=(StdMeshMatrix& lhs, const StdMeshMatrix& rhs)
|
|
|
|
{
|
|
|
|
lhs = lhs * rhs;
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshMatrix operator+(const StdMeshMatrix& lhs, const StdMeshMatrix& rhs)
|
2009-07-08 22:01:15 +00:00
|
|
|
{
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshMatrix m;
|
|
|
|
m(0,0) = lhs(0,0) + rhs(0,0);
|
|
|
|
m(1,0) = lhs(1,0) + rhs(1,0);
|
|
|
|
m(2,0) = lhs(2,0) + rhs(2,0);
|
|
|
|
m(0,1) = lhs(0,1) + rhs(0,1);
|
|
|
|
m(1,1) = lhs(1,1) + rhs(1,1);
|
|
|
|
m(2,1) = lhs(2,1) + rhs(2,1);
|
|
|
|
m(0,2) = lhs(0,2) + rhs(0,2);
|
|
|
|
m(1,2) = lhs(1,2) + rhs(1,2);
|
|
|
|
m(2,2) = lhs(2,2) + rhs(2,2);
|
|
|
|
m(0,3) = lhs(0,3) + rhs(0,3);
|
|
|
|
m(1,3) = lhs(1,3) + rhs(1,3);
|
|
|
|
m(2,3) = lhs(2,3) + rhs(2,3);
|
|
|
|
return m;
|
|
|
|
}
|
2009-07-08 22:01:15 +00:00
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshQuaternion operator-(const StdMeshQuaternion& rhs)
|
|
|
|
{
|
|
|
|
StdMeshQuaternion q;
|
2010-01-26 16:17:43 +00:00
|
|
|
q.w = -rhs.w;
|
2010-01-05 16:20:46 +00:00
|
|
|
q.x = -rhs.x;
|
|
|
|
q.y = -rhs.y;
|
|
|
|
q.z = -rhs.z;
|
|
|
|
return q;
|
|
|
|
}
|
2009-07-08 22:01:15 +00:00
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshQuaternion operator*(const StdMeshQuaternion& lhs, const StdMeshQuaternion& rhs)
|
|
|
|
{
|
|
|
|
StdMeshQuaternion q;
|
|
|
|
q.w = lhs.w*rhs.w - lhs.x*rhs.x - lhs.y*rhs.y - lhs.z*rhs.z;
|
|
|
|
q.x = lhs.w*rhs.x + lhs.x*rhs.w + lhs.y*rhs.z - lhs.z*rhs.y;
|
|
|
|
q.y = lhs.w*rhs.y + lhs.y*rhs.w + lhs.z*rhs.x - lhs.x*rhs.z;
|
|
|
|
q.z = lhs.w*rhs.z + lhs.z*rhs.w + lhs.x*rhs.y - lhs.y*rhs.x;
|
|
|
|
return q;
|
|
|
|
}
|
2009-07-08 22:01:15 +00:00
|
|
|
|
2010-01-05 21:35:30 +00:00
|
|
|
StdMeshQuaternion& operator*=(StdMeshQuaternion& lhs, float rhs)
|
2010-01-05 16:20:46 +00:00
|
|
|
{
|
2010-01-05 21:35:30 +00:00
|
|
|
lhs.w *= rhs;
|
|
|
|
lhs.x *= rhs;
|
|
|
|
lhs.y *= rhs;
|
|
|
|
lhs.z *= rhs;
|
|
|
|
return lhs;
|
2010-01-05 16:20:46 +00:00
|
|
|
}
|
2009-07-08 22:01:15 +00:00
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshQuaternion operator*(const StdMeshQuaternion& lhs, float rhs)
|
|
|
|
{
|
2010-01-05 21:35:30 +00:00
|
|
|
StdMeshQuaternion q(lhs);
|
|
|
|
q *= rhs;
|
|
|
|
return q;
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshQuaternion operator*(float lhs, const StdMeshQuaternion& rhs)
|
|
|
|
{
|
2010-03-27 16:05:02 +00:00
|
|
|
return rhs * lhs;
|
2010-01-05 21:35:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshQuaternion& operator+=(StdMeshQuaternion& lhs, const StdMeshQuaternion& rhs)
|
|
|
|
{
|
|
|
|
lhs.w += rhs.w;
|
|
|
|
lhs.x += rhs.x;
|
|
|
|
lhs.y += rhs.y;
|
|
|
|
lhs.z += rhs.z;
|
|
|
|
return lhs;
|
2009-07-08 22:01:15 +00:00
|
|
|
}
|
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshQuaternion operator+(const StdMeshQuaternion& lhs, const StdMeshQuaternion& rhs)
|
2009-07-08 22:01:15 +00:00
|
|
|
{
|
2010-01-05 21:35:30 +00:00
|
|
|
StdMeshQuaternion q(lhs);
|
|
|
|
q += rhs;
|
2010-01-05 16:20:46 +00:00
|
|
|
return q;
|
|
|
|
}
|
2009-07-08 22:01:15 +00:00
|
|
|
|
2010-01-22 18:27:02 +00:00
|
|
|
StdMeshQuaternion operator-(const StdMeshQuaternion& lhs, const StdMeshQuaternion& rhs)
|
|
|
|
{
|
|
|
|
StdMeshQuaternion q;
|
|
|
|
q.w = lhs.w - rhs.w;
|
|
|
|
q.x = lhs.x - rhs.x;
|
|
|
|
q.y = lhs.y - rhs.y;
|
|
|
|
q.z = lhs.z - rhs.z;
|
|
|
|
return q;
|
|
|
|
}
|
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshTransformation operator*(const StdMeshTransformation& lhs, const StdMeshTransformation& rhs)
|
|
|
|
{
|
|
|
|
StdMeshTransformation t;
|
|
|
|
t.rotate = lhs.rotate * rhs.rotate;
|
|
|
|
t.scale = lhs.scale * rhs.scale;
|
|
|
|
t.translate = lhs.translate + lhs.rotate * (lhs.scale * rhs.translate);
|
|
|
|
return t;
|
2009-07-08 22:01:15 +00:00
|
|
|
}
|
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshVector operator-(const StdMeshVector& rhs)
|
2009-07-08 22:01:15 +00:00
|
|
|
{
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshVector v;
|
|
|
|
v.x = -rhs.x;
|
|
|
|
v.y = -rhs.y;
|
|
|
|
v.z = -rhs.z;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2010-01-05 21:35:30 +00:00
|
|
|
StdMeshVector& operator+=(StdMeshVector& lhs, const StdMeshVector& rhs)
|
|
|
|
{
|
|
|
|
lhs.x += rhs.x;
|
|
|
|
lhs.y += rhs.y;
|
|
|
|
lhs.z += rhs.z;
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshVector operator+(const StdMeshVector& lhs, const StdMeshVector& rhs)
|
|
|
|
{
|
2010-01-05 21:35:30 +00:00
|
|
|
StdMeshVector v(lhs);
|
|
|
|
v += rhs;
|
2010-01-05 16:20:46 +00:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshVector operator*(const StdMeshVector& lhs, const StdMeshVector& rhs)
|
|
|
|
{
|
|
|
|
StdMeshVector v;
|
|
|
|
v.x = lhs.x * rhs.x;
|
|
|
|
v.y = lhs.y * rhs.y;
|
|
|
|
v.z = lhs.z * rhs.z;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2010-01-05 21:35:30 +00:00
|
|
|
StdMeshVector& operator*=(StdMeshVector& lhs, float rhs)
|
2010-01-05 16:20:46 +00:00
|
|
|
{
|
2010-01-05 21:35:30 +00:00
|
|
|
lhs.x *= rhs;
|
|
|
|
lhs.y *= rhs;
|
|
|
|
lhs.z *= rhs;
|
|
|
|
return lhs;
|
2010-01-05 16:20:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshVector operator*(const StdMeshVector& lhs, float rhs)
|
2010-01-05 21:35:30 +00:00
|
|
|
{
|
|
|
|
StdMeshVector v(lhs);
|
|
|
|
v *= rhs;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshVector operator*(float lhs, const StdMeshVector& rhs)
|
2010-01-05 16:20:46 +00:00
|
|
|
{
|
|
|
|
return rhs * lhs;
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshVector operator/(const StdMeshVector& lhs, const StdMeshVector& rhs)
|
|
|
|
{
|
|
|
|
StdMeshVector v;
|
|
|
|
v.x = lhs.x/rhs.x;
|
|
|
|
v.y = lhs.y/rhs.y;
|
|
|
|
v.z = lhs.z/rhs.z;
|
2010-03-28 18:58:01 +00:00
|
|
|
return v;
|
2010-01-05 16:20:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshVector operator/(float lhs, const StdMeshVector& rhs)
|
|
|
|
{
|
|
|
|
StdMeshVector v;
|
|
|
|
v.x = lhs/rhs.x;
|
|
|
|
v.y = lhs/rhs.y;
|
|
|
|
v.z = lhs/rhs.z;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshVector operator/(const StdMeshVector& lhs, float rhs)
|
|
|
|
{
|
|
|
|
StdMeshVector v;
|
|
|
|
v.x = lhs.x/rhs;
|
|
|
|
v.y = lhs.y/rhs;
|
|
|
|
v.z = lhs.z/rhs;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2010-01-05 21:35:30 +00:00
|
|
|
StdMeshVector operator*(const StdMeshMatrix& lhs, const StdMeshVector& rhs) // does not apply translation part
|
|
|
|
{
|
|
|
|
StdMeshVector v;
|
|
|
|
v.x = lhs(0,0)*rhs.x + lhs(0,1)*rhs.y + lhs(0,2)*rhs.z;
|
|
|
|
v.y = lhs(1,0)*rhs.x + lhs(1,1)*rhs.y + lhs(1,2)*rhs.z;
|
|
|
|
v.z = lhs(2,0)*rhs.x + lhs(2,1)*rhs.y + lhs(2,2)*rhs.z;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshVector operator*(const StdMeshQuaternion& lhs, const StdMeshVector& rhs)
|
|
|
|
{
|
2010-01-25 04:00:59 +00:00
|
|
|
StdMeshVector v = { lhs.x, lhs.y, lhs.z };
|
|
|
|
StdMeshVector uv = 2.0f * StdMeshVector::Cross(v, rhs);
|
|
|
|
StdMeshVector uuv = StdMeshVector::Cross(v, uv);
|
2010-01-05 16:20:46 +00:00
|
|
|
return rhs + lhs.w * uv + uuv;
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshVertex& operator+=(StdMeshVertex& lhs, const StdMeshVertex& rhs)
|
|
|
|
{
|
|
|
|
lhs.nx += rhs.nx;
|
|
|
|
lhs.ny += rhs.ny;
|
|
|
|
lhs.nz += rhs.nz;
|
|
|
|
lhs.x += rhs.x;
|
|
|
|
lhs.y += rhs.y;
|
|
|
|
lhs.z += rhs.z;
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshVertex operator+(const StdMeshVertex& lhs, const StdMeshVertex& rhs)
|
|
|
|
{
|
|
|
|
StdMeshVertex vtx(lhs);
|
|
|
|
vtx += rhs;
|
|
|
|
return vtx;
|
|
|
|
}
|
2009-07-08 22:01:15 +00:00
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshVertex operator*(float lhs, const StdMeshVertex& rhs)
|
|
|
|
{
|
|
|
|
StdMeshVertex vtx;
|
|
|
|
vtx.nx = lhs*rhs.nx;
|
|
|
|
vtx.ny = lhs*rhs.ny;
|
|
|
|
vtx.nz = lhs*rhs.nz;
|
|
|
|
vtx.x = lhs*rhs.x;
|
|
|
|
vtx.y = lhs*rhs.y;
|
|
|
|
vtx.z = lhs*rhs.z;
|
|
|
|
return vtx;
|
2009-07-08 22:01:15 +00:00
|
|
|
}
|
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshVertex operator*(const StdMeshVertex& lhs, float rhs)
|
2009-07-08 22:01:15 +00:00
|
|
|
{
|
2010-01-05 16:20:46 +00:00
|
|
|
return rhs * lhs;
|
|
|
|
}
|
2009-07-08 22:01:15 +00:00
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
StdMeshVertex operator*(const StdMeshMatrix& lhs, const StdMeshVertex& rhs)
|
|
|
|
{
|
|
|
|
StdMeshVertex vtx;
|
|
|
|
vtx.nx = lhs(0,0)*rhs.nx + lhs(0,1)*rhs.ny + lhs(0,2)*rhs.nz;
|
|
|
|
vtx.ny = lhs(1,0)*rhs.nx + lhs(1,1)*rhs.ny + lhs(0,2)*rhs.nz;
|
|
|
|
vtx.nz = lhs(2,0)*rhs.nx + lhs(2,1)*rhs.ny + lhs(2,2)*rhs.nz;
|
|
|
|
vtx.x = lhs(0,0)*rhs.x + lhs(0,1)*rhs.y + lhs(0,2)*rhs.z + lhs(0,3);
|
|
|
|
vtx.y = lhs(1,0)*rhs.x + lhs(1,1)*rhs.y + lhs(1,2)*rhs.z + lhs(1,3);
|
|
|
|
vtx.z = lhs(2,0)*rhs.x + lhs(2,1)*rhs.y + lhs(2,2)*rhs.z + lhs(2,3);
|
2010-01-05 21:35:30 +00:00
|
|
|
vtx.u = rhs.u; vtx.v = rhs.v;
|
2010-01-05 16:20:46 +00:00
|
|
|
return vtx;
|
2009-07-08 22:01:15 +00:00
|
|
|
}
|
|
|
|
|
2010-01-05 16:20:46 +00:00
|
|
|
/* Boring math stuff ends here */
|
|
|
|
|
2010-01-05 21:35:30 +00:00
|
|
|
StdMeshTransformation StdMeshTrack::GetTransformAt(float time) const
|
2009-07-08 22:01:15 +00:00
|
|
|
{
|
2009-08-01 19:36:13 +00:00
|
|
|
std::map<float, StdMeshKeyFrame>::const_iterator iter = Frames.lower_bound(time);
|
2009-07-08 22:01:15 +00:00
|
|
|
|
2009-08-01 19:36:13 +00:00
|
|
|
// If this points to end(), then either
|
|
|
|
// a) time > animation length
|
|
|
|
// b) The track does not include a frame for the very end of the animation
|
|
|
|
// Both is considered an error
|
|
|
|
assert(iter != Frames.end());
|
2009-07-08 22:01:15 +00:00
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
if (iter == Frames.begin())
|
2010-01-05 21:35:30 +00:00
|
|
|
return iter->second.Transformation;
|
2009-07-08 22:01:15 +00:00
|
|
|
|
2009-08-01 19:36:13 +00:00
|
|
|
std::map<float, StdMeshKeyFrame>::const_iterator prev_iter = iter;
|
|
|
|
-- prev_iter;
|
2009-07-08 22:01:15 +00:00
|
|
|
|
2009-08-01 19:36:13 +00:00
|
|
|
float dt = iter->first - prev_iter->first;
|
|
|
|
float weight1 = (time - prev_iter->first) / dt;
|
|
|
|
float weight2 = (iter->first - time) / dt;
|
2009-07-08 22:01:15 +00:00
|
|
|
|
2009-08-01 19:36:13 +00:00
|
|
|
assert(weight1 >= 0 && weight2 >= 0 && weight1 <= 1 && weight2 <= 1);
|
|
|
|
assert(fabs(weight1 + weight2 - 1) < 1e-6);
|
2009-07-08 22:01:15 +00:00
|
|
|
|
2010-01-26 16:17:43 +00:00
|
|
|
/*StdMeshTransformation transformation;
|
2010-01-05 21:35:30 +00:00
|
|
|
transformation.scale = weight1 * iter->second.Transformation.scale + weight2 * prev_iter->second.Transformation.scale;
|
|
|
|
transformation.rotate = weight1 * iter->second.Transformation.rotate + weight2 * prev_iter->second.Transformation.rotate; // TODO: slerp or renormalize
|
|
|
|
transformation.translate = weight1 * iter->second.Transformation.translate + weight2 * prev_iter->second.Transformation.translate;
|
2010-01-26 16:17:43 +00:00
|
|
|
return transformation;*/
|
|
|
|
return StdMeshTransformation::Nlerp(prev_iter->second.Transformation, iter->second.Transformation, weight1);
|
2009-07-08 22:01:15 +00:00
|
|
|
}
|
|
|
|
|
2009-07-09 22:18:26 +00:00
|
|
|
StdMeshAnimation::StdMeshAnimation(const StdMeshAnimation& other):
|
2010-03-28 18:58:01 +00:00
|
|
|
Name(other.Name), Length(other.Length), Tracks(other.Tracks.size())
|
2009-07-09 22:18:26 +00:00
|
|
|
{
|
2009-08-01 19:36:13 +00:00
|
|
|
// Note that all Tracks are already default-initialized to zero
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int i = 0; i < Tracks.size(); ++i)
|
|
|
|
if (other.Tracks[i])
|
2009-08-01 19:36:13 +00:00
|
|
|
Tracks[i] = new StdMeshTrack(*other.Tracks[i]);
|
2009-07-09 22:18:26 +00:00
|
|
|
}
|
|
|
|
|
2009-07-08 22:01:15 +00:00
|
|
|
StdMeshAnimation::~StdMeshAnimation()
|
|
|
|
{
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int i = 0; i < Tracks.size(); ++i)
|
2009-08-01 19:36:13 +00:00
|
|
|
delete Tracks[i];
|
2009-07-08 22:01:15 +00:00
|
|
|
}
|
|
|
|
|
2009-07-09 22:18:26 +00:00
|
|
|
StdMeshAnimation& StdMeshAnimation::operator=(const StdMeshAnimation& other)
|
|
|
|
{
|
2010-03-28 18:58:01 +00:00
|
|
|
if (this == &other) return *this;
|
2009-07-09 22:18:26 +00:00
|
|
|
|
2009-08-01 19:36:13 +00:00
|
|
|
Name = other.Name;
|
|
|
|
Length = other.Length;
|
2009-07-09 22:18:26 +00:00
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int i = 0; i < Tracks.size(); ++i)
|
2009-08-01 19:36:13 +00:00
|
|
|
delete Tracks[i];
|
2009-07-09 22:18:26 +00:00
|
|
|
|
2009-08-01 19:36:13 +00:00
|
|
|
Tracks.resize(other.Tracks.size());
|
2009-07-09 22:18:26 +00:00
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int i = 0; i < Tracks.size(); ++i)
|
|
|
|
if (other.Tracks[i])
|
2009-08-01 19:36:13 +00:00
|
|
|
Tracks[i] = new StdMeshTrack(*other.Tracks[i]);
|
2009-07-09 22:18:26 +00:00
|
|
|
|
2009-08-01 19:36:13 +00:00
|
|
|
return *this;
|
2009-07-09 22:18:26 +00:00
|
|
|
}
|
|
|
|
|
2010-01-11 23:54:36 +00:00
|
|
|
StdSubMesh::StdSubMesh():
|
2010-03-28 18:58:01 +00:00
|
|
|
Material(NULL)
|
2010-01-11 23:54:36 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMesh::StdMesh()
|
2009-07-08 22:01:15 +00:00
|
|
|
{
|
2009-08-01 19:36:13 +00:00
|
|
|
BoundingBox.x1 = BoundingBox.y1 = BoundingBox.z1 = 0.0f;
|
|
|
|
BoundingBox.x2 = BoundingBox.y2 = BoundingBox.z2 = 0.0f;
|
2010-03-17 20:15:00 +00:00
|
|
|
BoundingRadius = 0.0f;
|
2009-07-08 22:01:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
StdMesh::~StdMesh()
|
|
|
|
{
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int i = 0; i < Bones.size(); ++i)
|
2009-08-01 19:36:13 +00:00
|
|
|
delete Bones[i];
|
2009-07-08 22:01:15 +00:00
|
|
|
}
|
|
|
|
|
2009-07-09 22:18:26 +00:00
|
|
|
void StdMesh::AddMasterBone(StdMeshBone* bone)
|
|
|
|
{
|
2009-08-01 19:36:13 +00:00
|
|
|
bone->Index = Bones.size(); // Remember index in master bone table
|
|
|
|
Bones.push_back(bone);
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int i = 0; i < bone->Children.size(); ++i)
|
2009-08-01 19:36:13 +00:00
|
|
|
AddMasterBone(bone->Children[i]);
|
2009-07-09 22:18:26 +00:00
|
|
|
}
|
|
|
|
|
2010-01-29 21:18:18 +00:00
|
|
|
const StdMeshBone* StdMesh::GetBoneByName(const StdStrBuf& name) const
|
|
|
|
{
|
|
|
|
// Lookup parent bone
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int i = 0; i < Bones.size(); ++i)
|
|
|
|
if (Bones[i]->Name == name)
|
2010-01-29 21:18:18 +00:00
|
|
|
return Bones[i];
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-07-10 19:57:11 +00:00
|
|
|
const StdMeshAnimation* StdMesh::GetAnimationByName(const StdStrBuf& name) const
|
|
|
|
{
|
2009-07-28 21:19:09 +00:00
|
|
|
StdCopyStrBuf name2(name);
|
2009-08-01 19:36:13 +00:00
|
|
|
std::map<StdCopyStrBuf, StdMeshAnimation>::const_iterator iter = Animations.find(name2);
|
2010-03-28 18:58:01 +00:00
|
|
|
if (iter == Animations.end()) return NULL;
|
2009-08-01 19:36:13 +00:00
|
|
|
return &iter->second;
|
2009-07-10 19:57:11 +00:00
|
|
|
}
|
|
|
|
|
2010-09-09 20:40:07 +00:00
|
|
|
void StdMesh::MirrorAnimation(const StdStrBuf& name, const StdMeshAnimation& animation)
|
|
|
|
{
|
|
|
|
StdCopyStrBuf name2(name);
|
|
|
|
assert(Animations.find(name2) == Animations.end());
|
|
|
|
|
|
|
|
StdMeshAnimation& new_anim = Animations.insert(std::make_pair(name2, animation)).first->second;
|
|
|
|
new_anim.Name = name2;
|
|
|
|
|
|
|
|
// Go through all bones
|
|
|
|
for(unsigned int i = 0; i < GetNumBones(); ++i)
|
|
|
|
{
|
|
|
|
// Only proceed if the bone is used in this animation
|
|
|
|
if(animation.Tracks[i] != NULL)
|
|
|
|
{
|
|
|
|
const StdMeshBone& bone = GetBone(i);
|
|
|
|
StdCopyStrBuf other_bone_name(bone.Name);
|
|
|
|
if(MirrorName(other_bone_name))
|
|
|
|
{
|
|
|
|
const StdMeshBone* other_bone = GetBoneByName(other_bone_name);
|
|
|
|
if(!other_bone)
|
|
|
|
throw std::runtime_error(std::string("No counterpart for bone ") + bone.Name.getData() + " found");
|
|
|
|
|
|
|
|
// Make sure to not swap tracks twice
|
|
|
|
if(other_bone->Index > bone.Index)
|
|
|
|
{
|
|
|
|
std::swap(new_anim.Tracks[i], new_anim.Tracks[other_bone->Index]);
|
2010-09-13 22:18:25 +00:00
|
|
|
#if 1
|
2010-09-09 20:40:07 +00:00
|
|
|
StdMeshTransformation own_trans = bone.GetParent()->InverseTransformation * bone.Transformation;
|
|
|
|
StdMeshTransformation other_own_trans = other_bone->GetParent()->InverseTransformation * other_bone->Transformation;
|
|
|
|
|
|
|
|
// Mirror all the keyframes of both tracks
|
|
|
|
for(std::map<float, StdMeshKeyFrame>::iterator iter = new_anim.Tracks[i]->Frames.begin(); iter != new_anim.Tracks[i]->Frames.end(); ++iter)
|
|
|
|
MirrorKeyFrame(iter->second, own_trans, StdMeshTransformation::Inverse(other_own_trans));
|
|
|
|
|
|
|
|
for(std::map<float, StdMeshKeyFrame>::iterator iter = new_anim.Tracks[other_bone->Index]->Frames.begin(); iter != new_anim.Tracks[other_bone->Index]->Frames.end(); ++iter)
|
|
|
|
MirrorKeyFrame(iter->second, other_own_trans, StdMeshTransformation::Inverse(own_trans));
|
2010-09-13 22:18:25 +00:00
|
|
|
#endif
|
2010-09-09 20:40:07 +00:00
|
|
|
}
|
|
|
|
}
|
2010-09-13 22:18:25 +00:00
|
|
|
else if(bone.Name.Compare_(".N", bone.Name.getLength()-2) != 0)
|
|
|
|
{
|
|
|
|
StdMeshTransformation own_trans = bone.Transformation;
|
|
|
|
if(bone.GetParent()) own_trans = bone.GetParent()->InverseTransformation * bone.Transformation;
|
|
|
|
|
|
|
|
for(std::map<float, StdMeshKeyFrame>::iterator iter = new_anim.Tracks[i]->Frames.begin(); iter != new_anim.Tracks[i]->Frames.end(); ++iter)
|
|
|
|
MirrorKeyFrame(iter->second, own_trans, StdMeshTransformation::Inverse(own_trans));
|
|
|
|
}
|
2010-09-09 20:40:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-04 22:33:05 +00:00
|
|
|
void StdMesh::PostInit()
|
2010-09-09 20:40:07 +00:00
|
|
|
{
|
|
|
|
// Mirror .R and .L animations without counterpart
|
|
|
|
for(std::map<StdCopyStrBuf, StdMeshAnimation>::iterator iter = Animations.begin(); iter != Animations.end(); ++iter)
|
|
|
|
{
|
|
|
|
// For debugging purposes:
|
2010-09-13 22:18:25 +00:00
|
|
|
// if(iter->second.Name == "Jump")
|
|
|
|
// MirrorAnimation(StdCopyStrBuf("Jump.Mirror"), iter->second);
|
2010-09-09 20:40:07 +00:00
|
|
|
|
|
|
|
StdCopyStrBuf buf = iter->second.Name;
|
|
|
|
if(MirrorName(buf))
|
|
|
|
{
|
|
|
|
if(Animations.find(buf) == Animations.end())
|
|
|
|
MirrorAnimation(buf, iter->second);
|
|
|
|
}
|
|
|
|
}
|
2010-12-04 22:33:05 +00:00
|
|
|
|
|
|
|
// Order submeshes so that opaque submeshes come before non-opaque ones
|
|
|
|
std::sort(SubMeshes.begin(), SubMeshes.end(), StdMeshSubMeshVisibilityCmpPred());
|
2010-09-09 20:40:07 +00:00
|
|
|
}
|
|
|
|
|
2010-03-16 22:31:53 +00:00
|
|
|
StdSubMeshInstance::StdSubMeshInstance(const StdSubMesh& submesh):
|
2010-03-28 18:58:01 +00:00
|
|
|
Vertices(submesh.GetNumVertices()), Faces(submesh.GetNumFaces()),
|
|
|
|
Material(NULL)
|
2010-03-16 22:31:53 +00:00
|
|
|
{
|
|
|
|
// Copy initial Vertices/Faces
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int i = 0; i < submesh.GetNumVertices(); ++i)
|
2010-03-16 22:31:53 +00:00
|
|
|
Vertices[i] = submesh.GetVertex(i);
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int i = 0; i < submesh.GetNumFaces(); ++i)
|
2010-03-16 22:31:53 +00:00
|
|
|
Faces[i] = submesh.GetFace(i);
|
|
|
|
|
2010-03-17 22:04:56 +00:00
|
|
|
SetMaterial(submesh.GetMaterial());
|
|
|
|
}
|
|
|
|
|
|
|
|
void StdSubMeshInstance::SetMaterial(const StdMeshMaterial& material)
|
|
|
|
{
|
|
|
|
Material = &material;
|
|
|
|
|
2010-03-16 22:31:53 +00:00
|
|
|
// Setup initial texture animation data
|
2010-03-17 22:04:56 +00:00
|
|
|
assert(Material->BestTechniqueIndex >= 0);
|
2010-03-16 22:31:53 +00:00
|
|
|
const StdMeshMaterialTechnique& technique = Material->Techniques[Material->BestTechniqueIndex];
|
2010-03-17 22:04:56 +00:00
|
|
|
PassData.resize(technique.Passes.size());
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int i = 0; i < PassData.size(); ++i)
|
2010-03-16 22:31:53 +00:00
|
|
|
{
|
|
|
|
const StdMeshMaterialPass& pass = technique.Passes[i];
|
2010-03-17 22:04:56 +00:00
|
|
|
// Clear from previous material
|
|
|
|
PassData[i].TexUnits.clear();
|
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int j = 0; j < pass.TextureUnits.size(); ++j)
|
2010-03-16 22:31:53 +00:00
|
|
|
{
|
|
|
|
TexUnit unit;
|
|
|
|
unit.Phase = 0;
|
|
|
|
unit.PhaseDelay = 0.0f;
|
2010-03-17 19:19:14 +00:00
|
|
|
unit.Position = 0.0;
|
2010-03-16 22:31:53 +00:00
|
|
|
PassData[i].TexUnits.push_back(unit);
|
|
|
|
}
|
|
|
|
}
|
2010-12-04 22:33:05 +00:00
|
|
|
|
|
|
|
// TODO: Reorder this submesh so that opaque submeshes are drawn
|
|
|
|
// before non-opaque ones.
|
2010-03-16 22:31:53 +00:00
|
|
|
}
|
|
|
|
|
2010-04-01 21:00:05 +00:00
|
|
|
void StdMeshInstance::SerializableValueProvider::CompileFunc(StdCompiler* pComp)
|
|
|
|
{
|
|
|
|
pComp->Value(Value);
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshInstance::AnimationNode::AnimationNode():
|
|
|
|
Type(LeafNode), Parent(NULL)
|
|
|
|
{
|
|
|
|
Leaf.Animation = NULL;
|
|
|
|
Leaf.Position = NULL;
|
|
|
|
}
|
|
|
|
|
2010-01-22 18:27:02 +00:00
|
|
|
StdMeshInstance::AnimationNode::AnimationNode(const StdMeshAnimation* animation, ValueProvider* position):
|
2010-03-28 18:58:01 +00:00
|
|
|
Type(LeafNode), Parent(NULL)
|
2009-12-30 20:41:56 +00:00
|
|
|
{
|
2010-01-22 18:27:02 +00:00
|
|
|
Leaf.Animation = animation;
|
|
|
|
Leaf.Position = position;
|
2009-12-30 20:41:56 +00:00
|
|
|
}
|
|
|
|
|
2010-01-22 18:27:02 +00:00
|
|
|
StdMeshInstance::AnimationNode::AnimationNode(AnimationNode* child_left, AnimationNode* child_right, ValueProvider* weight):
|
2010-03-28 18:58:01 +00:00
|
|
|
Type(LinearInterpolationNode), Parent(NULL)
|
2009-12-30 20:41:56 +00:00
|
|
|
{
|
2010-01-22 18:27:02 +00:00
|
|
|
LinearInterpolation.ChildLeft = child_left;
|
|
|
|
LinearInterpolation.ChildRight = child_right;
|
|
|
|
LinearInterpolation.Weight = weight;
|
2009-12-30 20:41:56 +00:00
|
|
|
}
|
|
|
|
|
2010-01-22 18:27:02 +00:00
|
|
|
StdMeshInstance::AnimationNode::~AnimationNode()
|
2009-12-30 20:41:56 +00:00
|
|
|
{
|
2010-03-28 18:58:01 +00:00
|
|
|
switch (Type)
|
2010-01-22 18:27:02 +00:00
|
|
|
{
|
|
|
|
case LeafNode:
|
|
|
|
delete Leaf.Position;
|
|
|
|
break;
|
|
|
|
case LinearInterpolationNode:
|
|
|
|
delete LinearInterpolation.ChildLeft;
|
|
|
|
delete LinearInterpolation.ChildRight;
|
|
|
|
delete LinearInterpolation.Weight;
|
|
|
|
break;
|
|
|
|
}
|
2009-12-30 20:41:56 +00:00
|
|
|
}
|
|
|
|
|
2010-01-22 18:27:02 +00:00
|
|
|
bool StdMeshInstance::AnimationNode::GetBoneTransform(unsigned int bone, StdMeshTransformation& transformation)
|
2009-12-30 20:41:56 +00:00
|
|
|
{
|
2010-01-22 18:27:02 +00:00
|
|
|
StdMeshTransformation combine_with;
|
|
|
|
StdMeshTrack* track;
|
2009-12-30 20:41:56 +00:00
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
switch (Type)
|
2010-01-22 18:27:02 +00:00
|
|
|
{
|
|
|
|
case LeafNode:
|
|
|
|
//if(!Leaf.Animation) return false;
|
|
|
|
track = Leaf.Animation->Tracks[bone];
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!track) return false;
|
2010-02-02 18:25:51 +00:00
|
|
|
transformation = track->GetTransformAt(fixtof(Leaf.Position->Value));
|
2010-01-22 18:27:02 +00:00
|
|
|
return true;
|
|
|
|
case LinearInterpolationNode:
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!LinearInterpolation.ChildLeft->GetBoneTransform(bone, transformation))
|
2010-01-22 18:27:02 +00:00
|
|
|
return LinearInterpolation.ChildRight->GetBoneTransform(bone, transformation);
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!LinearInterpolation.ChildRight->GetBoneTransform(bone, combine_with))
|
2010-01-22 18:27:02 +00:00
|
|
|
return true; // First Child affects bone
|
|
|
|
|
2010-02-02 18:25:51 +00:00
|
|
|
transformation = StdMeshTransformation::Nlerp(transformation, combine_with, fixtof(LinearInterpolation.Weight->Value));
|
2010-01-22 18:27:02 +00:00
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
assert(false);
|
|
|
|
return false;
|
|
|
|
}
|
2009-12-30 20:41:56 +00:00
|
|
|
}
|
|
|
|
|
2010-04-01 21:00:05 +00:00
|
|
|
void StdMeshInstance::AnimationNode::CompileFunc(StdCompiler* pComp, const StdMesh* Mesh)
|
|
|
|
{
|
|
|
|
static const StdEnumEntry<NodeType> NodeTypes[] =
|
|
|
|
{
|
|
|
|
{ "Leaf", LeafNode },
|
|
|
|
{ "LinearInterpolation", LinearInterpolationNode },
|
|
|
|
|
|
|
|
{ NULL, static_cast<NodeType>(0) }
|
|
|
|
};
|
|
|
|
|
|
|
|
pComp->Value(mkNamingAdapt(Slot, "Slot"));
|
|
|
|
pComp->Value(mkNamingAdapt(Number, "Number"));
|
2010-04-02 13:15:58 +00:00
|
|
|
pComp->Value(mkNamingAdapt(mkEnumAdaptT<uint8_t>(Type, NodeTypes), "Type"));
|
2010-04-01 21:00:05 +00:00
|
|
|
|
|
|
|
switch(Type)
|
|
|
|
{
|
|
|
|
case LeafNode:
|
|
|
|
if(pComp->isCompiler())
|
|
|
|
{
|
|
|
|
StdCopyStrBuf anim_name;
|
|
|
|
pComp->Value(mkNamingAdapt(toC4CStrBuf(anim_name), "Animation"));
|
|
|
|
Leaf.Animation = Mesh->GetAnimationByName(anim_name);
|
|
|
|
if(!Leaf.Animation) pComp->excCorrupt("No such animation: \"%s\"", anim_name.getData());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pComp->Value(mkNamingAdapt(mkParAdapt(mkDecompileAdapt(Leaf.Animation->Name), StdCompiler::RCT_All), "Animation"));
|
|
|
|
}
|
|
|
|
|
|
|
|
pComp->Value(mkNamingAdapt(mkValueProviderAdapt(&Leaf.Position), "Position"));
|
|
|
|
break;
|
|
|
|
case LinearInterpolationNode:
|
|
|
|
pComp->Value(mkParAdapt(mkNamingPtrAdapt(LinearInterpolation.ChildLeft, "ChildLeft"), Mesh));
|
|
|
|
pComp->Value(mkParAdapt(mkNamingPtrAdapt(LinearInterpolation.ChildRight, "ChildRight"), Mesh));
|
|
|
|
pComp->Value(mkNamingAdapt(mkValueProviderAdapt(&LinearInterpolation.Weight), "Weight"));
|
|
|
|
if(pComp->isCompiler())
|
|
|
|
{
|
|
|
|
if(LinearInterpolation.ChildLeft->Slot != Slot)
|
|
|
|
pComp->excCorrupt("Slot of left child does not match parent slot");
|
|
|
|
if(LinearInterpolation.ChildRight->Slot != Slot)
|
|
|
|
pComp->excCorrupt("Slof of right child does not match parent slot");
|
|
|
|
LinearInterpolation.ChildRight->Parent = this;
|
|
|
|
LinearInterpolation.ChildRight->Parent = this;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
pComp->excCorrupt("Invalid animation node type");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void StdMeshInstance::AnimationNode::DenumeratePointers()
|
|
|
|
{
|
|
|
|
SerializableValueProvider* value_provider = NULL;
|
|
|
|
switch(Type)
|
|
|
|
{
|
|
|
|
case LeafNode:
|
|
|
|
value_provider = dynamic_cast<SerializableValueProvider*>(Leaf.Position);
|
|
|
|
break;
|
|
|
|
case LinearInterpolationNode:
|
|
|
|
value_provider = dynamic_cast<SerializableValueProvider*>(LinearInterpolation.Weight);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(value_provider) value_provider->DenumeratePointers();
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshInstance::AttachedMesh::AttachedMesh():
|
|
|
|
Number(0), Parent(NULL), Child(NULL), OwnChild(true), ChildDenumerator(NULL), ParentBone(0), ChildBone(0), FinalTransformDirty(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshInstance::AttachedMesh::AttachedMesh(unsigned int number, StdMeshInstance* parent, StdMeshInstance* child, bool own_child, Denumerator* denumerator,
|
2010-08-31 21:44:56 +00:00
|
|
|
unsigned int parent_bone, unsigned int child_bone, const StdMeshMatrix& transform, uint32_t flags):
|
2010-04-01 21:00:05 +00:00
|
|
|
Number(number), Parent(parent), Child(child), OwnChild(own_child), ChildDenumerator(denumerator),
|
2010-08-31 21:44:56 +00:00
|
|
|
ParentBone(parent_bone), ChildBone(child_bone), AttachTrans(transform), Flags(flags),
|
2010-03-28 18:58:01 +00:00
|
|
|
FinalTransformDirty(true)
|
2010-01-29 21:18:18 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshInstance::AttachedMesh::~AttachedMesh()
|
|
|
|
{
|
2010-03-28 18:58:01 +00:00
|
|
|
if (OwnChild)
|
2010-01-29 21:18:18 +00:00
|
|
|
delete Child;
|
2010-04-01 21:00:05 +00:00
|
|
|
delete ChildDenumerator;
|
2010-01-29 21:18:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool StdMeshInstance::AttachedMesh::SetParentBone(const StdStrBuf& bone)
|
|
|
|
{
|
2011-08-19 22:01:08 +00:00
|
|
|
const StdMeshBone* bone_obj = Parent->GetMesh().GetBoneByName(bone);
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!bone_obj) return false;
|
2010-01-29 21:18:18 +00:00
|
|
|
ParentBone = bone_obj->Index;
|
|
|
|
|
|
|
|
FinalTransformDirty = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool StdMeshInstance::AttachedMesh::SetChildBone(const StdStrBuf& bone)
|
|
|
|
{
|
2011-08-19 22:01:08 +00:00
|
|
|
const StdMeshBone* bone_obj = Child->GetMesh().GetBoneByName(bone);
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!bone_obj) return false;
|
2010-01-29 21:18:18 +00:00
|
|
|
ChildBone = bone_obj->Index;
|
|
|
|
|
|
|
|
FinalTransformDirty = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void StdMeshInstance::AttachedMesh::SetAttachTransformation(const StdMeshMatrix& transformation)
|
|
|
|
{
|
|
|
|
AttachTrans = transformation;
|
|
|
|
FinalTransformDirty = true;
|
|
|
|
}
|
|
|
|
|
2010-04-01 21:00:05 +00:00
|
|
|
void StdMeshInstance::AttachedMesh::CompileFunc(StdCompiler* pComp, DenumeratorFactoryFunc Factory)
|
|
|
|
{
|
|
|
|
if(pComp->isCompiler())
|
|
|
|
{
|
|
|
|
FinalTransformDirty = true;
|
|
|
|
ChildDenumerator = Factory();
|
|
|
|
}
|
|
|
|
|
2010-08-31 21:44:56 +00:00
|
|
|
const StdBitfieldEntry<uint8_t> AM_Entries[] =
|
|
|
|
{
|
|
|
|
{ "DrawBefore", AM_DrawBefore },
|
|
|
|
|
|
|
|
{ NULL, 0 }
|
|
|
|
};
|
|
|
|
|
2010-04-01 21:00:05 +00:00
|
|
|
pComp->Value(mkNamingAdapt(Number, "Number"));
|
|
|
|
pComp->Value(mkNamingAdapt(ParentBone, "ParentBone")); // TODO: Save as string
|
|
|
|
pComp->Value(mkNamingAdapt(ChildBone, "ChildBone")); // TODO: Save as string (note we can only resolve this in DenumeratePointers then!)
|
|
|
|
pComp->Value(mkNamingAdapt(mkTransformAdapt(AttachTrans), "AttachTransformation"));
|
2010-08-31 21:44:56 +00:00
|
|
|
|
|
|
|
uint8_t dwSyncFlags = static_cast<uint8_t>(Flags);
|
2011-03-30 23:25:27 +00:00
|
|
|
pComp->Value(mkNamingAdapt(mkBitfieldAdapt(dwSyncFlags, AM_Entries), "Flags", 0u));
|
2010-08-31 21:44:56 +00:00
|
|
|
if(pComp->isCompiler()) Flags = dwSyncFlags;
|
2010-04-01 21:00:05 +00:00
|
|
|
|
|
|
|
pComp->Value(mkParAdapt(*ChildDenumerator, this));
|
|
|
|
}
|
|
|
|
|
|
|
|
void StdMeshInstance::AttachedMesh::DenumeratePointers()
|
|
|
|
{
|
|
|
|
ChildDenumerator->DenumeratePointers(this);
|
|
|
|
}
|
|
|
|
|
2009-07-10 19:57:11 +00:00
|
|
|
StdMeshInstance::StdMeshInstance(const StdMesh& mesh):
|
2011-08-19 22:01:08 +00:00
|
|
|
Mesh(&mesh), CurrentFaceOrdering(FO_Fixed),
|
|
|
|
BoneTransforms(Mesh->GetNumBones(), StdMeshMatrix::Identity()),
|
|
|
|
SubMeshInstances(Mesh->GetNumSubMeshes()), AttachParent(NULL),
|
2010-03-28 18:58:01 +00:00
|
|
|
BoneTransformsDirty(false)
|
2009-07-10 19:57:11 +00:00
|
|
|
{
|
2011-08-19 22:01:08 +00:00
|
|
|
for (unsigned int i = 0; i < Mesh->GetNumSubMeshes(); ++i)
|
2010-01-11 23:54:36 +00:00
|
|
|
{
|
2011-08-19 22:01:08 +00:00
|
|
|
const StdSubMesh& submesh = Mesh->GetSubMesh(i);
|
2010-03-16 22:31:53 +00:00
|
|
|
SubMeshInstances[i] = new StdSubMeshInstance(submesh);
|
2010-01-11 23:54:36 +00:00
|
|
|
}
|
2009-07-23 23:52:18 +00:00
|
|
|
}
|
|
|
|
|
2010-01-10 21:02:40 +00:00
|
|
|
StdMeshInstance::~StdMeshInstance()
|
|
|
|
{
|
2010-01-29 21:18:18 +00:00
|
|
|
// If we are attached then detach from parent
|
2010-03-28 18:58:01 +00:00
|
|
|
if (AttachParent)
|
2010-01-29 21:18:18 +00:00
|
|
|
AttachParent->Parent->DetachMesh(AttachParent->Number);
|
|
|
|
|
|
|
|
// Remove all attach children
|
2010-03-28 18:58:01 +00:00
|
|
|
while (!AttachChildren.empty())
|
2010-01-29 21:18:18 +00:00
|
|
|
DetachMesh(AttachChildren.back()->Number);
|
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
while (!AnimationStack.empty())
|
2010-01-22 18:27:02 +00:00
|
|
|
StopAnimation(AnimationStack.front());
|
|
|
|
assert(AnimationNodes.empty());
|
2010-03-16 22:31:53 +00:00
|
|
|
|
|
|
|
// Delete submeshes
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int i = 0; i < SubMeshInstances.size(); ++i)
|
2010-03-16 22:31:53 +00:00
|
|
|
delete SubMeshInstances[i];
|
2010-01-10 21:02:40 +00:00
|
|
|
}
|
|
|
|
|
2009-07-23 23:52:18 +00:00
|
|
|
void StdMeshInstance::SetFaceOrdering(FaceOrdering ordering)
|
|
|
|
{
|
2010-03-28 18:58:01 +00:00
|
|
|
if (CurrentFaceOrdering != ordering)
|
2010-01-06 01:28:49 +00:00
|
|
|
{
|
|
|
|
CurrentFaceOrdering = ordering;
|
2010-03-28 18:58:01 +00:00
|
|
|
if (ordering == FO_Fixed)
|
2010-01-11 23:54:36 +00:00
|
|
|
{
|
|
|
|
// Copy original face ordering from StdMesh
|
2011-08-19 22:01:08 +00:00
|
|
|
for (unsigned int i = 0; i < Mesh->GetNumSubMeshes(); ++i)
|
2010-01-11 23:54:36 +00:00
|
|
|
{
|
2011-08-19 22:01:08 +00:00
|
|
|
const StdSubMesh& submesh = Mesh->GetSubMesh(i);
|
2010-03-16 22:31:53 +00:00
|
|
|
//SubMeshInstances[i]->Faces = submesh.GetFaces();
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int j = 0; j < submesh.GetNumFaces(); ++j)
|
2010-03-16 22:31:53 +00:00
|
|
|
SubMeshInstances[i]->Faces[j] = submesh.GetFace(j);
|
2010-01-11 23:54:36 +00:00
|
|
|
}
|
|
|
|
}
|
2010-01-06 01:28:49 +00:00
|
|
|
|
2010-06-08 22:55:34 +00:00
|
|
|
//BoneTransformsDirty = true;
|
2010-01-10 21:02:40 +00:00
|
|
|
|
2010-01-29 21:18:18 +00:00
|
|
|
// Update attachments (only own meshes for now... others might be displayed both attached and non-attached...)
|
|
|
|
// still not optimal.
|
2010-03-28 18:58:01 +00:00
|
|
|
for (AttachedMeshIter iter = AttachChildren.begin(); iter != AttachChildren.end(); ++iter)
|
|
|
|
if ((*iter)->OwnChild)
|
2010-01-29 21:18:18 +00:00
|
|
|
(*iter)->Child->SetFaceOrdering(ordering);
|
2010-01-06 01:28:49 +00:00
|
|
|
}
|
2009-07-10 19:57:11 +00:00
|
|
|
}
|
|
|
|
|
2010-06-08 22:55:34 +00:00
|
|
|
void StdMeshInstance::SetFaceOrderingForClrModulation(uint32_t clrmod)
|
|
|
|
{
|
|
|
|
// TODO: This could do face ordering only for non-opaque submeshes
|
|
|
|
|
|
|
|
bool opaque = true;
|
|
|
|
for(unsigned int i = 0; i < SubMeshInstances.size(); ++i)
|
|
|
|
if(!SubMeshInstances[i]->Material->IsOpaque())
|
|
|
|
{ opaque = false; break; }
|
|
|
|
|
|
|
|
if(!opaque)
|
|
|
|
SetFaceOrdering(FO_FarthestToNearest);
|
|
|
|
else if( ((clrmod >> 24) & 0xff) != 0xff)
|
|
|
|
SetFaceOrdering(FO_NearestToFarthest);
|
|
|
|
else
|
|
|
|
SetFaceOrdering(FO_Fixed);
|
|
|
|
}
|
|
|
|
|
2010-01-22 18:27:02 +00:00
|
|
|
StdMeshInstance::AnimationNode* StdMeshInstance::PlayAnimation(const StdStrBuf& animation_name, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight)
|
2009-07-12 14:27:04 +00:00
|
|
|
{
|
2011-08-19 22:01:08 +00:00
|
|
|
const StdMeshAnimation* animation = Mesh->GetAnimationByName(animation_name);
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!animation) { delete position; delete weight; return NULL; }
|
2010-01-22 18:27:02 +00:00
|
|
|
|
|
|
|
return PlayAnimation(*animation, slot, sibling, position, weight);
|
2009-12-30 20:41:56 +00:00
|
|
|
}
|
|
|
|
|
2010-01-22 18:27:02 +00:00
|
|
|
StdMeshInstance::AnimationNode* StdMeshInstance::PlayAnimation(const StdMeshAnimation& animation, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight)
|
2009-12-30 20:41:56 +00:00
|
|
|
{
|
2010-01-22 18:27:02 +00:00
|
|
|
// Default
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!sibling) sibling = GetRootAnimationForSlot(slot);
|
2010-01-22 18:27:02 +00:00
|
|
|
assert(!sibling || sibling->Slot == slot);
|
|
|
|
|
|
|
|
// Find two subsequent numbers in case we need to create two nodes, so
|
|
|
|
// script can deduce the second node.
|
|
|
|
unsigned int Number1, Number2;
|
2010-03-28 18:58:01 +00:00
|
|
|
for (Number1 = 0; Number1 < AnimationNodes.size(); ++Number1)
|
|
|
|
if (AnimationNodes[Number1] == NULL && (!sibling || Number1+1 == AnimationNodes.size() || AnimationNodes[Number1+1] == NULL))
|
2010-01-22 18:27:02 +00:00
|
|
|
break;
|
2010-03-28 18:58:01 +00:00
|
|
|
/* for(Number2 = Number1+1; Number2 < AnimationNodes.size(); ++Number2)
|
|
|
|
if(AnimationNodes[Number2] == NULL)
|
|
|
|
break;*/
|
2010-01-22 18:27:02 +00:00
|
|
|
Number2 = Number1 + 1;
|
2009-12-30 20:41:56 +00:00
|
|
|
|
2010-02-02 18:25:51 +00:00
|
|
|
position->Value = BoundBy(position->Value, Fix0, ftofix(animation.Length));
|
|
|
|
weight->Value = BoundBy(weight->Value, Fix0, itofix(1));
|
2010-01-29 21:18:18 +00:00
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
if (Number1 == AnimationNodes.size()) AnimationNodes.push_back( (StdMeshInstance::AnimationNode*) NULL);
|
|
|
|
if (sibling && Number2 == AnimationNodes.size()) AnimationNodes.push_back( (StdMeshInstance::AnimationNode*) NULL);
|
2010-01-06 01:11:56 +00:00
|
|
|
|
2010-01-22 18:27:02 +00:00
|
|
|
AnimationNode* child = new AnimationNode(&animation, position);
|
|
|
|
AnimationNodes[Number1] = child;
|
|
|
|
child->Number = Number1;
|
|
|
|
child->Slot = slot;
|
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
if (sibling)
|
2010-01-22 18:27:02 +00:00
|
|
|
{
|
|
|
|
AnimationNode* parent = new AnimationNode(child, sibling, weight);
|
|
|
|
AnimationNodes[Number2] = parent;
|
|
|
|
parent->Number = Number2;
|
|
|
|
parent->Slot = slot;
|
|
|
|
|
|
|
|
child->Parent = parent;
|
|
|
|
parent->Parent = sibling->Parent;
|
|
|
|
parent->LinearInterpolation.ChildLeft = sibling;
|
|
|
|
parent->LinearInterpolation.ChildRight = child;
|
2010-03-28 18:58:01 +00:00
|
|
|
if (sibling->Parent)
|
2010-01-22 18:27:02 +00:00
|
|
|
{
|
2010-03-28 18:58:01 +00:00
|
|
|
if (sibling->Parent->LinearInterpolation.ChildLeft == sibling)
|
2010-01-22 18:27:02 +00:00
|
|
|
sibling->Parent->LinearInterpolation.ChildLeft = parent;
|
|
|
|
else
|
|
|
|
sibling->Parent->LinearInterpolation.ChildRight = parent;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2010-01-22 18:27:02 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// set new parent
|
|
|
|
AnimationNodeList::iterator iter = GetStackIterForSlot(slot, false);
|
|
|
|
// slot must not be empty, since sibling uses same slot
|
|
|
|
assert(iter != AnimationStack.end() && *iter != NULL);
|
|
|
|
*iter = parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
sibling->Parent = parent;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
delete weight;
|
|
|
|
AnimationNodeList::iterator iter = GetStackIterForSlot(slot, true);
|
|
|
|
assert(!*iter); // we have a sibling if slot is not empty
|
|
|
|
*iter = child;
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
|
2010-01-06 01:11:56 +00:00
|
|
|
BoneTransformsDirty = true;
|
2010-01-22 18:27:02 +00:00
|
|
|
return child;
|
2009-07-12 14:27:04 +00:00
|
|
|
}
|
|
|
|
|
2010-01-22 18:27:02 +00:00
|
|
|
void StdMeshInstance::StopAnimation(AnimationNode* node)
|
2009-07-10 19:57:11 +00:00
|
|
|
{
|
2010-01-22 18:27:02 +00:00
|
|
|
ClearAnimationListRecursively(AnimationNodes, node);
|
2009-07-10 19:57:11 +00:00
|
|
|
|
2010-01-22 18:27:02 +00:00
|
|
|
AnimationNode* parent = node->Parent;
|
2010-03-28 18:58:01 +00:00
|
|
|
if (parent == NULL)
|
2010-01-22 18:27:02 +00:00
|
|
|
{
|
|
|
|
AnimationNodeList::iterator iter = GetStackIterForSlot(node->Slot, false);
|
|
|
|
assert(iter != AnimationStack.end() && *iter == node);
|
|
|
|
AnimationStack.erase(iter);
|
|
|
|
delete node;
|
|
|
|
}
|
|
|
|
else
|
2009-12-30 20:41:56 +00:00
|
|
|
{
|
2010-01-22 18:27:02 +00:00
|
|
|
assert(parent->Type == AnimationNode::LinearInterpolationNode);
|
|
|
|
|
|
|
|
// Remove parent interpolation node and re-link
|
|
|
|
AnimationNode* other_child;
|
2010-03-28 18:58:01 +00:00
|
|
|
if (parent->LinearInterpolation.ChildLeft == node)
|
2009-12-30 20:41:56 +00:00
|
|
|
{
|
2010-01-22 18:27:02 +00:00
|
|
|
other_child = parent->LinearInterpolation.ChildRight;
|
|
|
|
parent->LinearInterpolation.ChildRight = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
other_child = parent->LinearInterpolation.ChildLeft;
|
|
|
|
parent->LinearInterpolation.ChildLeft = NULL;
|
|
|
|
}
|
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
if (parent->Parent)
|
2010-01-22 18:27:02 +00:00
|
|
|
{
|
|
|
|
assert(parent->Parent->Type == AnimationNode::LinearInterpolationNode);
|
2010-03-28 18:58:01 +00:00
|
|
|
if (parent->Parent->LinearInterpolation.ChildLeft == parent)
|
2010-01-22 18:27:02 +00:00
|
|
|
parent->Parent->LinearInterpolation.ChildLeft = other_child;
|
|
|
|
else
|
|
|
|
parent->Parent->LinearInterpolation.ChildRight = other_child;
|
|
|
|
other_child->Parent = parent->Parent;
|
2009-12-30 20:41:56 +00:00
|
|
|
}
|
2010-01-22 18:27:02 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
AnimationNodeList::iterator iter = GetStackIterForSlot(node->Slot, false);
|
|
|
|
assert(iter != AnimationStack.end() && *iter == parent);
|
|
|
|
*iter = other_child;
|
|
|
|
|
|
|
|
other_child->Parent = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
AnimationNodes[parent->Number] = NULL;
|
|
|
|
// Recursively deletes parent and its descendants
|
|
|
|
delete parent;
|
2009-12-30 20:41:56 +00:00
|
|
|
}
|
2009-07-10 19:57:11 +00:00
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
while (!AnimationNodes.empty() && AnimationNodes.back() == NULL)
|
2010-01-22 18:27:02 +00:00
|
|
|
AnimationNodes.erase(AnimationNodes.end()-1);
|
|
|
|
BoneTransformsDirty = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshInstance::AnimationNode* StdMeshInstance::GetAnimationNodeByNumber(unsigned int number)
|
|
|
|
{
|
2010-03-28 18:58:01 +00:00
|
|
|
if (number >= AnimationNodes.size()) return NULL;
|
2010-01-22 18:27:02 +00:00
|
|
|
return AnimationNodes[number];
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshInstance::AnimationNode* StdMeshInstance::GetRootAnimationForSlot(int slot)
|
|
|
|
{
|
|
|
|
AnimationNodeList::iterator iter = GetStackIterForSlot(slot, false);
|
2010-03-28 18:58:01 +00:00
|
|
|
if (iter == AnimationStack.end()) return NULL;
|
2010-01-22 18:27:02 +00:00
|
|
|
return *iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
void StdMeshInstance::SetAnimationPosition(AnimationNode* node, ValueProvider* position)
|
|
|
|
{
|
|
|
|
assert(node->GetType() == AnimationNode::LeafNode);
|
|
|
|
delete node->Leaf.Position;
|
|
|
|
node->Leaf.Position = position;
|
|
|
|
|
2010-02-06 10:34:53 +00:00
|
|
|
position->Value = BoundBy(position->Value, Fix0, ftofix(node->Leaf.Animation->Length));
|
|
|
|
|
2010-01-22 18:27:02 +00:00
|
|
|
BoneTransformsDirty = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void StdMeshInstance::SetAnimationWeight(AnimationNode* node, ValueProvider* weight)
|
|
|
|
{
|
|
|
|
assert(node->GetType() == AnimationNode::LinearInterpolationNode);
|
|
|
|
delete node->LinearInterpolation.Weight; node->LinearInterpolation.Weight = weight;
|
|
|
|
|
2010-02-06 10:34:53 +00:00
|
|
|
weight->Value = BoundBy(weight->Value, Fix0, itofix(1));
|
|
|
|
|
2010-01-22 18:27:02 +00:00
|
|
|
BoneTransformsDirty = true;
|
|
|
|
}
|
|
|
|
|
2010-03-16 22:31:53 +00:00
|
|
|
void StdMeshInstance::ExecuteAnimation(float dt)
|
2010-01-22 18:27:02 +00:00
|
|
|
{
|
2011-08-19 22:01:08 +00:00
|
|
|
// Iterate from the back since slots might be removed
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int i = AnimationStack.size(); i > 0; --i)
|
2011-08-19 22:01:08 +00:00
|
|
|
if(!ExecuteAnimationNode(AnimationStack[i-1]))
|
|
|
|
StopAnimation(AnimationStack[i-1]);
|
2010-01-27 20:03:24 +00:00
|
|
|
|
2010-03-16 22:31:53 +00:00
|
|
|
// Update animated textures
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int i = 0; i < SubMeshInstances.size(); ++i)
|
2010-03-16 22:31:53 +00:00
|
|
|
{
|
|
|
|
StdSubMeshInstance& submesh = *SubMeshInstances[i];
|
|
|
|
const StdMeshMaterial& material = submesh.GetMaterial();
|
|
|
|
const StdMeshMaterialTechnique& technique = material.Techniques[material.BestTechniqueIndex];
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int j = 0; j < submesh.PassData.size(); ++j)
|
2010-03-16 22:31:53 +00:00
|
|
|
{
|
|
|
|
StdSubMeshInstance::Pass& pass = submesh.PassData[j];
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int k = 0; k < pass.TexUnits.size(); ++k)
|
2010-03-16 22:31:53 +00:00
|
|
|
{
|
|
|
|
const StdMeshMaterialTextureUnit& texunit = technique.Passes[j].TextureUnits[k];
|
2010-03-17 19:19:14 +00:00
|
|
|
StdSubMeshInstance::TexUnit& texunit_instance = submesh.PassData[j].TexUnits[k];
|
2010-03-28 18:58:01 +00:00
|
|
|
if (texunit.HasFrameAnimation())
|
2010-03-16 22:31:53 +00:00
|
|
|
{
|
|
|
|
const unsigned int NumPhases = texunit.GetNumTextures();
|
|
|
|
const float PhaseDuration = texunit.Duration / NumPhases;
|
|
|
|
|
|
|
|
const float Position = texunit_instance.PhaseDelay + dt;
|
|
|
|
const unsigned int AddPhases = static_cast<unsigned int>(Position / PhaseDuration);
|
|
|
|
|
|
|
|
texunit_instance.Phase = (texunit_instance.Phase + AddPhases) % NumPhases;
|
|
|
|
texunit_instance.PhaseDelay = Position - AddPhases * PhaseDuration;
|
|
|
|
}
|
2010-03-17 19:19:14 +00:00
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
if (texunit.HasTexCoordAnimation())
|
2010-03-17 19:19:14 +00:00
|
|
|
texunit_instance.Position += dt;
|
2010-03-16 22:31:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-27 20:03:24 +00:00
|
|
|
// Update animation for attached meshes
|
2010-03-28 18:58:01 +00:00
|
|
|
for (AttachedMeshList::iterator iter = AttachChildren.begin(); iter != AttachChildren.end(); ++iter)
|
2010-03-16 22:31:53 +00:00
|
|
|
(*iter)->Child->ExecuteAnimation(dt);
|
2009-07-10 19:57:11 +00:00
|
|
|
}
|
|
|
|
|
2010-08-31 21:44:56 +00:00
|
|
|
StdMeshInstance::AttachedMesh* StdMeshInstance::AttachMesh(const StdMesh& mesh, AttachedMesh::Denumerator* denumerator, const StdStrBuf& parent_bone, const StdStrBuf& child_bone, const StdMeshMatrix& transformation, uint32_t flags)
|
2010-01-10 21:02:40 +00:00
|
|
|
{
|
2010-01-29 21:18:18 +00:00
|
|
|
StdMeshInstance* instance = new StdMeshInstance(mesh);
|
|
|
|
instance->SetFaceOrdering(CurrentFaceOrdering);
|
2010-08-31 21:44:56 +00:00
|
|
|
AttachedMesh* attach = AttachMesh(*instance, denumerator, parent_bone, child_bone, transformation, flags, true);
|
2010-04-01 21:00:05 +00:00
|
|
|
if (!attach) { delete instance; delete denumerator; return NULL; }
|
2010-01-29 21:18:18 +00:00
|
|
|
return attach;
|
|
|
|
}
|
|
|
|
|
2010-08-31 21:44:56 +00:00
|
|
|
StdMeshInstance::AttachedMesh* StdMeshInstance::AttachMesh(StdMeshInstance& instance, AttachedMesh::Denumerator* denumerator, const StdStrBuf& parent_bone, const StdStrBuf& child_bone, const StdMeshMatrix& transformation, uint32_t flags, bool own_child)
|
2010-01-29 21:18:18 +00:00
|
|
|
{
|
2010-04-01 21:00:05 +00:00
|
|
|
std::auto_ptr<AttachedMesh::Denumerator> auto_denumerator(denumerator);
|
|
|
|
|
2010-01-29 21:18:18 +00:00
|
|
|
// We don't allow an instance to be attached to multiple parent instances for now
|
2010-03-28 18:58:01 +00:00
|
|
|
if (instance.AttachParent) return NULL;
|
2010-01-29 21:18:18 +00:00
|
|
|
|
|
|
|
// Make sure there are no cyclic attachments
|
2010-03-28 18:58:01 +00:00
|
|
|
for (StdMeshInstance* Parent = this; Parent->AttachParent != NULL; Parent = Parent->AttachParent->Parent)
|
|
|
|
if (Parent == &instance)
|
2010-01-29 21:18:18 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
AttachedMesh* attach = NULL;
|
|
|
|
unsigned int number = 1;
|
2010-01-10 21:02:40 +00:00
|
|
|
|
|
|
|
// Find free index.
|
2010-03-28 18:58:01 +00:00
|
|
|
for (AttachedMeshIter iter = AttachChildren.begin(); iter != AttachChildren.end(); ++iter)
|
|
|
|
if ((*iter)->Number >= number)
|
2010-01-29 21:18:18 +00:00
|
|
|
number = (*iter)->Number + 1;
|
2010-01-10 21:02:40 +00:00
|
|
|
|
2011-08-19 22:01:08 +00:00
|
|
|
const StdMeshBone* parent_bone_obj = Mesh->GetBoneByName(parent_bone);
|
|
|
|
const StdMeshBone* child_bone_obj = instance.Mesh->GetBoneByName(child_bone);
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!parent_bone_obj || !child_bone_obj) return NULL;
|
2010-01-10 21:02:40 +00:00
|
|
|
|
2010-01-29 21:18:18 +00:00
|
|
|
// TODO: Face Ordering is not lined up... can't do that properly here
|
2010-08-31 21:44:56 +00:00
|
|
|
attach = new AttachedMesh(number, this, &instance, own_child, auto_denumerator.release(), parent_bone_obj->Index, child_bone_obj->Index, transformation, flags);
|
2010-01-29 21:18:18 +00:00
|
|
|
instance.AttachParent = attach;
|
2010-08-31 21:44:56 +00:00
|
|
|
|
|
|
|
// If DrawInFront is set then sort before others so that drawing order is easy
|
|
|
|
if(flags & AM_DrawBefore)
|
|
|
|
AttachChildren.insert(AttachChildren.begin(), attach);
|
|
|
|
else
|
|
|
|
AttachChildren.insert(AttachChildren.end(), attach);
|
2010-01-29 21:18:18 +00:00
|
|
|
|
|
|
|
return attach;
|
2010-01-10 21:02:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool StdMeshInstance::DetachMesh(unsigned int number)
|
|
|
|
{
|
2010-03-28 18:58:01 +00:00
|
|
|
for (AttachedMeshList::iterator iter = AttachChildren.begin(); iter != AttachChildren.end(); ++iter)
|
2010-01-10 21:02:40 +00:00
|
|
|
{
|
2010-03-28 18:58:01 +00:00
|
|
|
if ((*iter)->Number == number)
|
2010-01-10 21:02:40 +00:00
|
|
|
{
|
2010-01-29 21:18:18 +00:00
|
|
|
// Reset attach parent of child so it does not try
|
|
|
|
// to detach itself on destruction.
|
|
|
|
(*iter)->Child->AttachParent = NULL;
|
|
|
|
|
|
|
|
delete *iter;
|
2010-01-10 21:02:40 +00:00
|
|
|
AttachChildren.erase(iter);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-01-29 21:18:18 +00:00
|
|
|
StdMeshInstance::AttachedMesh* StdMeshInstance::GetAttachedMeshByNumber(unsigned int number) const
|
2010-01-10 21:02:40 +00:00
|
|
|
{
|
2010-03-28 18:58:01 +00:00
|
|
|
for (AttachedMeshIter iter = AttachChildren.begin(); iter != AttachChildren.end(); ++iter)
|
|
|
|
if ((*iter)->Number == number)
|
2010-01-29 21:18:18 +00:00
|
|
|
return *iter;
|
2010-01-10 21:02:40 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-06-08 22:55:34 +00:00
|
|
|
bool StdMeshInstance::UpdateBoneTransforms()
|
2009-07-10 19:57:11 +00:00
|
|
|
{
|
2010-06-08 22:55:34 +00:00
|
|
|
bool was_dirty = BoneTransformsDirty;
|
|
|
|
|
2010-01-06 01:11:56 +00:00
|
|
|
// Nothing changed since last time
|
2010-03-28 18:58:01 +00:00
|
|
|
if (BoneTransformsDirty)
|
2009-08-01 19:36:13 +00:00
|
|
|
{
|
2010-01-29 21:18:18 +00:00
|
|
|
// Compute transformation matrix for each bone.
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int i = 0; i < BoneTransforms.size(); ++i)
|
2010-01-29 21:18:18 +00:00
|
|
|
{
|
|
|
|
StdMeshTransformation Transformation;
|
2010-01-22 18:27:02 +00:00
|
|
|
|
2011-08-19 22:01:08 +00:00
|
|
|
const StdMeshBone& bone = Mesh->GetBone(i);
|
2010-01-29 21:18:18 +00:00
|
|
|
const StdMeshBone* parent = bone.GetParent();
|
|
|
|
assert(!parent || parent->Index < i);
|
2009-12-30 20:41:56 +00:00
|
|
|
|
2010-01-29 21:18:18 +00:00
|
|
|
bool have_transform = false;
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int j = 0; j < AnimationStack.size(); ++j)
|
2010-01-29 21:18:18 +00:00
|
|
|
{
|
2010-03-28 18:58:01 +00:00
|
|
|
if (have_transform)
|
2010-01-29 21:18:18 +00:00
|
|
|
{
|
|
|
|
StdMeshTransformation other;
|
2010-03-28 18:58:01 +00:00
|
|
|
if (AnimationStack[j]->GetBoneTransform(i, other))
|
2010-01-29 21:18:18 +00:00
|
|
|
Transformation = StdMeshTransformation::Nlerp(Transformation, other, 1.0f); // TODO: Allow custom weighing for slot combination
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
have_transform = AnimationStack[j]->GetBoneTransform(i, Transformation);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!have_transform)
|
2009-08-01 19:36:13 +00:00
|
|
|
{
|
2010-03-28 18:58:01 +00:00
|
|
|
if (parent)
|
2010-01-29 21:18:18 +00:00
|
|
|
BoneTransforms[i] = BoneTransforms[parent->Index];
|
|
|
|
else
|
|
|
|
BoneTransforms[i] = StdMeshMatrix::Identity();
|
2010-01-22 18:27:02 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-01-29 21:18:18 +00:00
|
|
|
BoneTransforms[i] = StdMeshMatrix::Transform(bone.Transformation * Transformation * bone.InverseTransformation);
|
2010-03-28 18:58:01 +00:00
|
|
|
if (parent) BoneTransforms[i] = BoneTransforms[parent->Index] * BoneTransforms[i];
|
2009-08-01 19:36:13 +00:00
|
|
|
}
|
|
|
|
}
|
2009-12-30 16:47:55 +00:00
|
|
|
|
2010-01-29 21:18:18 +00:00
|
|
|
// Compute transformation for each vertex. We could later think about
|
|
|
|
// doing this on the GPU using a vertex shader. This would then probably
|
|
|
|
// need to go to CStdGL::PerformMesh and CStdD3D::PerformMesh.
|
|
|
|
// (can only work for fixed face ordering though)
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int i = 0; i < SubMeshInstances.size(); ++i)
|
2010-01-05 21:35:30 +00:00
|
|
|
{
|
2011-08-19 22:01:08 +00:00
|
|
|
const StdSubMesh& submesh = Mesh->GetSubMesh(i);
|
2010-03-16 22:31:53 +00:00
|
|
|
std::vector<StdMeshVertex>& instance_vertices = SubMeshInstances[i]->Vertices;
|
2010-01-29 21:18:18 +00:00
|
|
|
assert(submesh.GetNumVertices() == instance_vertices.size());
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int j = 0; j < instance_vertices.size(); ++j)
|
2010-01-11 23:54:36 +00:00
|
|
|
{
|
2010-01-29 21:18:18 +00:00
|
|
|
const StdSubMesh::Vertex& vertex = submesh.GetVertex(j);
|
|
|
|
StdMeshVertex& instance_vertex = instance_vertices[j];
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!vertex.BoneAssignments.empty())
|
2010-01-11 23:54:36 +00:00
|
|
|
{
|
2010-01-29 21:18:18 +00:00
|
|
|
instance_vertex.x = instance_vertex.y = instance_vertex.z = 0.0f;
|
|
|
|
instance_vertex.nx = instance_vertex.ny = instance_vertex.nz = 0.0f;
|
|
|
|
instance_vertex.u = vertex.u; instance_vertex.v = vertex.v;
|
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
for (unsigned int k = 0; k < vertex.BoneAssignments.size(); ++k)
|
2010-01-29 21:18:18 +00:00
|
|
|
{
|
|
|
|
const StdMeshVertexBoneAssignment& assignment = vertex.BoneAssignments[k];
|
2009-08-01 19:36:13 +00:00
|
|
|
|
2010-01-29 21:18:18 +00:00
|
|
|
instance_vertex += assignment.Weight * (BoneTransforms[assignment.BoneIndex] * vertex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
instance_vertex = vertex;
|
2010-01-11 23:54:36 +00:00
|
|
|
}
|
2009-08-01 19:36:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-22 18:27:02 +00:00
|
|
|
// Update attachment's attach transformations. Note this is done recursively.
|
2010-03-28 18:58:01 +00:00
|
|
|
for (AttachedMeshList::iterator iter = AttachChildren.begin(); iter != AttachChildren.end(); ++iter)
|
2010-01-10 21:02:40 +00:00
|
|
|
{
|
2010-01-29 21:18:18 +00:00
|
|
|
AttachedMesh* attach = *iter;
|
|
|
|
const bool ChildBoneTransformsDirty = attach->Child->BoneTransformsDirty;
|
|
|
|
attach->Child->UpdateBoneTransforms();
|
2010-01-10 21:02:40 +00:00
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
if (BoneTransformsDirty || ChildBoneTransformsDirty || attach->FinalTransformDirty)
|
2010-01-29 21:18:18 +00:00
|
|
|
{
|
2010-06-08 22:55:34 +00:00
|
|
|
was_dirty = true;
|
|
|
|
|
2010-01-29 21:18:18 +00:00
|
|
|
// Compute matrix to change the coordinate system to the one of the attached bone:
|
|
|
|
// The idea is that a vertex at the child bone's position transforms to the parent bone's position.
|
|
|
|
// Therefore (read from right to left) we first apply the inverse of the child bone transformation,
|
|
|
|
// then an optional scaling matrix, and finally the parent bone transformation
|
|
|
|
|
|
|
|
// TODO: we can cache the three matrices in the middle since they don't change over time,
|
|
|
|
// reducing this to two matrix multiplications instead of four each frame.
|
|
|
|
// Might even be worth to compute the complete transformation directly when rendering then
|
|
|
|
// (saves per-instance memory, but requires recomputation if the animation does not change).
|
|
|
|
// TODO: We might also be able to cache child inverse, and only recomupte it if
|
|
|
|
// child bone transforms are dirty (saves matrix inversion for unanimated attach children).
|
|
|
|
attach->FinalTrans = BoneTransforms[attach->ParentBone]
|
2011-08-19 22:01:08 +00:00
|
|
|
* StdMeshMatrix::Transform(Mesh->GetBone(attach->ParentBone).Transformation)
|
2010-03-28 18:58:01 +00:00
|
|
|
* attach->AttachTrans
|
2011-08-19 22:01:08 +00:00
|
|
|
* StdMeshMatrix::Transform(attach->Child->Mesh->GetBone(attach->ChildBone).InverseTransformation)
|
2010-03-28 18:58:01 +00:00
|
|
|
* StdMeshMatrix::Inverse(attach->Child->BoneTransforms[attach->ChildBone]);
|
|
|
|
|
2010-01-29 21:18:18 +00:00
|
|
|
attach->FinalTransformDirty = false;
|
|
|
|
}
|
|
|
|
}
|
2010-01-06 01:11:56 +00:00
|
|
|
|
|
|
|
BoneTransformsDirty = false;
|
2010-06-08 22:55:34 +00:00
|
|
|
return was_dirty;
|
|
|
|
}
|
|
|
|
|
|
|
|
void StdMeshInstance::ReorderFaces(StdMeshMatrix* global_trans)
|
|
|
|
{
|
|
|
|
if(CurrentFaceOrdering != FO_Fixed)
|
|
|
|
{
|
|
|
|
for (unsigned int i = 0; i < SubMeshInstances.size(); ++i)
|
|
|
|
{
|
|
|
|
StdMeshInstanceFaceOrderingCmpPred pred(*this, i, global_trans ? *global_trans : StdMeshMatrix::Identity());
|
|
|
|
std::sort(SubMeshInstances[i]->Faces.begin(), SubMeshInstances[i]->Faces.end(), pred);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Also reorder submeshes, attached meshes and include AttachTransformation for attached meshes...
|
2009-07-23 23:52:18 +00:00
|
|
|
}
|
|
|
|
|
2010-04-01 21:00:05 +00:00
|
|
|
void StdMeshInstance::CompileFunc(StdCompiler* pComp, AttachedMesh::DenumeratorFactoryFunc Factory)
|
|
|
|
{
|
|
|
|
if(pComp->isCompiler())
|
|
|
|
{
|
|
|
|
// Only initially created instances can be compiled
|
|
|
|
assert(!AttachParent);
|
|
|
|
assert(AttachChildren.empty());
|
|
|
|
assert(AnimationStack.empty());
|
|
|
|
BoneTransformsDirty = true;
|
|
|
|
|
2011-06-05 12:12:02 +00:00
|
|
|
bool valid;
|
|
|
|
pComp->Value(mkNamingAdapt(valid, "Valid"));
|
|
|
|
if(!valid) pComp->excCorrupt("Mesh instance is invalid");
|
|
|
|
|
2010-04-01 21:00:05 +00:00
|
|
|
int32_t iAnimCnt = AnimationStack.size();
|
|
|
|
pComp->Value(mkNamingCountAdapt(iAnimCnt, "AnimationNode"));
|
|
|
|
|
|
|
|
for(int32_t i = 0; i < iAnimCnt; ++i)
|
|
|
|
{
|
|
|
|
AnimationNode* node = NULL;
|
2011-08-19 22:01:08 +00:00
|
|
|
pComp->Value(mkParAdapt(mkNamingPtrAdapt(node, "AnimationNode"), Mesh));
|
2010-04-01 21:00:05 +00:00
|
|
|
AnimationNodeList::iterator iter = GetStackIterForSlot(node->Slot, true);
|
|
|
|
if(*iter != NULL) { delete node; pComp->excCorrupt("Duplicate animation slot index"); }
|
|
|
|
*iter = node;
|
|
|
|
|
|
|
|
// Add nodes into lookup table
|
|
|
|
std::vector<AnimationNode*> nodes(1, node);
|
|
|
|
while(!nodes.empty())
|
|
|
|
{
|
|
|
|
node = nodes.back();
|
|
|
|
nodes.erase(nodes.end()-1);
|
|
|
|
|
2011-03-30 23:25:27 +00:00
|
|
|
if (AnimationNodes.size() <= node->Number)
|
|
|
|
AnimationNodes.resize(node->Number+1);
|
2010-04-01 21:00:05 +00:00
|
|
|
if(AnimationNodes[node->Number] != NULL) pComp->excCorrupt("Duplicate animation node number");
|
|
|
|
AnimationNodes[node->Number] = node;
|
|
|
|
|
|
|
|
if(node->Type == AnimationNode::LinearInterpolationNode)
|
|
|
|
{
|
|
|
|
nodes.push_back(node->LinearInterpolation.ChildLeft);
|
|
|
|
nodes.push_back(node->LinearInterpolation.ChildRight);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t iAttachedCnt;
|
|
|
|
pComp->Value(mkNamingCountAdapt(iAttachedCnt, "Attached"));
|
|
|
|
|
|
|
|
for(int32_t i = 0; i < iAttachedCnt; ++i)
|
|
|
|
{
|
|
|
|
AttachChildren.push_back(new AttachedMesh);
|
|
|
|
AttachedMesh* attach = AttachChildren.back();
|
|
|
|
|
|
|
|
attach->Parent = this;
|
|
|
|
pComp->Value(mkNamingAdapt(mkParAdapt(*attach, Factory), "Attached"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-06-05 12:12:02 +00:00
|
|
|
// Write something to make sure that the parent
|
|
|
|
// named section ([Mesh] or [ChildInstance]) is written.
|
|
|
|
// StdCompilerIni does not make a difference between
|
|
|
|
// non-existing and empty named sections.
|
|
|
|
bool valid = true;
|
|
|
|
pComp->Value(mkNamingAdapt(valid, "Valid"));
|
|
|
|
|
2010-04-01 21:00:05 +00:00
|
|
|
int32_t iAnimCnt = AnimationStack.size();
|
|
|
|
pComp->Value(mkNamingCountAdapt(iAnimCnt, "AnimationNode"));
|
|
|
|
|
|
|
|
for(AnimationNodeList::iterator iter = AnimationStack.begin(); iter != AnimationStack.end(); ++iter)
|
2011-08-19 22:01:08 +00:00
|
|
|
pComp->Value(mkParAdapt(mkNamingPtrAdapt(*iter, "AnimationNode"), Mesh));
|
2010-04-01 21:00:05 +00:00
|
|
|
|
|
|
|
int32_t iAttachedCnt = AttachChildren.size();
|
|
|
|
pComp->Value(mkNamingCountAdapt(iAttachedCnt, "Attached"));
|
|
|
|
|
|
|
|
for(unsigned int i = 0; i < AttachChildren.size(); ++i)
|
|
|
|
pComp->Value(mkNamingAdapt(mkParAdapt(*AttachChildren[i], Factory), "Attached"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void StdMeshInstance::DenumeratePointers()
|
|
|
|
{
|
|
|
|
for(unsigned int i = 0; i < AnimationNodes.size(); ++i)
|
|
|
|
if(AnimationNodes[i])
|
|
|
|
AnimationNodes[i]->DenumeratePointers();
|
|
|
|
|
|
|
|
for(unsigned int i = 0; i < AttachChildren.size(); ++i)
|
|
|
|
AttachChildren[i]->DenumeratePointers();
|
|
|
|
}
|
|
|
|
|
2010-01-22 18:27:02 +00:00
|
|
|
StdMeshInstance::AnimationNodeList::iterator StdMeshInstance::GetStackIterForSlot(int slot, bool create)
|
|
|
|
{
|
|
|
|
// TODO: bsearch
|
2010-03-28 18:58:01 +00:00
|
|
|
for (AnimationNodeList::iterator iter = AnimationStack.begin(); iter != AnimationStack.end(); ++iter)
|
2010-01-22 18:27:02 +00:00
|
|
|
{
|
2010-03-28 18:58:01 +00:00
|
|
|
if ((*iter)->Slot == slot)
|
2010-01-22 18:27:02 +00:00
|
|
|
{
|
|
|
|
return iter;
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
else if ((*iter)->Slot > slot)
|
2010-01-22 18:27:02 +00:00
|
|
|
{
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!create)
|
2010-01-22 18:27:02 +00:00
|
|
|
return AnimationStack.end();
|
|
|
|
else
|
2010-01-24 01:48:55 +00:00
|
|
|
return AnimationStack.insert(iter, NULL);
|
2010-01-22 18:27:02 +00:00
|
|
|
}
|
|
|
|
}
|
2010-01-23 13:15:56 +00:00
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!create)
|
2010-01-22 18:27:02 +00:00
|
|
|
return AnimationStack.end();
|
|
|
|
else
|
2010-01-24 01:48:55 +00:00
|
|
|
return AnimationStack.insert(AnimationStack.end(), NULL);
|
2010-01-22 18:27:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool StdMeshInstance::ExecuteAnimationNode(AnimationNode* node)
|
|
|
|
{
|
|
|
|
ValueProvider* provider = NULL;
|
2010-05-04 15:35:18 +00:00
|
|
|
C4Real min;
|
|
|
|
C4Real max;
|
2010-01-27 21:03:26 +00:00
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
switch (node->GetType())
|
2010-01-22 18:27:02 +00:00
|
|
|
{
|
|
|
|
case AnimationNode::LeafNode:
|
|
|
|
provider = node->GetPositionProvider();
|
2010-02-02 18:25:51 +00:00
|
|
|
min = Fix0;
|
|
|
|
max = ftofix(node->GetAnimation()->Length);
|
2010-01-22 18:27:02 +00:00
|
|
|
break;
|
|
|
|
case AnimationNode::LinearInterpolationNode:
|
|
|
|
provider = node->GetWeightProvider();
|
2010-02-02 18:25:51 +00:00
|
|
|
min = Fix0;
|
|
|
|
max = itofix(1);
|
2010-01-22 18:27:02 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-05-04 15:35:18 +00:00
|
|
|
const C4Real old_value = provider->Value;
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!provider->Execute())
|
2010-01-22 18:27:02 +00:00
|
|
|
{
|
2010-03-28 18:58:01 +00:00
|
|
|
if (node->GetType() == AnimationNode::LeafNode) return false;
|
2010-01-22 18:27:02 +00:00
|
|
|
|
|
|
|
// Remove the child with less weight (normally weight reaches 0.0 or 1.0)
|
2010-03-28 18:58:01 +00:00
|
|
|
if (node->GetWeight() > itofix(1, 2))
|
2010-01-22 18:27:02 +00:00
|
|
|
{
|
|
|
|
// Remove both children (by parent) if other wants to be deleted as well
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!ExecuteAnimationNode(node->GetRightChild())) return false;
|
2010-01-22 18:27:02 +00:00
|
|
|
// Remove left child as it has less weight
|
|
|
|
StopAnimation(node->LinearInterpolation.ChildLeft);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Remove both children (by parent) if other wants to be deleted as well
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!ExecuteAnimationNode(node->GetLeftChild())) return false;
|
2010-01-22 18:27:02 +00:00
|
|
|
// Remove right child as it has less weight
|
|
|
|
StopAnimation(node->LinearInterpolation.ChildRight);
|
|
|
|
}
|
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
|
2010-01-22 18:27:02 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-03-28 18:58:01 +00:00
|
|
|
if (provider->Value != old_value)
|
2010-01-27 21:03:26 +00:00
|
|
|
{
|
|
|
|
provider->Value = BoundBy(provider->Value, min, max);
|
|
|
|
BoneTransformsDirty = true;
|
|
|
|
}
|
2010-01-22 18:27:02 +00:00
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
if (node->GetType() == AnimationNode::LinearInterpolationNode)
|
2010-01-22 18:27:02 +00:00
|
|
|
{
|
|
|
|
const bool left_result = ExecuteAnimationNode(node->GetLeftChild());
|
|
|
|
const bool right_result = ExecuteAnimationNode(node->GetRightChild());
|
|
|
|
|
|
|
|
// Remove this node completely
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!left_result && !right_result)
|
2010-01-22 18:27:02 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Note that either of this also removes node
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!left_result)
|
2010-01-22 18:27:02 +00:00
|
|
|
StopAnimation(node->GetLeftChild());
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!right_result)
|
2010-01-22 18:27:02 +00:00
|
|
|
StopAnimation(node->GetRightChild());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|