2004-05-30 02:46:58 +02:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Name: Model.cpp
|
|
|
|
// Author: Rich Cross
|
|
|
|
// Contact: rich@wildfiregames.com
|
|
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2004-06-03 20:38:14 +02:00
|
|
|
#include "precompiled.h"
|
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
#include "Model.h"
|
2004-12-12 20:43:55 +01:00
|
|
|
#include "ModelDef.h"
|
2004-05-30 02:46:58 +02:00
|
|
|
#include "Quaternion.h"
|
|
|
|
#include "Bound.h"
|
|
|
|
#include "SkeletonAnim.h"
|
|
|
|
#include "SkeletonAnimDef.h"
|
|
|
|
#include "SkeletonAnimManager.h"
|
2004-11-08 23:02:01 +01:00
|
|
|
#include "MeshManager.h"
|
2005-08-12 19:06:53 +02:00
|
|
|
#include "lib/res/graphics/ogl_tex.h"
|
2005-04-03 07:02:00 +02:00
|
|
|
#include "lib/res/h_mgr.h"
|
2005-05-20 19:09:47 +02:00
|
|
|
#include "Profile.h"
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2005-02-11 13:57:19 +01:00
|
|
|
#include "ps/CLogger.h"
|
|
|
|
#define LOG_CATEGORY "graphics"
|
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Constructor
|
|
|
|
CModel::CModel()
|
2005-10-26 03:03:28 +02:00
|
|
|
: m_Parent(0), m_Flags(0), m_Anim(0), m_AnimTime(0),
|
|
|
|
m_BoneMatrices(0), m_InvBoneMatrices(0),
|
|
|
|
m_PositionValid(false), m_ShadingColor(1,1,1,1)
|
2004-05-30 02:46:58 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Destructor
|
|
|
|
CModel::~CModel()
|
|
|
|
{
|
2005-10-26 03:03:28 +02:00
|
|
|
// Detach us from our parent
|
|
|
|
if (m_Parent)
|
|
|
|
{
|
|
|
|
for(std::vector<Prop>::iterator iter = m_Parent->m_Props.begin();
|
|
|
|
iter != m_Parent->m_Props.end();
|
|
|
|
++iter)
|
|
|
|
{
|
|
|
|
if (iter->m_Model == this)
|
|
|
|
{
|
|
|
|
m_Parent->m_Props.erase(iter);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_Parent = 0;
|
|
|
|
}
|
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
ReleaseData();
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ReleaseData: delete anything allocated by the model
|
|
|
|
void CModel::ReleaseData()
|
|
|
|
{
|
|
|
|
delete[] m_BoneMatrices;
|
|
|
|
delete[] m_InvBoneMatrices;
|
|
|
|
for (size_t i=0;i<m_Props.size();i++) {
|
|
|
|
delete m_Props[i].m_Model;
|
|
|
|
}
|
|
|
|
m_Props.clear();
|
2004-12-12 19:40:00 +01:00
|
|
|
m_pModelDef = CModelDefPtr();
|
2004-12-16 13:01:47 +01:00
|
|
|
|
|
|
|
Handle h = m_Texture.GetHandle();
|
2005-09-02 04:54:02 +02:00
|
|
|
ogl_tex_free(h);
|
2004-12-16 13:01:47 +01:00
|
|
|
m_Texture.SetHandle(0);
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// InitModel: setup model from given geometry
|
2004-12-12 19:40:00 +01:00
|
|
|
bool CModel::InitModel(CModelDefPtr modeldef)
|
2004-05-30 02:46:58 +02:00
|
|
|
{
|
|
|
|
// clean up any existing data first
|
|
|
|
ReleaseData();
|
|
|
|
|
|
|
|
m_pModelDef = modeldef;
|
|
|
|
|
2005-08-09 17:55:44 +02:00
|
|
|
size_t numBones=modeldef->GetNumBones();
|
|
|
|
if (numBones != 0) {
|
2004-05-30 02:46:58 +02:00
|
|
|
// allocate matrices for bone transformations
|
|
|
|
m_BoneMatrices=new CMatrix3D[numBones];
|
|
|
|
m_InvBoneMatrices=new CMatrix3D[numBones];
|
|
|
|
// store default pose until animation assigned
|
|
|
|
CBoneState* defpose=modeldef->GetBones();
|
|
|
|
for (uint i=0;i<numBones;i++) {
|
|
|
|
CMatrix3D& m=m_BoneMatrices[i];
|
|
|
|
m.SetIdentity();
|
|
|
|
m.Rotate(defpose[i].m_Rotation);
|
|
|
|
m.Translate(defpose[i].m_Translation);
|
|
|
|
m.GetInverse(m_InvBoneMatrices[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-10-26 03:03:28 +02:00
|
|
|
m_PositionValid = true;
|
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// SkinPoint: skin the given point using the given blend and matrix data
|
|
|
|
static CVector3D SkinPoint(const CVector3D& pos,const SVertexBlend& blend,
|
|
|
|
const CMatrix3D* bonestates)
|
2004-06-08 14:10:51 +02:00
|
|
|
{
|
|
|
|
CVector3D result,tmp;
|
|
|
|
|
|
|
|
// must have at least one valid bone if we're using SkinPoint
|
2005-06-28 06:06:25 +02:00
|
|
|
debug_assert(blend.m_Bone[0]!=0xff);
|
2004-06-08 14:10:51 +02:00
|
|
|
|
|
|
|
const CMatrix3D& m=bonestates[blend.m_Bone[0]];
|
|
|
|
m.Transform(pos,result);
|
|
|
|
result*=blend.m_Weight[0];
|
|
|
|
|
2004-06-07 22:00:56 +02:00
|
|
|
for (int i=1;i<SVertexBlend::SIZE && blend.m_Bone[i]!=0xff;i++) {
|
2004-06-08 14:10:51 +02:00
|
|
|
const CMatrix3D& m=bonestates[blend.m_Bone[i]];
|
2004-06-07 22:00:56 +02:00
|
|
|
m.Transform(pos,tmp);
|
2004-05-30 02:46:58 +02:00
|
|
|
result+=tmp*blend.m_Weight[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// CalcBound: calculate the world space bounds of this model
|
|
|
|
void CModel::CalcBounds()
|
|
|
|
{
|
2005-02-10 00:19:48 +01:00
|
|
|
// Need to calculate the object bounds first, if that hasn't already been done
|
|
|
|
if (! m_Anim)
|
|
|
|
CalcObjectBounds();
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (m_Anim->m_ObjectBounds.IsEmpty())
|
|
|
|
CalcAnimatedObjectBound(m_Anim->m_AnimDef, m_Anim->m_ObjectBounds);
|
2005-06-28 06:06:25 +02:00
|
|
|
debug_assert(! m_Anim->m_ObjectBounds.IsEmpty()); // (if this happens, it'll be recalculating the bounds every time)
|
2005-02-10 00:19:48 +01:00
|
|
|
m_ObjectBounds = m_Anim->m_ObjectBounds;
|
|
|
|
}
|
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
m_ObjectBounds.Transform(GetTransform(),m_Bounds);
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// CalcObjectBounds: calculate object space bounds of this model, based solely on vertex positions
|
|
|
|
void CModel::CalcObjectBounds()
|
|
|
|
{
|
|
|
|
m_ObjectBounds.SetEmpty();
|
|
|
|
|
2005-08-09 17:55:44 +02:00
|
|
|
size_t numverts=m_pModelDef->GetNumVertices();
|
2004-05-30 02:46:58 +02:00
|
|
|
SModelVertex* verts=m_pModelDef->GetVertices();
|
|
|
|
|
2005-08-09 17:55:44 +02:00
|
|
|
for (size_t i=0;i<numverts;i++) {
|
2004-05-30 02:46:58 +02:00
|
|
|
m_ObjectBounds+=verts[i].m_Coords;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// CalcAnimatedObjectBound: calculate bounds encompassing all vertex positions for given animation
|
|
|
|
void CModel::CalcAnimatedObjectBound(CSkeletonAnimDef* anim,CBound& result)
|
|
|
|
{
|
|
|
|
result.SetEmpty();
|
|
|
|
|
2005-02-10 00:19:48 +01:00
|
|
|
// Set the current animation on which to perform calculations (if it's necessary)
|
|
|
|
if (anim != m_Anim->m_AnimDef)
|
|
|
|
{
|
|
|
|
CSkeletonAnim dummyanim;
|
|
|
|
dummyanim.m_AnimDef=anim;
|
|
|
|
if (!SetAnimation(&dummyanim)) return;
|
|
|
|
}
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2005-08-09 17:55:44 +02:00
|
|
|
size_t numverts=m_pModelDef->GetNumVertices();
|
2004-05-30 02:46:58 +02:00
|
|
|
SModelVertex* verts=m_pModelDef->GetVertices();
|
2005-02-10 00:19:48 +01:00
|
|
|
|
|
|
|
// Remove any transformations, so that we calculate the bounding box
|
|
|
|
// at the origin. The box is later re-transformed onto the object, without
|
|
|
|
// having to recalculate the size of the box.
|
|
|
|
CMatrix3D transform, oldtransform = GetTransform();
|
2005-10-26 03:03:28 +02:00
|
|
|
CModel* oldparent = m_Parent;
|
|
|
|
|
|
|
|
m_Parent = 0;
|
2005-02-10 00:19:48 +01:00
|
|
|
transform.SetIdentity();
|
2005-10-26 03:03:28 +02:00
|
|
|
CRenderableObject::SetTransform(transform);
|
2005-02-10 00:19:48 +01:00
|
|
|
|
2005-05-01 21:09:13 +02:00
|
|
|
// Following seems to stomp over the current animation time - which, unsurprisingly,
|
|
|
|
// introduces artefacts in the currently playing animation. Save it here and restore it
|
|
|
|
// at the end.
|
|
|
|
float AnimTime = m_AnimTime;
|
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
// iterate through every frame of the animation
|
2005-10-26 03:03:28 +02:00
|
|
|
for (size_t j=0;j<anim->GetNumFrames();j++) {
|
|
|
|
m_PositionValid = false;
|
|
|
|
ValidatePosition();
|
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
// extend bounds by vertex positions at the frame
|
2005-08-09 17:55:44 +02:00
|
|
|
for (size_t i=0;i<numverts;i++) {
|
2005-10-26 03:03:28 +02:00
|
|
|
CVector3D tmp = SkinPoint(verts[i].m_Coords,verts[i].m_Blend,GetBoneMatrices());
|
2004-05-30 02:46:58 +02:00
|
|
|
result+=tmp;
|
|
|
|
}
|
|
|
|
// advance to next frame
|
2005-10-26 03:03:28 +02:00
|
|
|
m_AnimTime += anim->GetFrameTime();
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
2005-02-10 00:19:48 +01:00
|
|
|
|
2005-10-26 03:03:28 +02:00
|
|
|
m_PositionValid = false;
|
|
|
|
m_Parent = oldparent;
|
2005-02-10 00:19:48 +01:00
|
|
|
SetTransform(oldtransform);
|
2005-05-01 21:09:13 +02:00
|
|
|
m_AnimTime = AnimTime;
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// BuildAnimation: load raw animation frame animation from given file, and build a
|
|
|
|
// animation specific to this model
|
2005-05-21 03:40:32 +02:00
|
|
|
CSkeletonAnim* CModel::BuildAnimation(const char* filename, const char* name, float speed, double actionpos, double actionpos2)
|
2004-05-30 02:46:58 +02:00
|
|
|
{
|
|
|
|
CSkeletonAnimDef* def=g_SkelAnimMan.GetAnimation(filename);
|
2005-05-21 03:40:32 +02:00
|
|
|
if (!def) return NULL;
|
|
|
|
|
2005-05-27 02:38:30 +02:00
|
|
|
|
|
|
|
CSkeletonAnim* anim=new CSkeletonAnim;
|
2005-05-21 03:40:32 +02:00
|
|
|
anim->m_Name = name;
|
2005-05-27 02:38:30 +02:00
|
|
|
anim->m_AnimDef=def;
|
|
|
|
anim->m_Speed=speed;
|
|
|
|
anim->m_ActionPos=(float)( actionpos /* * anim->m_AnimDef->GetDuration() */ / speed );
|
|
|
|
anim->m_ActionPos2=(float)( actionpos2 /* * anim->m_AnimDef->GetDuration() */ / speed );
|
|
|
|
|
2005-02-10 00:19:48 +01:00
|
|
|
anim->m_ObjectBounds.SetEmpty();
|
|
|
|
InvalidateBounds();
|
2004-05-30 02:46:58 +02:00
|
|
|
|
|
|
|
return anim;
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Update: update this model by the given time, in seconds
|
|
|
|
void CModel::Update(float time)
|
|
|
|
{
|
|
|
|
if (m_Anim && m_BoneMatrices) {
|
2005-05-27 02:38:30 +02:00
|
|
|
// adjust for animation speed
|
|
|
|
float animtime=time*m_AnimSpeed;
|
2004-05-30 02:46:58 +02:00
|
|
|
|
|
|
|
// update animation time, but don't calculate bone matrices - do that (lazily) when
|
|
|
|
// something requests them; that saves some calculation work for offscreen models,
|
|
|
|
// and also assures the world space, inverted bone matrices (required for normal
|
|
|
|
// skinning) are up to date with respect to m_Transform
|
2005-05-21 03:40:32 +02:00
|
|
|
m_AnimTime += animtime;
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2005-05-27 02:38:30 +02:00
|
|
|
|
|
|
|
float duration=m_Anim->m_AnimDef->GetDuration();
|
2005-05-21 03:40:32 +02:00
|
|
|
if (m_AnimTime > duration) {
|
2005-05-27 02:38:30 +02:00
|
|
|
if( m_Flags & MODELFLAG_NOLOOPANIMATION )
|
|
|
|
{
|
|
|
|
SetAnimation( m_NextAnim );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m_AnimTime=(float) fmod(m_AnimTime,duration);
|
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// mark vertices as dirty
|
|
|
|
SetDirty(RENDERDATA_UPDATE_VERTICES);
|
|
|
|
|
|
|
|
// mark matrices as dirty
|
2005-10-26 03:03:28 +02:00
|
|
|
InvalidatePosition();
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// update props
|
2005-10-26 03:03:28 +02:00
|
|
|
for (uint i=0; i<m_Props.size(); i++)
|
|
|
|
{
|
2004-05-30 02:46:58 +02:00
|
|
|
m_Props[i].m_Model->Update(time);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
2005-10-26 03:03:28 +02:00
|
|
|
// InvalidatePosition
|
|
|
|
void CModel::InvalidatePosition()
|
2004-05-30 02:46:58 +02:00
|
|
|
{
|
2005-10-26 03:03:28 +02:00
|
|
|
m_PositionValid = false;
|
2005-05-20 19:09:47 +02:00
|
|
|
|
2005-10-26 03:03:28 +02:00
|
|
|
for (uint i = 0; i < m_Props.size(); ++i)
|
|
|
|
m_Props[i].m_Model->InvalidatePosition();
|
|
|
|
}
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2005-10-26 03:03:28 +02:00
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ValidatePosition: ensure that current transform and bone matrices are both uptodate
|
|
|
|
void CModel::ValidatePosition()
|
|
|
|
{
|
|
|
|
if (m_PositionValid)
|
|
|
|
{
|
|
|
|
debug_assert(!m_Parent || m_Parent->m_PositionValid);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_Parent && !m_Parent->m_PositionValid)
|
|
|
|
{
|
|
|
|
// Make sure we don't base our calculations on
|
|
|
|
// a parent animation state that is out of date.
|
|
|
|
m_Parent->ValidatePosition();
|
|
|
|
|
|
|
|
// Parent will recursively call our validation.
|
|
|
|
debug_assert(m_PositionValid);
|
|
|
|
return;
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
2005-10-26 03:03:28 +02:00
|
|
|
if (m_Anim && m_BoneMatrices)
|
|
|
|
{
|
|
|
|
PROFILE( "generating bone matrices" );
|
|
|
|
|
|
|
|
debug_assert(m_pModelDef->GetNumBones() == m_Anim->m_AnimDef->GetNumKeys());
|
|
|
|
|
|
|
|
m_Anim->m_AnimDef->BuildBoneMatrices(m_AnimTime,m_BoneMatrices);
|
|
|
|
|
|
|
|
const CMatrix3D& transform=GetTransform();
|
|
|
|
for (size_t i=0;i<m_pModelDef->GetNumBones();i++) {
|
|
|
|
m_BoneMatrices[i].Concatenate(transform);
|
|
|
|
m_BoneMatrices[i].GetInverse(m_InvBoneMatrices[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_PositionValid = true;
|
|
|
|
|
|
|
|
// re-position and validate all props
|
|
|
|
for (size_t j = 0; j < m_Props.size(); ++j)
|
|
|
|
{
|
2004-06-19 16:39:24 +02:00
|
|
|
const Prop& prop=m_Props[j];
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2005-10-26 03:03:28 +02:00
|
|
|
CMatrix3D proptransform = prop.m_Point->m_Transform;;
|
|
|
|
if (prop.m_Point->m_BoneIndex != 0xff)
|
|
|
|
proptransform.Concatenate(m_BoneMatrices[prop.m_Point->m_BoneIndex]);
|
|
|
|
else
|
|
|
|
proptransform.Concatenate(m_Transform);
|
|
|
|
|
|
|
|
prop.m_Model->SetTransform(proptransform);
|
|
|
|
prop.m_Model->ValidatePosition();
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-10-26 03:03:28 +02:00
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// SetAnimation: set the given animation as the current animation on this model;
|
|
|
|
// return false on error, else true
|
2005-05-27 02:38:30 +02:00
|
|
|
bool CModel::SetAnimation(CSkeletonAnim* anim, bool once, float speed, CSkeletonAnim* next)
|
2004-05-30 02:46:58 +02:00
|
|
|
{
|
2005-02-11 13:57:19 +01:00
|
|
|
m_Anim=NULL; // in case something fails
|
|
|
|
|
|
|
|
if (anim) {
|
2004-11-11 08:09:32 +01:00
|
|
|
m_Flags &= ~MODELFLAG_NOLOOPANIMATION;
|
2005-05-21 03:40:32 +02:00
|
|
|
if (once)
|
2005-05-27 02:38:30 +02:00
|
|
|
{
|
2004-11-11 08:09:32 +01:00
|
|
|
m_Flags |= MODELFLAG_NOLOOPANIMATION;
|
2005-05-27 02:38:30 +02:00
|
|
|
m_NextAnim = next;
|
|
|
|
}
|
2004-11-11 08:09:32 +01:00
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
if (!m_BoneMatrices) {
|
|
|
|
// not boned, can't animate
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-05-21 03:40:32 +02:00
|
|
|
if (anim->m_AnimDef->GetNumKeys() != m_pModelDef->GetNumBones()) {
|
2005-02-10 00:19:48 +01:00
|
|
|
// mismatch between model's skeleton and animation's skeleton
|
2005-02-11 13:57:19 +01:00
|
|
|
LOG(ERROR, LOG_CATEGORY, "Mismatch between model's skeleton and animation's skeleton (%d model bones != %d animation keys)",
|
|
|
|
m_pModelDef->GetNumBones(), anim->m_AnimDef->GetNumKeys());
|
2004-05-30 02:46:58 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-02-10 00:19:48 +01:00
|
|
|
// reset the cached bounds when the animation is changed
|
|
|
|
m_ObjectBounds.SetEmpty();
|
|
|
|
InvalidateBounds();
|
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
// start anim from beginning
|
2005-05-27 02:38:30 +02:00
|
|
|
m_AnimTime=0;
|
|
|
|
|
|
|
|
// Adjust speed by animation base rate.
|
|
|
|
m_AnimSpeed = speed * anim->m_Speed;
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
2005-10-26 03:03:28 +02:00
|
|
|
m_Anim = anim;
|
2005-02-11 13:57:19 +01:00
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// AddProp: add a prop to the model on the given point
|
2005-05-21 03:40:32 +02:00
|
|
|
void CModel::AddProp(SPropPoint* point, CModel* model)
|
2004-05-30 02:46:58 +02:00
|
|
|
{
|
|
|
|
// position model according to prop point position
|
|
|
|
model->SetTransform(point->m_Transform);
|
2005-10-26 03:03:28 +02:00
|
|
|
model->m_Parent = this;
|
2004-05-30 02:46:58 +02:00
|
|
|
|
|
|
|
// check if we're already using this point, and replace
|
|
|
|
// model on it if so
|
|
|
|
uint i;
|
|
|
|
for (i=0;i<m_Props.size();i++) {
|
|
|
|
if (m_Props[i].m_Point==point) {
|
2004-12-12 19:40:00 +01:00
|
|
|
delete m_Props[i].m_Model;
|
2004-05-30 02:46:58 +02:00
|
|
|
m_Props[i].m_Model=model;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// not using point; add new prop
|
|
|
|
Prop prop;
|
|
|
|
prop.m_Point=point;
|
|
|
|
prop.m_Model=model;
|
|
|
|
m_Props.push_back(prop);
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// RemoveProp: remove a prop from the given point
|
|
|
|
void CModel::RemoveProp(SPropPoint* point)
|
|
|
|
{
|
|
|
|
typedef std::vector<Prop>::iterator Iter;
|
|
|
|
for (Iter iter=m_Props.begin();iter!=m_Props.end();++iter) {
|
|
|
|
const Prop& prop=*iter;
|
|
|
|
if (prop.m_Point==point) {
|
2005-05-10 09:13:25 +02:00
|
|
|
delete prop.m_Model;
|
2004-05-30 02:46:58 +02:00
|
|
|
m_Props.erase(iter);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Clone: return a clone of this model
|
|
|
|
CModel* CModel::Clone() const
|
|
|
|
{
|
2005-05-21 03:40:32 +02:00
|
|
|
CModel* clone = new CModel;
|
|
|
|
clone->m_ObjectBounds = m_ObjectBounds;
|
2004-05-30 02:46:58 +02:00
|
|
|
clone->InitModel(m_pModelDef);
|
|
|
|
clone->SetTexture(m_Texture);
|
2005-05-21 03:40:32 +02:00
|
|
|
if (m_Texture.GetHandle())
|
|
|
|
h_add_ref(m_Texture.GetHandle());
|
2005-03-22 18:09:36 +01:00
|
|
|
clone->SetMaterial(m_Material);
|
2004-05-30 02:46:58 +02:00
|
|
|
clone->SetAnimation(m_Anim);
|
2004-10-06 20:45:59 +02:00
|
|
|
clone->SetFlags(m_Flags);
|
2004-05-30 02:46:58 +02:00
|
|
|
for (uint i=0;i<m_Props.size();i++) {
|
|
|
|
// eek! TODO, RC - need to investigate shallow clone here
|
2005-04-07 06:29:07 +02:00
|
|
|
clone->AddProp(m_Props[i].m_Point, m_Props[i].m_Model->Clone());
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
return clone;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// SetTransform: set the transform on this object, and reorientate props accordingly
|
2005-10-26 03:03:28 +02:00
|
|
|
void CModel::SetTransform(const CMatrix3D& transform)
|
2004-05-30 02:46:58 +02:00
|
|
|
{
|
|
|
|
// call base class to set transform on this object
|
|
|
|
CRenderableObject::SetTransform(transform);
|
2005-02-10 00:19:48 +01:00
|
|
|
InvalidateBounds();
|
2005-10-26 03:03:28 +02:00
|
|
|
InvalidatePosition();
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
2004-10-30 23:57:46 +02:00
|
|
|
|
2005-04-07 06:29:07 +02:00
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2004-10-30 23:57:46 +02:00
|
|
|
void CModel::SetMaterial(const CMaterial &material)
|
|
|
|
{
|
2005-03-22 18:09:36 +01:00
|
|
|
m_Material = material;
|
|
|
|
if(m_Material.GetTexture().Trim(PS_TRIM_BOTH).Length() > 0)
|
|
|
|
{
|
|
|
|
}
|
2004-10-30 23:57:46 +02:00
|
|
|
}
|
2005-04-07 06:29:07 +02:00
|
|
|
|
|
|
|
void CModel::SetPlayerID(int id)
|
|
|
|
{
|
|
|
|
m_Material.SetPlayerColor(id);
|
|
|
|
for (std::vector<Prop>::iterator it = m_Props.begin(); it != m_Props.end(); ++it)
|
|
|
|
it->m_Model->SetPlayerID(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CModel::SetPlayerColor(CColor& colour)
|
|
|
|
{
|
|
|
|
m_Material.SetPlayerColor(colour);
|
|
|
|
}
|
2005-09-06 10:25:41 +02:00
|
|
|
|
|
|
|
void CModel::SetShadingColor(CColor& colour)
|
|
|
|
{
|
|
|
|
m_ShadingColor = colour;
|
|
|
|
for (std::vector<Prop>::iterator it = m_Props.begin(); it != m_Props.end(); ++it)
|
|
|
|
it->m_Model->SetShadingColor(colour);
|
|
|
|
}
|