#ifdef LINUX
#ifndef GL_GLEXT_PROTOTYPES
#define GL_GLEXT_PROTOTYPES
#endif
#endif
#include <GL/glew.h>
#include <Cg/cgGL.h>
#include "Shader.h"
#include <math.h>
namespace Graphics
{
#ifndef APIENTRYP
#define APIENTRYP APIENTRY *
#endif
#ifndef GL_TEXTURE0_ARB
#define GL_TEXTURE0_ARB 0x84c0
#endif
#ifndef GL_ARRAY_BUFFER_ARB
#define GL_ARRAY_BUFFER_ARB 0x8892
#endif
namespace
{
void SetTexture(CGparameter pParamTextureValidVS, CGparameter pParamTextureValidPS, CGparameter pTexture, CGparameter pMatrix, unsigned int pTextureObject, double* pTextureMatrix)
{
if (pTextureObject > 0)
{
cgSetParameter1i( pParamTextureValidVS, 1 );
cgSetParameter1i( pParamTextureValidPS, 1 );
cgGLSetTextureParameter( pTexture, pTextureObject );
cgGLEnableTextureParameter( pTexture );
cgSetMatrixParameterdc( pMatrix, pTextureMatrix );
}
else
{
cgSetParameter1i( pParamTextureValidVS, 0 );
cgSetParameter1i( pParamTextureValidPS, 0 );
}
}
void SetMaterial(CGparameter pParamAmbient, CGparameter pParamDiffuse, CGparameter pParamSpecular, CGparameter pParamEmissive,
float* pAmbient, float* pDiffuse, float* pSpecular, float* pEmission, float pShininess)
{
cgSetParameter4fv( pParamAmbient, pAmbient );
cgSetParameter4fv( pParamDiffuse, pDiffuse );
float pBuffer[4];
pBuffer[0] = pSpecular[0];
pBuffer[1] = pSpecular[1];
pBuffer[2] = pSpecular[2];
pBuffer[3] = pShininess;
cgSetParameter4fv( pParamSpecular, pBuffer );
cgSetParameter4fv( pParamEmissive, pEmission );
}
double sDefaultAttenuationNone[3] = { 1.0, 0.0, 0.0 };
double sDefaultAttenuationLinear[3] = { 0.0, 0.01, 0.0 };
double sDefaultAttenuationQuadratic[3] = { 0.0, 0.0, 0.0001 };
}
Shader::Shader()
{
static bool init = true;
if ( init )
{
GLenum err = glewInit();
if (GLEW_OK != err)
{
FBTrace(
"GLEW error: %s\n", glewGetErrorString(err));
}
else
{
FBTrace(
"GLEW version: %s\n", glewGetString(GLEW_VERSION));
}
init = false;
}
}
Shader::~Shader()
{
if ( mVertexShader )
{
cgDestroyProgram( mVertexShader );
}
if ( mPixelShader )
{
cgDestroyProgram( mPixelShader );
}
if ( mContext )
{
cgDestroyContext( mContext );
}
}
bool Shader::Initialize(const char* pVertexShaderPath, const char* pPixelShaderPath, const char* pVertexShaderOptions, const char* pPixelShaderOptions)
{
mContext = cgCreateContext();
if( !mContext )
{
ShowError("Could not create CG context");
return false;
}
CGprofile lVertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX);
CGprofile lPixelProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT);
if( !cgGLIsProfileSupported(lVertexProfile) )
{
ShowError("Vertex programming extensions not supported");
return false;
}
if( !cgGLIsProfileSupported(lPixelProfile) )
{
ShowError("Pixel programming extensions not supported");
return false;
}
cgGLSetOptimalOptions(lVertexProfile);
cgGLSetOptimalOptions(lPixelProfile);
mVertexProfile = lVertexProfile;
mPixelProfile = lPixelProfile;
if( !CreateVertexShader( pVertexShaderPath, pVertexShaderOptions ) )
{
return false;
}
if( !CreatePixelShader( pPixelShaderPath, pPixelShaderOptions ) )
{
return false;
}
return true;
}
void Shader::BeginShading(FBRenderOptions* pRenderOptions, FBArrayTemplate<FBLight*>* pAffectingLightList)
{
BindShaderPrograms();
UploadParameters(pRenderOptions, pAffectingLightList);
}
void Shader::EndShading()
{
UnsetTextures();
UnbindShaderPrograms();
}
void Shader::BindShaderPrograms()
{
cgGLBindProgram(mVertexShader);
cgGLBindProgram(mPixelShader);
cgGLEnableProfile(mVertexProfile);
cgGLEnableProfile(mPixelProfile);
}
void Shader::UnbindShaderPrograms()
{
cgGLDisableProfile(mVertexProfile);
cgGLDisableProfile(mPixelProfile);
cgGLUnbindProgram(mVertexProfile);
cgGLUnbindProgram(mPixelProfile);
}
void Shader::UploadParameters( FBRenderOptions* pRenderOptions, FBArrayTemplate<FBLight*>* pAffectingLightList )
{
if (pRenderOptions->IsIDBufferRendering())
return;
FBRenderer* lRender = FBSystem::TheOne().Renderer;
FBMatrix lCameraMVMatrix;
lRender->CurrentCamera->GetCameraMatrix( lCameraMVMatrix,
kFBModelView );
FBMatrix lViewRotationMatrix;
FBColorAndAlpha lAmbienColor = (FBColor)FBGlobalLight::TheOne().AmbientColor;
cgSetParameter4dv( mParamLightAmbient, (double*)lAmbienColor );
FBArrayTemplate<FBLight*> lLightList;
int lLightCount = kMaxLight;
if (pAffectingLightList && pAffectingLightList->GetCount() )
{
if (pAffectingLightList->GetCount() < lLightCount)
lLightCount = pAffectingLightList->GetCount();
for (
int i = 0;
i < lLightCount; ++
i)
{
FBLight* lFBLight = pAffectingLightList->GetAt(
i);
if (lFBLight)
lLightList.Add( lFBLight );
}
}
else
{
FBPropertyListLight* lSceneLightsList = &FBSystem::TheOne().Scene->Lights;
if (lSceneLightsList->GetCount() < lLightCount)
lLightCount = lSceneLightsList->GetCount();
for (
int i = 0;
i < lLightCount; ++
i)
{
FBLight* lFBLight = FBCast<FBLight>(lSceneLightsList->GetAt(
i)->GetHIObject());
if (lFBLight)
lLightList.Add( lFBLight );
}
}
lLightCount = lLightList.GetCount();
if ( lLightCount == 0 )
{
cgSetParameter4dv( mParamLightPositions[0], lViewPosition.mValue );
cgSetParameter4dv( mParamLightColours[0], kDiffuse.mValue );
cgSetParameter4dv( mParamLightAttenuations[0], kAttenuation.mValue );
cgSetParameter4dv( mParamLightDirections[0], lDirection0.mValue );
cgSetParameter4dv( mParamLightPositions[1], lViewPosition.mValue );
cgSetParameter4dv( mParamLightColours[1], kDiffuse.mValue );
cgSetParameter4dv( mParamLightAttenuations[1], kAttenuation.mValue );
cgSetParameter4dv( mParamLightDirections[1], lDirection1.mValue );
lLightCount = 2;
}
else
{
for(
int i = 0;
i < lLightCount; ++
i )
{
FBLight* light = lLightList[
i];
cgSetParameter4dv( mParamLightPositions[
i], lViewPosition.mValue );
FBColorAndAlpha diffuseColor = (FBColor)light->DiffuseColor;
double attenuation[4];
{
switch(light->AttenuationType)
{
attenuation[0] = sDefaultAttenuationLinear[0];
attenuation[1] = sDefaultAttenuationLinear[1];
attenuation[2] = sDefaultAttenuationLinear[2];
break;
attenuation[0] = sDefaultAttenuationQuadratic[0];
attenuation[1] = sDefaultAttenuationQuadratic[1];
attenuation[2] = sDefaultAttenuationQuadratic[2];
break;
default:
attenuation[0] = sDefaultAttenuationNone[0];
attenuation[1] = sDefaultAttenuationNone[1];
attenuation[2] = sDefaultAttenuationNone[2];
break;
}
attenuation[3] = light->Intensity / 100.0;
diffuseColor.mValue[3] = 1.0;
}
else
{
attenuation[0] = 1.0; attenuation[1] = 0.0; attenuation[2] = 0.0;
attenuation[3] = light->Intensity/100.0;
diffuseColor.mValue[3] = 0.0;
}
cgSetParameter4dv( mParamLightColours[i], (double*)diffuseColor );
cgSetParameter4dv( mParamLightAttenuations[i], attenuation );
FBMatrix rotationMatrix;
lViewDirection.mValue[3] = cos( (3.141592654*light->OuterAngle/180.0f)/2.0f);
else
lViewDirection.mValue[3] = 0.0;
cgSetParameter4dv( mParamLightDirections[i], lViewDirection.mValue);
}
}
cgSetParameter1i( mParamLightCount, lLightCount );
}
void Shader::UnsetTextures()
{
cgGLDisableTextureParameter( mParamColorTexture );
cgGLDisableTextureParameter( mParamNormalMap );
}
CGprogram Shader::CreateShader(CGprofile pProfile, const char* pPath, const char** pArgs)
{
CGprogram lProgram = cgCreateProgramFromFile( mContext, CG_SOURCE, pPath,
if( lProgram )
{
cgGLLoadProgram( lProgram );
}
else
{
ShowError( cgGetLastListing(mContext) );
}
return lProgram;
}
bool Shader::CreateVertexShader( const char* pPath, const char* pOptions )
{
const int MAX_ARGS = 10;
const char* lArgs[MAX_ARGS];
int lArgCount = 0;
if (pOptions)
{
lOptions = strdup(pOptions);
char* lOption = strtok(lOptions," ");
while (lOption)
{
if (lArgCount>=MAX_ARGS)
{
free(lOptions);
return false;
}
lArgs[lArgCount++] = lOption;
lOption = strtok(
NULL,
" ");
}
}
mVertexShader = CreateShader(mVertexProfile, pPath, lArgs);
if (lOptions)
{
free(lOptions);
}
if ( !mVertexShader )
{
return false;
}
mParamColorTextureValidVS = cgGetNamedParameter( mVertexShader, "ColorTextureValid" );
mParamColorTextureMatrix = cgGetNamedParameter( mVertexShader, "ColorTextureMatrix" );
mParamNormalMapValidVS = cgGetNamedParameter( mVertexShader, "NormalMapValid" );
mParamNormalMapMatrix = cgGetNamedParameter( mVertexShader, "NormalMapMatrix" );
assert(mParamColorTextureValidVS);
assert(mParamColorTextureMatrix);
assert(mParamNormalMapValidVS);
assert(mParamNormalMapMatrix);
return true;
}
bool Shader::CreatePixelShader( const char* pPath, const char* pOptions )
{
const int MAX_ARGS = 10;
const char* lArgs[MAX_ARGS];
int lArgCount = 0;
if (pOptions)
{
lOptions = strdup(pOptions);
char* lOption = strtok(lOptions," ");
while (lOption)
{
if (lArgCount>=(MAX_ARGS-1))
{
free(lOptions);
return false;
}
lArgs[lArgCount++] = lOption;
lOption = strtok(
NULL,
" ");
}
}
char lMaxLightArg[64];
sprintf(lMaxLightArg, "-DMAX_LIGHT_COUNT=%d", kMaxLight);
lArgs[lArgCount++] = lMaxLightArg;
mPixelShader = CreateShader(mPixelProfile, pPath, lArgs);
if (lOptions)
{
free(lOptions);
}
if ( !mPixelShader )
{
return false;
}
mParamMatEmissive = cgGetNamedParameter( mPixelShader, "MaterialEmission" );
mParamMatAmbient = cgGetNamedParameter( mPixelShader, "MaterialAmbient" );
mParamMatDiffuse = cgGetNamedParameter( mPixelShader, "MaterialDiffuse" );
mParamMatSpecular = cgGetNamedParameter( mPixelShader, "MaterialSpecular" );
mParamLightAmbient = cgGetNamedParameter( mPixelShader, "GlobalAmbientLight" );
mParamColorTexture = cgGetNamedParameter( mPixelShader, "ColorTexture" );
mParamColorTextureValidPS = cgGetNamedParameter( mPixelShader, "ColorTextureValid" );
mParamNormalMap = cgGetNamedParameter( mPixelShader, "NormalMap" );
mParamNormalMapValidPS = cgGetNamedParameter( mPixelShader, "NormalMapValid" );
mParamIDBufferRender = cgGetNamedParameter( mPixelShader, "IDBufferRender" );
mParamLightCount = cgGetNamedParameter( mPixelShader, "LightCount" );
assert(mParamMatEmissive);
assert(mParamMatAmbient);
assert(mParamMatDiffuse);
assert(mParamMatSpecular);
assert(mParamLightAmbient);
assert(mParamColorTexture);
assert(mParamColorTextureValidPS);
assert(mParamNormalMap);
assert(mParamNormalMapValidPS);
assert(mParamIDBufferRender);
assert(mParamLightCount);
char variableName[64];
for(
int i = 0;
i < kMaxLight; ++
i )
{
sprintf_s( variableName,
"LightPositions[%d]",
i );
mParamLightPositions[
i] = cgGetNamedParameter( mPixelShader, variableName );
sprintf_s( variableName,
"LightDirections[%d]",
i );
mParamLightDirections[
i] = cgGetNamedParameter( mPixelShader, variableName );
mParamLightColours[
i] = cgGetNamedParameter( mPixelShader, variableName );
sprintf_s( variableName,
"LightAttenuations[%d]",
i );
mParamLightAttenuations[
i] = cgGetNamedParameter( mPixelShader, variableName );
assert(mParamLightDirections[
i]);
assert(mParamLightColours[i]);
assert(mParamLightAttenuations[i]);
}
return true;
}
void Shader::SwitchMaterial(FBRenderOptions* pRenderOptions, FBShaderModelInfo* pShaderModelInfo, FBMaterial* pMaterial, double pShaderTransparencyFactor)
{
if (pMaterial)
{
FBColor lAmbientColor = pMaterial->Ambient;
FBColor lDiffuseColor = pMaterial->Diffuse;
FBColor lSpecularColor = pMaterial->Specular;
FBColor lEmissiveColor = pMaterial->Emissive;
float lShininess = pMaterial->Shininess;
float lAmbient[4], lDiffuse[4], lSpecular[4], lEmissive[4];
#define ConvertColor( floatColor, doubleColor ) { floatColor[0] = doubleColor[0], floatColor[1] = doubleColor[1], floatColor[2] = doubleColor[2], floatColor[3] = 1.0f; }
ConvertColor(lAmbient, lAmbientColor);
ConvertColor(lDiffuse, lDiffuseColor);
ConvertColor(lSpecular, lSpecularColor);
ConvertColor(lEmissive, lEmissiveColor);
#undef ConvertColor
lDiffuse[3] = mAlpha = (1.0 - pMaterial->TransparencyFactor) * pShaderTransparencyFactor;
if (pRenderOptions->IsIDBufferRendering())
{
SetTexture(mParamNormalMapValidVS, mParamNormalMapValidPS, mParamNormalMap, mParamNormalMapMatrix, 0,
NULL);
}
else
{
SetMaterial(mParamMatAmbient, mParamMatDiffuse, mParamMatSpecular, mParamMatEmissive,
lAmbient, lDiffuse, lSpecular, lEmissive, lShininess);
if (lNormalMapTexture ==
NULL)
if (lNormalMapTexture)
{
lNormalMapTexture->OGLInit();
SetTexture(mParamNormalMapValidVS, mParamNormalMapValidPS, mParamNormalMap, mParamNormalMapMatrix, lNormalMapTexture->GetTextureObject(), lNormalMapTexture->GetMatrix());
}
else
{
SetTexture(mParamNormalMapValidVS, mParamNormalMapValidPS, mParamNormalMap, mParamNormalMapMatrix, 0,
NULL);
}
}
cgSetParameter1i(mParamIDBufferRender, pRenderOptions->IsIDBufferRendering() ? 1 : 0);
FBTexture* lDiffuseTexture =
NULL;
if (pShaderModelInfo->GetOriginalTextureFlag())
if (lDiffuseTexture)
{
lDiffuseTexture->OGLInit();
SetTexture(mParamColorTextureValidVS, mParamColorTextureValidPS, mParamColorTexture, mParamColorTextureMatrix, lDiffuseTexture->GetTextureObject(), lDiffuseTexture->GetMatrix());
}
else
SetTexture(mParamColorTextureValidVS, mParamColorTextureValidPS, mParamColorTexture, mParamColorTextureMatrix, 0,
NULL);
}
}
void Shader::UploadModelViewMatrixArrayForDrawInstanced(const double* pModelViewMatrixArray, int pCount)
{
}
void Shader::ShaderPassModelDraw ( FBRenderOptions* pRenderOptions,
FBRenderingPass pPass, FBShaderModelInfo* pInfo)
{
if (pRenderOptions->IsIDBufferRendering())
{
FBColor lColorId = pInfo->GetFBModel()->UniqueColorId;
float lDiffuse[4] = {lColorId[0], lColorId[1], lColorId[2], mAlpha};
cgSetParameter4fv(mParamMatDiffuse, lDiffuse);
}
}
void Shader::ShowError(const char* pText)
{
const char* lErrStr = ( pText ) ? pText : cgGetErrorString(cgGetError());
}
}