// ----------------------------------------------------------------------------
// 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 "XEffects.h"



extern EffectHandler*		effect;
extern IrrlichtDevice*		device;
extern IVideoDriver*		driver;


extern "C"
{

/* ////////////////////////////////////////////////////////////////////////////
BITPLANES XEFFECT EXTENSION SUPPORT
*/


// We need to pass the view projection matrix to the SSAO shader, so we create a class that inherits from
// IPostProcessingRenderCallback and pass the shader constant in OnPreRender using setPostProcessingEffectConstant.
class SSAORenderCallback : public IPostProcessingRenderCallback
{
	public:
	SSAORenderCallback(irr::s32 materialTypeIn) : materialType(materialTypeIn) {}

	void OnPreRender(EffectHandler* effect)
	{
		IVideoDriver* driver = effect->getIrrlichtDevice()->getVideoDriver();
		viewProj = driver->getTransform(ETS_PROJECTION) * driver->getTransform(ETS_VIEW);
		effect->setPostProcessingEffectConstant(materialType, "mViewProj", viewProj.pointer(), 16);
	}

	void OnPostRender(EffectHandler* effect) {}

	core::matrix4 viewProj;
	s32 materialType;
};


/* ----------------------------------------------------------------------------
Make the window resizable.
*/
DLL_EXPORT void BBCALL iXFXStart( bool vsm, bool softShadows, bool bitdepth32 )
{
	effect = new EffectHandler(device, driver->getScreenSize(), vsm, softShadows, bitdepth32 );
}


/* ----------------------------------------------------------------------------
Make the window resizable.
*/
DLL_EXPORT void BBCALL iXFXEnableDepthPass( bool enable )
{
	effect->enableDepthPass(enable);
}


/* ----------------------------------------------------------------------------
Make the window resizable.
*/
DLL_EXPORT void BBCALL iXFXAddPostProcessingFromFile(
		const char * name, int effectType )
{
	irr::s32 handle = effect->addPostProcessingEffectFromFile( core::stringc( name ));

	if ( effectType == 1 )
	{
		// Create our custom IPostProcessingRenderCallback and pass it to setPostProcessingRenderCallback
		// so that we can perform operations before and after the SSAO effect is rendered.
		SSAORenderCallback* ssaoCallback = new SSAORenderCallback(handle);
		effect->setPostProcessingRenderCallback(handle, ssaoCallback);

		ITexture* randVecTexture = effect->generateRandomVectorTexture(dimension2du(512, 512));
		effect->setPostProcessingUserTexture(randVecTexture);
	}
}


/* ----------------------------------------------------------------------------
Make the window resizable.
*/
DLL_EXPORT void BBCALL iXFXSetPostProcessingUserTexture( ITexture * texture )
{
	effect->setPostProcessingUserTexture(texture);
}


/* ----------------------------------------------------------------------------
Make the window resizable.
*/
DLL_EXPORT void BBCALL iXFXAddShadowToNode( ISceneNode * node,
		E_FILTER_TYPE filterType, E_SHADOW_MODE shadowType )
{
	effect->addShadowToNode( node, filterType, shadowType );
}


/* ----------------------------------------------------------------------------
Make the window resizable.
*/
DLL_EXPORT void BBCALL iXFXRemoveShadowFromNode( ISceneNode * node )
{
	effect->removeShadowFromNode( node );
}


/* ----------------------------------------------------------------------------
Make the window resizable.
*/
DLL_EXPORT void BBCALL iXFXExcludeNodeFromLightingCalculations( ISceneNode * node )
{
	effect->excludeNodeFromLightingCalculations( node );
}


/* ----------------------------------------------------------------------------
Make the window resizable.
*/
DLL_EXPORT void BBCALL iXFXAddNodeToDepthPass( ISceneNode * node )
{
	effect->addNodeToDepthPass( node );
}


/* ----------------------------------------------------------------------------
Make the window resizable.
*/
DLL_EXPORT void BBCALL iXFXSetAmbientColor( u32 R, u32 G, u32 B, u32 Alpha )
{
	effect->setAmbientColor(SColor(R,G,B,Alpha));
}


/* ----------------------------------------------------------------------------
Make the window resizable.
*/
DLL_EXPORT void BBCALL iXFXSetClearColor( u32 R, u32 G, u32 B, u32 Alpha )
{
	effect->setClearColour(SColor(R,G,B,Alpha));
}


/* ----------------------------------------------------------------------------
Add a special dynamic shadow casting light
The first parameter specifies the shadow map resolution for the shadow light.
The shadow map is always square, so you need only pass 1 dimension, preferably
a power of two between 512 and 2048, maybe larger depending on your quality
requirements and target hardware. We will just pass the value the user picked.
The second parameter is the light position, the third parameter is the (look at)
target, the next is the light color, and the next two are very important
values, the nearValue and farValue, be sure to set them appropriate to the current
scene. The last parameter is the FOV (Field of view), since the light is similar to
a spot light, the field of view will determine its area of influence. Anything that
is outside of a lights frustum (Too close, too far, or outside of it's field of view)
will be unlit by this particular light, similar to how a spot light works.
We will add one red light and one yellow light.
*/
DLL_EXPORT void BBCALL iXFXAddShadowLight(
		u32 shadowDimen,
		float posX, float posY, float posZ,
		float targetX, float targetY, float targetZ,
		float R, float G, float B, float Alpha,
		float lightNearDist , float lightFarDist, float angleDegrees )
{
	effect->addShadowLight(SShadowLight( shadowDimen,
			vector3df(posX,posY,posZ),
			vector3df(targetX,targetY,targetZ),
			SColorf(R,G,B,Alpha),
			lightNearDist, lightFarDist, angleDegrees * DEGTORAD));
}


/* ----------------------------------------------------------------------------
Make the window resizable.
*/
DLL_EXPORT void BBCALL iXFXSetShadowLightPosition(
		u32 index, float posX, float posY, float posZ )
{
	effect->getShadowLight(index).setPosition(vector3df(posX,posY,posZ));
}


/* ----------------------------------------------------------------------------
Make the window resizable.
*/
DLL_EXPORT float BBCALL iXFXGetShadowLightPositionX( u32 index )
{
	return effect->getShadowLight(index).getPosition().X;
}
DLL_EXPORT float BBCALL iXFXGetShadowLightPositionY( u32 index )
{
	return effect->getShadowLight(index).getPosition().Y;
}
DLL_EXPORT float BBCALL iXFXGetShadowLightPositionZ( u32 index )
{
	return effect->getShadowLight(index).getPosition().Z;
}

/* ----------------------------------------------------------------------------
Make the window resizable.
*/
DLL_EXPORT void BBCALL iXFXSetShadowLightTarget(
		u32 index, float posX, float posY, float posZ )
{
	effect->getShadowLight(index).setTarget(vector3df(posX,posY,posZ));
}


/* ----------------------------------------------------------------------------
Make the window resizable.
*//*
DLL_EXPORT void BBCALL iXEffectsGetShadowLightTarget(
		u32 index, float &posX, float &posY, float &posZ )
{
	vector3df pos = effect->getShadowLight(index).getTarget();
	posX = pos.X;
	posY = pos.Y;
	posZ = pos.Z;
}*/
DLL_EXPORT float BBCALL iXFXGetShadowLightTargetX( u32 index )
{
	return effect->getShadowLight(index).getTarget().X;
}
DLL_EXPORT float BBCALL iXFXGetShadowLightTargetY( u32 index )
{
	return effect->getShadowLight(index).getTarget().Y;
}
DLL_EXPORT float BBCALL iXFXGetShadowLightTargetZ( u32 index )
{
	return effect->getShadowLight(index).getTarget().Z;
}

/* ----------------------------------------------------------------------------
Make the window resizable.
*/
DLL_EXPORT void BBCALL iXFXSetShadowLightColor(
		u32 index, float R, float G, float B, float Alpha )
{
	effect->getShadowLight(index).setLightColor(SColorf(R,G,B,Alpha));
}


/* ----------------------------------------------------------------------------
Make the window resizable.
*//*
DLL_EXPORT void BBCALL iiXEffectsGetShadowLightColor(
		u32 index, float &R, float &G, float &B, float &Alpha )
{
	SColorf color = effect->getShadowLight(index).getLightColor();
	R = color.a;
	G = color.g;
	B = color.b;
	Alpha = color.a;
}*/
DLL_EXPORT float BBCALL iXFXGetShadowLightColorRed( u32 index )
{
	return effect->getShadowLight(index).getLightColor().getRed();
}
DLL_EXPORT float BBCALL iXFXGetShadowLightColorGrn( u32 index )
{
	return effect->getShadowLight(index).getLightColor().getGreen();
}
DLL_EXPORT float BBCALL iXFXGetShadowLightColorBlu( u32 index )
{
	return effect->getShadowLight(index).getLightColor().getBlue();
}
DLL_EXPORT float BBCALL iXFXGetShadowLightColorAlpha( u32 index )
{
	return effect->getShadowLight(index).getLightColor().getAlpha();
}
}