Files
scummvm/engines/hpl1/engine/graphics/Mesh.cpp
T

979 lines
29 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Copyright (C) 2006-2010 - Frictional Games
*
* This file is part of HPL1 Engine.
*/
#include "hpl1/engine/graphics/Mesh.h"
#include "hpl1/engine/graphics/Animation.h"
#include "hpl1/engine/graphics/Beam.h"
#include "hpl1/engine/graphics/BillBoard.h"
#include "hpl1/engine/graphics/Bone.h"
#include "hpl1/engine/graphics/BoneState.h"
#include "hpl1/engine/graphics/Material.h"
#include "hpl1/engine/graphics/ParticleSystem3D.h"
#include "hpl1/engine/graphics/Skeleton.h"
#include "hpl1/engine/graphics/SubMesh.h"
#include "hpl1/engine/graphics/VertexBuffer.h"
#include "hpl1/engine/resources/AnimationManager.h"
#include "hpl1/engine/resources/MaterialManager.h"
#include "hpl1/engine/math/Math.h"
#include "hpl1/engine/physics/PhysicsBody.h"
#include "hpl1/engine/physics/PhysicsJointBall.h"
#include "hpl1/engine/physics/PhysicsJointHinge.h"
#include "hpl1/engine/physics/PhysicsJointScrew.h"
#include "hpl1/engine/physics/PhysicsJointSlider.h"
#include "hpl1/engine/physics/PhysicsWorld.h"
#include "hpl1/engine/scene/Light3DPoint.h"
#include "hpl1/engine/scene/Light3DSpot.h"
#include "hpl1/engine/scene/MeshEntity.h"
#include "hpl1/engine/scene/Node3D.h"
#include "hpl1/engine/scene/SoundEntity.h"
#include "hpl1/engine/scene/World3D.h"
namespace hpl {
//////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
cMesh::cMesh(const tString asName, cMaterialManager *apMaterialManager,
cAnimationManager *apAnimationManager) : iResourceBase(asName, 0) {
mpMaterialManager = apMaterialManager;
mpAnimationManager = apAnimationManager;
mpSkeleton = NULL;
mpRootNode = hplNew(cNode3D, ());
}
//-----------------------------------------------------------------------
cMesh::~cMesh() {
for (int i = 0; i < (int)mvSubMeshes.size(); i++) {
hplDelete(mvSubMeshes[i]);
}
if (mpSkeleton)
hplDelete(mpSkeleton);
for (int i = 0; i < (int)mvAnimations.size(); i++) {
// mpAnimationManager->Destroy(mvAnimations[i]);
hplDelete(mvAnimations[i]);
}
if (mpRootNode)
hplDelete(mpRootNode);
STLDeleteAll(mvColliders);
STLDeleteAll(mvPhysicJoints);
STLDeleteAll(mvLights);
STLDeleteAll(mvBillboards);
STLDeleteAll(mvBeams);
STLDeleteAll(mvParticleSystems);
STLDeleteAll(mvReferences);
STLDeleteAll(mvSoundEntities);
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
bool cMesh::CreateFromFile(const tString asFile) {
return false;
}
//-----------------------------------------------------------------------
cSubMesh *cMesh::CreateSubMesh(const tString &asName) {
cSubMesh *pSubMesh = hplNew(cSubMesh, (asName, mpMaterialManager));
pSubMesh->mpParent = this;
mvSubMeshes.push_back(pSubMesh);
m_mapSubMeshes.insert(tSubMeshMap::value_type(asName, pSubMesh));
return pSubMesh;
}
//-----------------------------------------------------------------------
cSubMesh *cMesh::GetSubMesh(unsigned int alIdx) {
if (alIdx >= mvSubMeshes.size())
return NULL;
return mvSubMeshes[alIdx];
}
cSubMesh *cMesh::GetSubMeshName(const tString &asName) {
tSubMeshMapIt it = m_mapSubMeshes.find(asName);
if (it == m_mapSubMeshes.end())
return NULL;
return it->second;
}
int cMesh::GetSubMeshNum() {
return (int)mvSubMeshes.size();
}
//-----------------------------------------------------------------------
void cMesh::SetSkeleton(cSkeleton *apSkeleton) {
mpSkeleton = apSkeleton;
}
cSkeleton *cMesh::GetSkeleton() {
return mpSkeleton;
}
//-----------------------------------------------------------------------
void cMesh::AddAnimation(cAnimation *apAnimation) {
mvAnimations.push_back(apAnimation);
tAnimationIndexMap::value_type value(apAnimation->GetName(), (int)mvAnimations.size() - 1);
m_mapAnimIndices.insert(value);
}
cAnimation *cMesh::GetAnimation(int alIndex) {
return mvAnimations[alIndex];
}
cAnimation *cMesh::GetAnimationFromName(const tString &asName) {
int lIdx = GetAnimationIndex(asName);
if (lIdx >= 0) {
return mvAnimations[lIdx];
} else {
return NULL;
}
}
int cMesh::GetAnimationIndex(const tString &asName) {
tAnimationIndexMapIt it = m_mapAnimIndices.find(asName);
if (it != m_mapAnimIndices.end()) {
return it->second;
} else {
return -1;
}
}
void cMesh::ClearAnimations(bool abDeleteAll) {
if (abDeleteAll) {
for (int i = 0; i < (int)mvAnimations.size(); i++) {
// mpAnimationManager->Destroy(mvAnimations[i]);
hplDelete(mvAnimations[i]);
}
}
mvAnimations.clear();
m_mapAnimIndices.clear();
}
int cMesh::GetAnimationNum() {
return (int)mvAnimations.size();
}
//-----------------------------------------------------------------------
void cMesh::SetupBones() {
if (mpSkeleton == NULL)
return;
// Here is the place to add more hardware friendly stuffs.
}
//-----------------------------------------------------------------------
cMeshJoint *cMesh::CreatePhysicsJoint(ePhysicsJointType aType) {
cMeshJoint *pJoint = hplNew(cMeshJoint, ());
pJoint->mType = aType;
mvPhysicJoints.push_back(pJoint);
return pJoint;
}
cMeshJoint *cMesh::GetPhysicsJoint(int alIdx) {
return mvPhysicJoints[alIdx];
}
int cMesh::GetPhysicsJointNum() {
return (int)mvPhysicJoints.size();
}
//-----------------------------------------------------------------------
iPhysicsJoint *cMesh::CreateJointInWorld(const tString &sNamePrefix, cMeshJoint *apMeshJoint,
iPhysicsBody *apParentBody, iPhysicsBody *apChildBody,
const cMatrixf &a_mtxOffset, iPhysicsWorld *apWorld) {
cVector3f vPivot = cMath::MatrixMul(a_mtxOffset, apMeshJoint->mvPivot);
cVector3f vPinDir = cMath::MatrixMul(a_mtxOffset.GetRotation(), apMeshJoint->mvPinDir);
///////////////////////////
// Hinge
if (apMeshJoint->mType == ePhysicsJointType_Hinge) {
iPhysicsJointHinge *pJoint = apWorld->CreateJointHinge(sNamePrefix + apMeshJoint->msName,
vPivot, vPinDir, apParentBody,
apChildBody);
pJoint->SetCollideBodies(apMeshJoint->mbCollide);
pJoint->SetMinAngle(cMath::ToRad(-apMeshJoint->mfMin));
pJoint->SetMaxAngle(cMath::ToRad(apMeshJoint->mfMax));
return pJoint;
}
///////////////////////////
// Ball
else if (apMeshJoint->mType == ePhysicsJointType_Ball) {
iPhysicsJointBall *pJoint = apWorld->CreateJointBall(sNamePrefix + apMeshJoint->msName,
vPivot, apParentBody, apChildBody);
pJoint->SetCollideBodies(apMeshJoint->mbCollide);
pJoint->SetConeLimits(vPinDir, cMath::ToRad(apMeshJoint->mfMin), cMath::ToRad(apMeshJoint->mfMax));
return pJoint;
}
///////////////////////////
// Slider
else if (apMeshJoint->mType == ePhysicsJointType_Slider) {
iPhysicsJointSlider *pJoint = apWorld->CreateJointSlider(sNamePrefix + apMeshJoint->msName, vPivot, vPinDir, apParentBody, apChildBody);
pJoint->SetCollideBodies(apMeshJoint->mbCollide);
pJoint->SetMinDistance(apMeshJoint->mfMin);
pJoint->SetMaxDistance(apMeshJoint->mfMax);
return pJoint;
}
///////////////////////////
// Screw
else if (apMeshJoint->mType == ePhysicsJointType_Screw) {
iPhysicsJointScrew *pJoint = apWorld->CreateJointScrew(sNamePrefix + apMeshJoint->msName,
vPivot, vPinDir, apParentBody, apChildBody);
pJoint->SetCollideBodies(apMeshJoint->mbCollide);
pJoint->SetMinDistance(apMeshJoint->mfMin);
pJoint->SetMaxDistance(apMeshJoint->mfMax);
return pJoint;
}
return NULL;
}
//-----------------------------------------------------------------------
void cMesh::CreateNodeBodies(iPhysicsBody **apRootBodyPtr, Common::Array<iPhysicsBody *> *apBodyVec,
cMeshEntity *apEntity, iPhysicsWorld *apPhysicsWorld,
const cMatrixf &a_mtxTransform) {
cMatrixf mtxOldOffset;
// Log("Creating node bodies!\n");
///////////////////////////////////
// Create bodies for the sub meshes (if available
for (int sub = 0; sub < GetSubMeshNum(); sub++) {
cSubMesh *pSubMesh = GetSubMesh(sub);
cSubMeshEntity *pSubEntity = apEntity->GetSubMeshEntity(sub);
tCollideShapeVec vShapes;
for (int shape = 0; shape < GetColliderNum(); shape++) {
cMeshCollider *pColl = GetCollider(shape);
if (pColl->msGroup == pSubMesh->GetGroup() && pColl->msGroup != "") {
mtxOldOffset = pColl->m_mtxOffset;
// Remove the scale
cMatrixf mtxSub = pSubEntity->GetWorldMatrix();
cMatrixf mtxScale = cMath::MatrixScale(pSubMesh->GetModelScale());
mtxSub = cMath::MatrixMul(mtxSub, cMath::MatrixInverse(mtxScale));
// Get the local offset of the collider, relative to the sub mesh
pColl->m_mtxOffset = cMath::MatrixMul(cMath::MatrixInverse(mtxSub),
pColl->m_mtxOffset);
// Create shape
iCollideShape *pShape = CreateCollideShapeFromCollider(pColl, apPhysicsWorld);
vShapes.push_back(pShape);
// Log("Created shape size: %s offset: %s\n",pShape->GetSize().ToString().c_str(),pShape->);
pColl->m_mtxOffset = mtxOldOffset;
}
}
// Create the compound shape if needed.
iCollideShape *pShape;
if (vShapes.size() > 1) {
pShape = apPhysicsWorld->CreateCompundShape(vShapes);
} else if (vShapes.size() == 1) {
pShape = vShapes[0];
} else {
Warning("No shapes for sub mesh '%s' with group: '%s'\n", pSubMesh->GetName().c_str(),
pSubMesh->GetGroup().c_str());
// return;
continue;
}
// Create body and set mass to 0 since these bodies are animated and
// can therefore be considered static.
iPhysicsBody *pBody = apPhysicsWorld->CreateBody(apEntity->GetName() + "_" + pSubMesh->GetName(),
pShape);
pBody->SetMass(0);
pBody->SetGravity(false);
pSubEntity->SetBody(pBody);
pSubEntity->SetUpdateBody(true);
apBodyVec->push_back(pBody);
}
///////////////////////////////////
// Create bodies for root
tCollideShapeVec vShapes;
for (int shape = 0; shape < GetColliderNum(); shape++) {
cMeshCollider *pColl = GetCollider(shape);
if (pColl->msGroup == "") {
// Create shape
iCollideShape *pShape = CreateCollideShapeFromCollider(pColl, apPhysicsWorld);
vShapes.push_back(pShape);
/*cMatrixf mtxOffset = */pShape->GetOffset();
// Log("Created shape size: %s at %s. Mtx: %s\n",pShape->GetSize().ToString().c_str(),
// pShape->GetOffset().GetTranslation().ToString().c_str(),
// mtxOffset.ToString().c_str());
}
}
bool bHasRoot = false;
iCollideShape *pShape;
if (vShapes.size() > 1) {
pShape = apPhysicsWorld->CreateCompundShape(vShapes);
bHasRoot = true;
} else if (vShapes.size() == 1) {
pShape = vShapes[0];
bHasRoot = true;
} else {
return;
}
if (bHasRoot) {
// Log("Creating root body!\n");
iPhysicsBody *pBody = apPhysicsWorld->CreateBody(apEntity->GetName(),
pShape);
pBody->CreateNode()->AddEntity(apEntity);
pBody->SetMass(0);
apEntity->SetBody(pBody);
pBody->SetMatrix(a_mtxTransform);
apBodyVec->push_back(pBody);
}
}
//-----------------------------------------------------------------------
void cMesh::CreateJointsAndBodies(Common::Array<iPhysicsBody *> *apBodyVec, cMeshEntity *apEntity,
Common::Array<iPhysicsJoint *> *apJointVec,
const cMatrixf &a_mtxOffset, iPhysicsWorld *apPhysicsWorld) {
Common::Array<iPhysicsBody *> vBodies;
//////////////////////////////////
// If the mesh has a skeleton, attach the bodies to the bones
// in the skeleton.
if (mpSkeleton) {
// TODO: Set root node to identity matrix
for (int bone = 0; bone < apEntity->GetBoneStateNum(); ++bone) {
cBoneState *pBoneState = apEntity->GetBoneState(bone);
/////////////////////////////////////////////////////
// Iterate the colliders and get the sum of offsets.
cVector3f vShapeWorldCenter(0, 0, 0);
float fColliderNum = 0;
for (int shape = 0; shape < GetColliderNum(); shape++) {
cMeshCollider *pColl = GetCollider(shape);
if (pColl->msGroup == pBoneState->GetName()) {
vShapeWorldCenter += pColl->m_mtxOffset.GetTranslation();
fColliderNum += 1;
}
}
vShapeWorldCenter = vShapeWorldCenter / fColliderNum;
cMatrixf mtxBodyWorld = cMath::MatrixTranslate(vShapeWorldCenter);
cMatrixf mtxInvBodyWorld = cMath::MatrixInverse(mtxBodyWorld);
cMatrixf mtxBone = pBoneState->GetWorldMatrix();
cMatrixf mtxInvBone = cMath::MatrixInverse(mtxBone);
cMatrixf mtxBoneToBody = cMath::MatrixMul(mtxInvBone, mtxBodyWorld);
///////////////////////////////////////////////////////////
// Iterate the colliders and search for the colliders for each object.
cMatrixf mtxOldOffset;
tCollideShapeVec vShapes;
for (int shape = 0; shape < GetColliderNum(); shape++) {
cMeshCollider *pColl = GetCollider(shape);
if (pColl->msGroup == pBoneState->GetName()) {
mtxOldOffset = pColl->m_mtxOffset;
cMatrixf mtxBodyToCollider = cMath::MatrixMul(mtxInvBodyWorld, pColl->m_mtxOffset);
pColl->m_mtxOffset = mtxBodyToCollider;
iCollideShape *pShape = CreateCollideShapeFromCollider(pColl, apPhysicsWorld);
vShapes.push_back(pShape);
// Setting old offset
pColl->m_mtxOffset = mtxOldOffset;
}
}
////////////////////////////////
// Create body
if (vShapes.size() > 0) {
// Create the compound shape if needed.
iCollideShape *pShape = nullptr;
if (vShapes.size() > 1) {
pShape = apPhysicsWorld->CreateCompundShape(vShapes);
} else if (vShapes.size() == 1) {
pShape = vShapes[0];
}
//////////////////////////////////////////
// Create normal body and set mass to 1 for now.
iPhysicsBody *pBody = apPhysicsWorld->CreateBody(apEntity->GetName() + "_" + pBoneState->GetName(),
pShape);
pBody->SetMass(1);
pBody->SetActive(false);
pBody->SetIsRagDoll(true);
pBody->SetCollideRagDoll(false);
pBody->SetMatrix(cMath::MatrixMul(a_mtxOffset, mtxBodyWorld));
pBoneState->SetBody(pBody);
pBoneState->SetBodyMatrix(mtxBoneToBody);
if (apBodyVec)
apBodyVec->push_back(pBody);
vBodies.push_back(pBody);
/////////////////////////////////////
// Create collider body
iPhysicsBody *pColliderBody = apPhysicsWorld->CreateBody(apEntity->GetName() + "_collider_" + pBoneState->GetName(),
pShape);
pColliderBody->SetMass(0);
pColliderBody->SetActive(false);
pColliderBody->SetCollideCharacter(false);
pBoneState->SetColliderBody(pColliderBody);
if (apBodyVec)
apBodyVec->push_back(pColliderBody);
}
}
// TODO: Reset root node matrix
}
///////////////////////////////////
// Create bodies for the sub meshes.
else {
for (int sub = 0; sub < GetSubMeshNum(); sub++) {
cSubMesh *pSubMesh = GetSubMesh(sub);
cSubMeshEntity *pSubEntity = apEntity->GetSubMeshEntity(sub);
bool bGroupShare = false;
// Check if the submesh is a child of another mesh,
// if so skip it.
for (int i = 0; i < GetSubMeshNum(); ++i) {
if (i == sub)
continue;
cSubMesh *pExtraSub = GetSubMesh(i);
cSubMeshEntity *pExtraEntity = apEntity->GetSubMeshEntity(i);
if (pSubMesh->GetGroup() == pExtraSub->GetNodeName()) {
pExtraEntity->AddChild(pSubEntity);
pSubEntity->SetMatrix(pSubMesh->GetLocalTransform());
bGroupShare = true;
break;
}
}
if (bGroupShare)
continue;
// Extra check to see if any other sub object chairs the group.
for (int i = 0; i < GetSubMeshNum(); ++i) {
if (i == sub)
continue;
cSubMesh *pExtraSub = GetSubMesh(i);
if (pExtraSub->GetGroup() == pSubMesh->GetGroup()) {
Error("SubMesh %s shares group with %s\n", pSubMesh->GetName().c_str(),
pExtraSub->GetName().c_str());
bGroupShare = true;
}
}
if (bGroupShare)
continue;
cMatrixf mtxOldOffset;
// Log("Sub: %s group: '%s'\n",pSubMesh->GetName().c_str(),pSubMesh->GetGroup().c_str());
// Iterate the colliders and search for the colliders for each object.
tCollideShapeVec vShapes;
for (int shape = 0; shape < GetColliderNum(); shape++) {
cMeshCollider *pColl = GetCollider(shape);
if (pColl->msGroup == pSubMesh->GetGroup()) {
mtxOldOffset = pColl->m_mtxOffset;
// Remove the scale
cMatrixf mtxSub = pSubEntity->GetWorldMatrix();
// Log("SubEntity '%s' : %s\n",pSubEntity->GetName().c_str(),mtxSub.ToString().c_str());
// if(pSubEntity->GetParent())
// Log("Node parent: %s\n",static_cast<cNode3D*>(pSubEntity->GetParent())->GetName());
// The scale should allready been removed.
/*cMatrixf mtxScale = cMath::MatrixScale(pSubMesh->GetModelScale());
mtxSub = cMath::MatrixMul(mtxSub, cMath::MatrixInverse(mtxScale));*/
// Get the local offset of the collider, relative to the sub mesh
pColl->m_mtxOffset = cMath::MatrixMul(cMath::MatrixInverse(mtxSub),
pColl->m_mtxOffset);
iCollideShape *pShape = CreateCollideShapeFromCollider(pColl, apPhysicsWorld);
vShapes.push_back(pShape);
// Log("Created shapes!\n");
// Setting old offset
pColl->m_mtxOffset = mtxOldOffset;
}
}
// Create the compound shape if needed.
iCollideShape *pShape;
if (vShapes.size() > 1) {
pShape = apPhysicsWorld->CreateCompundShape(vShapes);
} else if (vShapes.size() == 1) {
pShape = vShapes[0];
} else {
Error("No shapes for submesh '%s' with group: '%s' in mesh '%s'\n", pSubMesh->GetName().c_str(),
pSubMesh->GetGroup().c_str(), msName.c_str());
continue;
}
// Create body and set mass to 1 for now.
iPhysicsBody *pBody = apPhysicsWorld->CreateBody(apEntity->GetName() + "_" + pSubMesh->GetName(),
pShape);
pBody->CreateNode()->AddEntity(pSubEntity);
pBody->SetMass(1);
pBody->SetMatrix(cMath::MatrixMul(a_mtxOffset, pSubEntity->GetWorldMatrix()));
pSubEntity->SetMatrix(cMatrixf::Identity);
pSubEntity->SetBody(pBody);
if (apBodyVec)
apBodyVec->push_back(pBody);
vBodies.push_back(pBody);
}
}
/////////////////////////////////////////////////////
// Iterate the mesh joints and create physics joints
for (int joint = 0; joint < GetPhysicsJointNum(); joint++) {
cMeshJoint *pMeshJoint = GetPhysicsJoint(joint);
// Convert name to global
tString sChildBody = apEntity->GetName() + "_" + pMeshJoint->msChildBody;
tString sParentBody = apEntity->GetName() + "_" + pMeshJoint->msParentBody;
// Get Parent and Child body
iPhysicsBody *pChildBody = NULL;
iPhysicsBody *pParentBody = NULL;
for (int body = 0; body < (int)vBodies.size(); body++) {
iPhysicsBody *pBody = vBodies[body];
if (pBody->GetName() == sChildBody) {
pChildBody = pBody;
} else if (pBody->GetName() == sParentBody) {
pParentBody = pBody;
}
}
if (pParentBody == NULL && pMeshJoint->msParentBody != "") {
Warning("Parent body '%s' for joint '%s' in mesh '%s' does not exist!\n", pMeshJoint->msParentBody.c_str(),
pMeshJoint->msName.c_str(), msName.c_str());
continue;
}
if (pChildBody == NULL) {
Error("Child body '%s' for joint '%s' in mesh '%s' does not exist!\n", pMeshJoint->msChildBody.c_str(),
pMeshJoint->msName.c_str(), msName.c_str());
continue;
}
iPhysicsJoint *pJoint = CreateJointInWorld(apEntity->GetName() + "_", pMeshJoint,
pParentBody, pChildBody,
a_mtxOffset, apPhysicsWorld);
if (apJointVec)
apJointVec->push_back(pJoint);
}
if (GetSkeleton())
apEntity->SetMatrix(a_mtxOffset);
}
//-----------------------------------------------------------------------
bool cMesh::HasSeveralBodies() {
if (GetColliderNum() <= 0)
return false;
tString sPrevGroup = GetCollider(0)->msGroup;
for (int shape = 1; shape < GetColliderNum(); shape++) {
cMeshCollider *pColl = GetCollider(shape);
if (pColl->msGroup != sPrevGroup)
return true;
}
return false;
}
//-----------------------------------------------------------------------
cMeshCollider *cMesh::CreateCollider(eCollideShapeType aType) {
cMeshCollider *pColl = hplNew(cMeshCollider, ());
pColl->mType = aType;
mvColliders.push_back(pColl);
return pColl;
}
cMeshCollider *cMesh::GetCollider(int alIdx) {
return mvColliders[alIdx];
}
int cMesh::GetColliderNum() {
return (int)mvColliders.size();
}
iCollideShape *cMesh::CreateCollideShapeFromCollider(cMeshCollider *pCollider, iPhysicsWorld *apWorld) {
switch (pCollider->mType) {
case eCollideShapeType_Box:
return apWorld->CreateBoxShape(pCollider->mvSize, &pCollider->m_mtxOffset);
case eCollideShapeType_Sphere:
return apWorld->CreateSphereShape(pCollider->mvSize, &pCollider->m_mtxOffset);
case eCollideShapeType_Cylinder:
return apWorld->CreateCylinderShape(pCollider->mvSize.x, pCollider->mvSize.y, &pCollider->m_mtxOffset);
case eCollideShapeType_Capsule:
return apWorld->CreateCapsuleShape(pCollider->mvSize.x, pCollider->mvSize.y, &pCollider->m_mtxOffset);
default:
return NULL;
}
}
iCollideShape *cMesh::CreateCollideShape(iPhysicsWorld *apWorld) {
if (mvColliders.empty())
return NULL;
// Create a single object
if (mvColliders.size() == 1) {
return CreateCollideShapeFromCollider(mvColliders[0], apWorld);
}
// Create compound object
else {
tCollideShapeVec vShapes;
vShapes.reserve(mvColliders.size());
for (size_t i = 0; i < mvColliders.size(); ++i) {
vShapes.push_back(CreateCollideShapeFromCollider(mvColliders[i], apWorld));
}
return apWorld->CreateCompundShape(vShapes);
}
}
//-----------------------------------------------------------------------
cMeshLight *cMesh::CreateLight(eLight3DType aType) {
cMeshLight *pLight = hplNew(cMeshLight, ());
mvLights.push_back(pLight);
return pLight;
}
cMeshLight *cMesh::GetLight(int alIdx) {
return mvLights[alIdx];
}
int cMesh::GetLightNum() {
return (int)mvLights.size();
}
iLight3D *cMesh::CreateLightInWorld(const tString &sNamePrefix, cMeshLight *apMeshLight,
cMeshEntity *apMeshEntity, cWorld3D *apWorld) {
iLight3D *pLight = NULL;
////////////////////////////////
// Spot
if (apMeshLight->mType == eLight3DType_Spot) {
cLight3DSpot *pLightSpot = apWorld->CreateLightSpot(sNamePrefix + "_" + apMeshLight->msName);
pLightSpot->SetDiffuseColor(apMeshLight->mColor);
pLightSpot->SetFarAttenuation(apMeshLight->mfRadius);
pLightSpot->SetFOV(apMeshLight->mfFOV);
if (apMeshLight->msFile != "")
pLightSpot->LoadXMLProperties(apMeshLight->msFile);
pLight = pLightSpot;
}
////////////////////////////////
// Point
else if (apMeshLight->mType == eLight3DType_Point) {
cLight3DPoint *pLightPoint = apWorld->CreateLightPoint(sNamePrefix + "_" + apMeshLight->msName);
pLightPoint->SetDiffuseColor(apMeshLight->mColor);
pLightPoint->SetFarAttenuation(apMeshLight->mfRadius);
pLightPoint->SetCastShadows(apMeshLight->mbCastShadows);
if (apMeshLight->msFile != "")
pLightPoint->LoadXMLProperties(apMeshLight->msFile);
pLight = pLightPoint;
} else {
return NULL;
}
pLight->SetMatrix(apMeshLight->m_mtxTransform);
apMeshEntity->AttachEntityToParent(pLight, apMeshLight->msParent);
return pLight;
}
//-----------------------------------------------------------------------
cMeshBillboard *cMesh::CreateBillboard() {
cMeshBillboard *pBillboard = hplNew(cMeshBillboard, ());
mvBillboards.push_back(pBillboard);
return pBillboard;
}
cMeshBillboard *cMesh::GetBillboard(int alIdx) {
return mvBillboards[alIdx];
}
int cMesh::GetBillboardNum() {
return (int)mvBillboards.size();
}
cBillboard *cMesh::CreateBillboardInWorld(const tString &sNamePrefix, cMeshBillboard *apMeshBillboard,
cMeshEntity *apMeshEntity, cWorld3D *apWorld) {
cBillboard *pBillboard = apWorld->CreateBillboard(sNamePrefix + "_" + apMeshBillboard->msName,
apMeshBillboard->mvSize);
pBillboard->SetAxis(apMeshBillboard->mvAxis);
pBillboard->SetPosition(apMeshBillboard->mvPosition);
pBillboard->SetForwardOffset(apMeshBillboard->mfOffset);
pBillboard->LoadXMLProperties(apMeshBillboard->msFile);
apMeshEntity->AttachEntityToParent(pBillboard, apMeshBillboard->msParent);
return pBillboard;
}
//-----------------------------------------------------------------------
cMeshBeam *cMesh::CreateBeam() {
cMeshBeam *pBeam = hplNew(cMeshBeam, ());
mvBeams.push_back(pBeam);
return pBeam;
}
cMeshBeam *cMesh::GetBeam(int alIdx) {
return mvBeams[alIdx];
}
int cMesh::GetBeamNum() {
return (int)mvBeams.size();
}
cBeam *cMesh::CreateBeamInWorld(const tString &sNamePrefix, cMeshBeam *apMeshBeam,
cMeshEntity *apMeshEntity, cWorld3D *apWorld) {
cBeam *pBeam = apWorld->CreateBeam(sNamePrefix + "_" + apMeshBeam->msName);
pBeam->SetPosition(apMeshBeam->mvStartPosition);
pBeam->GetEnd()->SetPosition(apMeshBeam->mvEndPosition);
pBeam->LoadXMLProperties(apMeshBeam->msFile);
apMeshEntity->AttachEntityToParent(pBeam, apMeshBeam->msStartParent);
apMeshEntity->AttachEntityToParent(pBeam->GetEnd(), apMeshBeam->msEndParent);
return pBeam;
}
//-----------------------------------------------------------------------
cMeshReference *cMesh::CreateReference() {
cMeshReference *pRef = hplNew(cMeshReference, ());
mvReferences.push_back(pRef);
return pRef;
}
cMeshReference *cMesh::GetReference(int alIdx) {
return mvReferences[alIdx];
}
int cMesh::GetReferenceNum() {
return (int)mvReferences.size();
}
iEntity3D *cMesh::CreateReferenceInWorld(const tString &sNamePrefix,
cMeshReference *apMeshRef,
cMeshEntity *apMeshEntity, cWorld3D *apWorld,
const cMatrixf &a_mtxOffset) {
if (apMeshRef->msParent != "") {
tString sName = sNamePrefix + "_" + apMeshRef->msName;
iEntity3D *pEntity = apWorld->CreateEntity(sName,
apMeshRef->m_mtxTransform,
apMeshRef->msFile, true);
if (pEntity)
apMeshEntity->AttachEntityToParent(pEntity, apMeshRef->msParent);
return pEntity;
} else {
tString sName = sNamePrefix + "_" + apMeshRef->msName;
iEntity3D *pEntity = apWorld->CreateEntity(sName,
cMath::MatrixMul(a_mtxOffset, apMeshRef->m_mtxTransform),
apMeshRef->msFile, true);
// Log("Created ref: %s\n",sName.c_str());
return pEntity;
}
}
//-----------------------------------------------------------------------
cMeshParticleSystem *cMesh::CreateParticleSystem() {
cMeshParticleSystem *pPS = hplNew(cMeshParticleSystem, ());
mvParticleSystems.push_back(pPS);
return pPS;
}
cMeshParticleSystem *cMesh::GetParticleSystem(int alIdx) {
return mvParticleSystems[alIdx];
}
int cMesh::GetParticleSystemNum() {
return (int)mvParticleSystems.size();
}
cParticleSystem3D *cMesh::CreateParticleSystemInWorld(const tString &sNamePrefix,
cMeshParticleSystem *apMeshPS,
cMeshEntity *apMeshEntity, cWorld3D *apWorld) {
cParticleSystem3D *pPS = apWorld->CreateParticleSystem(sNamePrefix + "_" + apMeshPS->msName,
apMeshPS->msType, apMeshPS->mvSize, apMeshPS->m_mtxTransform);
if (pPS == NULL) {
Error("Couldn't create particle system '%s'\n", apMeshPS->msType.c_str());
return NULL;
}
apMeshEntity->AttachEntityToParent(pPS, apMeshPS->msParent);
return pPS;
}
//-----------------------------------------------------------------------
cMeshSoundEntity *cMesh::CreateSoundEntity() {
cMeshSoundEntity *pSound = hplNew(cMeshSoundEntity, ());
mvSoundEntities.push_back(pSound);
return pSound;
}
cMeshSoundEntity *cMesh::GetSoundEntity(int alIdx) {
return mvSoundEntities[alIdx];
}
int cMesh::GetSoundEntityNum() {
return (int)mvSoundEntities.size();
}
cSoundEntity *cMesh::CreateSoundEntityInWorld(const tString &sNamePrefix, cMeshSoundEntity *apMeshSound,
cMeshEntity *apMeshEntity, cWorld3D *apWorld) {
tString sName = sNamePrefix + "_" + apMeshSound->msName;
cSoundEntity *pSound = apWorld->CreateSoundEntity(sName,
apMeshSound->msType, false);
// Log("Created sound entity: '%s'\n",sName.c_str());
if (pSound == NULL) {
Error("Couldn't create sound entity '%s'\n", apMeshSound->msType.c_str());
return NULL;
}
pSound->SetPosition(apMeshSound->mvPosition);
apMeshEntity->AttachEntityToParent(pSound, apMeshSound->msParent);
return pSound;
}
//-----------------------------------------------------------------------
cNode3D *cMesh::GetRootNode() {
return mpRootNode;
}
void cMesh::AddNode(cNode3D *apNode) {
mvNodes.push_back(apNode);
}
int cMesh::GetNodeNum() {
return (int)mvNodes.size();
}
cNode3D *cMesh::GetNode(int alIdx) {
return mvNodes[alIdx];
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PRIAVTE METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
} // namespace hpl