First of all we need to create a new Win32 project, "Windows Application" selected and "Empty Project" checked.
There are some options to set into Project Properties:
- 1. Configuration Properties - C/C++ - General - Additional Include Directories:
- <Havok_Home>\Source; <Irrlicht_Home>\include;
- <Havok_Home>\Lib\win32_vs2010\debug_multithreaded; <Irrlicht_Home>\lib\Win32-visualstudio;
- hkBase.lib; hkSceneData.lib; hkSerialize.lib; hkInternal.lib; hkGeometryUtilities.lib; hkVisualize.lib; hkcdInternal.lib; hkcdCollide.lib; hkpCollide.lib; hkpConstraintSolver.lib; hkpDynamics.lib; hkpInternal.lib; hkpUtilities.lib; hkpVehicle.lib; Irrlicht.lib;
Create a header file "game.h":
Code: Select all
#ifndef GAME_H
#define GAME_H
// Common includes
#include <Common/Base/hkBase.h>
#include <Common/Base/Memory/System/Util/hkMemoryInitUtil.h>
#include <Common/Base/Memory/Allocator/Malloc/hkMallocAllocator.h>
// Physics includes
#include <Physics/Collide/hkpCollide.h>
#include <Physics/Collide/Shape/Convex/Sphere/hkpSphereShape.h>
#include <Physics/Collide/Shape/Convex/Box/hkpBoxShape.h>
#include <Physics/Collide/Shape/Compound/Collection/List/hkpListShape.h>
#include <Physics/Collide/Shape/Convex/ConvexTranslate/hkpConvexTranslateShape.h>
#include <Physics/Collide/Shape/Misc/Bv/hkpBvShape.h>
#include <Physics/Collide/Shape/Misc/PhantomCallback/hkpPhantomCallbackShape.h>
#include <Physics/Collide/Dispatch/hkpAgentRegisterUtil.h>
#include <Physics/Dynamics/hkpDynamics.h>
#include <Physics/Dynamics/World/hkpWorld.h>
#include <Physics/Dynamics/Entity/hkpRigidBody.h>
#include <Physics/Dynamics/Constraint/ConstraintKit/hkpGenericConstraintData.h>
#include <Physics/Dynamics/Constraint/ConstraintKit/hkpConstraintConstructionKit.h>
#include <Physics/Dynamics/Constraint/hkpConstraintInstance.h>
#include <Physics/Utilities/Dynamics/Inertia/hkpInertiaTensorComputer.h>
static const int NUM_BODIES = 10;
static const float FRAME_PERIOD = 0.01667f; // ~60 fps
static const int NUM_FRAMES = 60;
class Game {
public:
Game();
~Game();
void step();
hkpRigidBody* m_bodies[NUM_BODIES];
hkpRigidBody* m_ground;
protected:
void createGround();
void createBodies();
void addBody(hkpRigidBody* body);
void removeBody(hkpRigidBody* body);
int m_currentBody;
int m_frameCount;
hkpWorld* m_world;
};
#endif
Code: Select all
#include "game.h"
#include <iostream>
static inline void HK_CALL errorReport(const char* msg, void* userContext) {
std::cerr<<msg<<std::endl;
}
Game::Game() : m_currentBody(0) {
//Initialize Havok
hkMemoryRouter* memoryRouter = hkMemoryInitUtil::initDefault(hkMallocAllocator::m_defaultMallocAllocator, hkMemorySystem::FrameInfo(1024 * 1024));
hkBaseSystem::init(memoryRouter, errorReport);
{
for(int i = 0; i < NUM_BODIES; i++)
m_bodies[i] = HK_NULL;
//Create the world
{
hkpWorldCinfo info;
info.m_gravity = hkVector4(0.0f, -9.8f, 0.0f);
info.setBroadPhaseWorldSize(1000.0f);
info.setupSolverInfo(hkpWorldCinfo::SOLVER_TYPE_8ITERS_MEDIUM);
info.m_collisionTolerance = 0.01f;
m_world = new hkpWorld(info);
m_world->lock();
}
//Register the single agent
{
hkpAgentRegisterUtil::registerAllAgents(m_world->getCollisionDispatcher());
}
createBodies();
createGround();
m_world->unlock();
}
}
Game::~Game() {
m_world->lock();
if(m_ground->isAddedToWorld())
m_world->removeEntity(m_ground);
for(int i = 0; i < NUM_BODIES; i++) {
if(m_bodies[i]->isAddedToWorld())
m_world->removeEntity(m_bodies[i]);
m_bodies[i]->removeReference();
}
m_world->unlock();
m_world->removeReference();
hkBaseSystem::quit();
hkMemoryInitUtil::quit();
}
void Game::createGround() {
const hkVector4 halfExtents(20.0f, 4.0f, 20.0f);
hkpShape* groundShape = new hkpBoxShape(halfExtents, 0.05f);
hkpRigidBodyCinfo bodyInfo;
bodyInfo.m_mass = 0.0f;
bodyInfo.m_shape = groundShape;
bodyInfo.m_motionType = hkpMotion::MOTION_FIXED;
bodyInfo.m_position.set(0.0f, 0.0f, 0.0f);
hkVector4 axis(0.0f, 0.0f, 1.0f);
bodyInfo.m_rotation = hkQuaternion(axis, -0.3f);
m_ground = new hkpRigidBody(bodyInfo);
groundShape->removeReference();
m_world->addEntity(m_ground);
m_ground->removeReference();
}
void Game::createBodies() {
const hkVector4 halfExtents(2.0f, 0.5f, 2.0f);
hkpShape* shape = new hkpBoxShape(halfExtents, 0.05f);
hkpMassProperties massProperties;
hkpInertiaTensorComputer::computeShapeVolumeMassProperties(shape, 5.0f, massProperties);
hkpRigidBodyCinfo bodyInfo;
bodyInfo.m_mass = massProperties.m_mass;
bodyInfo.m_centerOfMass = massProperties.m_centerOfMass;
bodyInfo.m_inertiaTensor = massProperties.m_inertiaTensor;
bodyInfo.m_shape = shape;
bodyInfo.m_motionType = hkpMotion::MOTION_BOX_INERTIA;
for(int i = 0; i < NUM_BODIES; i++) {
m_bodies[i] = new hkpRigidBody(bodyInfo);
}
shape->removeReference();
}
void Game::addBody(hkpRigidBody* currentBody) {
currentBody->setLinearVelocity(hkVector4::getZero());
currentBody->setAngularVelocity(hkVector4::getZero());
hkVector4 position(-5.0f, 17.0f, 0.0f);
currentBody->setPosition(position);
hkQuaternion rot;
rot.setIdentity();
currentBody->setRotation(rot);
m_world->addEntity(currentBody);
}
void Game::removeBody(hkpRigidBody* body) {
m_world->removeEntity(body);
}
void Game::step() {
m_world->stepDeltaTime(FRAME_PERIOD);
m_world->lock();
if(m_frameCount == 0) {
if(m_bodies[m_currentBody]->isAddedToWorld()) {
removeBody(m_bodies[m_currentBody]);
}
addBody(m_bodies[m_currentBody]);
m_currentBody = (++m_currentBody % NUM_BODIES);
}
m_frameCount = (++m_frameCount % NUM_FRAMES);
m_world->unlock();
}
#include <Common/Base/keycode.cxx>
// we're not using any product apart from Havok Physics.
#undef HK_FEATURE_PRODUCT_AI
#undef HK_FEATURE_PRODUCT_ANIMATION
#undef HK_FEATURE_PRODUCT_CLOTH
#undef HK_FEATURE_PRODUCT_DESTRUCTION
#undef HK_FEATURE_PRODUCT_BEHAVIOR
// Also we're not using any serialization/versioning so we don't need any of these.
#define HK_EXCLUDE_FEATURE_SerializeDeprecatedPre700
#define HK_EXCLUDE_FEATURE_RegisterVersionPatches
#define HK_EXCLUDE_FEATURE_MemoryTracker
#include <Common/Base/Config/hkProductFeatures.cxx>
Code: Select all
#include <irrlicht.h>
#include "game.h"
#include "MyEventReceiver.h"
using namespace irr;
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif
struct RenderData {
scene::ISceneNode* groundNode;
scene::ISceneNode* bodyNodes[10];
RenderData() {
groundNode = NULL;
for(int i = 0; i < 10; i++) {
bodyNodes[i] = NULL;
}
}
} g_renderData;
static void renderScene(Game* app, video::IVideoDriver* driver, scene::ISceneManager* smgr) {
//render the ground
{
if(g_renderData.groundNode) {
//position and rotation computed by Havok
hkVector4 tmp = app->m_ground->getPosition();
hkQuaternion quaternion = app->m_ground->getRotation();
g_renderData.groundNode->setPosition(core::vector3df(tmp(0), tmp(1), tmp(2)));
if(quaternion.hasValidAxis()) {
hkReal angle = quaternion.getAngle() * 180.0f / HK_REAL_PI;
hkVector4 axis;
quaternion.getAxis(axis);
g_renderData.groundNode->setRotation(core::vector3df(axis(0)*angle, axis(1)*angle, axis(2)*angle));
}
g_renderData.groundNode->setMaterialTexture(0, driver->getTexture("./media/wall.bmp"));
g_renderData.groundNode->setMaterialFlag(video::EMF_LIGHTING, false);
}
}
//render the bodies
{
for(int i = 0; i < NUM_BODIES; i++) {
if(g_renderData.bodyNodes[i]) {
hkVector4 tmp = app->m_bodies[i]->getPosition();
hkQuaternion quaternion = app->m_bodies[i]->getRotation();
g_renderData.bodyNodes[i]->setPosition(core::vector3df(tmp(0), tmp(1), tmp(2)));
if(quaternion.hasValidAxis()) {
hkReal angle = quaternion.getAngle() * 180.0f / HK_REAL_PI;
hkVector4 axis;
quaternion.getAxis(axis);
g_renderData.bodyNodes[i]->setRotation(core::vector3df(axis(0)*angle, axis(1)*angle, axis(2)*angle));
}
g_renderData.bodyNodes[i]->setMaterialTexture(0, driver->getTexture("./media/t351sml.jpg"));
g_renderData.bodyNodes[i]->setMaterialFlag(video::EMF_LIGHTING, false);
}
}
}
}
int main() {
MyEventReceiver receiver;
IrrlichtDevice* device = createDevice(video::EDT_OPENGL, core::dimension2d<u32>(1366, 768), 32, true, false, true, &receiver);
if(!device)
return 1;
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
device->getCursorControl()->setVisible(false);
scene::ICameraSceneNode* cam = smgr->addCameraSceneNode(0, core::vector3df(0, 10, -40), core::vector3df(0, 0, 0));
smgr->getActiveCamera()->setNearValue(0.1f);
g_renderData.groundNode = smgr->addCubeSceneNode(1.0f, 0, -1, core::vector3df(0, 0, 0), core::vector3df(0, 0, 0), core::vector3df(40.0f, 8.0f, 40.0f));
for(int i = 0; i < NUM_BODIES; i++) {
g_renderData.bodyNodes[i] = smgr->addCubeSceneNode(1.0f, 0, -1, core::vector3df(0, 0, 0), core::vector3df(0, 0, 0), core::vector3df(4.0f, 1.0f, 4.0f));
}
Game* app = new Game();
while(device->run()) {
if(receiver.IsKeyDown(KEY_ESCAPE)) {
device->drop();
return 0;
}
driver->beginScene(true, true, video::SColor(255, 113, 113, 133));
app->step();
renderScene(app, driver, smgr);
smgr->drawAll();
//Sincerely I don't know if this is the right thing to do, but it works :)
u32 start = device->getTimer()->getRealTime();
u32 left = device->getTimer()->getRealTime();
while((left-start) < (FRAME_PERIOD * 1000)) {
left = device->getTimer()->getRealTime();
}
driver->endScene();
}
device->drop();
return 0;
}