// ----------------------------------------------------------------------------
// Blitz-Irrlicht 1.8.3 Wrapper by Ed Musolino 2015
// Based off of Frank Dodd's Irrlicht 1.7 Freebasic Wrapper (2006-2010)
// ----------------------------------------------------------------------------

//  This software is provided 'as-is', without any express Or implied
//  warranty.  In no event will the authors be held liable For any damages
//  arising from the use of this software.

//  Permission is granted To anyone To use this software For any purpose,
//  including commercial applications, And To alter it And redistribute it
//  freely, subject To the following restrictions:

//  1. The Origin of this software must Not be misrepresented; you must not
//     claim that you wrote the original software. If you use this software
//     in a product, an acknowledgement in the product documentation would be
//     appreciated but is Not required.
//  2. Altered source versions must be clearly marked as such, And must Not be
//     misrepresented as being the original software.
//  3. This notice may Not be removed Or altered from any source distribution.
//
// /////////////////////////////////////////////////////////////////////////////

#include "bIrrlicht.h"

//Node Collision Information
extern float g_NodeCollisionPointX;
extern float g_NodeCollisionPointY;
extern float g_NodeCollisionPointZ;
extern float g_NodeCollisionPointNX;
extern float g_NodeCollisionPointNY;
extern float g_NodeCollisionPointNZ;

extern float g_NewPositionX;
extern float g_NewPositionY;
extern float g_NewPositionZ;
extern float g_HitPositionX;
extern float g_HitPositionY;
extern float g_HitPositionZ;
extern bool g_Falling;

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


extern "C"
{

/*
ResetEntity (entity)
Parameters
entity - entity handle  

Description
Resets the collision state of an entity.
*/
DLL_EXPORT void BBCALL iResetNode( ISceneNode *node )
{

}


/*
EntityRadius (entity,x_radius#[,y_radius#])
Parameters
entity - entity handle 
x_radius# - x radius of entity's collision ellipsoid 
y_radius# (optional) - y radius of entity's collision ellipsoid. If omitted the x_radius# will be used for the y_radius#.  

Description
Sets the radius of an entity's collision ellipsoid. 
*/
DLL_EXPORT void BBCALL iNodeRadius( ISceneNode *node, float x_radius, float y_radius )
{
	if(!y_radius)
		y_radius = x_radius;


}


/*
EntityBox (entity,x#,y#,z#,width#,height#,depth#)
Parameters
entity - entity handle# 
x# - x position of entity's collision box 
y# - y position of entity's collision box 
z# - z position of entity's collision box 
width# - width of entity's collision box 
height# - height of entity's collision box 
depth# - depth of entity's collision box  

Description
Sets the dimensions of an entity's collision box. 
*/
DLL_EXPORT void BBCALL iNodeBox( ISceneNode *node, float x, float y, float z, float width, float height, float depth )
{

}

/*
EntityType (entity,collision_type[,recursive])
Parameters
entity - entity handle 
collision_type - collision type of entity. Must be in the range 0-999. 
recursive (optional) - true to apply collision type to entity's children. Defaults to false.  

Description
Sets the collision type for an entity. 
*/
DLL_EXPORT void BBCALL iNodeType( ISceneNode *node, int collision_type, bool recursive )
{
	//return node->getType();  //WRONG TYPE
}



/*
EntityPickMode (entity,pick_geometry[,obscurer])
Parameters
entity - entity handle 

pick_geometry - type of geometry used for picking: 
0: Unpickable (default) 
1: Sphere (EntityRadius is used) 
2: Polygon 
3: Box (EntityBox is used) 

obscurer (optional) - True to determine that the entity 'obscures' other entities during an EntityVisible call. Defaults to True.  

Description
Sets the pick mode for an entity. 
*/
DLL_EXPORT void BBCALL iNodePickMode( ISceneNode *node, int pick_geometry, bool obscurer )
{

}



/*
EntityCollided ( entity,type )
Parameters
entity - entity handle 
type - type of entity  

Description
Returns the handle of the entity of the specified type that collided with the specified entity. 
*/
DLL_EXPORT ISceneNode * BBCALL iNodeCollided( ISceneNode *node, int type )
{

	return NULL;	//CHANGE TO RETURN NODE WHEN WRITTEN
}



/*
CountCollisions ( entity )
Parameters
entity - entity handle  

Description
Returns how many collisions an entity was involved in during the last UpdateWorld. 
*/
DLL_EXPORT int BBCALL iCountCollisions( ISceneNode *node )
{

	return NULL;	//CHANGE TO RETURN NODE WHEN WRITTEN
}


/*
CollisionX# ( entity,index )
Parameters
entity - entity handle 
index - index of collision  

Description
Returns the world x coordinate of a particular collision. 
*/
DLL_EXPORT float BBCALL iCollisionX( ISceneNode *node, int index )
{

	return NULL;	//CHANGE TO RETURN NODE WHEN WRITTEN
}



/*
CollisionY# ( entity,index )
Parameters
entity - entity handle 
index - index of collision  

Description
Returns the world y coordinate of a particular collision. 
*/
DLL_EXPORT float BBCALL iCollisionY( ISceneNode *node, int index )
{

	return NULL;	//CHANGE TO RETURN NODE WHEN WRITTEN
}



/*
CollisionZ# ( entity,index )
Parameters
entity - entity handle 
index - index of collision  

Description
Returns the world z coordinate of a particular collision. 
*/
DLL_EXPORT float BBCALL iCollisionZ( ISceneNode *node, int index )
{

	return NULL;	//CHANGE TO RETURN NODE WHEN WRITTEN
}



/*
CollisionNX# ( entity,index )
Parameters
entity - entity handle 
index - index of collision  

Description
Returns the x component of the normal of a particular collision. 
*/
DLL_EXPORT float BBCALL iCollisionNX( ISceneNode *node, int index )
{

	return NULL;	//CHANGE TO RETURN NODE WHEN WRITTEN
}



/*
CollisionNY# ( entity,index )
Parameters
entity - entity handle 
index - index of collision  

Description
Returns the y component of the normal of a particular collision. 
*/
DLL_EXPORT float BBCALL iCollisionNY( ISceneNode *node, int index )
{

	return NULL;	//CHANGE TO RETURN NODE WHEN WRITTEN
}



/*
CollisionNZ# ( entity,index )
Parameters
entity - entity handle 
index - index of collision  

Description
Returns the z component of the normal of a particular collision. 
*/
DLL_EXPORT float BBCALL iCollisionNZ( ISceneNode *node, int index )
{

	return NULL;	//CHANGE TO RETURN NODE WHEN WRITTEN
}



/*
CollisionTime ( entity,index )
Parameters
entity - entity handle 
index - index of collision  

Description
Returns the time taken to calculate a particular collision. 
*/
DLL_EXPORT int BBCALL iCollisionTime( ISceneNode *node, int index )
{

	return NULL;	//CHANGE TO RETURN NODE WHEN WRITTEN
}



/*
CollisionEntity ( entity,index )
Parameters
entity - entity handle 
index - index of collision  

Description
Returns the other entity involved in a particular collision. Index should be in the range 1...CountCollisions( entity ), inclusive. 
*/
DLL_EXPORT ISceneNode * BBCALL iCollisionNode( ISceneNode *node, int index )
{

	return NULL;	//CHANGE TO RETURN NODE WHEN WRITTEN
}



/*
CollisionSurface ( entity,index )
Parameters
entity - entity handle 
index - index of collision  

Description
Returns the handle of the surface belonging to the specified entity that was closest to the point of a particular collision. 
*/
DLL_EXPORT ISceneNode * BBCALL iCollisionSurface( ISceneNode *node, int index )
{

	return NULL;	//CHANGE TO RETURN NODE WHEN WRITTEN
}



/*
CollisionTriangle ( entity,index )
Parameters
entity - entity handle 
index - index of collision  

Description
Returns the index number of the triangle belonging to the specified entity that was closest to the point of a particular collision. 
Index should be in the range 1...CountCollisions( entity ), inclusive. 
*/
DLL_EXPORT ISceneNode * BBCALL iCollisionTriangle( ISceneNode *node, int index )
{

	return NULL;	//CHANGE TO RETURN NODE WHEN WRITTEN
}



/*
GetEntityType ( entity )
Parameters
entity - entity handle  

Description
Returns the collision type of an entity as set by the EntityType command. 
*/
DLL_EXPORT int BBCALL iGetNodeType( ISceneNode *node )
{

	return NULL;	//CHANGE TO RETURN NODE WHEN WRITTEN
}





/*	///////////////////////////////////////////////////////////////////
	BELOW HERE IS THE ORIGINAL COLLISION COMMANDS WHICH NEED RE-WRITTEN
*/	///////////////////////////////////////////////////////////////////

/* ----------------------------------------------------------------------------
create a triangle selector from all triangles in a mesh
*//*
DLL_EXPORT int * BBCALL iGetCollisionGroupFromMesh( IAnimatedMesh* mesh, ISceneNode* node, int iframe )
{
    scene::ITriangleSelector* selector;
	if ( mesh )
	{
		selector =
				smgr->createTriangleSelector( mesh->getMesh(iframe), node);
		node->setTriangleSelector(selector);
		selector->drop();
	}
	return (int *)selector;
}*/

DLL_EXPORT int * BBCALL iGetCollisionGroupFromMesh( ISceneNode* node, int iframe )
{
    scene::ITriangleSelector* selector=NULL;
    IAnimatedMeshSceneNode* msn = (IAnimatedMeshSceneNode*)node;
	scene::IAnimatedMesh* mesh = msn->getMesh();

	if ( mesh )
	{
		selector =
				smgr->createTriangleSelector( mesh->getMesh(iframe), node);
		node->setTriangleSelector(selector);
		selector->drop();
	}
	return (int *)selector;
}

/* ----------------------------------------------------------------------------
creates a collision selector from a complex node like a map
*/
DLL_EXPORT int * BBCALL iGetCollisionGroupFromComplexMesh( IAnimatedMesh* mesh, ISceneNode* node, int iframe )
{
	ITriangleSelector* selector = smgr->createOctreeTriangleSelector(
									mesh->getMesh(iframe), node, 128);
    node->setTriangleSelector(selector);
    selector->drop();

    return (int *)selector;
}


/* ----------------------------------------------------------------------------
creates a collision selector from triangles in a nodes bounding box
*/
DLL_EXPORT int * BBCALL iGetCollisionGroupFromBox( ISceneNode *  node )
{
    ITriangleSelector* selector = smgr->createTriangleSelectorFromBoundingBox( node );
    node->setTriangleSelector(selector);
    selector->drop();
    return (int *)selector;
}

/* ----------------------------------------------------------------------------
creates a collision selector from a terrain node
*//*
DLL_EXPORT int * BBCALL iGetCollisionGroupFromTerrain( ITerrainSceneNode *  node, int level_of_detail )
{
    return (int *)smgr->createTerrainTriangleSelector( node, level_of_detail );
	//node->setTriangleSelector(selector);	//MAYBE COMBINE LATER
}*/
DLL_EXPORT int * BBCALL iGetCollisionGroupFromTerrain( ITerrainSceneNode *  node, int level_of_detail )
{
    ITriangleSelector* selector = smgr->createTerrainTriangleSelector( node, level_of_detail );
	node->setTriangleSelector(selector);	//MAYBE COMBINE LATER
	selector->drop();
	return (int *)selector;
}

/* ----------------------------------------------------------------------------
removes the collision group
*/
DLL_EXPORT void BBCALL iRemoveCollisionGroup( ITriangleSelector* selector, ISceneNode * node )
{
    if ( node ) node->setTriangleSelector( NULL );
	selector->drop();
}


/* ----------------------------------------------------------------------------
attach a triangle selector to a node. recommended by agamemnus
*/
DLL_EXPORT void BBCALL iSetNodeTriangleSelector( ISceneNode * node, ITriangleSelector * selector )
{
    node->setTriangleSelector(selector);
}

/* ----------------------------------------------------------------------------
creates a meta-selector that is a group of selector objects
*/
DLL_EXPORT int * BBCALL iCreateCombinedCollisionGroup( void )
{
    return (int *)smgr->createMetaTriangleSelector();
}

/* ----------------------------------------------------------------------------
creates a meta-selector that is a group of selector objects
*/
DLL_EXPORT void BBCALL iAddCollisionGroupToCombination( IMetaTriangleSelector *ms, ITriangleSelector *ts )
{
    ms->addTriangleSelector( ts );
}

/* ----------------------------------------------------------------------------
remove all triangle selectors from the meta selector
*/
DLL_EXPORT void BBCALL iRemoveAllCollisionGroupsFromCombination( IMetaTriangleSelector *ms )
{
    ms->removeAllTriangleSelectors();
}

/* ----------------------------------------------------------------------------
remove a triangle selector from the meta selector group
*/
DLL_EXPORT void BBCALL iRemoveCollisionGroupFromCombination( IMetaTriangleSelector *ms, ITriangleSelector *ts )
{
    ms->removeTriangleSelector( ts );
}

/* ----------------------------------------------------------------------------
create a triangle selector from all triangles in a mesh
*/
DLL_EXPORT void BBCALL iAttachCollisionGroupToNode( scene::ITriangleSelector* selector, ISceneNode* node )
{
	node->setTriangleSelector(selector);
}


/* ----------------------------------------------------------------------------
detect the collision point of a ray in the scene with a collision object if a
collision was detected 1 is returned and vector collision contains the
co-ordinates of the point of collision
*/
DLL_EXPORT int BBCALL iGetCollisionPoint(
                                    IRR_VECTOR &vectorStart,
                                    IRR_VECTOR &vectorEnd,
                                    ITriangleSelector *ts,
                                    IRR_VECTOR &vectorCollision )
{
    line3d< f32 > ray(  vectorStart.x, vectorStart.y, vectorStart.z,
                        vectorEnd.x, vectorEnd.y, vectorEnd.z );
    vector3df collideVect;
    triangle3df collideTri;
    int collided;
    ISceneNode *collideNode;

    if ( collided = smgr->getSceneCollisionManager()->getCollisionPoint(
        ray, ts, collideVect, collideTri, collideNode ))
    {
        vectorCollision.x = collideVect.X;
        vectorCollision.y = collideVect.Y;
        vectorCollision.z = collideVect.Z;
    }
    return collided;
}

/* ----------------------------------------------------------------------------
get a ray that goes from the specified camera and through the screen coordinates
the information is coppied into the supplied start and end vectors
*/
DLL_EXPORT void BBCALL iGetRayFromScreenCoordinates(						//	NEEDS RE-WRITTEN FOR BLITZ
                                    int x,
                                    int y,
                                    ICameraSceneNode *camera,
                                    IRR_VECTOR &vectorStart,
                                    IRR_VECTOR &vectorEnd )
{
    line3d< f32 > ray;
    position2d< s32 > position( x, y );

    ray = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(
            position, camera );

    vectorStart.x = ray.start.X;
    vectorStart.y = ray.start.Y;
    vectorStart.z = ray.start.Z;

    vectorEnd.x = ray.end.X;
    vectorEnd.y = ray.end.Y;
    vectorEnd.z = ray.end.Z;
}

/* ----------------------------------------------------------------------------
a ray is cast through the camera and the nearest node that is hit by the ray is
returned. if no node is hit zero is returned for the object
*/
DLL_EXPORT int * BBCALL iGetCollisionNodeFromCamera( ICameraSceneNode *camera )
{
    return (int *)smgr->getSceneCollisionManager()->getSceneNodeFromCameraBB( camera );
}

/* ----------------------------------------------------------------------------
a ray is cast through the supplied coordinates and the nearest node that is hit
by the ray is returned. if no node is hit zero is returned for the object

DLL_EXPORT void *BBCALL IrrGetCollisionNodeFromRay(						//	NEEDS RE-WRITTEN FOR BLITZ
                                    IRR_VECTOR &vectorStart,
                                    IRR_VECTOR &vectorEnd )
{
    line3d< f32 > ray(  vectorStart.x, vectorStart.y, vectorStart.z,
                        vectorEnd.x, vectorEnd.y, vectorEnd.z );
    return (void *)smgr->getSceneCollisionManager()->getSceneNodeFromRayBB( ray );
}*/

DLL_EXPORT int * BBCALL iGetCollisionNodeFromRay ( float x, float y, float z, float dx, float dy, float dz )
{
    line3d< f32 > ray(  x, y, z,
                        dx, dy, dz );
    return (int *)smgr->getSceneCollisionManager()->getSceneNodeFromRayBB( ray );
}

/* ----------------------------------------------------------------------------
a ray is cast through the screen at the specified co-ordinates and the nearest
node that is hit by the ray is returned. if no node is hit zero is returned for
the object
*/
DLL_EXPORT int * BBCALL iGetCollisionNodeFromScreenCoordinates( int x, int y )
{
    position2d< s32 > position( x, y );

    return (int *)smgr->getSceneCollisionManager()->
            getSceneNodeFromScreenCoordinatesBB( position );
}

/* ----------------------------------------------------------------------------
screen co-ordinates are returned for the position of the specified 3d
co-ordinates if an object were drawn at them on the screen, this is ideal for
drawing 2D bitmaps or text around or on your 3D object on the screen

DLL_EXPORT void BBCALL IrrGetScreenCoordinatesFrom3DPosition(					//	NEEDS RE-WRITTEN FOR BLITZ
                                    int *x,
                                    int *y,
                                    IRR_VECTOR vect )
{
    vector3df pos( vect.x, vect.y, vect.z );
    position2d< s32 > position = smgr->getSceneCollisionManager()->
            getScreenCoordinatesFrom3DPosition( pos );
    *x = position.X;
    *y = position.Y;
}*/

DLL_EXPORT int BBCALL iGetScreenXFrom3DPosition(					//	NEEDS RE-WRITTEN FOR BLITZ
                                    float x,
                                    float y,
                                    float z )
{
    vector3df pos( x, y, z );
    position2d< s32 > position = smgr->getSceneCollisionManager()->
            getScreenCoordinatesFrom3DPosition( pos );
    return position.X;
}

DLL_EXPORT int BBCALL iGetScreenYFrom3DPosition(					//	NEEDS RE-WRITTEN FOR BLITZ
                                    float x,
                                    float y,
                                    float z )
{
    vector3df pos( x, y, z );
    position2d< s32 > position = smgr->getSceneCollisionManager()->
            getScreenCoordinatesFrom3DPosition( pos );
    return position.Y;
}
/* ----------------------------------------------------------------------------
The following functions are required for IrrSetupIrrSceneCollision
*/

void ISceneNode_assignTriangleSelector(scene::ISceneNode* node, scene::ISceneManager* smgr, io::IFileSystem* ifs)
{
  if (!node || !smgr || !ifs)
    return;

  if (node->getType() == scene::ESNT_OCTREE)
  {
    io::IAttributes* attribs = ifs->createEmptyAttributes();
    if (attribs)
    {
      node->serializeAttributes(attribs);

      // get the mesh name out
      core::stringc name = attribs->getAttributeAsString("Mesh");

      attribs->drop();

      // get the animated mesh for the object
      scene::IAnimatedMesh* mesh = smgr->getMesh(name.c_str());
      if (mesh)
      {
        scene::ITriangleSelector* selector =
          smgr->createOctreeTriangleSelector(mesh->getMesh(0), node, 128);
        node->setTriangleSelector(selector);
        selector->drop();
      }
    }
  }
  else if (node->getType() == scene::ESNT_MESH)
  {
    scene::IMeshSceneNode* msn = (scene::IMeshSceneNode*)node;

    if (msn->getMesh())
    {
      scene::ITriangleSelector* selector =
        smgr->createTriangleSelector(msn->getMesh(), msn);
      msn->setTriangleSelector(selector);
      selector->drop();
    }
  }
  else if (node->getType() == scene::ESNT_ANIMATED_MESH)
  {
    scene::IAnimatedMeshSceneNode* msn = (scene::IAnimatedMeshSceneNode*)node;

    scene::IAnimatedMesh* am = msn->getMesh();
    if (am)
    {
      scene::ITriangleSelector* selector =
        smgr->createTriangleSelector(am->getMesh(0), msn);
      msn->setTriangleSelector(selector);
      selector->drop();
    }
  }
  else if (node->getType() == scene::ESNT_TERRAIN)
  {
    scene::ITerrainSceneNode* tsn = (scene::ITerrainSceneNode*)node;

    scene::ITriangleSelector* selector =
      smgr->createTerrainTriangleSelector(tsn, 0); // probably don't want lod 0 all the time...
    tsn->setTriangleSelector(selector);
    selector->drop();
  }
  else if (node->getType() == scene::ESNT_CUBE)
  {
    scene::ITriangleSelector* selector =
      smgr->createTriangleSelectorFromBoundingBox(node);
    node->setTriangleSelector(selector);
    selector->drop();
  }
  else
  {
    // not something we want to collide with
  }
}


void ISceneNode_assignTriangleSelectors(scene::ISceneNode* node, scene::ISceneManager* smgr, io::IFileSystem* ifs)
{
  // assign a selector for this node
  ISceneNode_assignTriangleSelector(node, smgr, ifs);

  // now recurse on children...
  core::list<scene::ISceneNode*>::ConstIterator begin = node->getChildren().begin();
  core::list<scene::ISceneNode*>::ConstIterator end   = node->getChildren().end();

  for (/**/; begin != end; ++begin)
    ISceneNode_assignTriangleSelectors(*begin, smgr, ifs);
}

void ISceneManager_assignTriangleSelectors(scene::ISceneManager* smgr, io::IFileSystem* ifs)
{
  ISceneNode_assignTriangleSelectors(smgr->getRootSceneNode(), smgr, ifs);
}

void ISceneNode_gatherTriangleSelectors(scene::ISceneNode* node, scene::IMetaTriangleSelector* meta)
{
  scene::ITriangleSelector* selector = node->getTriangleSelector();
  if (selector)
    meta->addTriangleSelector(selector);

  // now recurse on children...
  core::list<scene::ISceneNode*>::ConstIterator begin = node->getChildren().begin();
  core::list<scene::ISceneNode*>::ConstIterator end   = node->getChildren().end();

  for (/**/; begin != end; ++begin)
    ISceneNode_gatherTriangleSelectors(*begin, meta);
}

void ISceneManager_gatherTriangleSelectors(scene::ISceneManager* smgr, scene::IMetaTriangleSelector* meta)
{
  ISceneNode_gatherTriangleSelectors(smgr->getRootSceneNode(), meta);
}


/* ----------------------------------------------------------------------------
create generic scene collision for an irr scene
*/
DLL_EXPORT void BBCALL iSetupIrrSceneCollision( ICameraSceneNode *camera )
{
  // recursively assign selectors to nodes

  ISceneManager_assignTriangleSelectors(smgr, device->getFileSystem());

  // recursively gather triangle selectors into a meta selector

  scene::IMetaTriangleSelector* meta = smgr->createMetaTriangleSelector();
  ISceneManager_gatherTriangleSelectors(smgr, meta);

  // create collision response using all objects for collision detection

  scene::ISceneNodeAnimator* anim =
    smgr->createCollisionResponseAnimator(meta, camera, core::vector3df(3,3,3), core::vector3df(0,-1,0), core::vector3df(0,6,0));
    camera->addAnimator(anim);
  anim->drop();

  // drop the meta selector. it is owned by the animator
  meta->drop();
}


// Support function for finding collided nodes using a subset of nodes in the scene
// recursive method for going through all scene nodes
void getNodeRayBB(ISceneNode* root,
               const core::line3df& ray,
               s32 bits,
               bool recurse,
               f32& outbestdistance,
               ISceneNode*& outbestnode)
{
    core::vector3df edges[8];

    const core::list<ISceneNode*>& children = root->getChildren();

    core::list<ISceneNode*>::ConstIterator it = children.begin();
    for (; it != children.end(); ++it)
    {
        ISceneNode* current = *it;

        if (current->isVisible() &&
//        (bNoDebugObjects ? !current->isDebugObject() : true) &&
        (bits==0 || (bits != 0 && (current->getID() & bits))))
        {
            // get world to object space transform
            core::matrix4 mat;
            if (!current->getAbsoluteTransformation().getInverse(mat))
                continue;

            // transform vector from world space to object space
            core::line3df line(ray);
            mat.transformVect(line.start);
            mat.transformVect(line.end);

            const core::aabbox3df& box = current->getBoundingBox();

            // do intersection test in object space
            if (box.intersectsWithLine(line))
            {
                box.getEdges(edges);
                f32 distance = 0.0f;

                for (s32 e=0; e<8; ++e)
                {
                    f32 t = edges[e].getDistanceFromSQ(line.start);
                    if (t > distance)
                        distance = t;
                }

                if (distance < outbestdistance)
                {
                    outbestnode = current;
                    outbestdistance = distance;
                }
            }
        }

        if ( recurse )
            getNodeRayBB(current, ray, bits, recurse, outbestdistance, outbestnode);
    }
}


// Support function for finding collided nodes using a subset of nodes in the scene
// recursive method for going through all scene nodes and testing them against a point
bool getNodePointBB(ISceneNode* root,
                    vector3df point,
                    s32 bits,
                    bool recurse,
                    ISceneNode*& outbestnode)
{
    core::vector3df edges[8];

    const core::list<ISceneNode*>& children = root->getChildren();

    core::list<ISceneNode*>::ConstIterator it = children.begin();
    for (; it != children.end(); ++it)
    {
        ISceneNode* current = *it;

        if (current->isVisible() &&
        //          (bNoDebugObjects ? !current->isDebugObject() : true) &&
        (bits==0 || (bits != 0 && (current->getID() & bits))))
        {
            // get world to object space transform
            core::matrix4 mat;
            if (!current->getAbsoluteTransformation().getInverse(mat))
                continue;

            // transform vector from world space to object space
            vector3df currentPoint( point );
            mat.transformVect(currentPoint);

            const core::aabbox3df& box = current->getBoundingBox();

            // do intersection test in object space
            if (box.isPointInside( currentPoint ))
            {
                outbestnode = current;
                return true;
            }
        }
        if ( recurse )
            if ( getNodePointBB(current, point, bits, recurse, outbestnode))
                return true;
    }
    return false;
}


/* ----------------------------------------------------------------------------
a ray is cast through the supplied coordinates and the nearest node that is hit
by the ray is returned. if no node is hit zero is returned for the object, only
a subset of objects are tested, i.e. the children of the supplied node that
match the supplied id. if the recurse option is enabled the entire tree of child
objects connected to this node are tested
*/
DLL_EXPORT void *BBCALL iGetChildCollisionNodeFromRay(			//NEEDS RE-WRITTEN FOR BLITZ
                                    ISceneNode *node,
                                    s32 id,
                                    bool recurse,
                                    IRR_VECTOR &vectorStart,
                                    IRR_VECTOR &vectorEnd )
{
	ISceneNode* best = 0;
	f32 dist = 9999999999.0f;
    core::line3d<f32> ray( vectorStart.x, vectorStart.y, vectorStart.z, vectorEnd.x, vectorEnd.y, vectorEnd.z );

	getNodeRayBB( node, ray, id, recurse, dist, best);

	return best;
}


/* ----------------------------------------------------------------------------
the node and its children are recursively tested and the first node that contains
the matched point is returned. if no node is hit zero is returned for the object,
only a subset of objects are tested, i.e. the children of the supplied node that
match the supplied id. if the recurse option is enabled the entire tree of child
objects connected to this node are tested
*/
DLL_EXPORT void *BBCALL iGetChildCollisionNodeFromPoint(			//NEEDS RE-WRITTEN FOR BLITZ
                                    ISceneNode *node,
                                    s32 id,
                                    bool recurse,
                                    IRR_VECTOR &vectorPoint )
{
	ISceneNode* best = 0;
	vector3df point( vectorPoint.x, vectorPoint.y, vectorPoint.z );

	getNodePointBB( node, point, id, recurse, best);

	return best;
}


/* ----------------------------------------------------------------------------
the rootNode and its children are recursively tested and the nearest node whose
bounding box is hit by the ray then has its triangles tested in detail to find
an exact point of collision on a specific triangle. If such a collision is
found the node, the point of collision and the normal of that collision is
returned. For the collision to work the node must have had a triangle selector
created for it.

DLL_EXPORT void BBCALL iiGetNodeAndCollisionPointFromRay (			//NEEDS RE-WRITTEN FOR BLITZ
        IRR_VECTOR &vectorStart,
        IRR_VECTOR &vectorEnd,
		ISceneNode **node,
		f32 &x,
		f32 &y,
		f32 &z,
		f32 &normalX,
		f32 &normalY,
		f32 &normalZ,
		s32 id,
		ISceneNode *rootNode )
{
	// create a ray to test for collision
	line3d<f32> curRay( vectorStart.x, vectorStart.y, vectorStart.z,
						vectorEnd.x,   vectorEnd.y,   vectorEnd.z );

	// test for the collision
	vector3d<f32> collisionPoint;
	triangle3d<f32> collisionTriangle;
	*node = smgr->getSceneCollisionManager()->getSceneNodeAndCollisionPointFromRay(
			curRay, collisionPoint, collisionTriangle,
			id, rootNode );

	// return the location of the collision
	x = collisionPoint.X;
	y = collisionPoint.Y;
	z = collisionPoint.Z;

	// calculate and return the normal of the collided triangle
	vector3d<f32>normal = collisionTriangle.getNormal();
	normal.normalize();
	normalX = normal.X;
	normalY = normal.Y;
	normalZ = normal.Z;
}
*/

DLL_EXPORT ISceneNode * BBCALL iGetCollisionNodeAndPointFromRay ( 
		float sx,float sy,float sz,
		float ex,float ey,float ez,
		s32 id,
		ISceneNode *rootNode )
{
	// Reset Results
	g_NodeCollisionPointX = 0.0;
	g_NodeCollisionPointY = 0.0;
	g_NodeCollisionPointZ = 0.0;
	g_NodeCollisionPointNX = 0.0;
	g_NodeCollisionPointNY = 0.0;
	g_NodeCollisionPointNZ = 0.0;

	// create a ray to test for collision
	line3d<f32> curRay( sx, sy, sz,
						ex, ey, ez );

	// test for the collision
	vector3d<f32> collisionPoint;
	triangle3d<f32> collisionTriangle;
	ISceneNode *node = smgr->getSceneCollisionManager()->getSceneNodeAndCollisionPointFromRay(
			curRay, collisionPoint, collisionTriangle,
			id, rootNode );

	// store the location of the collision
	g_NodeCollisionPointX = collisionPoint.X;
	g_NodeCollisionPointY = collisionPoint.Y;
	g_NodeCollisionPointZ = collisionPoint.Z;

	// calculate and store the normal of the collided triangle
	vector3d<f32>normal = collisionTriangle.getNormal();
	normal.normalize();
	g_NodeCollisionPointNX = normal.X;
	g_NodeCollisionPointNY = normal.Y;
	g_NodeCollisionPointNZ = normal.Z;

	return node;
}

DLL_EXPORT float BBCALL iPickedX ( void ) 
{
	return g_NodeCollisionPointX;
}

DLL_EXPORT float BBCALL iPickedY ( void ) 
{
	return g_NodeCollisionPointY;
}

DLL_EXPORT float BBCALL iPickedZ ( void ) 
{
	return g_NodeCollisionPointZ;
}

DLL_EXPORT float BBCALL iPickedNX ( void ) 
{
	return g_NodeCollisionPointNX;
}

DLL_EXPORT float BBCALL iPickedNY ( void ) 
{
	return g_NodeCollisionPointNY;
}

DLL_EXPORT float BBCALL iPickedNZ ( void ) 
{
	return g_NodeCollisionPointNZ;
}

/* ----------------------------------------------------------------------------
determine if the axis aligned bounding boxes of two nodes are in contact
*/
DLL_EXPORT bool BBCALL iAreNodesIntersecting(
											ISceneNode* nodeA,
											ISceneNode* nodeB )
{
	aabbox3d<f32> boxA, boxB;

	boxA = nodeA->getTransformedBoundingBox();
	boxB = nodeB->getTransformedBoundingBox();

	return boxA.intersectsWithBox( boxB );
}




/* ----------------------------------------------------------------------------
get the distance between two nodes using a customised squareroot function
*/
DLL_EXPORT bool BBCALL iIsPointInsideNode(	ISceneNode* nodeA,
										float X, float Y, float Z )
{
	return nodeA->getTransformedBoundingBox().isPointInside(vector3df(X,Y,Z));
}


/* ----------------------------------------------------------------------------
Collides a moving ellipsoid With a 3d world With gravity And returns the
resulting New position of the ellipsoid. (contributed by The Car)
*/
DLL_EXPORT void BBCALL iGetCollisionResultPosition(	ITriangleSelector *selector,			//NEEDS RE-WRITTEN FOR BLITZ
												float ellipsoidPositionX,
												float ellipsoidPositionY,
												float ellipsoidPositionZ,
												float ellipsoidRadius,
												float velocityX,
												float velocityY,
												float velocityZ,
												float gravityX,
												float gravityY,
												float gravityZ,
												float slidingSpeed
												)
{
	core::triangle3df triout;
	core::vector3df hitPosition;
	bool falling;
	ISceneNode* sceneNode;

	core::vector3df newPosition = smgr->getSceneCollisionManager()->getCollisionResultPosition(
			selector,
			core::vector3df(ellipsoidPositionX, ellipsoidPositionY, ellipsoidPositionZ),
			core::vector3df(ellipsoidRadius, ellipsoidRadius, ellipsoidRadius),
			core::vector3df(velocityX, velocityY, velocityZ),
			triout, hitPosition, falling, sceneNode,slidingSpeed,
			core::vector3df(gravityX, gravityY, gravityZ));

	g_NewPositionX = newPosition.X;
	g_NewPositionY = newPosition.Y;
	g_NewPositionZ = newPosition.Z;

	g_HitPositionX = hitPosition.X;
	g_HitPositionY = hitPosition.Y;
	g_HitPositionZ = hitPosition.Z;

	g_Falling = falling ? 1 : 0;
}

DLL_EXPORT bool BBCALL iCollFalling ( void )
{
	return g_Falling;
}

DLL_EXPORT float BBCALL iCollHitPositionX ( void )
{
	return g_HitPositionX;
}

DLL_EXPORT float BBCALL iCollHitPositionY ( void )
{
	return g_HitPositionY;
}

DLL_EXPORT float BBCALL iCollHitPositionZ ( void )
{
	return g_HitPositionZ;
}

DLL_EXPORT float BBCALL iCollNewPositionX ( void )
{
	return g_NewPositionX;
}

DLL_EXPORT float BBCALL iCollNewPositionY ( void )
{
	return g_NewPositionY;
}

DLL_EXPORT float BBCALL iCollNewPositionZ ( void )
{
	return g_NewPositionZ;
}

/* ----------------------------------------------------------------------------
Calculates the intersection between a ray projected through the specified
screen co-ordinates and a plane defined a normal and distance from the
world origin (contributed by agamemnus)
*/
DLL_EXPORT void BBCALL iGet3DPositionFromScreenCoordinates (			//NEEDS RE-WRITTEN FOR BLITZ
		int screenX,
		int screenY,
		float &x,
		float &y,
		float &z,
		irr::scene::ICameraSceneNode* camera,
		float normalX,
		float normalY,
		float normalZ,
		float distanceFromOrigin )
{
	// storage for the result of the intersection
	core::vector3d<f32> endingpos;

	// define a plane from a normal and a distance from the origin
//	core::plane3d<f32> plane(core::vector3d<f32>(0.f,0.f,1.f), 0.f);
	core::plane3d<f32> plane(core::vector3d<f32>(normalX,normalY,normalZ), distanceFromOrigin);

	// create a ray from the screen coordinates
	line3d<f32> ray = smgr->getSceneCollisionManager()-> getRayFromScreenCoordinates(core::position2d<s32>(screenX, screenY), camera);

	// calculate the intersection with the ray and the plane
	plane.getIntersectionWithLimitedLine(ray.start, ray.end, endingpos);

	// copy the point of intersection into the output
	x = endingpos.X;
	y = endingpos.Y;
	z = endingpos.Z;
}

DLL_EXPORT float BBCALL i3DPositionXFromScreen (
		int screenX,
		int screenY,
//		float &x,
//		float &y,
//		float &z,
		irr::scene::ICameraSceneNode* camera,
		float normalX,
		float normalY,
		float normalZ,
		float distanceFromOrigin )
{
	// storage for the result of the intersection
	core::vector3d<f32> endingpos;

	// define a plane from a normal and a distance from the origin
//	core::plane3d<f32> plane(core::vector3d<f32>(0.f,0.f,1.f), 0.f);
	core::plane3d<f32> plane(core::vector3d<f32>(normalX,normalY,normalZ), distanceFromOrigin);

	// create a ray from the screen coordinates
	line3d<f32> ray = smgr->getSceneCollisionManager()-> getRayFromScreenCoordinates(core::position2d<s32>(screenX, screenY), camera);

	// calculate the intersection with the ray and the plane
	plane.getIntersectionWithLimitedLine(ray.start, ray.end, endingpos);

	// copy the point of intersection into the output
	return endingpos.X;
//	y = endingpos.Y;
//	z = endingpos.Z;
}

DLL_EXPORT float BBCALL i3DPositionYFromScreen (
		int screenX,
		int screenY,
//		float &x,
//		float &y,
//		float &z,
		irr::scene::ICameraSceneNode* camera,
		float normalX,
		float normalY,
		float normalZ,
		float distanceFromOrigin )
{
	// storage for the result of the intersection
	core::vector3d<f32> endingpos;

	// define a plane from a normal and a distance from the origin
//	core::plane3d<f32> plane(core::vector3d<f32>(0.f,0.f,1.f), 0.f);
	core::plane3d<f32> plane(core::vector3d<f32>(normalX,normalY,normalZ), distanceFromOrigin);

	// create a ray from the screen coordinates
	line3d<f32> ray = smgr->getSceneCollisionManager()-> getRayFromScreenCoordinates(core::position2d<s32>(screenX, screenY), camera);

	// calculate the intersection with the ray and the plane
	plane.getIntersectionWithLimitedLine(ray.start, ray.end, endingpos);

	// copy the point of intersection into the output
//	return endingpos.X;
	return endingpos.Y;
//	z = endingpos.Z;
}

DLL_EXPORT float BBCALL i3DPositionZFromScreen (
		int screenX,
		int screenY,
//		float &x,
//		float &y,
//		float &z,
		irr::scene::ICameraSceneNode* camera,
		float normalX,
		float normalY,
		float normalZ,
		float distanceFromOrigin )
{
	// storage for the result of the intersection
	core::vector3d<f32> endingpos;

	// define a plane from a normal and a distance from the origin
//	core::plane3d<f32> plane(core::vector3d<f32>(0.f,0.f,1.f), 0.f);
	core::plane3d<f32> plane(core::vector3d<f32>(normalX,normalY,normalZ), distanceFromOrigin);

	// create a ray from the screen coordinates
	line3d<f32> ray = smgr->getSceneCollisionManager()-> getRayFromScreenCoordinates(core::position2d<s32>(screenX, screenY), camera);

	// calculate the intersection with the ray and the plane
	plane.getIntersectionWithLimitedLine(ray.start, ray.end, endingpos);

	// copy the point of intersection into the output
//	return endingpos.X;
//	y = endingpos.Y;
	return endingpos.Z;
}

/* ----------------------------------------------------------------------------
Calculates the intersection between a ray projected through the specified
screen co-ordinates and a plane defined a normal and distance from the
world origin (contributed by agamemnus)
*/
DLL_EXPORT void BBCALL iGet2DPositionFromScreenCoordinates (int screenX, int screenY, float &x, float &y, irr::scene::ICameraSceneNode* camera)		//NEEDS RE-WRITTEN FOR BLITZ
{
	core::vector3d<f32> endingpos;
	core::plane3d<f32> plane(core::vector3d<f32>(0.f,0.f,1.f), 0.f);
	line3d<f32> ray = smgr->getSceneCollisionManager()-> getRayFromScreenCoordinates(core::position2d<s32>(screenX, screenY), camera);
	plane.getIntersectionWithLimitedLine(ray.start, ray.end, endingpos);
	x = endingpos.X;
	y = endingpos.Y;
}




}

