// ----------------------------------------------------------------------------
// 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 ISceneManager *smgr;

extern "C"
{
/*
EntityX# ( entity[,global] )
Parameters
entity = handle of Loaded or Created Entity 
global = True for Global coordinates, False for Local. Optional, defaults to False.  
*/
DLL_EXPORT float BBCALL iNodeX ( IAnimatedMeshSceneNode* node, bool global = false )
{
    // get the model positionX
	if(global)
		return node->getAbsolutePosition().X;
	return node->getPosition().X;
}

/*
EntityY# ( entity[,global] )
Parameters
entity = handle of Loaded or Created Entity 
global = True for Global coordinates, False for Local. Optional, defaults to False.  
*/
DLL_EXPORT float BBCALL iNodeY ( IAnimatedMeshSceneNode* node, bool global = false )
{
    // get the model positionY
	if(global)
		return node->getAbsolutePosition().Y;
	return node->getPosition().Y;
}

/*
EntityZ# ( entity[,global] )
Parameters
entity = handle of Loaded or Created Entity 
global = True for Global coordinates, False for Local. Optional, defaults to False.  

Description
The Z-coordinate of the entity. 
If the global flag is set to False then the parent's local coordinate system is used. 
*/
DLL_EXPORT float BBCALL iNodeZ ( IAnimatedMeshSceneNode* node, bool global = false )
{
    // get the model positionZ
	if(global)
		return node->getAbsolutePosition().Z;
    return node->getPosition().Z;
}


/*
EntityRoll# ( entity[,global] )
Parameters
entity - name of entity that will have roll angle returned 
global (optional) - true if the roll angle returned should be relative to 0 rather than a parent entity's roll angle. False by default.  

Description
Returns the roll angle of an entity. 

The roll angle is also the z angle of an entity.  
*/
DLL_EXPORT float BBCALL iNodeRoll ( IAnimatedMeshSceneNode* node, bool global = false )
{
    // get the rotation of a node - Pitch, Yaw, Roll
	if(global)
		return node->getAbsoluteTransformation().getRotationDegrees().Z;
    return node->getRotation().Z;
}


/*
EntityYaw# ( entity[,global] )
Parameters
entity - name of entity that will have yaw angle returned 
global (optional) - true if the yaw angle returned should be relative to 0 rather than a parent entity's yaw angle. False by default.  

Description
Returns the yaw angle of an entity. 

The yaw angle is also the y angle of an entity.  
*/
DLL_EXPORT float BBCALL iNodeYaw ( IAnimatedMeshSceneNode* node, bool global = false )
{
    // get the rotation of a node - Pitch, Yaw
	if(global)
		return node->getAbsoluteTransformation().getRotationDegrees().Y;
    return node->getRotation().Y;
}


/*
EntityPitch# ( entity[,global] )
Parameters
entity - name of entity that will have pitch angle returned 
global (optional) - true if the pitch angle returned should be relative to 0 rather than a parent entity's pitch angle. False by default.  

Description
Returns the pitch angle of an entity. 

The pitch angle is also the x angle of an entity.  
*/
DLL_EXPORT float BBCALL iNodePitch ( IAnimatedMeshSceneNode* node, bool global = false )
{
    // get the rotation of a node - Pitch, Yaw, Roll
	if(global)
		return node->getAbsoluteTransformation().getRotationDegrees().X;
    return node->getRotation().X;
}


/*
EntityClass$( entity )
Parameters
entity - a valid entity handle  

Description
Returns a string containing the class of the specified entity. 

Possible return values are: 

Pivot 
Light 
Camera 
Mirror 
Listener 
Sprite 
Terrain 
Plane 
Mesh 
MD2 
BSP 

Note that the command will fail if a valid entity handle is not supplied, and will not just return an empty string.  
*/
DLL_EXPORT int BBCALL iNodeClass ( ISceneNode *node )
{//ESCENE_NODE_TYPE
     ESCENE_NODE_TYPE iNodeTypes[] = {
            ESNT_SCENE_MANAGER, ESNT_CUBE, ESNT_SPHERE, ESNT_TEXT, ESNT_WATER_SURFACE, ESNT_TERRAIN,
			ESNT_SKY_BOX, ESNT_SKY_DOME, ESNT_SHADOW_VOLUME, ESNT_OCTREE, ESNT_MESH, ESNT_LIGHT,
			ESNT_EMPTY, ESNT_DUMMY_TRANSFORMATION, ESNT_CAMERA, ESNT_BILLBOARD, ESNT_ANIMATED_MESH,
			ESNT_PARTICLE_SYSTEM, ESNT_Q3SHADER_SCENE_NODE, ESNT_MD3_SCENE_NODE, ESNT_VOLUME_LIGHT,
			ESNT_CAMERA_MAYA, ESNT_CAMERA_FPS, ESNT_UNKNOWN, ESNT_ANY};
	
	return (int)iNodeTypes[node->getType()];
}


/*
EntityName$ ( entity )
Parameters
entity - entity handle  

Description
Returns the name of an entity. An entity's name may be set in a modelling program, or manually set using NameEntity.  
*/
DLL_EXPORT const c8 * BBCALL iNodeName( ISceneNode* node )
{
    return node->getName();
}

DLL_EXPORT int BBCALL iNodeID( ISceneNode* node )
{
    return node->getID();
}

/* ----------------------------------------------------------------------------
get a scene node based on its ID and returns null if no node is found
*/
DLL_EXPORT int * BBCALL iGetNodeByID( int id )
{
    return ( int * )smgr->getSceneNodeFromId ( id, NULL );
}


/* ----------------------------------------------------------------------------
get a node in the scene based upon its name and returns null is no node is found
*/
DLL_EXPORT int * BBCALL iGetNodeByName( char * name )
{
    return ( int * )smgr->getSceneNodeFromName( name, NULL );
}

/*
CountChildren ( entity )
Parameters
entity - entity handle  

Description
Returns the number of children of an entity.  
*/
DLL_EXPORT int BBCALL iCountChildren( ISceneNode* node )
{
	return node->getChildren().getSize();
}


/*
GetChild (entity,index)
Parameters
entity - entity handle 
index - index of child entity. Should be in the range 1...CountChildren( entity ) inclusive.  

Description
Returns a child of an entity.  
*/
DLL_EXPORT ISceneNode* BBCALL iGetChild( ISceneNode* node, int idx )
{
	unsigned int count = 1;
    const core::list<ISceneNode*>& children = node->getChildren();
	core::list<ISceneNode*>::ConstIterator it = children.begin();

	if(count == idx)
		return *(it);

	while (it != children.end())
	{
		if(count == idx)
			return *(it);
		else
			count++;
			it++;
	}
	return NULL;
}


/*
FindChild ( entity,child_name$ )
Parameters
entity - entity handle 
child_name$ - child name to find within entity  

Description
Returns the first child of the specified entity with name matching child_name$.  
*/
DLL_EXPORT int* BBCALL iFindChild( ISceneNode* node, const c8 * name )
{
	return (int*)NULL;
}


/*
EntityPick ( entity,range# )
Parameters
entity - entity handle 
range# - range of pick area around entity  

Description
Returns the nearest entity 'ahead' of the specified entity. An entity must have a non-zero EntityPickMode to be pickable.  
*/
DLL_EXPORT int* BBCALL iNodePick( ISceneNode* node, float range )
{
	return (int*)NULL;
}


/*
LinePick ( x#,y#,z#,dx#,dy#,dz#[,radius#] )
Parameters
x# - x coordinate of start of line pick 
y# - y coordinate of start of line pick 
z# - z coordinate of start of line pick 
dx# - distance x of line pick 
dy# - distance y of line pick 
dz# - distance z of line pick 
radius (optional) - radius of line pick  

Description
Returns the first entity between x,y,z to x+dx,y+dy,z+dz. 
*/
DLL_EXPORT ISceneNode * BBCALL iLinePick ( 
		float x,float y,float z,
		float dx,float dy,float dz )
{
	// 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( x, y, z,
						dx, dy, dz );

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

	// 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 ISceneNode * BBCALL iCameraPick(
											ICameraSceneNode *camera, 
											int x,
											int y )
                                    
{
	// 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;

    line3d< f32 > curRay;
    position2d< s32 > position( x, y );

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

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

	// 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;

}

/*
EntityVisible ( src_entity,dest_entity )
Parameters
src_entity - source entity handle 
dest_entity - destination entity handle  

Description
Returns true if src_entity and dest_entity can 'see' each other.  
*/
DLL_EXPORT int* BBCALL iNodeVisible( ISceneNode* src_node, ISceneNode* dest_node )
{
	return (int*)NULL;
}


/*
EntityDistance# ( src_entity,dest_entity)
Parameters
src_entity - source entity handle 
dest_entity - destination entity handle  

Description
Returns the distance between src_entity and dest_entity.  
*/
float fsquareroot( float x )
{
    union{
        int intPart;
        float floatPart;
    } converter;
    union{
        int intPart;
        float floatPart;
    } converter2;

    converter.floatPart = x;
    converter2.floatPart = x;
    converter.intPart = 0x1FBCF800 + (converter.intPart >> 1);
    converter2.intPart = 0x5f3759df - (converter2.intPart >> 1);
    return 0.5f*(converter.floatPart + (x * converter2.floatPart));
}

DLL_EXPORT float BBCALL iNodeDistance( ISceneNode *nodeA, ISceneNode *nodeB )
{
	core::vector3df posA = nodeA->getAbsolutePosition();
	posA -= nodeB->getAbsolutePosition();

	return fsquareroot( posA.X * posA.X + posA.Y * posA.Y + posA.Z * posA.Z );
}

/*
DeltaYaw# ( src_entity,dest_entity )
Parameters
src_entity - source entity handle 
dest_entity - destination entity handle  

Description
Returns the yaw angle, that src_entity should be rotated by in order to face dest_entity. 

This command can be used to be point one entity at another, rotating on the y axis only.  
*/
DLL_EXPORT float BBCALL iDeltaYaw( ISceneNode* src_node, ISceneNode* dest_node )
{
	return NULL;
}


/*
DeltaPitch# ( src_entity,dest_entity )
Parameters
src_entity - source entity handle 
dest_entity - destination entity handle  

Description
Returns the pitch angle, that src_entity should be rotated by in order to face dest_entity. 

This command can be used to be point one entity at another, rotating on the x axis only. 
*/
DLL_EXPORT float BBCALL iDeltaPitch( ISceneNode* src_node, ISceneNode* dest_node )
{
	return NULL;
}

/*
TFormPoint x#, y#, z#, source_entity, dest_entity
Parameters
x#, y#, z# = coordinates of a point in 3d space 

source_entity = handle of source entity, or 0 for 3d world 
dest_entity = handle of destination entity, or 0 for 3d world  

Description
Transforms between coordinate systems. After using TFormPoint the new 
coordinates can be read with TFormedX(), TFormedY() and TFormedZ(). 


See EntityX() for details about local coordinates. 

Consider a sphere built with CreateSphere(). The 'north pole' is at (0,1,0). 
At first, local and global coordinates are the same. As the sphere is moved, 
turned and scaled the global coordinates of the point change. 

But it is always at (0,1,0) in the sphere's local space.  
*/
DLL_EXPORT void BBCALL iTFormPoint( float x, float y, float z, ISceneNode* src_node, ISceneNode* dest_node )
{

}


/*
TFormVector x#, y#, z#, source_entity, dest_entity
Parameters
x#, y#, z# = components of a vector in 3d space 

source_entity = handle of source entity, or 0 for 3d world 
dest_entity = handle of destination entity, or 0 for 3d world  

Description
Transforms between coordinate systems. After using TFormVector the new 
components can be read with TFormedX(), TFormedY() and TFormedZ(). 


See EntityX() for details about local coordinates. 


Similar to TFormPoint, but operates on a vector. A vector can be thought of 
as 'displacement relative to current location'. 

For example, vector (1,2,3) means one step to the right, two steps up 
and three steps forward. 

This is analogous to PositionEntity and MoveEntity: 

PositionEntity entity, x,y,z ; put entity at point (x,y,z) 

MoveEntity entity, x,y,z ; add vector (x,y,z) to current position  
*/
DLL_EXPORT void BBCALL iTFormVector( float x, float y, float z, ISceneNode* src_node, ISceneNode* dest_node )
{

}


/*
TFormNormal x#, y#, z#, source_entity, dest_entity
Parameters
x#, y#, z# = components of a vector in 3d space 

source_entity = handle of source entity, or 0 for 3d world 
dest_entity = handle of destination entity, or 0 for 3d world  

Description
Transforms between coordinate systems. After using TFormNormal the new 
components can be read with TFormedX(), TFormedY() and TFormedZ(). 

This is exactly the same as TFormVector but with one added feature. 
After the transformation the new vector is 'normalized', meaning it 
is scaled to have length 1. 

For example, suppose the result of TFormVector is (1,2,2). 
This vector has length Sqr( 1*1 + 2*2 + 2*2 ) = Sqr( 9 ) = 3. 

This means TFormNormal would produce ( 1/3, 2/3, 2/3 ).  
*/
DLL_EXPORT void BBCALL iTFormNormal( float x, float y, float z, ISceneNode* src_node, ISceneNode* dest_node )
{

}


/*
TFormedX()
Parameters
None.  

Description
Returns the X component of the last TFormPoint, TFormVector or TFormNormal operation.  
*/
DLL_EXPORT float BBCALL iTFormX( void )
{
	return NULL;
}

/*
TFormedY()
Parameters
None.  

Description
Returns the Y component of the last TFormPoint, TFormVector or TFormNormal operation.  
*/
DLL_EXPORT float BBCALL iTFormY( void )
{
	return NULL;
}


/*
TFormedZ()
Parameters
None.  

Description
Returns the Z component of the last TFormPoint, TFormVector or TFormNormal operation.  
*/
DLL_EXPORT float BBCALL iTFormZ( void )
{
	return NULL;
}


/*
GetMatElement# ( entity,row,column )
Parameters
entity - entity handle 
row - matrix row index 
column - matrix column index  

Description
Returns the value of an element from within an entity's transformation matrix. 

The transformation matrix is what is used by Blitz internally to position, scale and rotate entities. 

GetMatElement is intended for use by advanced users only.  
*/
DLL_EXPORT float BBCALL iGetMatElement( ISceneNode* node, int row, int column )
{
	return NULL;
}




//DEBUG STATE
DLL_EXPORT void BBCALL iDebugNode( ISceneNode* node, int state )
{
    node->setDebugDataVisible( state );
}

/* ----------------------------------------------------------------------------
add a stencil shadow to an node
*/
DLL_EXPORT int* BBCALL iNodeShadow( IAnimatedMeshSceneNode* node )//, IAnimatedMesh* mesh )
{
	// add shadow
	IAnimatedMesh* mesh = node->getMesh();
	if(mesh)
		return (int*)node->addShadowVolumeSceneNode( mesh );
	else
		return false;
}

DLL_EXPORT bool BBCALL iRemoveNodeShadow( IShadowVolumeSceneNode* node, ISceneNode* shadow )
{
	// remove shadow
	node->removeChild( shadow );
	return false;
}

/* ----------------------------------------------------------------------------
set the material of a node
*/
#define MAX_MAT_FLAGS 20
DLL_EXPORT void BBCALL iNodeMaterialFlag( void *vptrNode, unsigned int uiFlag, bool boValue )
{
    E_MATERIAL_FLAG emfFlagTable[] = {
            EMF_WIREFRAME,
            EMF_POINTCLOUD,
            EMF_GOURAUD_SHADING,
            EMF_LIGHTING,
            EMF_ZBUFFER,

            EMF_ZWRITE_ENABLE,
            EMF_BACK_FACE_CULLING,
            EMF_FRONT_FACE_CULLING,
            EMF_BILINEAR_FILTER,
            EMF_TRILINEAR_FILTER,

            EMF_ANISOTROPIC_FILTER,
            EMF_FOG_ENABLE,
            EMF_NORMALIZE_NORMALS,
	        EMF_TEXTURE_WRAP,
	        EMF_ANTI_ALIASING,

	        EMF_COLOR_MASK,
	        EMF_COLOR_MATERIAL,
			EMF_USE_MIP_MAPS,
			EMF_BLEND_OPERATION,
			EMF_POLYGON_OFFSET
    };


    // if a valid flag is selected
    if ( uiFlag < MAX_MAT_FLAGS )
    {
        // change the flags property on this node
        ((ISceneNode*)vptrNode)->setMaterialFlag(
                emfFlagTable[uiFlag], boValue );
    }
}

/* ----------------------------------------------------------------------------
set the way the materials applied to the node are rendered
*/
DLL_EXPORT void BBCALL iNodeMaterialType( ISceneNode* node, unsigned int uiType )
{
	/* set the material type directly this may be a preset material type of one
	 * created with a shader program */
	node->setMaterialType(( E_MATERIAL_TYPE )uiType);
}






}