// ----------------------------------------------------------------------------
// 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 IrrlichtDevice*		device;
extern IVideoDriver*		driver;
extern ISceneManager*		smgr;
extern IGUIEnvironment*		guienv;
extern StackedEventReceiver receiver;

extern EffectHandler*		effect;

extern int g_CameraCLSRed;
extern int g_CameraCLSGrn;
extern int g_CameraCLSBlu;

extern int g_TextColorAlpha;
extern int g_TextColorRed;
extern int g_TextColorGrn;
extern int g_TextColorBlu;

extern E_DRIVER_TYPE g_iDevice;
extern bool g_vsync;


/*
char DecryptMystring(char RawStr)
    {
        const char DecryptedStr = "";
        for (int i = 0; i < RawStr.Length; i++)
        {
            DecryptedStr += (char)((int)RawStr[i] - 80 + i);
        }

        return DecryptedStr;
    }

char EncryptMystring(string RawStr)
    {
        const char EncryptedStr = "";
        for (int i = 0; i < RawStr.Length; i++)
        {
            EncryptedStr += (char)((int)RawStr[i] + 80 - i);
        }

        return EncryptedStr;
    }

char Encrypted = EncryptMystring("AAbbBb");
char Decrypted = DecryptMystring(Encrypted);
*/
/* ////////////////////////////////////////////////////////////////////////////
Global Function Declarations


all of the below functions are declared as C functions and are exposed without
any mangled names so that they can be easily imported into imperative
languages like Blitz
*/
extern "C"
{


//Graphics3D
DLL_EXPORT bool BBCALL iIrr3D(
                              unsigned int iWidth,
                              unsigned int iHeight,
                              unsigned int iBPP,
                              bool boFullscreen )
{
    bool boInitStatus = false;
//    E_DRIVER_TYPE iDeviceTypes[] = {
//            EDT_NULL, EDT_SOFTWARE, EDT_SOFTWARE, EDT_OPENGL, EDT_DIRECT3D8, EDT_DIRECT3D9 };

    // create an irrlicht device object the root of all irrlicht functionality
    // if it is successfully created
	if ( device = createDevice(
            g_iDevice,
            dimension2d<u32>( iWidth, iHeight),
            iBPP,
			boFullscreen,
			true,
			g_vsync,
			true ? &receiver : 0 ))
    {

        /* Get a pointer to the video driver, the SceneManager and the
        graphical user interface environment */
        // if we can successfully create these objects
        if (( driver = device->getVideoDriver()) &&
                ( smgr = device->getSceneManager()) &&
                ( guienv = device->getGUIEnvironment()) )
		{
			// the system has started up correctly
            boInitStatus = true;

			// apply an unlight material to the scene so that drawing functions display in set color
			SMaterial unlitMaterial;
			unlitMaterial.Lighting = false;
			driver->setMaterial(unlitMaterial);
		}
    }
    return boInitStatus;
}

DLL_EXPORT bool BBCALL iIrr3DAdvanced (
		int drivertype,			// Default of EDT_OPENGL is used if <= -1.
		int width,				// Default of 800 is used if <= 0
		int height,				// Default of 600 is used if <= 0
		u32 bits,				// Default of 16 (bits) is used if <= 0.
		u32 fullscreen,			// Run in windowed or fullscreen mode
		u32 shadows,			// Does nothing (at this time).
		u32 dontignoreinput,	// capture irrlicht events
		u32 vsyncEnabled,		// sync with the vertical blank for tear free frames

		// Extended values for IrrStartAdvanced (versus IrrStart)
		u32 devicetype,			// Leave at 0 for "EIDT_BEST".
		bool doublebufferEnabled,	// Should be set to 1.
		u32 antialiasEnabled,	// enable full screen antialiasing
		u32 highprecisionfpu )	// enable high precision fpu calculations
{
	E_DEVICE_TYPE devicetypeEnum[] = {EIDT_BEST, EIDT_WIN32, EIDT_WINCE, EIDT_X11, EIDT_OSX, EIDT_SDL, EIDT_FRAMEBUFFER, EIDT_CONSOLE};
	E_DRIVER_TYPE drivertypeEnum[] = {EDT_NULL, EDT_SOFTWARE, EDT_BURNINGSVIDEO, EDT_OPENGL, EDT_DIRECT3D8, EDT_DIRECT3D9};

	SIrrlichtCreationParameters params;

	if (width <= 0) width = 800;
	if (height <= 0) height = 600;

	params.AntiAlias = antialiasEnabled;

	if (bits > 0) params.Bits = bits;

	params.DeviceType = devicetypeEnum[devicetype];
	params.Doublebuffer = (bool)doublebufferEnabled;
	params.DriverType = drivertypeEnum[drivertype];
	params.EventReceiver = &receiver;
	params.Fullscreen = (fullscreen != 0);
	params.IgnoreInput = ((1 - dontignoreinput) != 0);
	params.HighPrecisionFPU = (highprecisionfpu != 0);
	//params.LoggingLevel = logginglevel;
	//params.Stencilbuffer = stencilbuffer;
	//params.Stereobuffer = stereobuffer;
	params.Vsync = (vsyncEnabled != 0);
	//params.WindowId = windowid;
	params.WindowSize = irr::core::dimension2d<u32>(width, height);
	//params.WithAlphaChanel = withalphachannel;
	//params.ZBufferBits = zbufferbits;

	// if we successfully created a an irrlicht device object
	bool initStatus = false;
	if (device = createDeviceEx(params))
	{
		// Get a pointer to the video driver, the SceneManager and the graphical user interface environment.
		if (( driver = device->getVideoDriver()) && ( smgr = device->getSceneManager()) && ( guienv = device->getGUIEnvironment()))
		{
			// The system has started up correctly:
			initStatus = true;

			// Apply an unlit material to the scene so that drawing functions display in a set color.
			SMaterial unlitMaterial;
			unlitMaterial.Lighting = false;
			driver->setMaterial(unlitMaterial);
		}
	}
	// inform the user whether the function was successful or not
	return initStatus;
}

DLL_EXPORT void BBCALL iVSync( bool apply )
{
	g_vsync = apply;
}

DLL_EXPORT void BBCALL iUseDirect3D9( void )
{
	g_iDevice = EDT_DIRECT3D9;
}

DLL_EXPORT void BBCALL iUseOpenGL( void )
{
	g_iDevice = EDT_OPENGL;
}

DLL_EXPORT void BBCALL iUseSoftware( void )
{
	g_iDevice = EDT_SOFTWARE;
}

DLL_EXPORT void BBCALL iEndIrr3D( void )
{
	device->closeDevice();
	device->drop();

	/* release resources managed by the wrapper and not irrlicht */
	//dropShaders();
}

DLL_EXPORT int BBCALL iGetFPS( void )
{
    return driver->getFPS();
}

DLL_EXPORT void BBCALL iAppTitle( const char *wcptrText )
{
	device->setWindowCaption(ConvertCharToWChar(wcptrText));
}

DLL_EXPORT int BBCALL iTime( void )
{
	if(device->isWindowActive())
		return device->getTimer()->getTime();
	return 0;
}

DLL_EXPORT int BBCALL iGraphicsWidth(void)
{
    irr::core::dimension2d<u32> screensize = device->getVideoDriver()->getScreenSize();
    return screensize.Width;
}

DLL_EXPORT int BBCALL iGraphicsHeight(void)
{
    irr::core::dimension2d<u32> screensize = device->getVideoDriver()->getScreenSize();
    return screensize.Height;
}

DLL_EXPORT void BBCALL iViewPort ( int X, int Y, int width, int height )
{
	driver->setViewPort(rect<s32>(X, Y, X+width, Y+height ));
}

//Dither

//WBuffer

//AntiAlias

//Wireframe

//HWMultiTex

//AmbientLight
/* ----------------------------------------------------------------------------
set the scene ambient lighting
*/
DLL_EXPORT void BBCALL iAmbientLight( float r, float g, float b )
{
    smgr->setAmbientLight( SColorf( r, g, b, 0.0f ));
}



//ClearCollisions
/*
ClearCollisions()
Parameters
None.  

Description
Clears the collision information list. 
*/



//Collisions
/*
Collisions (src_type,dest_type,method,response)
Parameters
src_type - entity type to be checked for collisions. 
dest_type - entity type to be collided with. 

method - collision detection method. 
1: ellipsoid-to-ellipsoid collisions 
2: ellipsoid-to-polygon collisions 
3: ellipsoid-to-box collisions 

response - what the source entity does when a collision occurs. 
1: stop 
2: slide1 - full sliding collision 
3: slide2 - prevent entities from sliding down slopes  

Description
Enables collisions between two different entity types. 

Entity types are just numbers you assign to an entity using EntityType. Blitz then uses the entity types to check for collisions between all the entities that have those entity types. 
*/



//UpdateWorld

//CaptureWorld

//RenderWorld
DLL_EXPORT int BBCALL iRun ( void )
{
    return device->run();
}

DLL_EXPORT void BBCALL iBeginScene ( void )
{
	// needs called each frame to keep engine running
	//device->run();
    // begin the scene
	driver->beginScene(true, true, SColor(0,g_CameraCLSRed,g_CameraCLSGrn,g_CameraCLSBlu));
}

DLL_EXPORT void BBCALL iBeginSceneAdvanced ( u32 sceneBackgroundColor,
										bool clearBackBuffer,
										bool clearZBuffer )
{
	driver->beginScene( clearBackBuffer, clearZBuffer, sceneBackgroundColor );
}

DLL_EXPORT void BBCALL iCameraCLSColor ( int r, int g, int b )
{
	g_CameraCLSRed = r;
	g_CameraCLSGrn = g;
	g_CameraCLSBlu = b;
}

DLL_EXPORT void BBCALL iDrawScene ( void )
{
	if(!device->isWindowMinimized())
	{
    // draw the scene
	if ( effect == NULL )
	    smgr->drawAll();
	else
		effect->update();
	}
	else
	{
		device->yield();
	}
}

DLL_EXPORT void BBCALL iDrawGUI ( void )
{
    // draw the gui interface
    guienv->drawAll();
}



DLL_EXPORT void BBCALL iEndScene ( void )
{
////////////////////////////////////////////////////////////////////////////////////////////////////////
	// COPYRIGHT REMOVED UPON COMPLETION
/*	if( device->getTimer()->getTime() < 30000)
	{
		irr::core::dimension2d<u32> screensize = device->getVideoDriver()->getScreenSize();
		IGUIFont* font = guienv->getBuiltInFont();
		stringw copyright = "BLITZ IRRLICHT BY ED MUSOLINO 2015 (AquaLung)";
		font->draw( copyright, core::rect<s32>((screensize.Width / 2) - 105,
													screensize.Height - 20,
													(screensize.Width / 2) + 1,
													screensize.Height ),
													video::SColor(255,255-g_CameraCLSRed,255,255-g_CameraCLSBlu));

//    driver->draw2DImage(
//            (ITexture*)BILogo,
//            position2d< s32 >((screensize.Width / 2) - 130,(screensize.Height - 100)),
//            rect< s32 >(0,0,30,30),
//            NULL,
//            video::SColor( 128, 255, 255, 255),
//            false );
	}*/

/*
 stringw toEncrypt = "fail";
 char key = 'x'; //remember 115 in ascii

 for (unsigned int temp = 0; temp < toEncrypt.size(); temp++)
   toEncrypt[temp] ^= key;
 //cout << "nThe encrypted data = " << toEncrypt;

 for (unsigned int temp = 0; temp < toEncrypt.size(); temp++)
   toEncrypt[temp] ^= key; //notice we're using the exact same key, to unencrypt the data.
 //cout << "nThe unencrypted data = " << toEncrypt;
*/

////////////////////////////////////////////////////////////////////////////////////////////////////////

	// end the scene and display it
	driver->endScene();
}



//ClearWorld

DLL_EXPORT void BBCALL iClearScene ( void )
{
	// delete all nodes from the scene
    smgr->clear();

	/* get the mesh cache for the scene */
    IMeshCache *mcache = smgr->getMeshCache();

    /* remove all mesh */
    mcache->clear();
}


//LoaderMatrix

//TrisRendered
DLL_EXPORT int BBCALL iTrisDrawn( void )
{
    return driver->getPrimitiveCountDrawn();
}

/* ----------------------------------------------------------------------------
query whether a feature is supported on the graphics card
*/
DLL_EXPORT bool BBCALL iQueryFeature( enum irr::video::E_VIDEO_DRIVER_FEATURE feature )
{
    return driver->queryFeature( feature );
}

/* ----------------------------------------------------------------------------
disable or enable a specific feature on a graphics card
*/
DLL_EXPORT void BBCALL iDisableFeature( enum irr::video::E_VIDEO_DRIVER_FEATURE feature, bool flag )
{
	driver->disableFeature( feature, flag );
}

/* ----------------------------------------------------------------------------
set the color of shadows in the scene
*/
DLL_EXPORT void BBCALL iShadowColor( int alpha, int R, int G, int B )
{
	// set shadow color
	smgr->setShadowColor(video::SColor(alpha,R,G,B));
}

/* ----------------------------------------------------------------------------
set the scene fog
*/
DLL_EXPORT void BBCALL iCameraFog( int R, int G, int B, bool fogtype, float start, float end, float density )
{
    driver->setFog( SColor(0, R, G, B), fogtype?EFT_FOG_LINEAR:EFT_FOG_EXP, start, end, density );
}

/* ----------------------------------------------------------------------------
draw a 3D line into the display
*/
DLL_EXPORT void BBCALL iDraw3DLine( float xStart, float yStart, float zStart, float xEnd, float yEnd, float zEnd, unsigned int R, unsigned int G, unsigned int B )
{
    // this node has no geometry only debug visuals
    video::SMaterial m;
    m.Lighting = false;
    driver->setMaterial(m);
    driver->setTransform(video::ETS_WORLD, core::matrix4());

    driver->draw3DLine( vector3df( xStart, yStart, zStart ), vector3df( xEnd, yEnd, zEnd ), SColor( 0, R, G, B));
}


/*
DLL_EXPORT void BBCALL iWritePixelFast(int x, int y, ITexture* texture = 0)
{
 //   video::ITexture* LastRenderTarget = driver->getRenderTarget();
    if (texture)
        driver->setRenderTarget(texture);
    
    driver->drawPixel(x,y,video::SColor(g_TextColorAlpha,g_TextColorRed,g_TextColorGrn,g_TextColorBlu));
 //   if (texture)
//        g_RenderSystem->setRenderTarget(LastRenderTarget);
}*/
DLL_EXPORT void BBCALL iWritePixelFast(int x, int y, IImage* image = 0)
{
 //   video::ITexture* LastRenderTarget = driver->getRenderTarget();
    if (image)
		image->setPixel(x,y,video::SColor(g_TextColorAlpha,g_TextColorRed,g_TextColorGrn,g_TextColorBlu));

 //   if (texture)
//        g_RenderSystem->setRenderTarget(LastRenderTarget);
}

DLL_EXPORT int BBCALL iReadPixelFast(int x, int y, IImage* image = 0)
{
	//return image pixel
    if (image)
	{
		SColor clr = image->getPixel(x,y);
		return clr.color;
	}
	else
		return false;
}

/* ----------------------------------------------------------------------------
load a scene created with irrEdit
*/
DLL_EXPORT void BBCALL iLoadScene( const c8* filename )
{
    smgr->loadScene(filename);
}


/* ----------------------------------------------------------------------------
save the current scene out to a file that is compatible with irrEdit
*/
DLL_EXPORT void BBCALL iSaveScene( const c8* filename )
{
    smgr->saveScene(filename);
}

/* ----------------------------------------------------------------------------
allow transparency to write to the z buffer
*/
DLL_EXPORT void BBCALL iTransparentZWrite ( bool on )
{
	if (on)
	{
		smgr->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true);
	}
	else
	{
		smgr->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, false);
	}
}

}