//
// Irrlicht Wrapper for Imperative Languages
// Frank Dodd (2006)
//
// Additional Work
// Michael Taupitz (2006)
//
// This wrapper DLL encapsulates a sub-set of the features of the powerful
// Irrlicht 3D Graphics Engine exposing the Object Oriented architecture and
// providing a functional 3D SDK for languages that are not object oriented.
//
// This source was created with the help of the great examples in the Irrlicht
// SDK and the excellent Irrlicht documentation. This software was developed
// using the GCC compiler and Code::Blocks IDE
//

/* ////////////////////////////////////////////////////////////////////////////
includes
*/
#include "irrlichtwrapper.h"
#include "CPureShader.h"

/* ////////////////////////////////////////////////////////////////////////////
global variables
*/

/* ////////////////////////////////////////////////////////////////////////////
external variables
*/
extern IrrlichtDevice *device;
extern IVideoDriver* driver;
extern ISceneManager* smgr;
extern IGUIEnvironment* guienv;

typedef int(*ShaderCallbackPtr)(irr::video::IMaterialRendererServices*,int);
//Shader-Callback-Class to use the Callback with PB
class MyShaderCallBack : public video::IShaderConstantSetCallBack
{
public:
    MyShaderCallBack(ShaderCallbackPtr callBack) {
        m_callback = callBack;
    }

	virtual void OnSetConstants(video::IMaterialRendererServices* services, s32 userData)
	{
       	int a=m_callback(services,userData);
	}
protected:
ShaderCallbackPtr m_callback;
};
/* ////////////////////////////////////////////////////////////////////////////
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 FreeBasic
*/

extern "C"
{

/* ////////////////////////////////////////////////////////////////////////////
SHADER FUNCTIONS
*/
/* ----------------------------------------------------------------------------
Add Shaders
*/
/**
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrAddHighLevelShaderMaterial(vertexShaderProgram.p-ascii, vertexProgramEntry.p-ascii, vsCompileTarget.l, pixelShaderProgram.p-ascii, pixelProgramEntry.p-ascii,  psCompileTarget.l, *ptr2shaderCallBack.l, basematerial.l, userData.l=#Null)
*/
STATIC_EXPORT int DLL_EXPORT IrrAddHighLevelShaderMaterial( char *vertexShaderProgram,
                                                 char *vertexProgramEntry,
                                                 E_VERTEX_SHADER_TYPE vsCompileTarget,
                                                 char *pixelShaderProgram,
                                                 char *pixelProgramEntry,
                                                 E_PIXEL_SHADER_TYPE psCompileTarget,
                                                 ShaderCallbackPtr shaderCallBack,
                                                 E_MATERIAL_TYPE  basematerial,
                                                 int userData
                                                )
{
    IShaderConstantSetCallBack *cb = NULL;
	IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices();

	if (shaderCallBack != NULL)
        cb = new MyShaderCallBack(shaderCallBack);
	int retVal = gpu->addHighLevelShaderMaterial(vertexShaderProgram,vertexProgramEntry,vsCompileTarget,
                                           pixelShaderProgram,pixelProgramEntry,psCompileTarget,
                                           cb,basematerial,userData);
//    cb->drop();
    return retVal;
}


/* ----------------------------------------------------------------------------
Add Shaders
*/
/**
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrAddHighLevelShaderMaterialFromFiles(vertexShaderProgramFile.p-ascii, vertexProgramEntry.p-ascii, vsCompileTarget.l, pixelShaderProgramFile.p-ascii, pixelProgramEntry.p-ascii,  psCompileTarget.l, *ptr2shaderCallBack.l, basematerial.l, userData.l=#Null)
*/
STATIC_EXPORT int DLL_EXPORT IrrAddHighLevelShaderMaterialFromFiles( char *vertexShaderProgramFile,
                                                 char *vertexProgramEntry,
                                                 E_VERTEX_SHADER_TYPE vsCompileTarget,
                                                 char *pixelShaderProgramFile,
                                                 char *pixelProgramEntry,
                                                 E_PIXEL_SHADER_TYPE psCompileTarget,
                                                 ShaderCallbackPtr shaderCallBack,
                                                 E_MATERIAL_TYPE  basematerial,
                                                 int userData
                                                )
{
    IShaderConstantSetCallBack *cb = NULL;
	IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices();

	if (shaderCallBack != NULL)
        cb = new MyShaderCallBack(shaderCallBack);
	int retVal =  gpu->addHighLevelShaderMaterialFromFiles(strlen(vertexShaderProgramFile)>0?vertexShaderProgramFile:0,vertexProgramEntry,vsCompileTarget,
                                           strlen(pixelShaderProgramFile)>0?pixelShaderProgramFile:0,pixelProgramEntry,psCompileTarget,
                                           cb,basematerial,userData);
//    cb->drop();
    return retVal;
}


/* ----------------------------------------------------------------------------
Add Shaders
*/
/**
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrAddShaderMaterial(vertexShaderProgram.p-ascii, pixelShaderProgram.p-ascii, *ptr2shaderCallBack.l, basematerial.l, userData.l=#Null)
*/
STATIC_EXPORT int DLL_EXPORT IrrAddShaderMaterial( char *vertexShaderProgram,
                                     char *pixelShaderProgram,
                                     ShaderCallbackPtr shaderCallBack,
                                     E_MATERIAL_TYPE  basematerial,
                                     int userData
                                   )
{
    IShaderConstantSetCallBack *cb = NULL;
	IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices();

	if (shaderCallBack != NULL)
        cb = new MyShaderCallBack(shaderCallBack);
	int retVal =  gpu->addShaderMaterial(vertexShaderProgram, pixelShaderProgram, cb,basematerial,userData);
//    cb->drop();
    return retVal;
}


/* ----------------------------------------------------------------------------
Add Shaders
*/
/**
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrAddShaderMaterialFromFiles(vertexShaderProgramFile.p-ascii, pixelShaderProgramFile.p-ascii, *ptr2shaderCallBack.l, basematerial.l, userData.l=#Null)
*/
STATIC_EXPORT int DLL_EXPORT IrrAddShaderMaterialFromFiles( char *vertexShaderProgramFile,
                                     char *pixelShaderProgramFile,
                                     ShaderCallbackPtr shaderCallBack,
                                     E_MATERIAL_TYPE  basematerial,
                                     int userData
                                   )
{
    IShaderConstantSetCallBack *cb = NULL;
	IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices();

	if (shaderCallBack != NULL)
        cb = new MyShaderCallBack(shaderCallBack);
	int retVal =  gpu->addShaderMaterialFromFiles(strlen(vertexShaderProgramFile)>0?vertexShaderProgramFile:0, strlen(pixelShaderProgramFile)>0?pixelShaderProgramFile:0, cb,basematerial,userData);
//    cb->drop();
    return retVal;
}



/* ----------------------------------------------------------------------------
Add Shaders
*/
/**
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrSetPixelShaderConstant(*ptr2MaterailRendererServices.l, *datas.f, startRegister.l, count.l)
*/
STATIC_EXPORT void DLL_EXPORT IrrSetPixelShaderConstant( IMaterialRendererServices* services,
                                            float *data,
                                            s32 startRegister,
                                            s32 count
                                            )
{
   services->setPixelShaderConstant(data,startRegister,count);
}

/**
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrSetPixelShaderConstantName(*ptr2MaterailRendererServices.l, name.p-ascii, startRegister.l, count.l)
*/
STATIC_EXPORT int DLL_EXPORT IrrSetPixelShaderConstantName( IMaterialRendererServices* services,
                                            char *name,
                                            f32* data,
                                            s32 count
                                            )
{
   return services->setPixelShaderConstant(name,data,count);
}


/**
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrSetVertexShaderConstant(*ptr2MaterailRendererServices.l, *datas.f, startRegister.l, count.l)
*/
STATIC_EXPORT void DLL_EXPORT IrrSetVertexShaderConstant( IMaterialRendererServices* services,
                                            float *data,
                                            s32 startRegister,
                                            s32 count
                                            )
{
    services->setVertexShaderConstant(data,startRegister,count);
}

/**
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrSetVertexShaderConstantName(*ptr2MaterailRendererServices.l, name.p-ascii, startRegister.l, count.l)
*/

STATIC_EXPORT int DLL_EXPORT IrrSetVertexShaderConstantName( IMaterialRendererServices* services,
                                            char *name,
                                            const f32* data,
                                            s32 count
                                            )
{
//    printf("name=%s, pointer=%x, counter=%d\n",name,data,count);
    return services->setVertexShaderConstant(name,data,count);
}



/**
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrAddSimpleShader( vertexShaderProgram.s, vertexShaderEntryPointName.s, vsCompileTarget.l, pixelShaderProgram.s,  pixelShaderEntryPointName.s, psCompileTarget.l,baseMaterial.l)
*/
STATIC_EXPORT void* DLL_EXPORT IrrAddSimpleShader(
                                    const c8* vertexShaderProgram,
                                    const c8* vertexShaderEntryPointName,
                                    E_VERTEX_SHADER_TYPE vsCompileTarget,
                                    const c8* pixelShaderProgram,
                                    const c8* pixelShaderEntryPointName,
                                    E_PIXEL_SHADER_TYPE psCompileTarget,
                                    E_MATERIAL_TYPE baseMaterial
)
{
    CPureShader* ps = new CPureShader(pixelShaderProgram, vertexShaderProgram);
    if (ps)
    {
        ps->init(vertexShaderEntryPointName, vsCompileTarget, pixelShaderEntryPointName, psCompileTarget, baseMaterial);
        return (void*) ps;
    }
    return NULL;
}


/**
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrSimpleShaderGetMaterial(*SimpleShader)
*/
STATIC_EXPORT u32 DLL_EXPORT IrrSimpleShaderGetMaterial(CPureShader* ps)
{
    if (ps)
        return ps->getMaterial();
    return -1;
}

/**
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrSimpleShaderSetVSConstant(*SimpleShader,constantname.p-ascii, *values.f, count.l)
*/
STATIC_EXPORT void DLL_EXPORT IrrSimpleShaderSetVSConstant(CPureShader* ps, const c8* constantname, f32* values, u32 count)
{
    if (ps)
        ps->setVSConstant(constantname, values, count);
}

/**
* This is for creating the PB-Importfile, and avoiding to make everything manual
#PBIMPORT:IrrSimpleShaderSetPSConstant(*SimpleShader,constantname.p-ascii, *values.f, count.l)
*/
STATIC_EXPORT void DLL_EXPORT IrrSimpleShaderSetPSConstant(CPureShader* ps, const c8* constantname, f32* values, u32 count)
{
    if (ps)
        ps->setPSConstant(constantname, values, count);
}






/* ////////////////////////////////////////////////////////////////////////////
all of the above functions are declared as C functions and are exposed without
any mangled names
*/
}
