/* 
GM Irrlicht
Irrlicht Port For Game Maker
Copyright 2004 Xception
remarks:
OpenGL mode doesn't work?
add function to attach window to GM window?
add missing functions
*/

#include <AggressiveOptimize.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <irrlicht.h>


using namespace irr;

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

#define export extern "C" __declspec( dllexport ) double // return double
#define exports extern "C" __declspec( dllexport ) char* // return string
#define gmreturn return (double)(int) // return pointer

#pragma comment(lib, "Irrlicht.lib")


// global variables
HWND IRR_HWND; // Irrlicht window handle
vector3df collisionPoint;
SColor fontColor(255,255,255,255);
SColor minColor(255,0,0,0);
SColor maxColor(255,255,255,255);
aabbox3d<f32> box(-10, 28,-10, 10, 30, 10);
SKeyMap keyMap[8];
IrrlichtDevice *device=NULL;
IVideoDriver* driver;
ISceneManager* smgr;
IGUIEnvironment* guienv;
ISceneCollisionManager* collision;



export startengine(double mode,double w, double h, double bits, double full, double stencil) // mode 1, 2, 3(software, dx, gl)
{
					keyMap[0].Action = EKA_MOVE_FORWARD;
                    keyMap[0].KeyCode = KEY_UP;
                    
                    keyMap[1].Action = EKA_MOVE_BACKWARD;
                    keyMap[1].KeyCode = KEY_DOWN;
                    
                    keyMap[2].Action = EKA_STRAFE_LEFT;
                    keyMap[2].KeyCode = KEY_LEFT;
                    
                    keyMap[3].Action = EKA_STRAFE_RIGHT;
                    keyMap[3].KeyCode = KEY_RIGHT;
                    

if(device) return 0;
	device =createDevice((EDriverType)(int)mode, dimension2d<s32>((int)w, (int)h), (int)bits, (bool)full, stencil, 0);

device->setWindowCaption(L"GM Irrlicht");
driver= device->getVideoDriver();
smgr = device->getSceneManager();
collision=smgr->getSceneCollisionManager();
guienv = device->getGUIEnvironment();
IRR_HWND=FindWindow("CIrrDeviceWin32","GM Irrlicht");
gmreturn IRR_HWND;
}

export setKeyboardFocus(double hwnd)
{
	SetFocus((HWND)(int)hwnd);
	SetCapture((HWND)(int)hwnd);
return 0;
}

export stopengine()
{
device->drop();
device=NULL;
return 0;
}

export drop(double d)
{
	return ((irr::IUnknown*)(int)d)->drop();
}

// Returns true if window is active. If the window is inactive, nothing need to be drawn. 
export isWindowActive()
{
	return device->isWindowActive();
}

// Sets the caption of the window. 
export setWindowCaption(char* text)
{
wchar_t wt[255]; 
	mbstowcs(wt,text,strlen(text)+1);
	device->setWindowCaption(wt);
return 0;
}


/* ++++++++++++++++++++++++++++++++ video driver functions +++++++++++++++++++++++++++++ */

/*
export vd_addDynamicLight(double light)
{
driver->addDynamicLight((SLight)(int)light);
return 0;
}
*/

// Applications must call this method before performing any rendering. 
export vd_beginScene(double back, double z, double a, double r, double g, double b)
{
return driver->beginScene(back, z, SColor((int)a,(int)r,(int)g,(int)b));
}

/*
Creates a software image from a file. 
No hardware texture will be created for this image. 
This method is useful for example if you want to read a heightmap for a terrain renderer. 
*/
export vd_createImageFromFile(char* name)
{
	gmreturn driver->createImageFromFile(name);
}

// Deletes all dynamic lights which were previously added with addDynamicLight
export vd_deleteAllDynamicLights()
{
	driver->deleteAllDynamicLights();
	return 0;
}

// Draws an 2d image, using a color (if color is other than Color(255,255,255,255)) 
//and the alpha channel of the texture if wanted. 
export vd_draw2DImageA(double img, double x, double y, double rx, double ry, 
					  double rx2, double ry2, double ca, double cr,
					  double cg, double cb)
{
	driver->draw2DImage((ITexture*)(int)img,position2d<s32>((int)x,(int)y),
		rect<s32>((int)rx,(int)ry,(int)rx2,(int)ry2),0,SColor((int)ca,(int)cr,(int)cg,(int)cb)
		,true);
	return 0;
}


// doesn't work
// Simply draws an 2d image, without any special effects 	
export vd_draw2DImage(double img, double x, double y)
{
	driver->draw2DImage((ITexture*)(int)img,position2d<s32>((int)x,(int)y));
	return 0;
}

// Draws a 2d line. 
export vd_draw2DLine(double x1, double y1, double x2, double y2, double a, double r, double g,
					 double b)
{
	driver->draw2DLine(position2d<s32>((int)x1,(int)y1),position2d<s32>((int)x2,(int)y2),
		SColor((int)a,(int)r,(int)g,(int)b));
	return 0;
}

// Draws an 2d rectangle. 
export vd_draw2DRectangle(double a, double r, double g, double b,
						  double x1, double y1, double x2, double y2)
{
	driver->draw2DRectangle(SColor((int)a,(int)r,(int)g,(int)b),rect<s32>((int)x1,(int)y1,(int)x2,(int)y2));
	return 0;
}



// Presents the rendered image on the screen. 
// Applications must call this method after performing any rendering. 
export vd_endScene()
{	
	return driver->endScene();
}

// Returns current amount of dynamic lights set 
export vd_getDynamicLightCount()
{
	return driver->getDynamicLightCount();
}


export vd_getFPS()
{
	return driver->getFPS();
}

// Returns the maximal amount of dynamic lights the device can handle
export vd_getMaximalDynamicLightAmount()
{
return driver->getMaximalDynamicLightAmount();
}

//   Returns amount of primitives (mostly triangles) which were drawn in the last frame.
export vd_getPrimitiveCountDrawn()
{
return driver->getPrimitiveCountDrawn();
}

// materials
export vd_getTexture(char* fn)
{
	gmreturn driver->getTexture(fn);
}

/*
Creates an 1bit alpha channel of the texture based of an color key position. 
This makes the texture transparent at the regions where this color key can be found 
when using for example draw2DImage with useAlphachannel = true. 
*/
export vd_makeColorKeyTexture(double texture, double x, double y)
{
	driver->makeColorKeyTexture((ITexture*)(int)texture,position2d<s32>((int)x,(int)y));
	return 0;
}


// Queries the features of the driver, returns true if a feature is available
export vd_queryFeature(double feature)
{
	return driver->queryFeature((E_VIDEO_DRIVER_FEATURE)(int) feature);
}

/*
Removes all texture from the texture cache and deletes them, freeing lot of memory. 
Please note that after calling this, the pointer to all ITextures may not be longer valid,
if they were not grabbed before by other parts of the engine for storing them longer. 
So it would be a good idea to set all materials which are using textures to null first. 
*/
export vd_removeAllTextures()
{
	driver->removeAllTextures();
	return 0;
}

// Removes a texture from the texture cache and deletes it
export vd_removeTexture(double texture)
{
	driver->removeTexture((ITexture*)(int)texture);
	return 0;
}

// Sets the dynamic ambient light color.
export vd_setAmbientLight(double a, double r, double g, double b)
{
driver->setAmbientLight(SColor((int)a,(int)r,(int)g,(int)b));
return 0;
}

// Sets the fog mode. These are global values attached to each 3d object rendered, which has the fog flag enabled in its material. 
export vd_setFog(double a, double r, double g, double b, double linear, double start, double end
			  , double density, double pixel, double range)
{
driver->setFog(SColor((int)a,(int)r,(int)g,(int)b),linear, (float)start, (float)end, 
			   (float)density, pixel, range);
return 0;
}


export vd_render(double back, double z, double a, double r, double g, double b)
{
	driver->beginScene(back, z, SColor(a,r,g,b));
	smgr->drawAll();

	driver->endScene();
return 0;
}

/*
Sets a new render target. 
This will only work, if the driver supports the EVDF_RENDER_TO_TARGET feature, which can be queried with queryFeature(). 
*/
export vd_setRenderTarget(double tex)
{
	driver->setRenderTarget((ITexture*)(int)tex);
	return 0;
}

/*
Enables or disables a texture creation flag. 
This flag defines how textures should be created. 
By changing this value, you can influence the speed of rendering a lot. 
But please note that the video drivers take this value only as recommendation
*/
export vd_setTextureCreationFlag(double flag, double state)
{
	driver->setTextureCreationFlag((E_TEXTURE_CREATION_FLAG)(int)flag,state);
	return 0;
}

// Sets a new viewport. Every rendering operation is done into this new area
export vd_setViewPort(double x1, double y1, double x2, double y2)
{
	driver->setViewPort(rect<s32>(x1,y1,x2,y2));
	return 0;
}

// camera functions

export cam_getAspectRatio(double cam)
{
	return ((ICameraSceneNode*)(int)cam)->getAspectRatio();
}

export cam_getFarValue(double cam)
{
	return ((ICameraSceneNode*)(int)cam)->getFarValue();
}

export cam_getFOV(double cam)
{
	return ((ICameraSceneNode*)(int)cam)->getFOV();
}

export cam_getNearValue(double cam)
{
	return ((ICameraSceneNode*)(int)cam)->getNearValue();
}

export cam_getTargetX(double cam)
{
	return ((ICameraSceneNode*)(int)cam)->getTarget().X;
}

export cam_getTargetY(double cam)
{
	return ((ICameraSceneNode*)(int)cam)->getTarget().Y;
}

export cam_getTargetZ(double cam)
{
	return ((ICameraSceneNode*)(int)cam)->getTarget().Z;
}

export cam_setAspectRatio(double cam, double asp)
{
((ICameraSceneNode*)(int)cam)->setAspectRatio((float)asp);
return 0;
}

export cam_setFarValue(double cam, double f)
{
 ((ICameraSceneNode*)(int)cam)->setFarValue((float)f);
 return 0;
}

export cam_setFOV(double cam, double fov)
{
((ICameraSceneNode*)(int)cam)->setFOV((float)fov);
return 0;
}

export cam_setInputReceiverEnabled(double cam, double mode)
{
((ICameraSceneNode*)(int)cam)->setInputReceiverEnabled(mode);
return 0;
}

export cam_setNearValue(double cam, double n)
{
 ((ICameraSceneNode*)(int)cam)->setNearValue((float)n);
 return 0;
}

export cam_setTarget(double cam, double x, double y, double z)
{
((ICameraSceneNode*)(int)cam)->setTarget(vector3df(x,y,z));
return 0;
}

export cam_setUpVector(double cam, double x, double y, double z)
{
((ICameraSceneNode*)(int)cam)->setUpVector(vector3df(x,y,z));
return 0;
}


/* +++++++++++++++++++++++++++ Animated Mesh Functions  +++++++++++++++++++++++ */

export am_getMesh(double m, double frame, double level, double startf, double endf)
{
	gmreturn ((IAnimatedMesh*)(int)m)->getMesh(frame,level,startf,endf);
}

/* ++++++++++++++++++ Animated Mesh SceneNode functions ++++++++++++++++++++++++ */


/*
Creates shadow volume scene node as child of this node and returns a pointer to it. 
The shadow can be rendered using the ZPass or the zfail method. 
ZPass is a little bit faster because the shadow volume creation is easier, 
but with this method there occur ugly looking artifacs when the camera is inside 
the shadow volume. These error do not occur with the ZFail method. 
*/
export amsn_addShadowVolume(double n, double id, double zf, double i)
{
	gmreturn ((IAnimatedMeshSceneNode*)(int)n)->addShadowVolumeSceneNode((int)id,zf,(float)i);
}

// Returns the current displayed frame number.
export amsn_getFrameNr(double obj)
{
return ((IAnimatedMeshSceneNode*)(int)obj)->getFrameNr();
}

export amsn_getMS3DJointNode(double obj, char* name)
{
	gmreturn ((IAnimatedMeshSceneNode*)(int)obj)->getMS3DJointNode(name);
}

// Sets the speed with witch the animation is played.
export amsn_setAnimationSpeed(double obj, double speed)
{
((IAnimatedMeshSceneNode*)(int)obj)->setAnimationSpeed((int)speed);
return 0;
}

// Sets the current frame number. From now on the animation is played from this frame
export amsn_setCurrentFrame(double obj, double frame)
{
((IAnimatedMeshSceneNode*)(int)obj)->setCurrentFrame((int)frame);
return 0;
}

// Sets the frame numbers between the animation is looped. The default is 0 - MaximalFrameCount of the mesh. 
export amsn_setFrameLoop(double obj,double start, double end)
{
IAnimatedMeshSceneNode* node=(IAnimatedMeshSceneNode*)(int)obj;
node->setFrameLoop((int)start,(int)end);
return 0;
}

// starts md2 animation, argument=name of animation
export amsn_setMD2Animation(double obj, char* ani)
{
return ((IAnimatedMeshSceneNode*)(int)obj)->setMD2Animation(ani);

}


/* ++++++++++++++++++++++++++++ Billboard Functions +++++++++++++++++++++++++++++++ */

export bb_getWidth(double n)
{
	return (((IBillboardSceneNode*)(int)n)->getSize()).Width;
}

export bb_getHeight(double n)
{
	return (((IBillboardSceneNode*)(int)n)->getSize()).Height;
}

export bb_setSize(double n, double w, double h)
{
	((IBillboardSceneNode*)(int)n)->setSize(dimension2d<f32>(w,h));
	return 0;
}


/* ++++++++++++++++++++++++ Terrain SceneNode Functions +++++++++++++++++++++++++++ */

export ter_getHeight(double n, double x, double y)
{
	f32 h=0;
	((ITerrainSceneNode*)(int)n)->getHeight(vector2d<f32>(x,y),h);
	return h;
}

/* +++++++++++++++++++++++++++++++++++ SceneManager +++++++++++++++++++++++++++++++ */

// Adds a scene node for rendering an animated mesh model. 
export sm_addAnimatedMesh(double m, double parent)
{
gmreturn smgr->addAnimatedMeshSceneNode((IAnimatedMesh*)(int)m, (ISceneNode*)(int)parent);
}

/*
Adds a billboard scene node to the scene graph. 
A billboard is like a 3d sprite: 
A 2d element, which always looks to the camera. 
It is usually used for things like explosions, fire, lensflares and things like that.
*/
export sm_addBillboard(double parent, double w, double h)
{

gmreturn smgr->addBillboardSceneNode((ISceneNode*)(int)parent, dimension2d<f32>((float)w,(float)h));
}

/*
Adds a scene node for rendering using a binary space partition tree. 
This is a nice method for rendering indoor scenes. 
Based on a mesh given as parameter, the tree will be build. 
Note that The build process can be slow, if there are lots of polygons. 
Note that the implementation of the BspTree in the Irrlicht Engine is currently not complete a little bit buggy. 
You may want to use the OctTree instead, it already works.
*/
export sm_addBspTree(double m, double parent)
{
gmreturn smgr->addBspTreeSceneNode((IMesh*)(int)m, (ISceneNode*)(int)parent);
}

// Adds a camera scene node to the scene graph and sets it as active camera.
export sm_addCamera(double p)
{
gmreturn smgr->addCameraSceneNode((ISceneNode*)(int)p);
}

// Adds a camera scene node which is able to be controled with the mouse and keys like in most first person shooters (FPS): 
export sm_addCameraFPS(double p, double rot, double move)
{
gmreturn smgr->addCameraSceneNodeFPS((ISceneNode*)(int)p, rot, move,-1,keyMap, 8);
}

// Adds a camera scene node which is able to be controlled with the mouse similar like in the 3D Software Maya 
export sm_addCameraMaya(double p, double rot, double zoom, double trans)
{
gmreturn smgr->addCameraSceneNodeMaya((ISceneNode*)(int)p, (float)rot,(float)zoom,(float)trans);
}

// Adds an empty scene node.
export sm_addEmptyNode(double p)
{
gmreturn smgr->addEmptySceneNode((ISceneNode*)(int)p);
}

/*
export addHillPlaneMesh()
{
smgr->addHillPlaneMesh(name, dimension2d<f32>((float)w,(float)h),
}
*/

// Adds a dynamic light scene node to the scene graph.
export sm_addLight(double p)
{

	gmreturn smgr->addLightSceneNode((ISceneNode*)(int)p);
}

// Adds a scene node for rendering a static mesh. 
export sm_addMesh(double m, double parent)
{
gmreturn smgr->addMeshSceneNode((IMesh*)(int)m, (ISceneNode*)(int)parent);
}

/*
Adds a scene node for rendering using a octtree to the scene graph. 
This a good method for rendering scenes with lots of geometry. 
The Octree is built on the fly from the mesh, much faster then a bsp tree. 
*/
export sm_addOctTree(double m, double parent, double polys) // minimal polys
{
	gmreturn smgr->addOctTreeSceneNode((IMesh*)(int)m, (ISceneNode*)(int)parent,-1,polys);
}

// Adds a particle system scene node to the scene graph.
export sm_addParticleSystem(double defemit, double parent)
{
	gmreturn smgr->addParticleSystemSceneNode(defemit, (ISceneNode*)(int)parent);
}

/* Adds a skybox scene node to the scene graph. 
A skybox is a big cube with 6 textures on it and is drawed around the camera position. 
*/
export sm_addSkyBox(double top, double bottom, double left, double right, double front, double back)
{
	gmreturn smgr->addSkyBoxSceneNode((ITexture*)(int)top,(ITexture*)(int)bottom,
		(ITexture*)(int)left,(ITexture*)(int)right,(ITexture*)(int)front,(ITexture*)(int)back);
}
		
/*
export sm_addTerrainMesh()
{
smgr->addTerrainMesh(
}
*/

/*
export sm_addTerrain()
{
	smgr->addTerrainSceneNode(
}
*/

// Adds a scene node for rendering a animated water surface mesh. 
// Looks really good when the Material type EMT_TRANSPARENT_REFLECTION is used. 
export sm_addWaterSurface(double m, double h, double sp, double l, double parent)
{
	gmreturn smgr->addWaterSurfaceSceneNode((IMesh*)(int)m,(float)h,(float)sp,(float)l, (ISceneNode*)(int)parent);
}

// Creates a special scene node animator for doing automatic collision detection and response.
export sm_createCollisionResponseAnimator(double world, double n, double erx, double ery, 
										  double erz, double gx, double gy, double gz, 
										  double acc, double sv)
{
	gmreturn smgr->createCollisionResponseAnimator((ITriangleSelector*)(int)world,
		(ISceneNode*)(int)n,vector3df((float)erx,(float)ery,(float)erz), 
		vector3df((float)gx,(float)gy,(float)gz),(float)acc, vector3df(0,0,0),(float)sv);
}

// Creates a scene node animator, which deletes the scene node after some time automaticly. 
export sm_createDeleteAnimator(double zeit)
{
	gmreturn smgr->createDeleteAnimator((int)zeit);
}

// Creates a fly circle animator, which lets the attached scene node fly around a center. 
export sm_createFlyCircleAnimator(double cx, double cy, double cz, double radius, double sp)
{
	gmreturn smgr->createFlyCircleAnimator(vector3df((float)cx,(float)cy,(float)cz),(float)radius,(float)sp);
}

// Creates a fly straight animator, which lets the attached scene node fly or move along a line between two points. 
export sm_createFlyStraightAnimator(double spx, double spy, double spz,
									double epx, double epy, double epz, double t, double loop)
{
	gmreturn smgr->createFlyStraightAnimator(vector3df((float)spx,(float)spy,(float)spz),
		vector3df((float)epx,(float)epy,(float)epz),(u32)t, loop);
}

// export createFollowSplineAnimator

/*
Creates a meta triangle selector which is nothing more than a collection of one or more 
triangle selectors providing together the interface of one triangle selector. 
In this way, collision tests can be done with different triangle soups in one pass. 
*/
export sm_createMetaTriangleSelector()
{
	gmreturn smgr->createMetaTriangleSelector();
}

/*
Creates a simple ITriangleSelector, based on a mesh. 
Triangle selectors can be used for doing collision detection. 
This triangle selector is optimized for huge amounts of triangle, it organizes them in an octtree. 
Please note that the created triangle selector is not automaticly attached to the scene node. 
You will have to call ISceneNode::setTriangleSelector() for this. 
To create and attach a triangle selector is done like this: 

          ITriangleSelector* s = sceneManager->createOctTreeTriangleSelector(yourMesh,
                                yourSceneNode);
          yourSceneNode->setTriangleSelector(s);
          s->drop();

Parameters: 
mesh:  Mesh of which the triangles are taken.  
node:  Scene node of which visibility and transformation is used.  
minimalPolysPerNode:  Specifies the minimal polygons contained a octree node. If a node gets less polys the this value, it will not be splitted into smaller nodes.  
*/
export sm_createOctTreeTriangleSelector(double mesh, double node, double minimal)
{
	gmreturn smgr->createOctTreeTriangleSelector((IMesh*)(int)mesh,(ISceneNode*)(int)node,(int)minimal);
}

// Creates a rotation animator, which rotates the attached scene node around itself. 
export sm_createRotationAnimator(double rx, double ry, double rz)
{
	gmreturn smgr->createRotationAnimator(vector3df((float)rx,(float)ry,(float)rz));
}

// export createTextureAnimator

/*
Creates a simple ITriangleSelector, based on a mesh. 
Triangle selectors can be used for doing collision detection. 
Don't use this selector for a huge amount of triangles like in Quake3 maps. 
Instead, use for example ISceneManager::createOctTreeTriangleSelector().
*/
export sm_createTriangleSelector(double m, double node)
{
	gmreturn smgr->createTriangleSelector((IMesh*)(int)m,(ISceneNode*)(int)node);
}

/*
Creates a simple dynamic ITriangleSelector, based on a axis aligned bounding box. 
Triangle selectors can be used for doing collision detection. 
Every time when triangles are queried, the triangle selector gets the bounding box of the scene node, an creates new triangles. 
In this way, it works good with animated scene nodes. 
*/
export sm_createTriangleSelectorFromBB(double node)
{
	gmreturn smgr->createTriangleSelectorFromBoundingBox((ISceneNode*)(int)node);
}

// Draws all the scene nodes. 
//This can only be invoked between IVideoDriver::beginScene() and IVideoDriver::endScene(). 
export sm_drawAll()
{
	smgr->drawAll();
	return 0;
}

// The active camera is returned. 
// Note that this can be NULL, if there was no camera created yet. 
export sm_getActiveCamera()
{
	gmreturn smgr->getActiveCamera();
}

/*
Gets pointer to an animateable mesh. 
Loads it if needed. 
Currently there are the following mesh formats supported: 
.obj, .ms3d(Milkshape3D), .bsp(Quake3 Level), .md2, .3ds, .x(DirectX)
*/
export sm_getMesh(char* fn)
{
gmreturn smgr->getMesh(fn);
}

// Returns a pointer to the mesh manipulator. 
export sm_getMeshManipulator()
{
	gmreturn smgr->getMeshManipulator();
}

/*
Returns the root scene node. 
This is the scene node wich is parent of all scene nodes. 
The root scene node is a special scene node which only exists to manage all scene nodes. 
It is not rendered and cannot be removed from the scene.
*/
export sm_getRootSceneNode()
{
	gmreturn smgr->getRootSceneNode();
}

// export sm_getSceneCollisionManager

// Returns the first scene node with the specified id.
export sm_getSceneNodeFromID(double id, double start)
{
	gmreturn smgr->getSceneNodeFromId((int)id, (ISceneNode*)(int)start);
}

// Sets the active camera. The previous active camera will be deactivated
export sm_setActiveCamera(double cam)
{
	smgr->setActiveCamera((ICameraSceneNode*)(int)cam);
	return 0;
}

export sm_setShadowColor(double a, double r, double g, double b)
{
	smgr->setShadowColor(SColor((int)a,(int)r,(int)g,(int)b));
	return 0;
}

	/* ++++++++++++++++++++++++++++++ nodes ++++++++++++++++++++++++++++++++++++ */

// Adds an animator which should animate this node
export n_addAnimator(double n, double animator)
{
	((ISceneNode*)(int)n)->addAnimator((ISceneNodeAnimator*)(int)animator);
	return 0;
}

// Adds a child to this scene node. 
// If the scene node already has got a parent, it is removed from there as child. 
export n_addChild(double n, double child)
{
((ISceneNode*)(int)n)->addChild((ISceneNode*)(int)child);
return 0;
}

// Returns the current absolute position of the node
export n_getAbsolutePositionX(double n)
{
return (((ISceneNode*)(int)n)->getAbsolutePosition()).X;
}

export n_getAbsolutePositionY(double n)
{
return (((ISceneNode*)(int)n)->getAbsolutePosition()).Y;
}

export n_getAbsolutePositionZ(double n)
{
return (((ISceneNode*)(int)n)->getAbsolutePosition()).Z;
}

// Gets the automatic culling state. 
export n_getAutomaticCulling(double n)
{
	return ((ISceneNode*)(int)n)->getAutomaticCulling();
}

// Returns the id of the scene node. This id can be used to identify the node
export n_geID(double n)
{
	return ((ISceneNode*)(int)n)->getID();
}

//Returns amount of materials used by this scene node. 
export n_getMaterialCount(double n)
{
	return ((ISceneNode*)(int)n)->getMaterialCount();
}

// Returns the name of the node. 
exports n_getName(double n)
{
	return (char*)((ISceneNode*)(int)n)->getName();
}

// Returns the current position of the node relative to the parent
export n_getPositionX(double n)
{
return (((ISceneNode*)(int)n)->getPosition()).X;
}

export n_getPositionY(double n)
{
return (((ISceneNode*)(int)n)->getPosition()).Y;
}

export n_getPositionZ(double n)
{
return (((ISceneNode*)(int)n)->getPosition()).Z;
}

// Returns the current rotation of the node relative to the parent
export n_getRotationX(double n)
{

return (((ISceneNode*)(int)n)->getRotation()).X;
}

export n_getRotationY(double n)
{
return (((ISceneNode*)(int)n)->getRotation()).Y;
}

export n_getRotationZ(double n)
{
return (((ISceneNode*)(int)n)->getRotation()).Z;
}

// Returns the current scale of the node
export n_getScaleX(double n)
{
return (((ISceneNode*)(int)n)->getScale()).X;
}

export n_getScaleY(double n)
{
return (((ISceneNode*)(int)n)->getScale()).Y;
}

export n_getScaleZ(double n)
{
return (((ISceneNode*)(int)n)->getScale()).Z;
}

// Returns a pointer to the TriangleSelector or NULL, if there is none. 
export n_getTriangleSelector(double n)
{
	gmreturn ((ISceneNode*)(int)n)->getTriangleSelector();
}

// Returns true if the node is visible. 
//This is only an option, set by the user and has nothing to do with geometry culling 
export n_isVisible(double n)
{
	return ((ISceneNode*)(int)n)->isVisible();
	
}

// Removes this scene node from the scene, deleting it. 
export n_remove(double n)
{
	((ISceneNode*)(int)n)->remove();
	return 0;
}

// Removes an animator from this scene node.
export n_removeAnimator(double n, double animator)
{
	((ISceneNode*)(int)n)->removeAnimator((ISceneNodeAnimator*)(int)animator);
	return 0;
}

// Removes all animators from this scene node.
export n_removeAnimators(double n)
{
	((ISceneNode*)(int)n)->removeAnimators();
	return 0;
}

// Removes a child from this scene node. 
export n_removeChild(double n, double child)
{
return ((ISceneNode*)(int)n)->removeChild((ISceneNode*)(int)child);
}

/*
Enables or disables automatic culling based on the bounding box. 
Automatic culling is enabled by default. 
Note that not all SceneNodes support culling (the billboard scene node for example) 
and that some nodes always cull their geometry because it is their only reason for existance, 
for example the OctreeSceneNode. 
*/
export n_setAutomaticCulling(double n, double mode)
{
	((ISceneNode*)(int)n)->setAutomaticCulling(mode);
	return 0;
}

// Sets if debug data like bounding boxes should be drawed. 
// Please note that not all scene nodes support this feature. 
export n_setDebugDataVisible(double n, double mode)
{
	((ISceneNode*)(int)n)->setDebugDataVisible(mode);
	return 0;
}

// sets the id of the scene node. This id can be used to identify the node. 
export n_setID(double n, double id)
{
	((ISceneNode*)(int)n)->setID((int)id);
	return 0;
}

// Sets all material flags at once to a new value.
export n_setMaterialFlag(double n, double fl, double mode)
{
	((ISceneNode*)(int)n)->setMaterialFlag((E_MATERIAL_FLAG)(int)fl,mode); // 2. parameter?
	return 0;
}

// Sets the texture of the specified layer in all materials of this scene node to the new texture.
export n_setMaterialTexture(double n, double tex, double layer)
{
//((ISceneNode*) (int)n)->setMaterialFlag(EMF_LIGHTING, false);
((ISceneNode*) (int)n)->setMaterialTexture((int)layer, (ITexture*)(int)tex);
return 0;
}

// Sets the material type of all materials s32 this scene node to a new material type.
export n_setMaterialType(double n, double mt)
{
	((ISceneNode*)(int)n)->setMaterialType((E_MATERIAL_TYPE)(int)mt);
	return 0;
}

// Sets the name of the node. 
export n_setName(double n, char* name)
{
	((ISceneNode*)(int)n)->setName((wchar_t*)name);
	return 0;
}

// Changes the parent of the scene node. 
export n_setParent(double n, double p)
{
	((ISceneNode*)(int)n)->setParent((ISceneNode*)(int)p);
	return 0;
}

// Sets the position of the node. Note that the position is relative to the parent.
export n_setPosition(double obj, double x, double y, double z)
{
ISceneNode* node=(ISceneNode*)(int)obj;
node->setPosition(vector3df((float)x,(float)y,(float)z));
return 0;
}

export n_setRelativePosition(double obj, double r, double x, double y, double z)
{
	((ISceneNode*)(int)obj)->setPosition(vector3df(x,y,z)+((ISceneNode*)(int)r)->getPosition());
	return 0;
}

export n_lift(double n, double speed)
{
	((ISceneNode*)(int)n)->setPosition(vector3df(0,(float)speed,0)+((ISceneNode*)(int)n)->getPosition());
	return 0;
}


export n_move(double n, double speed)
{
	
matrix4 m = ((ISceneNode*)(int)n)->getRelativeTransformation(); 
vector3df v; 

v.X = m.M[8] * speed; 
v.Y = m.M[9] * speed; 
v.Z = m.M[10] * speed; 
//Add to last position 
m.M[12] = v.X + m.M[12]; 
m.M[13] = v.Y + m.M[13]; 
m.M[14] = v.Z + m.M[14]; 
//Set the new position 
((ISceneNode*)(int)n)->setPosition(vector3df(m.M[12], m.M[13], m.M[14])); 
return 0;
}

// Sets the rotation of the node in degrees. This only modifies the relative rotation of the node.
export n_setRotation(double obj, double x, double y, double z)
{
ISceneNode* node=(ISceneNode*)(int)obj;
node->setRotation(vector3df((float)x,(float)y,(float)z));
return 0;
}

// rotates the node
export n_rotate(double obj, double x, double y, double z)
{
ISceneNode* node=(ISceneNode*)(int)obj;
node->setRotation(vector3df((float)x,(float)y,(float)z)+(node->getRotation()));
return 0;
}

// Sets the scale of the scene node.
export n_setScale(double obj, double x, double y, double z)
{
ISceneNode* node=(ISceneNode*)(int)obj;
node->setScale(vector3df((float)x,(float)y,(float)z));
return 0;
}

/*
Sets the triangle selector of the scene node. 
The Selector can be used by the engine for doing collision detection. 
You can create a TriangleSelector with ISceneManager::createTriangleSelector() or ISceneManager::createOctTreeTriangleSelector(). 
Some nodes may create their own selector by default, 
so it would be good to check if there is already a selector in this node by calling ISceneNode::getTriangleSelector(). 
*/
export n_SetTriangleSelector(double node, double triselector)
{
	((ISceneNode*) (int)node)->setTriangleSelector((ITriangleSelector*)(int)triselector);
	return 0;
}

// Sets if the node should be visible or not. All children of this node won't be visible too. 
export n_SetVisible(double node, double visible)
{
	((ISceneNode*) (int)node)->setVisible(visible);
	return 0;
}


export n_updateAbsolutePosition(double n)
{
	((ISceneNode*)(int)n)->updateAbsolutePosition();
	return 0;
}

// cursor

// Returns true if the cursor is visible, false if not. 
export cur_isVisible()
{
	return device->getCursorControl()->isVisible();
}

// New position of the cursor. The coordinates are pixel units
export cur_setPosition(double x, double y)
{
device->getCursorControl()->setPosition((int)x,(int)y);
return 0;
}

// sets cursor visibility
export cur_setVisible(double mode)
{
device->getCursorControl()->setVisible(mode);
return 0;
}


// file system
export addZipArchive(char* name)
{
return device->getFileSystem()->addZipFileArchive(name);
}


/* +++++++++++++++++++++++++++++ SceneCollisionManager +++++++++++++++++++++++++++++++ */


// Finds the collision point of a line and lots of triangles, if there is one. 
// todo: return point and triangle
export scm_getCollisionPoint(double x1, double y1, double z1, 
							 double x2, double y2, double z2, double ts)
{
	vector3df v;
	triangle3df tr;
	return collision->getCollisionPoint(line3d<f32>((float)x1,(float)y1,(float)z1,
		(float)x2,(float)y2,(float)z2),(ITriangleSelector*)(int)ts,collisionPoint,tr);
}


export scm_getCollisionPointX()
{
	return collisionPoint.X;
}

export scm_getCollisionPointY()
{
	return collisionPoint.Y;
}

export scm_getCollisionPointZ()
{
	return collisionPoint.Z;
}


// export scm_getCollisionResultPosition 

/*
Returns the scene node, at which the overgiven camera is looking at 
and which id matches the bitmask. 
A ray is simply casted from the position of the camera to the view target position, 
and all scene nodes are tested against this ray.
*/
export scm_getSNFromCameraBB(double cam, double mask)
{
	gmreturn collision->getSceneNodeFromCameraBB((ICameraSceneNode*)(int)cam,(int)mask);
}

// Returns the nearest scene node which collides with a 3d ray and which id matches a bitmask.
export scm_getSNFromRayBB(double x1, double y1, double z1, 
						  double x2, double y2, double z2, double mask)
{
	gmreturn collision->getSceneNodeFromRayBB(line3d<f32>((float)x1,(float)y1,(float)z1,(float)x2,
		(float)y2,(float)z2),(int)mask);
}

// Returns the scene node, which is currently visible under the overgiven screencoordinates, 
// viewed from the currently active camera
export scm_getSNFromScreenCoordBB(double x, double y, double mask)
{
	gmreturn collision->getSceneNodeFromScreenCoordinatesBB(position2d<s32>((int)x,(int)y),(int)mask);
}

export scm_getScreenCoordinatesFrom3DPositionX(double x, double y, double z, double cam)
{
	return ((position2d<s32>)(collision->getScreenCoordinatesFrom3DPosition(vector3df(x,y,z),(ICameraSceneNode*)(int)cam))).X;
}

export scm_getScreenCoordinatesFrom3DPositionY(double x, double y, double z, double cam)
{
	return ((position2d<s32>)(collision->getScreenCoordinatesFrom3DPosition(vector3df(x,y,z),(ICameraSceneNode*)(int)cam))).Y;
}

export scm_setCollisionResultPosition(double world, double n, double dx, double dy, double dz,
								  double slide, double gx, double gy, double gz)
{
	ISceneNode* node=(ISceneNode*)(int)n;
	aabbox3d<f32> box = node->getBoundingBox();
    vector3df radius = box.MaxEdge - box.getCenter();
	vector3df pos=node->getPosition();
	triangle3df triout;
	bool outFalling;
	node->setPosition(collision->getCollisionResultPosition((ITriangleSelector*)(int)world,pos,radius,
		vector3df(dx,dy,dz),triout,outFalling,slide,vector3df(gx,gy,gz)));
	return outFalling;
}
/* +++++++++++++++++ Axis Aligned Bounding Box functions  ++++++++++++++++++++++ */

export aabb_intersectsWithBox(double n1, double n2)
{
	return (((ISceneNode*)(int)n1)->getTransformedBoundingBox()).intersectsWithBox(((ISceneNode*)(int)n2)->getTransformedBoundingBox());
}

export aabb_intersectsWithLine(double n1, double x1, double y1, double z1, double x2, double y2, double z2)
{
	return (((ISceneNode*)(int)n1)->getTransformedBoundingBox()).intersectsWithLine(line3d<f32>((float)x1,(float)y1,(float)z1,(float)x2,(float)y2,(float)z2));
}

export aabb_isPointInside(double n1, double x, double y, double z)
{
	return (((ISceneNode*)(int)n1)->getTransformedBoundingBox()).isPointInside(vector3d<f32>((float)x,(float)y,(float)z));
}

/* ++++++++++++++++++ Meta Triangle Selector functions (finished) ++++++++++++++++++++++++ */

export mts_addTriangleSelector(double mts, double ts)
{
	((IMetaTriangleSelector*)(int)mts)->addTriangleSelector((ITriangleSelector*)(int)ts);
	return 0;
}

export mts_removeAllTriangleSelectors(double mts)
{
	((IMetaTriangleSelector*)(int)mts)->removeAllTriangleSelectors();
	return 0;
}

export mts_removeTriangleSelector(double mts, double ts)
{
	((IMetaTriangleSelector*)(int)mts)->removeTriangleSelector((ITriangleSelector*)(int)ts);
	return 0;
}

/* +++++++++++++++++ Material functions ++++++++++++++++++++++++++++++++++++++++++++ */

// sets material for each layer, use scene node functions to change all layers/materials
export mat_setAmbientColor(double n, double layer, double a, double r, double g, double b)
{
	(((ISceneNode*)(int)n)->getMaterial((int)layer)).AmbientColor.set((s32)a,(s32)r,(s32)g,(s32)b);
return 0;
}

export mat_setBackFaceCulling(double n, double layer, double bfc)
{
	(((ISceneNode*)(int)n)->getMaterial((int)layer)).BackfaceCulling=bfc;
return 0;
}

export mat_setBilinearFilter(double n, double layer, double bf)
{
	(((ISceneNode*)(int)n)->getMaterial((int)layer)).BilinearFilter=bf;
return 0;
}

export mat_setDiffuseColor(double n, double layer, double a, double r, double g, double b)
{
	(((ISceneNode*)(int)n)->getMaterial((int)layer)).DiffuseColor.set((s32)a,(s32)r,(s32)g,(s32)b);
return 0;
}

export mat_setEmissiveColor(double n, double layer, double a, double r, double g, double b)
{
	(((ISceneNode*)(int)n)->getMaterial((int)layer)).EmissiveColor.set((s32)a,(s32)r,(s32)g,(s32)b);
return 0;
}

export mat_setFog(double n, double layer, double fog)
{
	(((ISceneNode*)(int)n)->getMaterial((int)layer)).FogEnable=fog;
return 0;
}

export mat_setGouraudShading(double n, double layer, double gs)
{
	(((ISceneNode*)(int)n)->getMaterial((int)layer)).GouraudShading=gs;
return 0;
}

export mat_setLighting(double n, double layer, double l)
{
	(((ISceneNode*)(int)n)->getMaterial((int)layer)).Lighting=l;
return 0;
}

export mat_setMaterialType(double n, double layer, double mt)
{
	(((ISceneNode*)(int)n)->getMaterial((int)layer)).MaterialType=(E_MATERIAL_TYPE)(int)mt;
return 0;
}

export mat_setShininess(double n, double layer, double s)
{
	(((ISceneNode*)(int)n)->getMaterial((int)layer)).Shininess=s;
return 0;
}

export mat_setTrilinearFilter(double n, double layer, double tf)
{
	(((ISceneNode*)(int)n)->getMaterial((int)layer)).TrilinearFilter=tf;
return 0;
}

export mat_setWireframe(double n, double layer, double wf)
{
	(((ISceneNode*)(int)n)->getMaterial((int)layer)).Wireframe=wf;
return 0;
}

export mat_setZBuffer(double n, double layer, double zb)
{
	(((ISceneNode*)(int)n)->getMaterial((int)layer)).ZBuffer=zb;
return 0;
}

export mat_setZWriteEnable(double n, double layer, double zw)
{
	(((ISceneNode*)(int)n)->getMaterial((int)layer)).ZWriteEnable=zw;
return 0;
}


/* +++++++++++++++++++++++++++++++ Light Functions (finished)+++++++++++++++++++++++++++++++ */

export l_setAmbientColor(double lsn, double r, double g, double b)
{
	(((ILightSceneNode*)(int)lsn)->getLightData()).AmbientColor=SColorf(r,g,b);
return 0;
}

export l_setCastShadows(double lsn, double cs)
{
	(((ILightSceneNode*)(int)lsn)->getLightData()).CastShadows=cs;
return 0;
}

export l_setDiffuseColor(double lsn, double r, double g, double b)
{
	(((ILightSceneNode*)(int)lsn)->getLightData()).DiffuseColor=SColorf(r,g,b);
return 0;
}

export l_setRadius(double lsn, double r)
{
	(((ILightSceneNode*)(int)lsn)->getLightData()).Radius=r;
return 0;
}

export l_setSpecularColor(double lsn, double r, double g, double b)
{
	(((ILightSceneNode*)(int)lsn)->getLightData()).SpecularColor=SColorf(r,g,b);
return 0;
}


/* +++++++++++++++++++ Particlesystem SceneNode functions (finished) ++++++++++++++++++++++ */

export ps_addAffector(double ps, double pa)
{
	((IParticleSystemSceneNode*)(int)ps)->addAffector((IParticleAffector*)(int)pa);
	return 0;
}


export ps_createBoxEmitter(double ps, double dirx, double diry, double dirz,
							 double minP, double maxP, double minLife, double maxLife,
							 double maxAngle)
{
	
	gmreturn ((IParticleSystemSceneNode*)(int)ps)->createBoxEmitter(box,vector3df(dirx,diry,dirz),
		minP,maxP,minColor, maxColor, minLife,maxLife,maxAngle);
}


export ps_createFadeOutParticleAffector(double ps, double a, double r, double g, double b, double t)
{
	gmreturn ((IParticleSystemSceneNode*)(int)ps)->createFadeOutParticleAffector(SColor(a,r,g,b),t);
}

export ps_createGravityAffector(double ps, double x, double y, double z, double t)
{
	gmreturn ((IParticleSystemSceneNode*)(int)ps)->createGravityAffector(vector3df(x,y,z),t);
}


export ps_setColor(double a1, double r1, double g1, double b1, double a2, double r2, double g2, double b2)
{
	minColor.set(a1,r1,g1,b1);
	maxColor.set(a2,r2,g2,b2);
	return 0;
}

export ps_createPointEmitter(double ps, double dirx, double diry, double dirz,
							 double minP, double maxP, double minLife, double maxLife,
							 double maxAngle)
{
	
	gmreturn ((IParticleSystemSceneNode*)(int)ps)->createPointEmitter(vector3df(dirx,diry,dirz),
		minP,maxP,minColor, maxColor, minLife,maxLife,maxAngle);
}


export ps_removeAllAffectors(double ps)
{
	((IParticleSystemSceneNode*)(int)ps)->removeAllAffectors();
	return 0;
}

export ps_setEmitter(double ps, double e)
{
	((IParticleSystemSceneNode*)(int)ps)->setEmitter((IParticleEmitter*)(int)e);
	return 0;
}

export ps_setParticleSize(double ps, double w, double h)
{
	((IParticleSystemSceneNode*)(int)ps)->setParticleSize(dimension2d<f32>(w,h));
	return 0;
}


/* +++++++++++++++++++ SceneNodeAnimatorCollisionResponse functions ++++++++++++++++++ */

export cr_getAccelerationPerSecond(double crn)
{
	return ((ISceneNodeAnimatorCollisionResponse*)(int)crn)->getAccelerationPerSecond();
}

// getEllipsoidRadius, getEllipsoidTranslation, getGravity, getWorld

export cr_isFalling(double crn)
{
	return ((ISceneNodeAnimatorCollisionResponse*)(int)crn)->isFalling();
}

export cr_setAccelerationPerSecond(double crn, double a)
{
	((ISceneNodeAnimatorCollisionResponse*)(int)crn)->setAccelerationPerSecond(a);
	return 0;
}

export cr_setEllipsoidRadius(double crn, double x, double y, double z)
{
	((ISceneNodeAnimatorCollisionResponse*)(int)crn)->setEllipsoidRadius(vector3df(x,y,z));
	return 0;
}

export cr_setEllipsoidTranslation(double crn, double x, double y, double z)
{
	((ISceneNodeAnimatorCollisionResponse*)(int)crn)->setEllipsoidTranslation(vector3df(x,y,z));
	return 0;
}

export cr_setGravity(double crn, double x, double y, double z)
{
	((ISceneNodeAnimatorCollisionResponse*)(int)crn)->setGravity(vector3df(x,y,z));
	return 0;
}

export cr_setWorld(double crn, double world)
{
	((ISceneNodeAnimatorCollisionResponse*)(int)crn)->setWorld((ITriangleSelector*)(int)world);
	return 0;
}


/* ++++++++++++++++++++++++++ Gui Environment +++++++++++++++++++++++++++ */

export gui_getBuiltInFont()
{
gmreturn guienv->getBuiltInFont();
}

export gui_getFont(char* fname)
{
gmreturn guienv->getFont(fname);
}

/* +++++++++++++++++++++++++++++ Gui Font +++++++++++++++++++++++++++++++++ */

export font_setColor(double r, double g, double b)
{
	fontColor.set(255,r,g,b);
return 0;

}

export font_draw(double font, char* text, double x, double y)
{
	wchar_t wt[255]; 
	mbstowcs(wt,text,strlen(text)+1);
	((IGUIFont*)(int)font)->draw(wt,rect<s32>(x,y,0,0),fontColor);
	return 0;
}


/* +++++++++++++++++++ other functions ++++++++++++++++++++++++++++++++++ */
export mapKey(double i, double key)
{
	keyMap[(int)i].KeyCode=(EKEY_CODE )(int)key;
	return 0;
}

export setBox(double x1, double y1, double z1, double x2, double y2, double z2)
{
	box.MinEdge=vector3df(x1,y1,z1);
	box.MaxEdge=vector3df(x2,y2,z2);
	return 0;
}