/* 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 . * */ /* * 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 *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 *apBodyVec, cMeshEntity *apEntity, Common::Array *apJointVec, const cMatrixf &a_mtxOffset, iPhysicsWorld *apPhysicsWorld) { Common::Array 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(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