#ifdef USE_PHYSICS

#include <irrlicht.h>
#include "irrlichtwrapper.h"

#include <Newton.h>
#include <IPhysics.h>

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;


extern IrrlichtDevice *device;
extern IVideoDriver* driver;
extern ISceneManager* smgr;
extern IGUIEnvironment* guienv;


CPhysics* physics;


/****h* Physics
* NAME
*    Using the Physics-Engine
* DESCRIPTION
*   This IrrlichtWrapper enabvles you to use the great physics-engine
*   with irrlicht. But ther is something to know about the details....
*   As 'Physics-Layer' we using IPhysics, that covers some of the Newton-
*   Features and is made to use it with Irrlicht.
*
*   At the Moment we offer some function to use Static and dynamic meshes.
*   Missing at the Moment are Joints, Sliders ect.
*
*   If you use the Physics-Enmgine, you have also to use/deliver the newton.dll !
*
*   The Use of the Physics are really easy. Take a look at the Physics-Examples
*   to get an idea of what possible.
****
*/


extern "C"
{
/* ----------------------------------------------------------------------------
init physics engine
*/

/****f* Physics/IrrPhysicsInit
* NAME
*    IrrPhysicsInit - init physics engine
* SYNOPSIS
*    IrrPhysicsInit()
* FUNCTION
*   Initialize the Physics-Engine (Newton).
*   You have to call this function before using any of the Physics-Functions
* RESULT
*    nothing
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrPhysicsInit()
*/
STATIC_EXPORT void DLL_EXPORT IrrPhysicsInit()
{
    physics = new CPhysics();
    physics->init(device);
}

/* ----------------------------------------------------------------------------
init physics engine
*/
/****f* Physics/IrrPhysicsClose
* NAME
*    IrrPhysicsClose - close physics engine
* SYNOPSIS
*    IrrPhysicsClose()
* FUNCTION
*   Closes the PhysicsEngine (Newton)
*   You have to call this function before closing your program.
* RESULT
*    nothing
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrPhysicsClose()
*/
STATIC_EXPORT void DLL_EXPORT IrrPhysicsClose()
{
    physics->close();
}

/****f* Physics/IrrPhysicsUpdate
* NAME
*    IrrPhysicsUpdate - update physics world
* SYNOPSIS
*    IrrPhysicsUpdate()
* FUNCTION
*   Updates the Newton-World. You need to call this in your
*   Main-Loop.
* RESULT
*    nothing
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrPhysicsUpdate()
*/
STATIC_EXPORT void DLL_EXPORT IrrPhysicsUpdate()
{
    physics->update();
}

/****f* Physics/IrrPhysicsAddStaticCube
* NAME
*    IrrPhysicsAddStaticCube - add a static cube
* SYNOPSIS
*    IrrPhysicsAddStaticCube(*ptr2IrrlichtSceneNode.l, size_X.f, size_y.f, size_z.f, mass.f)
* FUNCTION
*   adds a static cube.
* INPUTS
*   *ptr2IrrlichtSceneNode.l    - valid pointer to a Irrlicht-SceneNode
*   size_X.f,size_y.f,size_z.f  - size of the cube
*   mass.f                      - mass of the cube
* RESULT
*    pointer to a physics entity
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrPhysicsAddStaticCube(*ptr2IrrlichtSceneNOde.l, size_X.f, size_y.f, size_z.f, mass.f)
*/
STATIC_EXPORT void* DLL_EXPORT IrrPhysicsAddStaticCube(ISceneNode* node, float size_x, float size_y, float size_z, float mass)
{

	SPhysicsPrimitive* staticCube = new SPhysicsPrimitive;
	staticCube->primitiveType = EPT_CUBE;
	staticCube->bodyType = EBT_STATIC;
	staticCube->size = vector3df(size_x,size_y,size_z);
	staticCube->mass = mass;
	staticCube->node = node;

    return physics->addEntity(staticCube);



}

/****f* Physics/IrrPhysicsAddDynamicCube
* NAME
*    IrrPhysicsAddDynamicCube - add a dynamic cube
* SYNOPSIS
*    IrrPhysicsAddDynamicCube(*ptr2IrrlichtSceneNode.l, size_X.f, size_y.f, size_z.f, mass.f)
* FUNCTION
*   adds a dynamic cube.
* INPUTS
*   *ptr2IrrlichtSceneNode.l    - valid pointer to a Irrlicht-SceneNode
*   size_X.f,size_y.f,size_z.f  - size of the cube
*   mass.f                      - mass of the cube
* RESULT
*    pointer to a physics entity
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrPhysicsAddDynamicCube(*ptr2IrrlichtSceneNOde.l, size_X.f, size_y.f, size_z.f, mass.f)
*/
STATIC_EXPORT void* DLL_EXPORT IrrPhysicsAddDynamicCube(ISceneNode* node, float size_x, float size_y, float size_z, float mass)
{

	SPhysicsPrimitive* dynamicCube = new SPhysicsPrimitive;
	dynamicCube->primitiveType = EPT_CUBE;
	dynamicCube->bodyType = EBT_DYNAMIC;
	dynamicCube->size = vector3df(size_x,size_y,size_z);
	dynamicCube->mass = mass;
	dynamicCube->node = node;

    return physics->addEntity(dynamicCube);
}


/****f* Physics/IrrPhysicsAddStaticSphere
* NAME
*    IrrPhysicsAddStaticSphere - add a static sphere
* SYNOPSIS
*    IrrPhysicsAddStaticSphere(*ptr2IrrlichtSceneNode.l, radius_X.f, radius_y.f, radius_z.f, mass.f)
* FUNCTION
*   add a static sphere
* INPUTS
*   *ptr2IrrlichtSceneNode.l    - valid pointer to a Irrlicht-SceneNode
*   radius_X.f,radius_y.fradius_z.f  - size of the sphere
*   mass.f                      - mass of the sphere
* RESULT
*    pointer to a physics entity
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrPhysicsAddStaticSphere(*ptr2IrrlichtSceneNOde.l, radius_X.f, radius_y.f, radius_z.f, mass.f)
*/
STATIC_EXPORT void* DLL_EXPORT IrrPhysicsAddStaticSphere(ISceneNode* node, float radius_x, float radius_y, float radius_z, float mass)
{
	SPhysicsPrimitive* staticSphere = new SPhysicsPrimitive;
	staticSphere->primitiveType = EPT_SPHERE;
	staticSphere->bodyType = EBT_STATIC;
	staticSphere->radius = radius_x;
	staticSphere->size = vector3df(radius_x,radius_y,radius_z);
	staticSphere->mass = mass;
	staticSphere->node = node;

    return physics->addEntity(staticSphere);
}

/****f* Physics/IrrPhysicsAddDynamicSphere
* NAME
*    IrrPhysicsAddDynamicSphere - add a dynamic sphere
* SYNOPSIS
*    IrrPhysicsAddDynamicSphere(*ptr2IrrlichtSceneNode.l, radius_X.f, radius_y.f, radius_z.f, mass.f)
* FUNCTION
*   add a dynamic sphere
* INPUTS
*   *ptr2IrrlichtSceneNode.l    - valid pointer to a Irrlicht-SceneNode
*   radius_X.f,radius_y.fradius_z.f  - size of the sphere
*   mass.f                      - mass of the sphere
* RESULT
*    pointer to a physics entity
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrPhysicsAddDynamicSphere(*ptr2IrrlichtSceneNOde.l, radius_X.f, radius_y.f, radius_z.f, mass.f)
*/
STATIC_EXPORT void* DLL_EXPORT IrrPhysicsAddDynamicSphere(ISceneNode* node, float radius_x, float radius_y, float radius_z, float mass)
{
	SPhysicsPrimitive* dynamicSphere = new SPhysicsPrimitive;
	dynamicSphere->primitiveType = EPT_SPHERE;
	dynamicSphere->bodyType = EBT_DYNAMIC;
	dynamicSphere->radius = radius_x; //vector3df(radius_x,radius_y,radius_z);
	dynamicSphere->size = vector3df(radius_x,radius_y,radius_z);
	dynamicSphere->mass = mass;
	dynamicSphere->node = node;

    return physics->addEntity(dynamicSphere);
}


/****f* Physics/IrrPhysicsAddStaticMesh
* NAME
*    IrrPhysicsAddStaticMesh - add a static Mesh
* SYNOPSIS
*    IrrPhysicsAddStaticMesh(*ptr2IrrlichtMesh.l, *ptr2IrrSceneNode.l,radius_X.f, radius_y.f, radius_z.f, mass.f)
* FUNCTION
*   add a static Mesh
* INPUTS
*   *ptr2IrrlichtMesh.l    - valid pointer to a Irrlicht-Mesh
*   *ptr2IrrSceneNode.l,   - valid pointer to a Irrlicht-SceneNOde
*   scale_X.f,scale_y.f,scale_z.f  - size of the sphere
* RESULT
*    pointer to a physics entity
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrPhysicsAddStaticMesh(*ptr2IrrlichtMesh.l,*ptr2IrrSceneNode.l, scale_X.f, scale_y.f, scale_z.f, mass.f)
*/
STATIC_EXPORT void* DLL_EXPORT IrrPhysicsAddStaticMesh(IAnimatedMesh * mesh, ISceneNode* node, float scale_x, float scale_y, float scale_z)
{
	SPhysicsStaticMesh* staticMesh = new SPhysicsStaticMesh;
	staticMesh->mesh = mesh;
	staticMesh->node = node;
	staticMesh->scale = vector3df(scale_x,scale_y,scale_z);

    return physics->addEntity(staticMesh);
}

/****f* Physics/IrrPhysicsAddTerrain
* NAME
*    IrrPhysicsAddTerrain - add a Terrain
* SYNOPSIS
*    IrrPhysicsAddTerrain(*ptr2IrrlichtTerrain.l)
* FUNCTION
*   add a Terrain
* INPUTS
*   *ptr2IrrlichtTerrain.l    - valid pointer to a Irrlicht-terrain
* RESULT
*    pointer to a physics entity
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrPhysicsAddTerrain(*ptr2IrrlichtTerrain.l)
*/
STATIC_EXPORT void* DLL_EXPORT IrrPhysicsAddTerrain(ITerrainSceneNode* node)
{
	SPhysicsTerrain  terrain;
	terrain.node = node;
	terrain.scale = vector3df(1,1,1);

    return physics->addEntity(&terrain);
}

/****f* Physics/IrrPhysicsAddMesh
* NAME
*    IrrPhysicsAddMesh - add a Mesh
* SYNOPSIS
*    IrrPhysicsAddMesh(*ptr2IrrlichtMesh.l, *ptr2IrrlichtSceneNode.l, scale_X.f, scale_y.f, scale_z.f, mass.f)
* FUNCTION
*   add a Mesh
* INPUTS
*   *ptr2IrrlichtMesh.l    - valid pointer to a Irrlicht-Mesh
*   *ptr2IrrlichtSeneNode.l    - valid pointer to a Irrlicht-SceneNOde
*   scale_X.f,scale_y.f,scale_z.f  - size of the sphere
*   mass.f  - mass of this entity
* RESULT
*    pointer to a physics entity
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrPhysicsAddMesh(*ptr2IrrlichtMesh.l, *ptr2IrrlichtSceneNode.l, scale_X.f, scale_y.f, scale_z.f, mass.f)
*/
STATIC_EXPORT void* DLL_EXPORT IrrPhysicsAddMesh(IAnimatedMesh* mesh, ISceneNode* node, f32 scale_x, f32 scale_y, f32 scale_z, f32 mass)
{
	SPhysicsMesh* dmesh = new SPhysicsMesh();
	dmesh->mesh = mesh;
	dmesh->node = node;
	dmesh->scale = vector3df(scale_x,scale_y,scale_z);
	dmesh->bodyType = EBT_DYNAMIC;
	dmesh->mass = mass;
    return (void*)physics->addEntity(dmesh);
}


/**
 * UNDOCUMENTED
#PBIMPORT:IrrPhysicsAddCar(*car.SPhysicsCar)
*/
STATIC_EXPORT void* DLL_EXPORT IrrPhysicsAddCar(SPhysicsCar* car)
{
	return physics->addCar(car);
}

/**
 * UNDOCUMENTED
#PBIMPORT:IrrPhysicsSetEntityPos(*ptr2IrrlichtPhysicsEntity.l, x.f,y.f,z.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrPhysicsSetEntityPos(IPhysicsEntity* entity, float x, float y, float z)
{
    entity->setPosition(vector3df(x,y,z));
}

/**
 * UNDOCUMENTED
#PBIMPORT:IrrPhysicsGetEntityPos(*ptr2IrrlichtPhysicsEntity.l, *x.f, *y.f, *z.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrPhysicsGetEntityPos(IPhysicsEntity* entity, float& x, float& y, float& z)
{
    vector3df pos = entity->getPosition();
    x=pos.X;
    y=pos.Y;
    z=pos.Z;
}

/**
 * UNDOCUMENTED
#PBIMPORT:IrrPhysicsSetEntityRot(*ptr2IrrlichtPhysicsEntity.l, x.f, y.f, z.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrPhysicsSetEntityRot(IPhysicsEntity* entity, float x, float y, float z)
{
    entity->setRotation(vector3df(x,y,z));
}

/**
 * UNDOCUMENTED
#PBIMPORT:IrrPhysicsGetEntityRot(*ptr2IrrlichtPhysicsEntity.l, *x.f, *y.f, *z.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrPhysicsGetEntityRot(IPhysicsEntity* entity, float& x, float& y, float& z)
{
    vector3df pos = entity->getRotation();
    x=pos.X;
    y=pos.Y;
    z=pos.Z;
}


/**
 * UNDOCUMENTED
#PBIMPORT:IrrPhysicsGetEntityVelocity(*ptr2IrrlichtPhysicsEntity.l, *x.f, *y.f, *z.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrPhysicsGetEntityVelocity(IPhysicsEntity* entity, float& x, float& y, float& z)
{
	f32 veloc[3];
    NewtonBody* b = entity->getBody();
    NewtonBodyGetVelocity(b, &veloc[0]);
    x=veloc[0];
    y=veloc[1];
    z=veloc[2];
}


/**
 * UNDOCUMENTED
#PBIMPORT:IrrPhysicsSetEntityVelocity(*ptr2IrrlichtPhysicsEntity.l, x.f, y.f, z.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrPhysicsSetEntityVelocity(IPhysicsEntity* entity, float x, float y, float z)
{
    vector3df velocity(x,y,z);
    NewtonBodySetVelocity(entity->getBody(), &velocity.X);

/*
	f32 veloc[3] = {x,y,z};
    NewtonBody* b = entity->getBody();
    NewtonBodySetVelocity(b, &veloc[0]);
*/
}

/**
 * UNDOCUMENTED
#PBIMPORT:IrrPhysicsSetEntityMassMatrix(*ptr2IrrlichtPhysicsEntity.l, mass.f, x.f, y.f, z.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrPhysicsSetEntityMassMatrix(IPhysicsEntity* entity, float mass, float x, float y, float z)
{
    NewtonBodySetMassMatrix(entity->getBody(),mass, x,y,z);
}



// -- Car-Special...

	// driving interface
/**
 * UNDOCUMENTED
#PBIMPORT:IrrPhysicsCarSetSteeringPercent(*ptr2IrrlichtPhysicsCar.l, steeringPercent.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrPhysicsCarSetSteeringPercent(IPhysicsCar* car, f32 steeringPercent) {
    car->setSteeringPercent(steeringPercent);
}

/**
 * UNDOCUMENTED
#PBIMPORT:IrrPhysicsCarSetThrottlePercent(*ptr2IrrlichtPhysicsCar.l, throttlePercent.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrPhysicsCarSetThrottlePercent(IPhysicsCar* car, f32 throttlePercent) {
    car->setThrottlePercent(throttlePercent);
}

/**
 * UNDOCUMENTED
#PBIMPORT:IrrPhysicsCarSetBrakesPercent(*ptr2IrrlichtPhysicsCar.l, brakesPercent.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrPhysicsCarSetBrakesPercent(IPhysicsCar* car, f32 brakesPercent) {
    car->setBrakesPercent(brakesPercent);
}

/*
STATIC_EXPORT void DLL_EXPORT IrrPhysicsCarSetSteering(SCar* car, f32 steerangle) {
    car->setSteering(steerangle);
}

STATIC_EXPORT void DLL_EXPORT IrrPhysicsCarSetTorque(SCar* car, f32 torque) {
    car->setTorque(torque);
}

STATIC_EXPORT void DLL_EXPORT IrrPhysicsCarSetBrakes(SCar* car, f32 brakes) {
    car->setBrakes(brakes);
}

STATIC_EXPORT void DLL_EXPORT IrrPhysicsCarSetVehicleSpeed(SCar* car, f32 speed) {
    car->setVehicleSpeed(speed);
}
*/


/**
 * schneller Hack zum normalise
 * UNDOCUMENTED
#PBIMPORT:IrrVectorNormalize(*x.f, *y.f, *z.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrVectorNormalize(f32 &x,f32 &y,f32 &z) {
    vector3df vec = vector3df(x,y,z).normalize();
    x = vec.X;
    y = vec.Y;
    z = vec.Z;
}


}


#endif
