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


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


#define BLEND_SCREEN        0
#define BLEND_ADD           1
#define BLEND_SUBTRACT      2
#define BLEND_MULTIPLY      3
#define BLEND_DIVIDE        4


/* ////////////////////////////////////////////////////////////////////////////
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"
{

DLL_EXPORT void BBCALL iTextureCreateFlag( E_TEXTURE_CREATION_FLAG flag, bool value )
{
	driver->setTextureCreationFlag( flag, value );
}

//CreateTexture
DLL_EXPORT int * BBCALL iCreateTexture( const char *name, int x, int y, ECOLOR_FORMAT format )
{
	return (int *)driver->addTexture(  dimension2d< u32 >( x, y ), name, format );
}

//LoadTexture
DLL_EXPORT int * BBCALL iLoadTexture( char *cptrFile )
{
	return (int *)driver->getTexture( cptrFile );
}

DLL_EXPORT int * BBCALL iCreateRenderTexture( int x, int y )
{
	// create render target
	video::ITexture* renderTexture = 0;

	if ( driver->queryFeature( EVDF_RENDER_TO_TARGET ))
	{
		renderTexture = driver->addRenderTargetTexture ( dimension2d<u32>( x, y ));
	}

	return (int *)renderTexture;
}

/* ----------------------------------------------------------------------------
draw scene manager objects to a texture surface
*/
DLL_EXPORT void BBCALL iDrawSceneToTexture ( ITexture * renderTarget )
{
	// set the texture as the render target
	driver->setRenderTarget( renderTarget, true, true, SColor(0,0,0,255));

	// draw whole scene into the texture
	smgr->drawAll();

	// set the display as the render target
	driver->setRenderTarget(0);
}

/* ----------------------------------------------------------------------------
Sets a texture as a render target, or sets the device if the pointer is 0.
*/
DLL_EXPORT void BBCALL iRenderTargetTexture (ITexture *renderTarget, u32 sceneBackgroundColor, bool clearBackBuffer, bool clearZBuffer )
{
	// set the texture as the render target
	if (renderTarget == 0)
	{
		driver->setRenderTarget(0);
		return;
	}
	driver->setRenderTarget ( renderTarget, clearBackBuffer, clearZBuffer, sceneBackgroundColor );
}

//LoadAnimTexture

//FreeTexture
DLL_EXPORT void BBCALL iFreeTexture( video::ITexture *texture )
{
	driver->removeTexture( texture );
}

//TextureBlend
DLL_EXPORT int BBCALL iTextureBlend(
								 video::ITexture *texturedest,
								 video::ITexture *texturesrc,
								 int xoffset,
								 int yoffset,
								 int operation )
{
	int fromx, fromy, tox, toy, columns, rows;
	int pixeldest, rdest, gdest, bdest, adest;
	int pixelsrc, rsrc, gsrc, bsrc, asrc;
	int blenderrorcode = 0;		/* no error */

	/* determine the texture metrics */
	ECOLOR_FORMAT formatdest = texturedest->getColorFormat();
	ECOLOR_FORMAT formatsrc = texturesrc->getColorFormat();

	/* the textures must be of compatible formats */
	if ( formatdest == formatsrc )
	{
		/* the textures must be 32 bit format at the moment */
		if ( formatdest == ECF_A8R8G8B8 )
		{
			/* determine the boundaries of the operation */
			const dimension2d<u32>*sizedest = &texturedest->getSize();
			const dimension2d<u32>*sizesrc = &texturedest->getSize();
			fromx = xoffset;
			fromy = yoffset;
			tox = sizesrc->Width;
			toy = sizesrc->Height;

			/* lock the textures and get their surfaces */
			unsigned int *pixelsdest = (unsigned int *)texturedest->lock();
			unsigned int *pixelssrc = (unsigned int *)texturesrc->lock();

			/* perform the requested operation */
			switch( operation )
			{
			case BLEND_SCREEN:
				/* itterate texture pixel columns */
				for ( columns = fromy; columns < toy; columns++ )
				{
					/* itterate a row of pixels */
					for ( rows = fromx; rows < tox; rows++ )
					{
						/* extract the pixels */
						pixeldest = *pixelsdest;
						rdest = (pixeldest >> 24 );
						gdest = (pixeldest >> 16 ) & 0xFF;
						bdest = (pixeldest >>  8 ) & 0xFF;
						adest = (pixeldest       ) & 0xFF;

						pixelsrc = *pixelssrc;
						rsrc = (pixelsrc >> 24 );
						gsrc = (pixelsrc >> 16 ) & 0xFF;
						bsrc = (pixelsrc >>  8 ) & 0xFF;
						asrc = (pixelsrc       ) & 0xFF;

						/* blend the pixels */
						rdest = 255 - ((255 - rsrc )*(255 - rdest)/255);
						gdest = 255 - ((255 - gsrc )*(255 - gdest)/255);
						bdest = 255 - ((255 - bsrc )*(255 - bdest)/255);
						adest = 255 - ((255 - asrc )*(255 - adest)/255);

						/* write the destination pixel */
						*pixelsdest = (rdest << 24) + (gdest << 16) + (bdest << 8) + adest;

						/* next pixels */
						pixelsdest++;
						pixelssrc++;
					}
				}
				break;

				/* pixel color values are added together overbright areas are clipped to white */
			case BLEND_ADD:
				/* itterate texture pixel columns */
				for ( columns = fromy; columns < toy; columns++ )
				{
					/* itterate a row of pixels */
					for ( rows = fromx; rows < tox; rows++ )
					{
						/* extract the pixels */
						pixeldest = *pixelsdest;
						rdest = (pixeldest >> 24 );
						gdest = (pixeldest >> 16 ) & 0xFF;
						bdest = (pixeldest >>  8 ) & 0xFF;
						adest = (pixeldest       ) & 0xFF;

						pixelsrc = *pixelssrc;
						rsrc = (pixelsrc >> 24 );
						gsrc = (pixelsrc >> 16 ) & 0xFF;
						bsrc = (pixelsrc >>  8 ) & 0xFF;
						asrc = (pixelsrc       ) & 0xFF;

						/* blend the pixels */
						rdest = rsrc + rdest; if ( rdest > 255 ) rdest = 255;
						gdest = gsrc + gdest; if ( gdest > 255 ) gdest = 255;
						bdest = bsrc + bdest; if ( bdest > 255 ) bdest = 255;
						adest = asrc + adest; if ( adest > 255 ) adest = 255;

						/* write the destination pixel */
						*pixelsdest = (rdest << 24) + (gdest << 16) + (bdest << 8) + adest;

						/* next pixels */
						pixelsdest++;
						pixelssrc++;
					}
				}
				break;

				/* pixel color values are subtracted under dark areas are clipped to white */
			case BLEND_SUBTRACT:
				/* itterate texture pixel columns */
				for ( columns = fromy; columns < toy; columns++ )
				{
					/* itterate a row of pixels */
					for ( rows = fromx; rows < tox; rows++ )
					{
						/* extract the pixels */
						pixeldest = *pixelsdest;
						rdest = (pixeldest >> 24 );
						gdest = (pixeldest >> 16 ) & 0xFF;
						bdest = (pixeldest >>  8 ) & 0xFF;
						adest = (pixeldest       ) & 0xFF;

						pixelsrc = *pixelssrc;
						rsrc = (pixelsrc >> 24 );
						gsrc = (pixelsrc >> 16 ) & 0xFF;
						bsrc = (pixelsrc >>  8 ) & 0xFF;
						asrc = (pixelsrc       ) & 0xFF;

						/* blend the pixels */
						rdest = rsrc - rdest; if ( rdest < 0 ) rdest = 0;
						gdest = gsrc - gdest; if ( gdest < 0 ) gdest = 0;
						bdest = bsrc - bdest; if ( bdest < 0 ) bdest = 0;
						adest = asrc - adest; if ( adest < 0 ) adest = 0;

						/* write the destination pixel */
						*pixelsdest = (rdest << 24) + (gdest << 16) + (bdest << 8) + adest;

						/* next pixels */
						pixelsdest++;
						pixelssrc++;
					}
				}
				break;

			case BLEND_MULTIPLY:
				/* itterate texture pixel columns */
				for ( columns = fromy; columns < toy; columns++ )
				{
					/* itterate a row of pixels */
					for ( rows = fromx; rows < tox; rows++ )
					{
						/* extract the pixels */
						pixeldest = *pixelsdest;
						rdest = (pixeldest >> 24 );
						gdest = (pixeldest >> 16 ) & 0xFF;
						bdest = (pixeldest >>  8 ) & 0xFF;
						adest = (pixeldest       ) & 0xFF;

						pixelsrc = *pixelssrc;
						rsrc = (pixelsrc >> 24 );
						gsrc = (pixelsrc >> 16 ) & 0xFF;
						bsrc = (pixelsrc >>  8 ) & 0xFF;
						asrc = (pixelsrc       ) & 0xFF;

						/* blend the pixels */
						rdest = (rsrc * rdest) / 255;
						gdest = (gsrc * gdest) / 255;
						bdest = (bsrc * bdest) / 255;
						adest = (asrc * adest) / 255;

						/* write the destination pixel */
						*pixelsdest = (rdest << 24) + (gdest << 16) + (bdest << 8) + adest;

						/* next pixels */
						pixelsdest++;
						pixelssrc++;
					}
				}
				break;

			case BLEND_DIVIDE:
				/* itterate texture pixel columns */
				for ( columns = fromy; columns < toy; columns++ )
				{
					/* itterate a row of pixels */
					for ( rows = fromx; rows < tox; rows++ )
					{
						/* extract the pixels */
						pixeldest = *pixelsdest;
						rdest = (pixeldest >> 24 );
						gdest = (pixeldest >> 16 ) & 0xFF;
						bdest = (pixeldest >>  8 ) & 0xFF;
						adest = (pixeldest       ) & 0xFF;

						pixelsrc = *pixelssrc;
						rsrc = (pixelsrc >> 24 );
						gsrc = (pixelsrc >> 16 ) & 0xFF;
						bsrc = (pixelsrc >>  8 ) & 0xFF;
						asrc = (pixelsrc       ) & 0xFF;

						/* blend the pixels */
						if ( rsrc > 0 ) rdest = rdest / rsrc; else rdest = 255;
						if ( gsrc > 0 ) gdest = gdest / gsrc; else gdest = 255;
						if ( bsrc > 0 ) bdest = bdest / bsrc; else bdest = 255;
						if ( asrc > 0 ) adest = adest / asrc; else adest = 255;

						/* write the destination pixel */
						*pixelsdest = (rdest << 24) + (gdest << 16) + (bdest << 8) + adest;

						/* next pixels */
						pixelsdest++;
						pixelssrc++;
					}
				}
				break;
			}

			/* the blend is complete unlock the texture surfaces */
			texturedest->unlock();
			texturesrc->unlock();

			/* regenerate mip map levels in the modified destination texture */
			texturedest->regenerateMipMapLevels();
		}
		else
			/* unsupported texture format, must be 32bit */
			blenderrorcode = 2;
	}
	else
		/* incompatible texture types */
		blenderrorcode = 1;

	return blenderrorcode;
}

//TextureCoords

//ScaleTexture

//PositionTexture

//RotateTexture

//TextureWidth
DLL_EXPORT int BBCALL iTextureWidth( ITexture * texture )
{
    core::dimension2d< u32 > size = texture->getSize();
    return size.Width;
}

//TextureHeight
DLL_EXPORT int BBCALL iTextureHeight( ITexture * texture )
{
    core::dimension2d< u32 > size = texture->getSize();
    return size.Height;
}

//TextureBuffer

//TextureName

//GetBrushTexture

//ClearTextureFilters

//TextureFilter

//SetCubeFace

//SetCubeMode


//MaskTexture - ADDIN
/* ----------------------------------------------------------------------------
color key the image making parts of it transparent
*/
DLL_EXPORT void BBCALL iMaskTexture( video::ITexture *texture, int red, int green, int blue, int alpha=0 )
{
	//driver->makeColorKeyTexture(texture, video::SColor(255, 255, 255, 255));
	driver->makeColorKeyTexture(texture, video::SColor(alpha, red, green, blue));
}

DLL_EXPORT int * BBCALL iLockTexture( video::ITexture *texture )
{
	return (int *)texture->lock();
}

DLL_EXPORT void BBCALL iUnlockTexture( video::ITexture *texture )
{
	texture->unlock();
	texture->regenerateMipMapLevels();
}

/* ----------------------------------------------------------------------------
create a normal map from a grayscale heightmap texture
*/
DLL_EXPORT void BBCALL iNormalMapTexture( video::ITexture *texture, float amplitude )
{
    driver->makeNormalMapTexture ( texture, amplitude );

}




}