//
// Irrlicht Wrapper for Imperative Languages
// Frank Dodd (2006)
//
// Additional Work
// Michael Taupitz (2006)
//
// This wrapper DLL encapsulates a sub-set of the features of the powerful
// Irrlicht 3D Graphics Engine exposing the Object Oriented architecture and
// providing a functional 3D SDK for languages that are not object oriented.
//
// This source was created with the help of the great examples in the Irrlicht
// SDK and the excellent Irrlicht documentation. This software was developed
// using the GCC compiler and Code::Blocks IDE
//

/* ////////////////////////////////////////////////////////////////////////////
includes
*/
#include "irrlichtwrapper.h"


/* ////////////////////////////////////////////////////////////////////////////
global variables
*/

/* ////////////////////////////////////////////////////////////////////////////
external variables
*/
extern IrrlichtDevice *device;
extern IVideoDriver* driver;
extern ISceneManager* smgr;
extern IGUIEnvironment* guienv;



/****h* Camera
* NAME
*    Camera-Functions
* DESCRIPTION
*   In this Section are several Functions to create Cameras and to modify them.
*   There are some Functions to manipulate the settings of a Camera. E.g. if you want
*   to make a Wide-Screen, you can set the Aspect ratio.
*
****
*/



/* ////////////////////////////////////////////////////////////////////////////
Global Function Declarations

all of the below functions are declared as C functions and are exposed without
any mangled names so that they can be easily imported into imperative
languages like FreeBasic
*/
extern "C"
{

/* ////////////////////////////////////////////////////////////////////////////
CAMERA FUNCTIONS
*/

/****f* Camera/IrrAddFPSCamera
* NAME
*    IrrAddFPSCamera - add a basic first person perspective camera to the scene
* SYNOPSIS
*    *CameraSceneNode.l = IrrAddFPSCamera( [bVerticalMovement.l, rotateSpeed.f, moveSpeed.f, keyMapSize.l, *keyMapArray.IRR_KEYMAP])
* INPUTS
*   bVerticalMovement.l     - Setting this to true makes the camera only move within a horizontal plane, and disables
*                             vertical movement as known from most ego shooters. Default is 'false', with which it is
*                             possible to fly around in space, if no gravity is there.
*   rotateSpeed.f           - Speed with wich the camera is rotated. This can be done only with the mouse.
*   moveSpeed.f             - Speed with which the camera is moved. Movement is done with the cursor keys.
*   keyMapSize.l            - Amount of items in the keymap array.
*   *keyMapArray.IRR_KEYMAP - Optional pointer to an array of a keymap, specifying what keys should be used to move
*                             the camera. If this is null, the default keymap is used. You can define actions more
*                             then one time in the array, to bind multiple keys to the same action.
* FUNCTION
*   Adds a camera scene node which is able to be controlled with the mouse and keys like in most first person shooters (FPS).
*   Look with the mouse, move with cursor keys. If you do not like the default key layout, you may want to specify your own.
* EXAMPLE
*   Dim keyMap.IRR_KEYMAP(8)
*
*   keyMap[0]\Action  = #IRR_EKA_MOVE_FORWARD;
*   keyMap[0]\KeyCode = #IRR_KEY_UP;
*   keyMap[1]\Action  = #IRR_EKA_MOVE_FORWARD;
*   keyMap[1]\KeyCode = #IRR_KEY_KEY_W;
*   keyMap[2]\Action = #IRR_EKA_MOVE_BACKWARD;
*   keyMap[2]\KeyCode = #IRR_KEY_DOWN;
*   keyMap[3]\Action = #IRR_EKA_MOVE_BACKWARD;
*   keyMap[3]\KeyCode = #IRR_KEY_KEY_S;
*
*   keyMap[4]\Action = #IRR_EKA_STRAFE_LEFT;
*   keyMap[4]\KeyCode = #IRR_KEY_LEFT;
*   keyMap[5]\Action = #IRR_EKA_STRAFE_LEFT;
*   keyMap[5]\KeyCode = #IRR_KEY_KEY_A;
*
*   keyMap[6]\Action = #IRR_EKA_STRAFE_RIGHT;
*   keyMap[6]\KeyCode = #IRR_KEY_RIGHT;
*   keyMap[7]\Action = #IRR_EKA_STRAFE_RIGHT;
*   keyMap[7]\KeyCode = #IRR_KEY_KEY_D;
*
*   *camera.l = IrrAddFPSCamera(#False,100,0,500.0,8, @keyMap[0])
* RESULT
*    Pointer to a FPSCamera-SceneNode
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrAddFPSCamera( bVerticalMovement.l = #False, rotateSpeed.f = 100.00, moveSpeed.f=500.00, keyMapSize.l=0, *keyMapArray.IRR_KEYMAP=#Null)
*/

STATIC_EXPORT void * DLL_EXPORT IrrAddFPSCamera( bool bVerticalMovement = false,
                                                 f32 rotateSpeed=100.00f, f32 moveSpeed = 500.0f,
                                                 s32 keyMapSize=0, SKeyMap* keyMapArray=NULL
                                                )
{
    return (void *)smgr->addCameraSceneNodeFPS(NULL, rotateSpeed, moveSpeed,-1,keyMapArray, keyMapSize, bVerticalMovement  );
}


/****f* Camera/IrrAddCamera
* NAME
*    IrrAddCamera - add a camera to the scene
* SYNOPSIS
*    *CameraSceneNode.l = IrrAddCamera(posX.f,posY.f,posZ.f, lookAtX.f, lookAtY.f, lookAtZ.f)
* INPUTS
*   posX.f,posY.f,posZ.f            - position of the camera
*  lookAtX.f,lookAtY.f,lookAtZ.f    - Target of tha Camera (point to look at)
* FUNCTION
*   Adds a camera scene node to the scene graph and sets it as active camera.
*   This camera does not react on user input like for example the one created with
*   IrrAddFPSCamera(). If you want to move or animate it, use animators or the
*   IrrSetNodePosition() , IrrSetCameraTarget() etc methods.
* EXAMPLE
*   *camera.l = IrrAddCamera(0,0,0, 10,0,0)
* RESULT
*    Pointer to a Camera-SceneNode
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrAddCamera(posX.f,posY.f,posZ.f, lookAtX.f, lookAtY.f, lookAtZ.f)
*/

STATIC_EXPORT void * DLL_EXPORT IrrAddCamera( float cameraX, float cameraY, float cameraZ, float targetX, float targetY, float targetZ )
{
	/*
	To look at the mesh, we place a camera into 3d space at the position
	(0, 30, -40). The camera looks from there to (0,5,0).
	*/
	return (void *)smgr->addCameraSceneNode(0,
            vector3df(cameraX,cameraY,cameraZ),
            vector3df(targetX,targetY,targetZ)
    );
}

/****f* Camera/IrrAddCameraMaya
* NAME
*    IrrAddCameraMaya - add a maya-camera to the scene
* SYNOPSIS
*    *CameraSceneNode.l = IrrAddCameraMaya(*parentNode.l, rotateSpeed.f, zoomSpeed.f, translationSpeed.f, [id.l])
* INPUTS
*   *parentNode.l       - pointer to a Scenen-Node that acts as Parent of this Camera (otherwise #Null)
*   rotateSpeed.f       - Rotation speed of the camera
*   zoomSpeed.f         - Zoom speed of the camera
*   translationSpeed.f  - Translation speed of the camera
*   id.l                - a optional id for this SceneNode.
* FUNCTION
*   Adds a maya style user controlled camera scene node to the scene graph.
*   The maya camera is able to be controlled with the mouse similar like in
*   the 3D Software Maya by Alias Wavefront.
* EXAMPLE
*   *camera.l = IrrAddCameraMaya(#Null, -1500.00, 200.00, 1500.00 )
* RESULT
*    Pointer to a Camera-SceneNode
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrAddCameraMaya(*parentNode.l=#NULL, rotateSpeed.f=-1500.0, zoomSpeed.f=200.00, translationSpeed.f=1500.00, id.l=-1)
*/

STATIC_EXPORT void * DLL_EXPORT IrrAddCameraMaya(ISceneNode *  parent, f32 rotateSpeed, f32 zoomSpeed, f32 translationSpeed, s32 id )
{
    return (void*) smgr->addCameraSceneNodeMaya(parent,rotateSpeed,zoomSpeed,translationSpeed,id);
}

/****f* Camera/IrrSetCameraTarget
* NAME
*    IrrSetCameraTarget - change lookat
* SYNOPSIS
*    IrrSetCameraTarget(*camera.l, x.f,y.f,z.f)
* INPUTS
*   *camera.l           - pointer to a camera
*   x.f,y.f,z.f         - defines the new Target of the Camera
* FUNCTION
*   Sets the look at target of the camera.
* EXAMPLE
*   IrrSetCameraTarget(*cam, 100.0, 0.0, 0.0)
* RESULT
*    nothing
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrSetCameraTarget(*camera.l, x.f,y.f,z.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrSetCameraTarget ( ICameraSceneNode* camera, float X, float Y,  float Z )
{
	camera->setTarget(core::vector3df(X,Y,Z));
}

/****f* Camera/IrrGetCameraTarget
* NAME
*    IrrGetCameraTarget - get the lookat
* SYNOPSIS
*   IrrGetCameraTarget(*camera.l, *x.f,*y.f,*z.f)
* INPUTS
*   *camera.l           - pointer to a camera
*   *x.f,*y.f,*z.f      - returns the Target of the Camera
* FUNCTION
*   Gets the look at target of the camera.
* EXAMPLE
*   IrrGetCameraTarget(*cam, @x.f,@y.f,@z.f)
* RESULT
*    nothing
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrGetCameraTarget(*camera.l, *x.f,*y.f,*z.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrGetCameraTarget ( ICameraSceneNode* camera, float &X, float &Y,  float &Z )
{
	vector3df vect = camera->getTarget();
	X = vect.X;
	Y = vect.Y;
	Z = vect.Z;
}

/****f* Camera/IrrSetCameraClipDistance
* NAME
*    IrrSetCameraClipDistance - set the distance at which the camera starts to clip polys
* SYNOPSIS
*   IrrSetCameraClipDistance(*camera.l, distance.f)
* INPUTS
*   *camera.l       - pointer to a camera
*   distance.f      - new far-value of the Camera
* FUNCTION
*   Sets the value of the far clipping plane (default: 2000.0f).
* EXAMPLE
*   IrrSetCameraClipDistance(*cam, 1000.00)
* RESULT
*    nothing
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrSetCameraClipDistance(*camera.l, distance.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrSetCameraClipDistance ( ICameraSceneNode* camera, float distance )
{
	camera->setFarValue(distance);
}

/****f* Camera/IrrGetCameraClipDistance
* NAME
*    IrrGetCameraClipDistance - get the distance at which the camera starts to clip polys
* SYNOPSIS
*   IrrGetCameraClipDistance(*camera.l, *distance.f)
* INPUTS
*   *camera.l       - pointer to a camera
*   *distance.f     - returns far-value of the Camera
* FUNCTION
*   Gets the value of the far clipping plane.
* EXAMPLE
*   IrrGetCameraClipDistance(*cam, @distance.f)
* RESULT
*    nothing
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrGetCameraClipDistance(*camera.l, *distance.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrGetCameraClipDistance ( ICameraSceneNode* camera, float &distance )
{
    distance = camera->getFarValue();
}

/****f* Camera/IrrSetActiveCamera
* NAME
*    IrrSetActiveCamera - set the active camera in the scene
* SYNOPSIS
*   IrrSetActiveCamera(*camera.l)
* INPUTS
*   *camera.l       - pointer to a camera
*
* FUNCTION
*   Sets the currently active camera.
*   The previous active camera will be deactivated.
*
* EXAMPLE
*   IrrSetActiveCamera(*cam)
* RESULT
*    nothing
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrSetActiveCamera(*camera.l)
*/
STATIC_EXPORT void DLL_EXPORT IrrSetActiveCamera ( ICameraSceneNode* camera )
{
    smgr->setActiveCamera(camera);
}

/****f* Camera/IrrSetActiveCamera
* NAME
*    IrrGetActiveCamera - get the active camera in the scene
* SYNOPSIS
*   *camera.l = IrrGetActiveCamera()
* INPUTS
*   *camera.l       - pointer to a camera
*
* FUNCTION
*   Gets the currently active camera.
*
* EXAMPLE
*   *cam.l =IrrGetActiveCamera()
* RESULT
*    nothing
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrGetActiveCamera()
*/
STATIC_EXPORT void *  DLL_EXPORT IrrGetActiveCamera (  )
{
    return smgr->getActiveCamera();

}

/****f* Camera/IrrSetCameraFOV
* NAME
*    IrrSetCameraFOV - sets the field of view
* SYNOPSIS
*   IrrSetCameraFOV(*camera.l, fov.f)
* INPUTS
*   *camera.l   - pointer to a camera
*   fov.f       - New field of view in radiants
* FUNCTION
*   Sets the field of view (Default: PI / 2.5f).
* EXAMPLE
*   IrrSetCameraFOV(*cam, #PI / 3.0)
* RESULT
*    nothing
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrSetCameraFOV(*camera.l, fov.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrSetCameraFOV ( ICameraSceneNode* camera, float fov )
{
	camera->setFOV(fov);
}

/****f* Camera/IrrGetCameraFOV
* NAME
*    IrrGetCameraFOV - gets the field of view
* SYNOPSIS
*   IrrSetCameraFOV(*camera.l, *fov.f)
* INPUTS
*   *camera.l   - pointer to a camera
*   *fov.f      - returns Field of view in radiants
* FUNCTION
*   Sets the field of view (Default: PI / 2.5f).
* EXAMPLE
*   IrrGetCameraFOV(*cam, @fov.f)
* RESULT
*    nothing
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrGetCameraFOV(*camera.l, *fov.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrGetCameraFOV ( ICameraSceneNode* camera, float &fov )
{
	fov = camera->getFOV();
}

/****f* Camera/IrrSetCameraAspectRatio
* NAME
*    IrrSetCameraAspectRatio - Sets the aspect ratio
* SYNOPSIS
*   IrrSetCameraAspectRatio(*camera.l, ratio.f)
* INPUTS
*   *camera.l   - pointer to a camera
*   ratio.f     - new aspect ratio
* FUNCTION
*   Sets the aspect ratio (default: 4.0f / 3.0f).
* EXAMPLE
*   IrrSetCameraAspectRatio(*cam, 1.0*(ScreenWidth/ScreenHeight))
* RESULT
*    nothing
* NOTES
*   If you want to change this, maybe for a Widescreen, you should
*   notice, that there is also IrrSetVieport(), that helps.
*
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrSetCameraAspectRatio(*camera.l, ratio.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrSetCameraAspectRatio( ICameraSceneNode* camera, float ratio )
{
    camera->setAspectRatio(ratio);
}

/****f* Camera/IrrGetCameraAspectRatio
* NAME
*    IrrGetCameraAspectRatio - Get the aspect ratio
* SYNOPSIS
*   IrrGetCameraAspectRatio(*camera.l, *ratio.f)
* INPUTS
*   *camera.l   - pointer to a camera
*   *ratio.f    - returns Apect Ratio of this Camera
* FUNCTION
*   Get the aspect ratio
* EXAMPLE
*   IrrGetCameraAspectRatio(*cam, @ratio.f)
* RESULT
*    nothing
*
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrGetCameraAspectRatio(*camera.l, *ratio.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrGetCameraAspectRatio( ICameraSceneNode* camera, float &ratio )
{
    ratio = camera->getAspectRatio();
}

/****f* Camera/IrrSetCameraNearValue
* NAME
*    IrrSetCameraNearValue - Sets the value of the near clipping plane.
* SYNOPSIS
*   IrrSetCameraNearValue(*camera.l, near.f)
* INPUTS
*   *camera.l   - pointer to a camera
*   near.f      - new near-value of this Camera
* FUNCTION
*   Sets the value of the near clipping plane. (default: 1.0f)
* EXAMPLE
*   IrrSetCameraNearValue(*cam, 1.2)
* RESULT
*    nothing
*
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrSetCameraNearValue(*camera.l, near.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrSetCameraNearValue( ICameraSceneNode* camera, float near )
{
    camera->setNearValue(near);
}

/****f* Camera/IrrGetCameraNearValue
* NAME
*    IrrGetCameraNearValue - Get the value of the near clipping plane.
* SYNOPSIS
*   IrrGetCameraNearValue(*camera.l, *near.f)
* INPUTS
*   *camera.l   - pointer to a camera
*   *near.f     - returns near-value of this Camera
* FUNCTION
*   Get the value of the near clipping plane. (default: 1.0f)
* EXAMPLE
*   IrrGetCameraNearValue(*cam,@near.f)
* RESULT
*    nothing
*
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrGetCameraNearValue(*camera.l, *near.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrGetCameraNearValue( ICameraSceneNode* camera, float & near )
{
    near = camera->getNearValue();
}

/****f* Camera/IrrSetCameraUpVector
* NAME
*    IrrSetCameraUpVector - Sets the up vector of the camera.
* SYNOPSIS
*   IrrSetCameraUpVector(*camera.l, upX.f, upY.f, upZ.f)
* INPUTS
*   *camera.l           - pointer to a camera
*   upX.f,upY.f,upZ.f   - new up-vector of this Camera
* FUNCTION
*   Sets the up vector of the camera.
* EXAMPLE
*   IrrSetCameraUpVector(*cam,up.f)
* RESULT
*    nothing
*
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrSetCameraUpVector(*camera.l, upX.f, upY.f, upZ.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrSetCameraUpVector( ICameraSceneNode* camera, float vec_x,float vec_y,float vec_z )
{
    camera->setUpVector(vector3df(vec_x,vec_y,vec_z));
}

/****f* Camera/IrrGetCameraUpVector
* NAME
*    IrrGetCameraUpVector - Get the up vector of the camera.
* SYNOPSIS
*   IrrGetCameraUpVector(*camera.l, *upX.f, *upY.f, *upZ.f)
* INPUTS
*   *camera.l              - pointer to a camera
*   *upX.f,*upY.f,*upZ.f   - returns up-vector of this Camera
* FUNCTION
*   Get the up vector of the camera.
* EXAMPLE
*   IrrGetCameraUpVector(*cam,@upX.f,@upY.f,@upZ.f)
* RESULT
*    nothing
*
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrGetCameraUpVector(*camera.l, *upX.f, *upY.f, *upZ.f)
*/
STATIC_EXPORT void DLL_EXPORT IrrGetCameraUpVector( ICameraSceneNode* camera, float & vec_x, float & vec_y, float & vec_z )
{
    vector3df vec = camera->getUpVector();
    vec_x = vec.X;
    vec_y = vec.Y;
    vec_z = vec.Z;

}

/****f* Camera/IrrSetCameraOrthogonal
* NAME
*    IrrSetCameraOrthogonal - Sets if this camera should return if it is orthogonal.
* SYNOPSIS
*   IrrSetCameraOrthogonal(*camera.l, bOrtho.l)
* INPUTS
*   *camera.l              - pointer to a camera
*   bOrtho.l               - Set / Unset set Ortho-Flag of the Camera
* FUNCTION
*  Sets if this camera should return if it is orthogonal.
*  This setting does not change anything of the view or projection matrix. However
*  it influences how collision detection and picking is done with this camera.
* EXAMPLE
*   IrrSetCameraOrthogonal(*cam,#True)
* RESULT
*    nothing
*
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrSetCameraOrthogonal(*camera.l,  bOrtho.l)
*/
STATIC_EXPORT void DLL_EXPORT IrrSetCameraOrthogonal( ICameraSceneNode* camera, bool ortho )
{
    camera->setIsOrthogonal(ortho);
}

/****f* Camera/IrrGetCameraOrthogonal
* NAME
*    IrrGetCameraOrthogonal - Returns if a camera is orthogonal.
* SYNOPSIS
*   IrrGetCameraOrthogonal(*camera.l)
* INPUTS
*   *camera.l              - pointer to a camera
* FUNCTION
*  Returns if a camera is orthogonal.
* EXAMPLE
*   IrrGetCameraOrthogonal(*cam)
* RESULT
*   The bOrtho-Flag of the Camera (#true or #False)
*
****
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrGetCameraOrthogonal(*camera.l)
*/
STATIC_EXPORT bool DLL_EXPORT IrrGetCameraOrthogonal( ICameraSceneNode* camera )
{
    return camera->isOrthogonal();
}


/* ////////////////////////////////////////////////////////////////////////////
all of the above functions are declared as C functions and are exposed without
any mangled names
*/
}
