#include "CPureShader.h"



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


CPureShader::CPureShader(const c8* pixelshader,  const c8* vertexshader)
:ps_shader(pixelshader), vs_shader(vertexshader) {
}

void CPureShader::init( const c8 *vertexShaderEntryPointName,
                        E_VERTEX_SHADER_TYPE vsCompileTarget,
                        const c8 *pixelShaderEntryPointName,
                        E_PIXEL_SHADER_TYPE psCompileTarget,
                        E_MATERIAL_TYPE baseMaterial
                        )
{
   video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
   if (!gpu)
   {
        m_Material = video::EMT_SOLID;
        logger->log("Could not get GPUProgrammingServices !!");
        return;
   }

    m_Material = gpu->addHighLevelShaderMaterial(
                                vs_shader.c_str(), vertexShaderEntryPointName, vsCompileTarget,
                                ps_shader.c_str(), pixelShaderEntryPointName, psCompileTarget,
                                this, baseMaterial);
    if (m_Material == -1)
        m_Material = video::EMT_SOLID;

}

void CPureShader::OnSetConstants(video::IMaterialRendererServices* services, s32 userData)
{

   // World/View/Projection matrix
   core::matrix4 worldViewProj;
   worldViewProj = driver->getTransform(video::ETS_PROJECTION);
   worldViewProj *= driver->getTransform(video::ETS_VIEW);
   worldViewProj *= driver->getTransform(video::ETS_WORLD);
   services->setVertexShaderConstant("mWorldViewProj", &worldViewProj[0], 16);

    u32 ps_count = ps_constants.size();
    for (u32 ii = 0; ii < ps_count;ii++) {
        services->setVertexShaderConstant(ps_constants[ii].Name.c_str(), &ps_constants[ii].val[0], ps_constants[ii].Size);
    }

    u32 vs_count = vs_constants.size();
    for (u32 ii = 0; ii < vs_count;ii++) {
        services->setVertexShaderConstant(vs_constants[ii].Name.c_str(), &vs_constants[ii].val[0], vs_constants[ii].Size);
    }

//   services->setPixelShaderConstant("fadeFactor", &m_fadeFactor, 1);
};
/** @brief getPSConstant
  *
  * @todo: document this function
  */
u32 CPureShader::getPSConstant(const c8* constantname, f32* values)
{
    core::stringc cname = constantname;
    u32 ps_count = ps_constants.size();
    for (u32 ii = 0; ii < ps_count;ii++) {
        if (cname == ps_constants[ii].Name) {
            //TODO: Copy Floats
            return ps_constants[ii].Size;
        }
    }
    return 0;
}

/** @brief setPSConstant
  *
  * @todo: document this function
  */
void CPureShader::setPSConstant(const c8* constantname, f32* values, u32 count)
{
    core::stringc cname = constantname;
    u32 ps_count = ps_constants.size();
    for (u32 ii = 0; ii < ps_count;ii++) {
        if (cname == ps_constants[ii].Name) {

            memcpy( (void*)&ps_constants[ii].val[0], (const void*)values, sizeof(f32)*count);
            ps_constants[ii].Size = count;
            return;


        }
    }
    sShaderConstant ssc; // = new sShaderConstant();

    memcpy(&ssc.val[0], values, sizeof(f32)*count);
    ssc.Size = count;
    ssc.Name = cname;

    ps_constants.push_back(ssc);
    return ;
}

/** @brief getVSConstant
  *
  * @todo: document this function
  */
u32 CPureShader::getVSConstant(const c8* constantname, f32* values)
{
    core::stringc cname = constantname;
    u32 vs_count = vs_constants.size();
    for (u32 ii = 0; ii < vs_count;ii++) {
        if (cname == vs_constants[ii].Name) {
            //TODO: Copy Floats
            return vs_constants[ii].Size;
        }
    }
    return 0;

}

/** @brief setVSConstant
  *
  * @todo: document this function
  */
void CPureShader::setVSConstant(const c8* constantname, f32* values, u32 count)
{

    core::stringc cname = constantname;
    u32 vs_count = vs_constants.size();
    for (u32 ii = 0; ii < vs_count;ii++) {
        if (cname == vs_constants[ii].Name) {

            memcpy( (void*)&vs_constants[ii].val[0], (const void*)values, sizeof(f32)*count);
            vs_constants[ii].Size = count;
            return;


        }
    }
    sShaderConstant ssc; // = new sShaderConstant();

    memcpy(&ssc.val[0], values, sizeof(f32)*count);
    ssc.Size = count;
    ssc.Name = cname;

    vs_constants.push_back(ssc);
    return ;

}


