// ----------------------------------------------------------------------------
// 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"
#include "CParticleEmissionAffector.h"
#include "CParticlePushAffector.h"
#include "CColorMorphAffector.h"
#include "CSplineAffector.h"



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




extern "C"
{

/* ----------------------------------------------------------------------------
add a particle system to the irrlicht scene manager
*/
DLL_EXPORT int * BBCALL iCreateParticleSystem ( bool defaultemitter , ISceneNode * parent, int id, float posX, float posY, float posZ, float rotX, float rotY, float rotZ, float scaleX, float scaleY, float scaleZ)
{
	return (int *)smgr->addParticleSystemSceneNode(defaultemitter, parent, id,
                    core::vector3df(posX, posY, posZ),
                    core::vector3df(rotX, rotY, rotZ),
                    core::vector3df(scaleX, scaleY, scaleZ)
    );
}

/* ----------------------------------------------------------------------------
set the size of a particle in the particle system
*/
DLL_EXPORT void BBCALL iParticleSize( IParticleEmitter *em, float x, float y )
{
	// this function is depreciated and no longer has an operation
    em->setMinStartSize( dimension2d<f32>(x,y));
    em->setMaxStartSize( dimension2d<f32>(x,y));
}

/* ----------------------------------------------------------------------------
set the size of a particle in the particle system
*/
DLL_EXPORT void BBCALL iParticleMinSize( IParticleEmitter *em, float x, float y )
{
    em->setMinStartSize( dimension2d<f32>(x,y));
}

/* ----------------------------------------------------------------------------
set the size of a particle in the particle system
*/
DLL_EXPORT void BBCALL iParticleMaxSize( IParticleEmitter *em, float x, float y )
{
    em->setMaxStartSize( dimension2d<f32>(x,y));
}

/* ----------------------------------------------------------------------------
create an emitter that can be added to a particle system
*/
DLL_EXPORT int * BBCALL iCreateParticleEmitter( IParticleSystemSceneNode* ps, float min_box_x, float min_box_y, float min_box_z, float max_box_x,		//IParticleEmitter *
														float max_box_y, float max_box_z, float direction_x, float direction_y, float direction_z, unsigned int min_paritlcles_per_second,
														unsigned int max_paritlcles_per_second, int min_start_color_red, int min_start_color_green, int min_start_color_blue,
														int max_start_color_red, int max_start_color_green, int max_start_color_blue, unsigned int min_lifetime,
														unsigned int max_lifetime, float min_start_sizeX, float min_start_sizeY, float max_start_sizeX,
														float max_start_sizeY, int max_angle_degrees)		
{
	IParticleEmitter* em = ps->createBoxEmitter(
		core::aabbox3d<f32>(min_box_x,min_box_y,min_box_z,max_box_x,max_box_y,max_box_z),
		core::vector3df(direction_x,direction_y,direction_z),
		min_paritlcles_per_second,max_paritlcles_per_second,
		video::SColor(0,min_start_color_red,min_start_color_green,min_start_color_blue),
		video::SColor(0,max_start_color_red,max_start_color_green,max_start_color_blue),
		min_lifetime,max_lifetime,
		max_angle_degrees );

    em->setMinStartSize( dimension2d<f32>(min_start_sizeX, min_start_sizeY));
    em->setMaxStartSize( dimension2d<f32>(max_start_sizeX, max_start_sizeY));
	ps->setEmitter(em);
	em->drop();
	return (int *)em;
}

/* ----------------------------------------------------------------------------
Creates a particle emitter for an animated mesh scene node
Parameters:
 node,:  Pointer to the animated mesh scene node to emit particles from
 useNormalDirection,:  If true, the direction of each particle created will be
						the normal of the vertex that it's emitting from. The
						normal is divided by the normalDirectionModifier
						parameter, which defaults to 100.0f.
 direction,:  Direction and speed of particle emission.
 normalDirectionModifier,:  If the emitter is using the normal direction then the
							normal of the vertex that is being emitted from is
							divided by this number.
 mbNumber,:  This allows you to specify a specific meshBuffer for the IMesh* to
			emit particles from. The default value is -1, which means a random
			meshBuffer picked from all of the meshes meshBuffers will be selected
			to pick a random vertex from. If the value is 0 or greater, it will
			only pick random vertices from the meshBuffer specified by this value.
 everyMeshVertex,:  If true, the emitter will emit between min/max particles every
					second, for every vertex in the mesh, if false, it will emit
					between min/max particles from random vertices in the mesh.
 minParticlesPerSecond,:  Minimal amount of particles emitted per second.
 maxParticlesPerSecond,:  Maximal amount of particles emitted per second.
 minStartColor,:  Minimal initial start color of a particle. The real color of every
				particle is calculated as random interpolation between minStartColor
				and maxStartColor.
 maxStartColor,:  Maximal initial start color of a particle. The real color of every
				particle is calculated as random interpolation between minStartColor
				and maxStartColor.
 lifeTimeMin,:  Minimal lifetime of a particle, in milliseconds.
 lifeTimeMax,:  Maximal lifetime of a particle, in milliseconds.
 maxAngleDegrees,:  Maximal angle in degrees, the emitting direction of the particle
					will differ from the orignial direction.

Returns:
Returns a pointer to the created particle emitter. To set this emitter as new
emitter of this particle system, just call setEmitter(). Note that you'll have
to drop() the returned pointer, after you don't need it any more, see
IReferenceCounted::drop() for more informations.
*/
DLL_EXPORT int * BBCALL iCreateAnimatedMeshSceneNodeEmitter (		//IParticleEmitter *
		IParticleSystemSceneNode* ps,
		IAnimatedMeshSceneNode* node,
		bool useNormalDirection,
		float normalDirectionModifier,
		bool emitFromEveryMeshVertex,
		IRR_PARTICLE_EMITTER prop )
{
	IParticleEmitter* em = ps->createAnimatedMeshSceneNodeEmitter(
			node,
			useNormalDirection,
			core::vector3df(prop.direction_x,prop.direction_y,prop.direction_z),
			normalDirectionModifier,
			-1,	// use a random meshbuffer from within the node
			emitFromEveryMeshVertex,
			prop.min_paritlcles_per_second,prop.max_paritlcles_per_second,
			video::SColor(0,prop.min_start_color_red,prop.min_start_color_green,prop.min_start_color_blue),
			video::SColor(0,prop.max_start_color_red,prop.max_start_color_green,prop.max_start_color_blue),
			prop.min_lifetime,prop.max_lifetime,
			prop.max_angle_degrees );

    em->setMinStartSize( dimension2d<f32>(prop.min_start_sizeX, prop.min_start_sizeY));
    em->setMaxStartSize( dimension2d<f32>(prop.max_start_sizeX, prop.max_start_sizeY));
	ps->setEmitter(em);
	em->drop();
	return (int *)em;
}

/* ----------------------------------------------------------------------------
Add an affector to the particle system to fade the particles out (the
documentation for this object doesnt seam to be correct) the fade out time is
actually a multiple of the particle lifetime)
*/
//IParticleFadeOutAffector*
DLL_EXPORT int * BBCALL iFadeOutAffector( IParticleSystemSceneNode* ps, unsigned int FadeFactor, unsigned int Red, unsigned int Green, unsigned int Blue )
{
	IParticleFadeOutAffector* paf = ps->createFadeOutParticleAffector(SColor(0,Red,Green,Blue), FadeFactor);
	ps->addAffector(paf);
	paf->drop();
	return (int *)paf;
}

/* ----------------------------------------------------------------------------
Add an affector to the particle system to alter their position with gravity
*/
DLL_EXPORT int * BBCALL iGravityAffector(	//IParticleGravityAffector*
		IParticleSystemSceneNode* ps,
		float x,
		float y,
		float z,
		unsigned int timeForceLost )
{
	IParticleGravityAffector* paf = ps->createGravityAffector(vector3df(x,y,z), timeForceLost);
	ps->addAffector(paf);
	paf->drop();
	return (int *)paf;
}

/* ----------------------------------------------------------------------------
Creates a point attraction affector. This affector modifies the positions of
the particles and attracts them to a specified point at a specified speed per
second.

Parameters:
 point,:    Point to attract particles to.
 speed,:    Speed in units per second, to attract to the specified point.
 attract,:  Whether the particles attract or detract from this point.
 affectX,:  Whether or not this will affect the X position of the particle.
 affectY,:  Whether or not this will affect the Y position of the particle.
 affectZ,:  Whether or not this will affect the Z position of the particle.

Returns:
Returns a pointer to the created particle affector. To add this affector as
new affector of this particle system, just call addAffector(). Note that
you'll have to drop() the returned pointer, after you don't need it any more,
see IReferenceCounted::drop() for more informations
*/
DLL_EXPORT int * BBCALL iAttractionAffector(		//IParticleAttractionAffector*
		IParticleSystemSceneNode* ps,
		float x,
		float y,
		float z,
		float speed,
		bool attract,
		bool affectX,
		bool affectY,
		bool affectZ )
{
	IParticleAttractionAffector* paf = ps->createAttractionAffector  (
			vector3df(x,y,z),
			speed,
			attract,
			affectX,
			affectY,
			affectZ );

	ps->addAffector(paf);
	paf->drop();
	return (int *)paf;
}

/* ----------------------------------------------------------------------------
Creates a rotation affector. This affector modifies the positions of the
particles and attracts them to a specified point at a specified speed per second.

Parameters:
 speed,:  Rotation in degrees per second
 pivotPoint,:  Point to rotate the particles around

Returns:
Returns a pointer to the created particle affector. To add this affector as new
affector of this particle system, just call addAffector(). Note that you'll have
to drop() the returned pointer, after you don't need it any more, see
IReferenceCounted::drop() for more informations.
*/
DLL_EXPORT int *  BBCALL iRotationAffector (		//IParticleRotationAffector *
		IParticleSystemSceneNode* ps,
		float SpeedX, float SpeedY, float SpeedZ,
		float PivotX, float PivotY, float PivotZ )
{
	IParticleRotationAffector* paf = ps->createRotationAffector(
			vector3df(SpeedX,SpeedY,SpeedZ), vector3df(PivotX,PivotY,PivotZ));

	ps->addAffector(paf);
	paf->drop();
	return (int *)paf;
}

/* ----------------------------------------------------------------------------
Creates a stop particle affector. The stop particle affector waits for the
specified period of time to elapse and then stops the specified emitter
emitting particles by setting its minimum and maximum particle emission rate
to zero. The emitter can easily be started up again by changing its emission
rate..

Parameters:
 time,:  The amount of milliseconds to elapse before stopping the emitter

Returns:
Returns a pointer to the created particle affector. To add this affector as new
affector of this particle system, just call addAffector(). Note that you'll have
to drop() the returned pointer, after you don't need it any more, see
IReferenceCounted::drop() for more informations.
*/
DLL_EXPORT int *  BBCALL iStopAffector (		//IParticleAffector * 
		IParticleSystemSceneNode* ps, u32 time, IParticleEmitter* em  )
{
	CParticleEmissionAffector* paf = new CParticleEmissionAffector( time, em );
	ps->addAffector(paf);
	paf->drop();
	return (int *)paf;
}

/* ----------------------------------------------------------------------------
Creates a point push affector. This affector modifies the positions of
the particles and pushes them toward or away from a specified point at a
specified speed per second. The strength of this effect is adjusted by a near
and a far distance and can be used in combination to create complex motions.

Parameters:
 point,:    Point to attract particles to.
 strength,: A vector describing the strength of the effect
 far,:		Furthest distance of effect
 near,:		Closest distance of effect
 distant,:  True if a common direction is applied to the particles and False
			when a radial effect is applied to the particles

Returns:
Returns a pointer to the created particle affector.
*/
DLL_EXPORT int *  BBCALL iPushAffector(		//IParticleAffector * 
		IParticleSystemSceneNode* ps,
		f32 x,
		f32 y,
		f32 z,
		f32 speedX,
		f32 speedY,
		f32 speedZ,
		f32 far,
		f32 near,
		f32 column,
		bool distant )
{
	CParticlePushAffector* paf = new CParticlePushAffector(
			vector3df(x,y,z),
			vector3df(speedX,speedY,speedZ),
			far,
			near,
			column,
			distant );

	ps->addAffector(paf);
	paf->drop();
	return (int *)paf;
}

/* ----------------------------------------------------------------------------
Creates a color morph affector. This affector modifies the color of the
particles over time in accordance with an array of color values supplied to the
call
*/
DLL_EXPORT int *  BBCALL iColorAffector(		//IParticleAffector *
		IParticleSystemSceneNode* ps,
		u32 numEntries,
		u32 * colors,	//u32 * colors,
		u32 * time,		//u32 * time,
		bool smooth )
{
    core::array<video::SColor> colorlist;
    core::array<u32> timelist;

    for ( u32 i=0; i< numEntries; i++ )
    {
        colorlist.push_back( SColor( colors[i] ));
        if ( time )
            timelist.push_back( time[i] );
    }

	CColorMorphAffector* paf = new CColorMorphAffector( colorlist, smooth, timelist );
	ps->addAffector(paf);
	paf->drop();

    colorlist.clear();
    timelist.clear();
	return (int *)paf;
}

/* ----------------------------------------------------------------------------
Creates a spline path affector. This affector moves the particles along the path
of a spline for very controled particle modifies the color of the
particles over time in accordance with an array of color values supplied to the
call
*/
DLL_EXPORT int *  BBCALL iSplineAffector(		//IParticleAffector *
		IParticleSystemSceneNode* ps,
        u32 iVertexCount,
        float *vVertices,
		f32 speed,
		f32 tightness,
		f32 attraction,
		bool deleteAtEnd )
{
	core::array<core::vector3df> splineVerts;

    for ( u32 i=0; i< (iVertexCount*12); i=i+12 )
    {
		splineVerts.push_back( core::vector3df( vVertices[i], vVertices[i+4], vVertices[i+8] ));
		//printf( "vVertices[i]",vVertices[i],"vVertices[i+4]",vVertices[i+4],"vVertices[i+8]",vVertices[i+8],"\n" );
    }

	CSplineAffector* paf = new CSplineAffector( splineVerts, speed, tightness, attraction, deleteAtEnd );
	ps->addAffector(paf);
	paf->drop();

    splineVerts.clear();
	return (int *)paf;
}

/* ----------------------------------------------------------------------------
remove all effectors from this particle system
*/
DLL_EXPORT void BBCALL iFreeAffectors( IParticleSystemSceneNode* ps )
{
	ps->removeAllAffectors();
}

/* ----------------------------------------------------------------------------
Set direction the emitter emits particles.
*/
DLL_EXPORT void BBCALL iParticleEmitterDirection( IParticleEmitter* pe, float x, float y, float z )
{
	pe->setDirection( vector3df( x,y,z ));
}

/* ----------------------------------------------------------------------------
Set minimum number of particles the emitter emits per second.
*/
DLL_EXPORT void BBCALL iEmitterMinParticlesPerSecond( IParticleEmitter* pe, unsigned int minPPS )
{
	pe->setMinParticlesPerSecond( minPPS );
}

/* ----------------------------------------------------------------------------
Set maximum number of particles the emitter emits per second.
*/
DLL_EXPORT void BBCALL iEmitterMaxParticlesPerSecond( IParticleEmitter* pe, unsigned int maxPPS )
{
	pe->setMaxParticlesPerSecond( maxPPS );
}

/* ----------------------------------------------------------------------------
Set minimum starting color for particles.
*/
DLL_EXPORT void BBCALL iEmitterMinStartColor( IParticleEmitter* pe, unsigned int R, unsigned int G, unsigned int B )
{
	pe->setMinStartColor( SColor(0,R,G,B ));
}

/* ----------------------------------------------------------------------------
Set maximum starting color for particles.
*/
DLL_EXPORT void BBCALL iEmitterMaxStartColor( IParticleEmitter* pe, unsigned int R, unsigned int G, unsigned int B )
{
	pe->setMaxStartColor( SColor(0,R,G,B ));
}



/* ----------------------------------------------------------------------------
Enable or disable an affector
*/
DLL_EXPORT void BBCALL iParticleAffectorEnable( IParticleAffector* foa, bool enable )
{
	foa->setEnabled( enable );
}

/* ----------------------------------------------------------------------------
Alter the fadeout affector changing the fade out time
*/
DLL_EXPORT void BBCALL iFadeOutParticleAffectorTime( IParticleFadeOutAffector* foa, unsigned int FadeFactor )
{
	foa->setFadeOutTime( FadeFactor );
}

/* ----------------------------------------------------------------------------
Alter the fadeout affector changing the target color
*/
DLL_EXPORT void BBCALL iFadeOutParticleAffectorTargetColor( IParticleFadeOutAffector* foa, unsigned int R, unsigned int G, unsigned int B  )
{
	foa->setTargetColor( SColor( 0,R,G,B )) ;
}

/* ----------------------------------------------------------------------------
Alter the direction and force of gravity
*/
DLL_EXPORT void BBCALL iGravityParticleAffectorDirection( IParticleGravityAffector* foa, float x, float y, float z )
{
	foa->setGravity( vector3df( x,y,z ));
}

/* ----------------------------------------------------------------------------
Set the time in milliseconds when the gravity force is totally lost and the
particle does not move any more
*/
DLL_EXPORT void BBCALL iGravityParticleAffectorTimeForceLost( IParticleGravityAffector* foa, float timeForceLost )
{
	foa->setTimeForceLost( timeForceLost );
}

/* ----------------------------------------------------------------------------
Set whether or not this will affect particles in the X direction.
*/
DLL_EXPORT void BBCALL iParticleAttractionAffectorAffectX( IParticleAttractionAffector* foa, bool affect )
{
	foa->setAffectX( affect );
}

/* ----------------------------------------------------------------------------
Set whether or not this will affect particles in the Y direction.
*/
DLL_EXPORT void BBCALL iParticleAttractionAffectorAffectY( IParticleAttractionAffector* foa, bool affect )
{
	foa->setAffectY( affect );
}

/* ----------------------------------------------------------------------------
Set whether or not this will affect particles in the Z direction.
*/
DLL_EXPORT void BBCALL iParticleAttractionAffectorAffectZ( IParticleAttractionAffector* foa, bool affect )
{
	foa->setAffectZ( affect );
}

/* ----------------------------------------------------------------------------
Set whether or not the particles are attracting or detracting.
*/
DLL_EXPORT void BBCALL iParticleAttractionAffectorAttract( IParticleAttractionAffector* foa, bool attract )
{
	foa->setAttract( attract );
}

/* ----------------------------------------------------------------------------
Set the point that particles will attract to.
*/
DLL_EXPORT void BBCALL iParticleAttractionAffectorPoint( IParticleAttractionAffector* foa, float x, float y, float z )
{
	foa->setPoint( vector3df( x,y,z ));
}

/* ----------------------------------------------------------------------------
Set the point that particles will rotate about.
*/
DLL_EXPORT void BBCALL iRotationAffectorPivotPoint( IParticleRotationAffector* foa, float x, float y, float z )
{
	foa->setPivotPoint( vector3df( x,y,z ));
}


/* ----------------------------------------------------------------------------
Set the point that particles will rotate about.
*/
DLL_EXPORT void BBCALL iFurthestDistanceOfEffect( CParticlePushAffector* foa, float NewDistance )
{
	foa->setFurthestDistanceOfEffect( NewDistance );
}

/* ----------------------------------------------------------------------------
Set the point that particles will rotate about.
*/
DLL_EXPORT void BBCALL iNearestDistanceOfEffect( CParticlePushAffector* foa, float NewDistance )
{
	foa->setNearestDistanceOfEffect( NewDistance );
}

/* ----------------------------------------------------------------------------
Set the point that particles will rotate about.
*/
DLL_EXPORT void BBCALL iColumnDistanceOfEffect( CParticlePushAffector* foa, float NewDistance )
{
	foa->setColumnDistanceOfEffect( NewDistance );
}

/* ----------------------------------------------------------------------------
Set the point that particles will rotate about.
*/
DLL_EXPORT void BBCALL iCenterOfEffect( CParticlePushAffector* foa, float x, float y, float z )
{
	foa->setCenterOfEffect( vector3df( x,y,z ));
}

/* ----------------------------------------------------------------------------
Set the point that particles will rotate about.
*/
DLL_EXPORT void BBCALL iStrengthOfEffect( CParticlePushAffector* foa, float x, float y, float z )
{
	foa->setStrengthOfEffect( vector3df( x,y,z ));
}















}


