Havok Integration: a simple demo

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
mym2o
Posts: 1
Joined: Tue Aug 28, 2012 12:43 am

Havok Integration: a simple demo

Post by mym2o »

This demo is taken from the Havok demos.
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;
    2. Configuration Properties - Linker - General - Additional Library Directories:
    • <Havok_Home>\Lib\win32_vs2010\debug_multithreaded; <Irrlicht_Home>\lib\Win32-visualstudio;
    3. Configuration Properties - Linker - input - Additional Dependencies:
    • 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;
Now we can start to write our code.
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
Then we create "game.cpp":

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>
Finally the "main.cpp":

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;
}
The code of "MyEventReceiver.h" is the same as in the Irrlicht Tutorial.
Post Reply