topical media & game development
lib-game-delta3d-sdk-examples-testProceduralAnimation-proceduralanimationcomponent.cpp / cpp
/*
* Delta3D Open Source Game and Simulation Engine
* Copyright (C) 2009 MOVES Institute
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library 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 Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Michael Guerrero
*/
include <proceduralanimationcomponent.h>
include <proceduralanimationactor.h>
include <testactorlibraryregistry.h>
include <dtABC/application.h>
include <dtGame/basemessages.h>
include <dtAnim/cal3dmodelwrapper.h>
include <dtAnim/cal3dmodeldata.h>
include <dtAnim/cal3ddatabase.h>
include <dtActors/staticmeshactorproxy.h>
include <dtActors/engineactorregistry.h>
include <dtUtil/mathdefines.h>
const std::string &ProceduralAnimationComponent::NAME = "ProceduralAnimationComponent";
//////////////////////////////////////////////////////////////////////////
ProceduralAnimationComponent::ProceduralAnimationComponent(const std::string &name)
: dtGame::BaseInputComponent(name)
{
// nada
}
//////////////////////////////////////////////////////////////////////////
ProceduralAnimationComponent::~ProceduralAnimationComponent()
{
}
//////////////////////////////////////////////////////////////////////////
void ProceduralAnimationComponent::ProcessMessage(const dtGame::Message &message)
{
if(message.GetMessageType() == dtGame::MessageType::INFO_MAP_LOADED)
{
CreateIKActorsForAesthetics();
// IK Actors need access to their pose databases so set them here
InitializeIKActors();
// Set the behavior for each of the actors
for (size_t actorIndex = 0; actorIndex < mActorList.size(); ++actorIndex)
{
ProceduralAnimationActor::eMode mode =
(actorIndex % 2) ? ProceduralAnimationActor::MODE_WATCH: ProceduralAnimationActor::MODE_AIM;
mActorList[actorIndex]->SetMode(mode);
mActorList[actorIndex]->SetTarget(GetGameManager()->GetApplication().GetCamera());
}
}
}
//////////////////////////////////////////////////////////////////////////
void ProceduralAnimationComponent::CreateIKActorGrid(const osg::Vec3& startPos,
const osg::Vec3& forwardDirection,
const osg::Vec3& sideDirection,
int forwardCount, int sideCount,
bool perturb)
{
dtGame::GameManager& gameManager = *GetGameManager();
osg::Vec3 currentPosition = startPos;
// Dynamically create a grid of actors
for (int i = 0; i < forwardCount; ++i)
{
currentPosition = startPos + sideDirection * i;
for (int j = 0; j < sideCount; ++j)
{
dtCore::RefPtr<ProceduralAnimationActorProxy> proxy;
gameManager.CreateActor(*TestActorLibraryRegistry::IK_ACTOR_TYPE, proxy);
if (proxy.valid())
{
gameManager.AddActor(*proxy, false, false);
ProceduralAnimationActor* actor = dynamic_cast<ProceduralAnimationActor*>(&proxy->GetGameActor());
actor->SetModel("SkeletalMeshes/PoseMeshMarine/Eye_Marine_with_posemesh.xml");
proxy->SetTranslation(currentPosition);
mActorList.push_back(actor);
}
currentPosition += forwardDirection;
if (perturb)
{
float factor = dtUtil::RandFloat(-0.5f, 0.5f);
currentPosition += osg::Vec3(factor, factor, factor);
}
}
}
}
//////////////////////////////////////////////////////////////////////////
void ProceduralAnimationComponent::CreateIKActorsForPerfTest()
{
const int HORIZONTAL_ELEMENTS = 15;
const int VERTICAL_ELEMENTS = 15;
const float ELEMENT_SPACE = 2.0f;
const float START_X = -(HORIZONTAL_ELEMENTS / 2) * ELEMENT_SPACE + ELEMENT_SPACE * 0.5f;
const float START_Z = -(VERTICAL_ELEMENTS / 2) * ELEMENT_SPACE;
osg::Vec3 startPos(START_X, osg::square(HORIZONTAL_ELEMENTS) / 2.5f, START_Z);
CreateIKActorGrid(startPos, osg::Z_AXIS * ELEMENT_SPACE, osg::X_AXIS * ELEMENT_SPACE,
VERTICAL_ELEMENTS, HORIZONTAL_ELEMENTS, false);
}
//////////////////////////////////////////////////////////////////////////
void ProceduralAnimationComponent::CreateIKActorsForAesthetics()
{
// Ground clamp dynamically created actors
mGroundClamper = new dtGame::DefaultGroundClamper;
mGroundClamper->SetTerrainActor(GetTerrain());
dtGame::GroundClampingData gcData;
gcData.SetAdjustRotationToGround(false);
gcData.SetUseModelDimensions(false);
const int HORIZONTAL_ELEMENTS = 5;
const int VERTICAL_ELEMENTS = 5;
const float ELEMENT_SPACE = 4.0f;
const float START_X = -(HORIZONTAL_ELEMENTS / 2) * ELEMENT_SPACE + ELEMENT_SPACE * 0.5f;
const float START_Y = -(VERTICAL_ELEMENTS / 2) * ELEMENT_SPACE;
osg::Vec3 startPos(START_X, START_Y, 0.0f);
CreateIKActorGrid(startPos, osg::Y_AXIS * ELEMENT_SPACE, osg::X_AXIS * ELEMENT_SPACE,
VERTICAL_ELEMENTS, HORIZONTAL_ELEMENTS);
for (size_t actorIndex = 0; actorIndex < mActorList.size(); ++actorIndex)
{
dtCore::Transform transform;
mActorList[actorIndex]->GetTransform(transform, dtCore::Transformable::REL_CS);
dtGame::GameActorProxy& proxy = mActorList[actorIndex]->GetGameActorProxy();
// Add this actor to the ground clamp batch
mGroundClamper->ClampToGround(dtGame::BaseGroundClamper::GroundClampingType::RANGED,
0.0, transform, proxy, gcData, true);
}
// Run the batch ground clamp
mGroundClamper->FinishUp();
}
//////////////////////////////////////////////////////////////////////////
void ProceduralAnimationComponent::InitializeIKActors()
{
// Give all IK actors access to the database
for (size_t actorIndex = 0; actorIndex < mActorList.size(); ++actorIndex)
{
dtAnim::PoseMeshDatabase* posemeshDatabase = GetPoseMeshDatabaseForActor(mActorList[actorIndex]);
// IKActors typically have a pose mesh with which to do their IK
if (posemeshDatabase)
{
mActorList[actorIndex]->SetPoseMeshDatabase(posemeshDatabase);
}
}
}
//////////////////////////////////////////////////////////////////////////
dtCore::Transformable* ProceduralAnimationComponent::GetTerrain()
{
dtActors::StaticMeshActorProxy* terrainProxy = NULL;
GetGameManager()->FindActorByType(*dtActors::EngineActorRegistry::STATIC_MESH_ACTOR_TYPE, terrainProxy);
if (terrainProxy)
{
dtCore::Transformable* terrain = NULL;
terrainProxy->GetActor(terrain);
return terrain;
}
else
{
LOG_WARNING("Unable to find terrain in map.");
}
return NULL;
}
//////////////////////////////////////////////////////////////////////////
void ProceduralAnimationComponent::SetAimTarget(const dtCore::Transformable* transformable)
{
// Give all IK actors something to aim at
for (size_t actorIndex = 0; actorIndex < mActorList.size(); ++actorIndex)
{
mActorList[actorIndex]->SetMode(ProceduralAnimationActor::MODE_AIM);
mActorList[actorIndex]->SetTarget(transformable);
}
}
////////////////////////////////////////////////////////////////////
bool ProceduralAnimationComponent::HandleKeyPressed(const dtCore::Keyboard* keyBoard, int key)
{
bool handled = true;
switch (key)
{
case osgGA::GUIEventAdapter::KEY_Escape:
{
GetGameManager()->GetApplication().Quit();
return true;
}
case '~':
{
GetGameManager()->GetApplication().SetNextStatisticsType();
return false;
}
default:
break;
};
if (!handled)
{
return GetGameManager()->GetApplication().KeyPressed(keyBoard, key);
}
return handled;
}
//////////////////////////////////////////////////////////////////////////
void ProceduralAnimationComponent::InitializePerformanceTest()
{
// Dynamically create a grid of actors
CreateIKActorsForPerfTest();
// IK Actors need access to their pose databases so set them here
InitializeIKActors();
SetAimTarget(GetGameManager()->GetApplication().GetCamera());
}
//////////////////////////////////////////////////////////////////////////
Each core model needs to work with its own pose mesh database.
This is not necessary for this example since they all share the same mesh but
is important in a real application that has more than one core model
dtAnim::PoseMeshDatabase* ProceduralAnimationComponent::GetPoseMeshDatabaseForActor(ProceduralAnimationActor* actor)
{
dtAnim::Cal3DDatabase& calDatabase = dtAnim::Cal3DDatabase::GetInstance();
dtAnim::Cal3DModelWrapper* wrapper = actor->GetHelper()->GetModelWrapper();
CalCoreModel* coreModel = wrapper->GetCalModel()->getCoreModel();
// See if this core model already has a pose mesh database that can be shared
std::map<CalCoreModel*, IKDatabase>::iterator mapIter;
mapIter = mPoseMeshMap.find(coreModel);
if (mapIter != mPoseMeshMap.end())
{
return mapIter->second.get();
}
// Get access to the pose mesh file name
dtAnim::Cal3DModelData* modelData = calDatabase.GetModelData(*wrapper);
if (!modelData->GetPoseMeshFilename().empty())
{
// Load up the pose mesh data
dtAnim::PoseMeshDatabase* newPoseDatabase = new dtAnim::PoseMeshDatabase(wrapper);
newPoseDatabase->LoadFromFile(modelData->GetPoseMeshFilename());
mPoseMeshMap.insert(std::make_pair(coreModel, newPoseDatabase));
return newPoseDatabase;
}
LOG_WARNING("IKActor: " + actor->GetName() + " has no pose mesh!");
return NULL;
}
//////////////////////////////////////////////////////////////////////////
(C) Æliens
04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.