deargui-vpl/ref/virtools/Samples/Behaviors/Shader/Sources/RCKShaderCG.cpp

2734 lines
96 KiB
C++

#include "stdafx.h"
#include "RCKShaderCG.h"
#include "ShaderManagerCG.h"
#include "CKGL15RasterizerContext.h"
#include "CKGL15Rasterizer.h"
#include "ShaderDescriptorCG.h"
//-------------------------------------------------------------------------------
ShaderConstantStore::ShaderConstantStore() : m_CGProgram(NULL), m_GLProgramID(0)
{
}
//-------------------------------------------------------------------------------
void ShaderConstantStore::SetProgram(CGprogram program, const char *programString)
{
XASSERT(!m_CGProgram); // This method should be called only once !
XASSERT(program);
GLuint progID = cgGLGetProgramID(program);
XASSERT(progID); // program should have been compiled successfully !!!
m_CGProgram = program;
m_GLProgramID = progID;
}
//-------------------------------------------------------------------------------
void ShaderConstantStore::EnsureSize(int cstCount)
{
XASSERT(!UsesNamedConstant());
XASSERT(cstCount >= 0);
XASSERT(m_ModifiedConstant.Size() == 0); // Not intended to be resized on the fly ...
bool hasNamedConstant = false;
for (int k = 0; k < m_ConstantArray.Size(); ++k)
{
if (m_ConstantArray[k].m_Name.Length() != 0)
{
hasNamedConstant = true;
}
}
if (cstCount > m_ConstantArray.Size())
{
XASSERT(!hasNamedConstant);
m_ConstantArray.Resize(cstCount);
}
for (int k = 0; k < cstCount; ++k)
{
m_ConstantArray[k].m_Index = k;
//m_ConstantArray[k].m_Name = "???";
}
}
//-------------------------------------------------------------------------------
int ShaderConstantStore::AddNamedConstant(const char *name)
{
XASSERT(UsesNamedConstant());
XASSERT(name);
XASSERT(strlen(name) > 0);
CShaderConstantState cst;
cst.m_Name = name;
cst.m_Index = m_ConstantArray.Size() - 1;
m_ConstantArray.PushBack(cst);
return m_ConstantArray.Size() - 1;
}
//-------------------------------------------------------------------------------
void ShaderConstantStore::SetConstant(int index, const float value[4])
{
XASSERT(m_ModifiedConstant.Size() <= m_ConstantArray.Size());
XASSERT(index >= 0 && index < m_ConstantArray.Size());
float *destValue = &m_ConstantArray[index].m_Value[0];
// TODO : no cache here !!
// To have a working cache; should do the following :
// 1 - use cgGLBindProgram, then get initial values
// 2 - ensure that cache is invalidated when there's a technique change (some techniques may rely on cgSetParameter to set their constant
// because of a profile we don't have a ShaderConstantStore implementation for ...)
/*
if (destValue[0] == value[0] &&
destValue[1] == value[1] &&
destValue[2] == value[2] &&
destValue[3] == value[3]
)
{
return;
}
*/
destValue[0] = value[0];
destValue[1] = value[1];
destValue[2] = value[2];
destValue[3] = value[3];
if (!m_ConstantArray[index].m_Modified)
{
m_ModifiedConstant.PushBack(index);
m_ConstantArray[index].m_Modified = true;
}
else
{
XASSERT(m_ModifiedConstant.Size() > 0);
}
XASSERT(m_ModifiedConstant.Size() <= m_ConstantArray.Size());
}
//-------------------------------------------------------------------------------
void ShaderConstantStore::Flush(CKRasterizerContext *rc)
{
GLCHECK();
XASSERT(m_ModifiedConstant.Size() <= m_ConstantArray.Size());
if (AreParametersLocal())
{
// flush modified parameters only
int modifiedConstantCount = m_ModifiedConstant.Size();
for (int ctIndex = 0; ctIndex < modifiedConstantCount; ++ctIndex)
{
int modifiedConstantIndex = m_ModifiedConstant[ctIndex];
SetConstantInternal(rc, m_ConstantArray[modifiedConstantIndex]);
m_ConstantArray[modifiedConstantIndex].m_Modified = false;
}
}
else
{
// parameters are global -> must set them all
// TODO : use EXT_gpu_program_parameters to set several constant at once
// and/or use a cache per profile
int constantCount = m_ConstantArray.Size();
for (int ctIndex = 0; ctIndex < constantCount; ++ctIndex)
{
SetConstantInternal(rc, m_ConstantArray[ctIndex]);
m_ConstantArray[ctIndex].m_Modified = false;
}
}
m_ModifiedConstant.Resize(0);
GLCHECK();
XASSERT(m_ModifiedConstant.Size() <= m_ConstantArray.Size());
}
////////////
// ARBVP1 //
////////////
//-------------------------------------------------------------------------------
void ShaderConstantStoreARBVP1::SetConstantInternal(CKRasterizerContext *rc, CShaderConstantState &cstState)
{
GLCHECK();
VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc;
XASSERT(ogRC->m_glProgramLocalParameter4fvARB);
ogRC->m_glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_ARB, cstState.m_Index, cstState.m_Value);
GLCHECK();
}
//-------------------------------------------------------------------------------
void ShaderConstantStoreARBVP1::BindProgramIntoGL(CKRasterizerContext *rc)
{
XASSERT(m_GLProgramID);
VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc;
XASSERT(ogRC->m_glBindProgramARB);
ogRC->m_glBindProgramARB(GL_VERTEX_PROGRAM_ARB, m_GLProgramID);
}
////////////
// ARBFP1 //
////////////
//-------------------------------------------------------------------------------
void ShaderConstantStoreARBFP1::SetConstantInternal(CKRasterizerContext *rc, CShaderConstantState &cstState)
{
GLCHECK();
VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc;
XASSERT(ogRC->m_glProgramLocalParameter4fvARB);
ogRC->m_glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, cstState.m_Index, cstState.m_Value);
GLCHECK();
}
//-------------------------------------------------------------------------------
void ShaderConstantStoreARBFP1::BindProgramIntoGL(CKRasterizerContext *rc)
{
XASSERT(m_GLProgramID);
VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc;
XASSERT(ogRC->m_glBindProgramARB);
ogRC->m_glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_GLProgramID);
}
/////////////////
// NV programs //
/////////////////
//-------------------------------------------------------------------------------
void ShaderConstantStoreNVVertex::SetProgram(CGprogram cgProgram, const char *programString)
{
ShaderConstantStore::SetProgram(cgProgram, programString);
const char *currConst = programString;
while (currConst)
{
currConst = strstr(currConst, "#const");
if (!currConst) break;
float value[] = { 0.f, 0.f, 0.f, 0.f };
int constantIndex;
if (sscanf(currConst, "#const c[%u] = %f %f %f %f", &constantIndex, &value[0], &value[1], &value[2], &value[3] ) >= 2)
{
EnsureSize(constantIndex + 1);
for (int c = 0; c < 4; ++c) m_ConstantArray[constantIndex].m_Value[c] = value[c];
}
currConst = strstr(currConst, "\n");
}
}
//-------------------------------------------------------------------------------
void ShaderConstantStoreNVVertex::SetConstantInternal(CKRasterizerContext *rc, CShaderConstantState &cstState)
{
// NB : constants are global for nv vertex programs
// -> must use glProgramParameters4fvNV
GLCHECK();
VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc;
XASSERT(ogRC->m_glProgramParameter4fvNV);
if (ogRC->m_glProgramParameter4fvNV)
{
ogRC->m_glProgramParameter4fvNV(GL_VERTEX_PROGRAM_NV, cstState.m_Index, cstState.m_Value);
}
GLCHECK();
}
//-------------------------------------------------------------------------------
void ShaderConstantStoreNVVertex::BindProgramIntoGL(CKRasterizerContext *rc)
{
GLCHECK();
XASSERT(m_GLProgramID);
VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc;
XASSERT(ogRC->m_glBindProgramNV);
if (ogRC->m_glBindProgramNV)
{
ogRC->m_glBindProgramNV(GL_VERTEX_PROGRAM_NV, m_GLProgramID);
}
GLCHECK();
}
//////////
// FP30 //
//////////
//-------------------------------------------------------------------------------
void ShaderConstantStoreFP30::SetConstantInternal(CKRasterizerContext *rc, CShaderConstantState &cstState)
{
// NB : constants are local and named for nv fragment programs (in fact, included directly in shader code)
// -> must use glProgramLocalParameter4fvARB
GLCHECK();
VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc;
XASSERT(ogRC->m_glProgramNamedParameter4fvNV);
if (ogRC->m_glProgramNamedParameter4fvNV)
{
XASSERT(cstState.m_Name.Length() != 0);
//XASSERT(cstState.m_Name != "???");
ogRC->m_glProgramNamedParameter4fvNV(m_GLProgramID, (GLsizei) cstState.m_Name.Length(), (const GLubyte *) cstState.m_Name.CStr(), cstState.m_Value);
}
GLCHECK();
}
//-------------------------------------------------------------------------------
void ShaderConstantStoreFP30::BindProgramIntoGL(CKRasterizerContext *rc)
{
GLCHECK();
XASSERT(m_GLProgramID);
VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc;
XASSERT(ogRC->m_glBindProgramNV);
if (ogRC->m_glBindProgramNV)
{
ogRC->m_glBindProgramNV(GL_FRAGMENT_PROGRAM_NV, m_GLProgramID);
}
GLCHECK();
}
//////////
// VP40 //
//////////
//-------------------------------------------------------------------------------
void ShaderConstantStoreVP40::SetConstantInternal(CKRasterizerContext *rc, CShaderConstantState &cstState)
{
GLCHECK();
VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc;
XASSERT(ogRC->m_glProgramLocalParameter4fvARB);
ogRC->m_glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_NV, cstState.m_Index, cstState.m_Value);
GLCHECK();
}
//-------------------------------------------------------------------------------
void ShaderConstantStoreVP40::BindProgramIntoGL(CKRasterizerContext *rc)
{
GLCHECK();
XASSERT(m_GLProgramID);
VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc;
XASSERT(ogRC->m_glBindProgramNV);
if (ogRC->m_glBindProgramNV)
{
ogRC->m_glBindProgramNV(GL_VERTEX_PROGRAM_NV, m_GLProgramID);
}
GLCHECK();
}
//////////
// FP40 //
//////////
//-------------------------------------------------------------------------------
void ShaderConstantStoreFP40::SetConstantInternal(CKRasterizerContext *rc, CShaderConstantState &cstState)
{
// NB : constants are local and named for nv fragment programs (in fact, included directly in shader code)
// -> must use glProgramLocalParameter4fvARB
GLCHECK();
VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc;
XASSERT(ogRC->m_glProgramParameter4fvNV);
if (ogRC->m_glProgramLocalParameter4fvARB)
{
ogRC->m_glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_NV, cstState.m_Index, cstState.m_Value);
}
GLCHECK();
}
//-------------------------------------------------------------------------------
void ShaderConstantStoreFP40::BindProgramIntoGL(CKRasterizerContext *rc)
{
GLCHECK();
XASSERT(m_GLProgramID);
VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc;
XASSERT(ogRC->m_glBindProgramNV);
if (ogRC->m_glBindProgramNV)
{
ogRC->m_glBindProgramNV(GL_FRAGMENT_PROGRAM_NV, m_GLProgramID);
}
GLCHECK();
}
//-----------------------------------------------------------------------------
RCKShaderCG::RCKShaderCG(ShaderManagerCG *man) :
m_ShaderManager(man),
m_CurrTechniqueIndex(-1),
m_ShaderText("// Shader")
#if defined(MULTIPLESHADERMANAGER)
,m_ShaderName(NULL)
#endif
,m_CurrentPassIndex(0)
,m_CurrentPassCount(0)
{
//--- Initialize the Effect for all render context
const int rcCount = man->m_rcList.Size();
m_Effect.Resize(rcCount);
m_Effect.Fill(NULL);
m_CurrentTechnique.Resize(rcCount);
m_CurrentTechnique.Fill(NULL);
m_CurrentTechniqueIndex.Resize(rcCount);
for (int k = 0; k < rcCount; ++k)
{
m_EffectStateCachePerContext.PushBack(new EffectStateCache);
}
m_CurrentTechnique.Fill(0);
m_CurrentActivePass.Resize(rcCount);
//--- Allocate a ShaderDescriptorCG for each RenderContext
m_ShaderDescriptor.Resize(rcCount);
for( int rcIndex=0 ; rcIndex<rcCount ; ++rcIndex ){
m_ShaderDescriptor[rcIndex] = new ShaderDescriptorCG::ShaderCG;
}
XASSERT(NUMBER_OF_CG_DOMAIN == 3); // for now ...
}
//-----------------------------------------------------------------------------
RCKShaderCG::~RCKShaderCG()
{
ClearStateCache();
//--- Release all CG Effects for all Render Context
///// and deallocate every ShaderDescriptorCG of each RenderContext
const int rcCount = m_Effect.Size();
for( int rcIndex=0 ; rcIndex<rcCount ; ++rcIndex ){
if( m_Effect[rcIndex] )
{
cgDestroyEffect( m_Effect[rcIndex] );
m_Effect[rcIndex] = NULL;
}
delete m_ShaderDescriptor[rcIndex];
delete m_EffectStateCachePerContext[rcIndex];
}
m_EffectStateCachePerContext.Clear();
m_Effect.Clear();
m_CurrentTechnique.Clear();
m_CurrentTechniqueIndex.Clear();
m_CurrentActivePass.Clear();
m_ShaderDescriptor.Clear();
}
//-----------------------------------------------------------------------------
CKBOOL RCKShaderCG::IsSupported() const
{
const int rcCount = m_Effect.Size();
for( int rcIndex=0 ; rcIndex<rcCount ; ++rcIndex ){
if( !m_Effect[rcIndex] ) return FALSE;
}
return TRUE;
}
void RCKShaderCG::SetText(const XString& Text){
if(m_Hide) return;
CKBOOL isTagged = Text.Contains(CKHideContentManager::GetTag());
if(Text.Contains("Please contact the Author if you want to get full access to this shader.")) {
XASSERT(m_Hide);
return;
}
if(m_Hide && (!isTagged)) {
const XString& hiddenText = CKHideContentManager::Hide(this, Text);
m_ShaderText = hiddenText;
delete &hiddenText;
m_Hide = TRUE;
}
else if(isTagged&&(!m_Hide)) {
m_ShaderText = Text;
m_Hide = TRUE;
}
else {
m_ShaderText = Text;
m_Hide = FALSE;
}
}
void RCKShaderCG::SetText(const XString& Text, CK_SHADER_MANAGER_TYPE type){
if(m_Hide) return;
CKBOOL isTagged = Text.Contains(CKHideContentManager::GetTag());
if(Text.Contains("Please contact the Author if you want to get full access to this shader.")) {
XASSERT(m_Hide);
return;
}
if(m_Hide && (!isTagged)) {
const XString& hiddenText = CKHideContentManager::Hide(this, Text);
m_ShaderText = hiddenText;
delete &hiddenText;
m_Hide = TRUE;
}
else if(isTagged&&(!m_Hide)) {
m_ShaderText = Text;
m_Hide = TRUE;
}
else {
m_ShaderText = Text;
m_Hide = FALSE;
}
}
void RCKShaderCG::SetHideFlag(CKBOOL hide) {
if(hide) {
CKBOOL isTagged = m_ShaderText.Contains(CKHideContentManager::GetTag());
if(!isTagged) {
const XString& hiddenSrc = CKHideContentManager::Hide(this, m_ShaderText);
m_ShaderText = hiddenSrc;
delete &hiddenSrc;
}
m_Hide = TRUE;
}
}
void RCKShaderCG::UnLock(const char* pass) {
if(CKHideContentManager::CheckAgainst(this, pass)) {
if(m_Hide) {
const XString& clearSrc = GetTextInternal();
m_Hide = FALSE;
SetText(clearSrc);
delete &clearSrc;
}
}
}
const XString& RCKShaderCG::GetTextInternal() const{
CKBOOL isTagged = m_ShaderText.Contains(CKHideContentManager::GetTag());
if(isTagged||m_Hide) {
return CKHideContentManager::Clarify((CKProtectable*)this, m_ShaderText);
}
else
return m_ShaderText;
}
const XString& RCKShaderCG::GetTextInternal(CK_SHADER_MANAGER_TYPE type){
CKBOOL isTagged = m_ShaderText.Contains(CKHideContentManager::GetTag());
if(isTagged||m_Hide) {
return CKHideContentManager::Clarify(this->GetProtectable(), m_ShaderText);
}
else
return m_ShaderText;
}
//-----------------------------------------------------------------------------
int RCKShaderCG::Begin( CKRenderContext* rc )
{
const int rcIndex = m_ShaderManager->_GetRenderContextIndex(rc);
int NumPasses = 0;
if(!m_CurrentTechnique[rcIndex]) {
m_CurrentTechnique[rcIndex] = cgGetFirstTechnique(m_Effect[rcIndex]);
m_CurrentTechniqueIndex[rcIndex] = 0;
}
passArray* pPassA = &m_CurrentActivePass[rcIndex];
int pCount = pPassA->Size();
CGpass pass = cgGetFirstPass(m_CurrentTechnique[rcIndex]);
while(pass) {
if(pCount <= NumPasses) {
pPassA->PushBack(pass);
++NumPasses;
}
else {
(*pPassA)[NumPasses] = pass;
++NumPasses;
}
pass = cgGetNextPass(pass);
}
m_CurrentPassIndex = 0;
m_CurrentPassCount = NumPasses;
return NumPasses;
}
// Defines a bool state that map directly to the state caching system in the rasterizer
#define DECLARE_RASTERIZER_STATE(Type, Name, RTState) \
void Name##_CB(CKRasterizerContext *rc, CachedRenderState<Type> &cachedState, const Type *value, bool reset) \
{ \
rc->SetRenderState(RTState, (CKDWORD &) *value); \
}
/////////////////
// BOOL STATES //
/////////////////
DECLARE_RASTERIZER_STATE(CGbool, DepthMask, VXRENDERSTATE_ZWRITEENABLE)
DECLARE_RASTERIZER_STATE(CGbool, ZWriteEnable, VXRENDERSTATE_ZWRITEENABLE)
DECLARE_RASTERIZER_STATE(CGbool, LightingEnable, VXRENDERSTATE_LIGHTING)
DECLARE_RASTERIZER_STATE(CGbool, LocalViewer, VXRENDERSTATE_LOCALVIEWER)
DECLARE_RASTERIZER_STATE(CGbool, Clipping, VXRENDERSTATE_CLIPPING)
DECLARE_RASTERIZER_STATE(CGbool, AlphaTestEnable, VXRENDERSTATE_ALPHATESTENABLE)
DECLARE_RASTERIZER_STATE(CGbool, BlendEnable, VXRENDERSTATE_ALPHABLENDENABLE)
DECLARE_RASTERIZER_STATE(CGbool, DepthTestEnable, VXRENDERSTATE_ZENABLE)
DECLARE_RASTERIZER_STATE(CGbool, DitherEnable, VXRENDERSTATE_DITHERENABLE)
DECLARE_RASTERIZER_STATE(CGbool, FogEnable, VXRENDERSTATE_FOGENABLE)
DECLARE_RASTERIZER_STATE(CGbool, LineSmoothEnable, VXRENDERSTATE_ANTIALIAS)
DECLARE_RASTERIZER_STATE(CGbool, NormalizeEnable, VXRENDERSTATE_NORMALIZENORMALS)
DECLARE_RASTERIZER_STATE(CGbool, PointSpriteEnable, VXRENDERSTATE_POINTSPRITEENABLE)
DECLARE_RASTERIZER_STATE(CGbool, StencilTestEnable, VXRENDERSTATE_STENCILENABLE)
// DECLARE_GL_STATE_CALLBACK_BOOL(SpecularEnable, VXRENDERSTATE_SPECULARENABLE) check this one
//DECLARE_GL_STATE_CALLBACK_BOOL(LineStipple, VXRENDERSTATE_LINEPATTERN)
static void CullFaceEnable_CB(CKRasterizerContext *rc, CachedRenderState<CGbool> &cachedState, const CGbool *value, bool reset)
{
GLCHECK();
if (value[0])
{
glEnable(GL_CULL_FACE);
}
else
{
glDisable(GL_CULL_FACE);
}
GLCHECK();
}
static void LightEnable_CB(CKRasterizerContext *rc, CachedRenderState<CGbool> &cachedState, const CGbool *value, bool reset)
{
GLCHECK();
(VCKGL15Rasterizer::CKGLRasterizerContext*) rc->EnableLight(cachedState.ArrayIndex, *value);
GLCHECK();
}
static void ClipPlaneEnable_CB(CKRasterizerContext *rc, CachedRenderState<CGbool> &cachedState, const CGbool *value, bool reset)
{
if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex <= 5)
{
GLCHECK();
if (*value)
{
glEnable(GL_CLIP_PLANE0 + cachedState.ArrayIndex);
}
else
{
glDisable(GL_CLIP_PLANE0 + cachedState.ArrayIndex);
}
GLCHECK();
}
}
static void MultisampleEnable_CB(CKRasterizerContext *rc, CachedRenderState<CGbool> &cachedState, const CGbool *value, bool reset)
{
GLCHECK();
if (*value)
{
glEnable(GL_MULTISAMPLE);
}
else
{
glDisable(GL_MULTISAMPLE);
}
GLCHECK();
}
static void Texture1DEnable_CB(CKRasterizerContext *rc, CachedRenderState<CGbool> &cachedState, const CGbool *value, bool reset)
{
if (reset) return;
GLCHECK();
if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 32)
{
VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc;
XASSERT(ogRC->m_glActiveTextureARB);
ogRC->m_glActiveTextureARB(GL_TEXTURE0_ARB + cachedState.ArrayIndex);
if (*value)
{
glEnable(GL_TEXTURE_1D);
}
else
{
glDisable(GL_TEXTURE_1D);
}
}
GLCHECK();
}
static void Texture2DEnable_CB(CKRasterizerContext *rc, CachedRenderState<CGbool> &cachedState, const CGbool *value, bool reset)
{
if (reset) return;
GLCHECK();
if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 32)
{
VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc;
XASSERT(ogRC->m_glActiveTextureARB);
ogRC->m_glActiveTextureARB(GL_TEXTURE0_ARB + cachedState.ArrayIndex);
if (*value)
{
glEnable(GL_TEXTURE_2D);
}
else
{
glDisable(GL_TEXTURE_2D);
}
}
GLCHECK();
}
static void Texture3DEnable_CB(CKRasterizerContext *rc, CachedRenderState<CGbool> &cachedState, const CGbool *value, bool reset)
{
if (reset) return;
GLCHECK();
if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 32)
{
VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc;
XASSERT(ogRC->m_glActiveTextureARB);
ogRC->m_glActiveTextureARB(GL_TEXTURE0_ARB + cachedState.ArrayIndex);
if (*value)
{
glEnable(GL_TEXTURE_3D);
}
else
{
glDisable(GL_TEXTURE_3D);
}
}
GLCHECK();
}
static void TextureCubeMapEnable_CB(CKRasterizerContext *rc, CachedRenderState<CGbool> &cachedState, const CGbool *value, bool reset)
{
if (reset) return;
GLCHECK();
if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 32)
{
VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc;
XASSERT(ogRC->m_glActiveTextureARB);
ogRC->m_glActiveTextureARB(GL_TEXTURE0_ARB + cachedState.ArrayIndex);
if (*value)
{
glEnable(GL_TEXTURE_CUBE_MAP);
}
else
{
glDisable(GL_TEXTURE_CUBE_MAP);
}
}
GLCHECK();
}
static void TextureRectangleEnable_CB(CKRasterizerContext *rc, CachedRenderState<CGbool> &cachedState, const CGbool *value, bool reset)
{
if (reset) return;
GLCHECK();
if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 32)
{
VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc;
XASSERT(ogRC->m_glActiveTextureARB);
ogRC->m_glActiveTextureARB(GL_TEXTURE0_ARB + cachedState.ArrayIndex);
if (*value)
{
glEnable(GL_TEXTURE_RECTANGLE_ARB);
}
else
{
glDisable(GL_TEXTURE_RECTANGLE_ARB);
}
}
GLCHECK();
}
// Registration of states with their default (reset) value
static RenderStateDescBool StateDescArrayBool[] =
{
RenderStateDescBool("CullFaceEnable", CullFaceEnable_CB, true),
RenderStateDescBool("ClipPlaneEnable", ClipPlaneEnable_CB, false),
RenderStateDescBool("DepthMask", DepthMask_CB, true),
RenderStateDescBool("ZWriteEnable", ZWriteEnable_CB, true),
RenderStateDescBool("LightEnable", LightEnable_CB, true),
RenderStateDescBool("LightingEnable", LightingEnable_CB, true),
RenderStateDescBool("LocalViewer", LocalViewer_CB, false),
RenderStateDescBool("Clipping", Clipping_CB, true),
RenderStateDescBool("AlphaTestEnable", AlphaTestEnable_CB, false),
RenderStateDescBool("AlphaBlendEnable", BlendEnable_CB, false),
RenderStateDescBool("BlendEnable", BlendEnable_CB, false),
RenderStateDescBool("ZEnable", DepthTestEnable_CB, true),
RenderStateDescBool("DepthTestEnable", DepthTestEnable_CB, true),
RenderStateDescBool("DitherEnable", DitherEnable_CB, false),
RenderStateDescBool("FogEnable", FogEnable_CB, false),
RenderStateDescBool("LineSmoothEnable", LineSmoothEnable_CB, false),
RenderStateDescBool("NormalizeEnable", NormalizeEnable_CB, false),
RenderStateDescBool("PointSpriteEnable", PointSpriteEnable_CB, false),
RenderStateDescBool("StencilTestEnable", StencilTestEnable_CB, false),
RenderStateDescBool("ClipPlaneEnable", ClipPlaneEnable_CB, false),
RenderStateDescBool("MultisampleEnable", MultisampleEnable_CB, true),
RenderStateDescBool("Texture1DEnable", Texture1DEnable_CB, false),
RenderStateDescBool("Texture2DEnable", Texture2DEnable_CB, false),
RenderStateDescBool("Texture3DEnable", Texture3DEnable_CB, false),
RenderStateDescBool("TextureRectangleEnable", TextureRectangleEnable_CB, false),
RenderStateDescBool("TextureCubeMapEnable", TextureRectangleEnable_CB, false),
};
////////////////
// INT STATES //
////////////////
DECLARE_RASTERIZER_STATE(int, StencilMask, VXRENDERSTATE_STENCILWRITEMASK)
// DECLARE_GL_STATE_CALLBACK_INT(DestBlend, VXRENDERSTATE_DESTBLEND) // CONERSION NEEDED !! possibly not always a win since the interface will call glBlendFunc twice ...
// DECLARE_GL_STATE_CALLBACK_INT(SrcBlend, VXRENDERSTATE_SRCBLEND) // CONVERSION NEEDED !! possibly not always a win since the interface will call glBlendFunc twice ...
// DECLARE_GL_STATE_CALLBACK_INT(DepthFunc, VXRENDERSTATE_ZFUNC)
// DECLARE_GL_STATE_CALLBACK_INT(ShadeModel, VXRENDERSTATE_SHADEMODE) // CONVERSION NEEDED !!
static void FrontFace_CB(CKRasterizerContext *rc, CachedRenderState<int> &cachedState, const int *value, bool reset)
{
// TODO : use state cache
GLCHECK();
CKBOOL ccw = (*value == GL_CCW) ? 1 : 0;
VCKGL15Rasterizer::CKGLRasterizerContext* ctx = (VCKGL15Rasterizer::CKGLRasterizerContext*) rc;
ccw = ccw ^ ctx->m_InverseWinding ^ ctx->m_TextureTarget;
glFrontFace(ccw ? GL_CCW : GL_CW);
GLCHECK();
}
static void BlendFunc_CB(CKRasterizerContext *rc, CachedRenderState<int> &cachedState, const int *value, bool reset)
{
GLCHECK();
glBlendFunc((GLenum) value[0], (GLenum) value[1]);
GLCHECK();
}
static void BlendEquation_CB(CKRasterizerContext *rc, CachedRenderState<int> &cachedState, const int *value, bool reset)
{
GLCHECK();
VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc;
if (ogRC->m_glBlendEquation)
{
ogRC->m_glBlendEquation((GLenum) value[0]);
}
// NOT SUPPORTED FOR NOW
GLCHECK();
}
static void FogMode_CB(CKRasterizerContext *rc, CachedRenderState<int> &cachedState, const int *value, bool reset)
{
GLCHECK();
glFogi(GL_FOG_MODE, *value);
GLCHECK();
}
static void PolygonMode_CB(CKRasterizerContext *rc, CachedRenderState<int> &cachedState, const int *value, bool reset)
{
GLCHECK();
glPolygonMode((GLenum) value[0], (GLenum) value[1]);
GLCHECK();
}
static void ShadeModel_CB(CKRasterizerContext *rc, CachedRenderState<int> &cachedState, const int *value, bool reset)
{
GLCHECK();
glShadeModel((GLenum) value[0]);
GLCHECK();
}
static void StencilFunc_CB(CKRasterizerContext *rc, CachedRenderState<int> &cachedState, const int *value, bool reset)
{
GLCHECK();
glStencilFunc((GLenum) value[0], value[1], value[2]);
GLCHECK();
}
static void StencilOp_CB(CKRasterizerContext *rc, CachedRenderState<int> &cachedState, const int *value, bool reset)
{
GLCHECK();
glStencilOp((GLenum) value[0], (GLenum) value[1], (GLenum) value[2]);
GLCHECK();
}
// Registration of states
static RenderStateDescInt StateDescArrayInt[] =
{
RenderStateDescInt("StencilMask", StencilMask_CB, 0xffffffff),
RenderStateDescInt("FrontFace", FrontFace_CB, GL_CW),
RenderStateDescInt("BlendFunc", BlendFunc_CB, GL_ONE, GL_ZERO),
RenderStateDescInt("BlendEquation", BlendEquation_CB, GL_FUNC_ADD),
RenderStateDescInt("FogMode", FogMode_CB, GL_LINEAR),
RenderStateDescInt("PolygonMode", PolygonMode_CB, GL_FRONT_AND_BACK, GL_FILL),
RenderStateDescInt("ShadeModel", ShadeModel_CB, GL_SMOOTH),
RenderStateDescInt("StencilFunc", StencilFunc_CB, GL_ALWAYS, 0, 0xFFFFFFFF),
RenderStateDescInt("StencilOp", StencilOp_CB, GL_KEEP, GL_KEEP, GL_KEEP)
};
//////////////////
// FLOAT STATES //
//////////////////
DECLARE_RASTERIZER_STATE(float, FogDensity, VXRENDERSTATE_FOGDENSITY)
DECLARE_RASTERIZER_STATE(float, FogStart, VXRENDERSTATE_FOGSTART)
DECLARE_RASTERIZER_STATE(float, FogEnd, VXRENDERSTATE_FOGEND)
DECLARE_RASTERIZER_STATE(float, PointSize, VXRENDERSTATE_POINTSIZE)
DECLARE_RASTERIZER_STATE(float, PointSizeMin, VXRENDERSTATE_POINTSIZE_MIN)
DECLARE_RASTERIZER_STATE(float, PointSizeMax, VXRENDERSTATE_POINTSIZE_MAX)
/*static void AlphaRef_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
rc->SetRenderState(VXRENDERSTATE_ALPHAREF, (CKDWORD) (*value * 255.f));
}*/
// Light callbacks
static void LightAmbient_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
GLCHECK();
if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 8)
{
((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->GLLightFV4(cachedState.ArrayIndex, GL_AMBIENT, value);
}
GLCHECK();
}
static void LightDiffuse_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
GLCHECK();
if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 8)
{
((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->GLLightFV4(cachedState.ArrayIndex, GL_DIFFUSE, value);
}
GLCHECK();
}
static void LightSpecular_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
GLCHECK();
if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 8)
{
((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->GLLightFV4(cachedState.ArrayIndex, GL_SPECULAR, value);
}
GLCHECK();
}
static void LightPosition_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
GLCHECK();
if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 8)
{
((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->GLLightFV4(cachedState.ArrayIndex, GL_POSITION, value);
}
GLCHECK();
}
static void LightSpotDirection_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
GLCHECK();
if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 8)
{
((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->GLLightFV3(cachedState.ArrayIndex, GL_SPOT_DIRECTION, value);
}
GLCHECK();
}
static void LightSpotExponent_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
GLCHECK();
if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 8)
{
((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->GLLightF(cachedState.ArrayIndex, GL_SPOT_EXPONENT, *value);
}
GLCHECK();
}
static void LightSpotCutoff_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
GLCHECK();
if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 8)
{
((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->GLLightF(cachedState.ArrayIndex, GL_SPOT_CUTOFF, *value);
}
GLCHECK();
}
static void LightConstantAttenuation_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
GLCHECK();
if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 8)
{
((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->GLLightF(cachedState.ArrayIndex, GL_CONSTANT_ATTENUATION, *value);
}
GLCHECK();
}
static void LightLinearAttenuation_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
GLCHECK();
if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 8)
{
((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->GLLightF(cachedState.ArrayIndex, GL_LINEAR_ATTENUATION, *value);
}
GLCHECK();
}
static void LightQuadraticAttenuation_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
GLCHECK();
if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 8)
{
((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->GLLightF(cachedState.ArrayIndex, GL_QUADRATIC_ATTENUATION, *value);
}
GLCHECK();
}
// Material callbacks
static void MaterialAmbient_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
GLCHECK();
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, value);
GLCHECK();
}
static void MaterialDiffuse_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
GLCHECK();
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, value);
GLCHECK();
}
static void MaterialEmission_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
GLCHECK();
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, value);
GLCHECK();
}
static void MaterialShininess_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
GLCHECK();
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, value);
GLCHECK();
}
static void MaterialSpecular_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
GLCHECK();
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, value);
GLCHECK();
}
//
static void FogColor_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
GLCHECK();
glFogfv(GL_FOG_COLOR, value);
GLCHECK();
}
static void LightModelAmbient_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
GLCHECK();
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, value);
GLCHECK();
}
static void PointDistanceAttenuation_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
GLCHECK();
VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc;
if (ogRC->m_glPointParameterfvARB)
{
ogRC->m_glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION, value);
}
GLCHECK();
}
static void PolygonOffset_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
GLCHECK();
glPolygonOffset(value[0], value[1]);
GLCHECK();
}
static void AlphaFunc_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
GLCHECK();
glAlphaFunc((GLenum) value[0], value[1]);
GLCHECK();
}
static void AlphaRef_CB(CKRasterizerContext *rc, CachedRenderState<float> &cachedState, const float *value, bool reset)
{
GLCHECK();
GLint func;
glGetIntegerv(GL_ALPHA_TEST_FUNC, &func);
glAlphaFunc((GLenum) func, (GLclampf) value[1]);
GLCHECK();
}
// Registration of states
static RenderStateDescFloat StateDescArrayFloat[] =
{
//RenderStateDescFloat("AlphaRef", AlphaRef_CB, 0.f),
RenderStateDescFloat("FogDensity", FogDensity_CB, 1.f),
RenderStateDescFloat("FogStart", FogStart_CB, 0.f),
RenderStateDescFloat("FogEnd", FogEnd_CB, 1.f),
RenderStateDescFloat("PointSize", PointSize_CB, 1.f),
RenderStateDescFloat("PointSizeMin", PointSizeMin_CB, 1.f),
RenderStateDescFloat("PointSizeMax", PointSizeMax_CB, 64.f),
//
RenderStateDescFloat("LightAmbient", LightAmbient_CB, 0.f, 0.f, 0.f, 0.f),
RenderStateDescFloat("LightDiffuse", LightDiffuse_CB, 0.f, 0.f, 0.f, 0.f),
RenderStateDescFloat("LightSpecular", LightSpecular_CB, 0.f, 0.f, 0.f, 0.f),
RenderStateDescFloat("LightPosition", LightPosition_CB, 0.f, 0.f, 0.f, 0.f),
RenderStateDescFloat("LightConstantAttenuation", LightConstantAttenuation_CB, 0.f),
RenderStateDescFloat("LightLinearAttenuation", LightLinearAttenuation_CB, 0.f),
RenderStateDescFloat("LightQuadraticAttenuation", LightQuadraticAttenuation_CB, 0.f),
RenderStateDescFloat("LightSpotDirection", LightSpotDirection_CB, 0.f, 0.f, 1.f, 0.f),
RenderStateDescFloat("LightSpotExponent", LightSpotExponent_CB, 0.f),
RenderStateDescFloat("LightSpotCutoff", LightSpotCutoff_CB, 180.f),
//
RenderStateDescFloat("MaterialAmbient", MaterialAmbient_CB, 0.f, 0.f, 0.f, 0.f),
RenderStateDescFloat("MaterialDiffuse", MaterialDiffuse_CB, 0.f, 0.f, 0.f, 0.f),
RenderStateDescFloat("MaterialEmissive", MaterialEmission_CB, 0.f, 0.f, 0.f, 0.f),
RenderStateDescFloat("MaterialEmission", MaterialEmission_CB, 0.f, 0.f, 0.f, 0.f),
RenderStateDescFloat("MaterialShininess", MaterialShininess_CB, 0.f),
RenderStateDescFloat("MaterialSpecular", MaterialSpecular_CB, 0.f, 0.f, 0.f, 0.f),
//
RenderStateDescFloat("FogColor", FogColor_CB, 0.f, 0.f, 0.f, 0.f),
//
RenderStateDescFloat("LightModelAmbient", LightModelAmbient_CB, 0.f, 0.f, 0.f, 0.f),
//
RenderStateDescFloat("PointDistanceAttenuation", PointDistanceAttenuation_CB, 1.f, 0.f, 0.f),
//
RenderStateDescFloat("PolygonOffset", PolygonOffset_CB, 0.f, 0.f),
//
RenderStateDescFloat("AlphaFunc", AlphaFunc_CB, GL_ALWAYS, 0.f),
RenderStateDescFloat("AlphaRef", AlphaRef_CB, 0.f),
};
////////////////////
// PROGRAM STATES //
////////////////////
//----------------------------------------------------------------------------------------
static void CGProgram_CB(CKRasterizerContext *rc, CachedRenderState<CGprogram> &cachedState, const CGprogram *value, bool reset)
{
GLCHECK();
CGprogram prog = *value;
if (!prog) return;
if (!reset)
{
if (cachedState.m_ShaderConstantStore)
{
// Bind and flush constants on our own instead of using CG
cachedState.ShaderManager->EnableProgram(rc, cachedState.m_ShaderConstantStore);
}
else
{
cachedState.ShaderManager->EnableProgram(prog);
}
}
// else no op ... programs will be disabled during a call to EndShaders or when switching shaders
GLCHECK();
}
//----------------------------------------------------------------------------------------
// Registration of states
static RenderStateDescProgram StateDescArrayProgram[] =
{
RenderStateDescProgram("VertexProgram", CGProgram_CB, NULL),
RenderStateDescProgram("VertexShader", CGProgram_CB, NULL),
RenderStateDescProgram("FragmentProgram", CGProgram_CB, NULL),
RenderStateDescProgram("PixelShader", CGProgram_CB, NULL)
};
//-----------------------------------------------------------------------------
// utility function : build state callback from a state assignement
template <class T>
bool BuildStateAssignmentCache(ShaderManagerCG *shaderManager,
CGstateassignment sa,
T &cachedState,
RenderStateDesc<typename T::Type> stateDescArray[],
int stateDescArraySize
)
{
XASSERT(shaderManager);
CGstate state = cgGetStateAssignmentState(sa);
const char *stateName = cgGetStateName(state);
//
//OutputDebugString(stateName);
/*if (strcmp(stateName, "ForceCGSetPassState") == 0)
{
// special pass to force an eval by cg
return false;
}*/
//
for (int cbIndex = 0; cbIndex < stateDescArraySize; ++cbIndex)
{
if (strcmp(stateDescArray[cbIndex].m_StateName, stateName) == 0)
{
cachedState.ShaderManager = shaderManager;
cachedState.Callback = stateDescArray[cbIndex].m_Callback;
XASSERT(sizeofarray(cachedState.DefaultValue) == sizeofarray(stateDescArray[cbIndex].m_DefaultValue));
for (int i = 0; i < sizeofarray(cachedState.DefaultValue); ++i)
{
cachedState.StaticValue[i] = cachedState.DefaultValue[i] = stateDescArray[cbIndex].m_DefaultValue[i];
}
cachedState.StateAssignment = sa;
cachedState.ArrayIndex = cgGetStateAssignmentIndex(sa);
//
cachedState.NeedReeval = true;
return true;
}
}
return false;
}
/*
static volatile bool DumpStateAssign = false;
//-----------------------------------------------------------------------------
template <class T> void ReplayStatesByType(CKRasterizerContext *rc,
XArray<T> &states,
const typename T::Type *(*cgGetSAValues)(CGstateassignment, int *),
bool doReset)
{
GLCHECK();
for (XArray<T>::Iterator it = states.Begin(); it != states.End(); ++it)
{
T &cachedState = *it;
if (doReset)
{
GLCHECK();
cachedState.Callback(rc, cachedState, cachedState.DefaultValue, true);
GLCHECK();
}
else
{
if (!cachedState.NeedReeval)
{
GLCHECK();
// value is static
cachedState.Callback(rc, cachedState, cachedState.StaticValue, false);
GLCHECK();
}
else
{
GLCHECK();
// must ask cg to reevaluate value
int valueCount;
const T::Type *values = cgGetSAValues(cachedState.StateAssignment, &valueCount);
if (numVals <= sizeofarray(cachedState.StaticValue))
{
for (int i = 0; i < numVals; ++i)
{
cachedState.StaticValue[i] = values[i];
}
cachedState.UseStaticValue = true;
}
cachedState.Callback(rc, cachedState, values, false);
GLCHECK();
}
}
}
GLCHECK();
}
*/
static void DumpStates(CKRasterizerContext *rc)
{
/*
static volatile bool dumpStates = false;
if (dumpStates)
{
struct { char *Name; int Value; } stateNames[] =
{
{"VXRENDERSTATE_ANTIALIAS ", 2},
{"VXRENDERSTATE_TEXTUREPERSPECTIVE ", 4}, //Enable Perspective correction (TRUE/FALSE)
{"VXRENDERSTATE_ZENABLE ", 7}, //Enable z test (TRUE/FALSE)
{"VXRENDERSTATE_FILLMODE ", 8}, //Fill mode (VXFILL_MODE)
{"VXRENDERSTATE_SHADEMODE ", 9}, //Shade mode (VXSHADE_MODE)
{"VXRENDERSTATE_LINEPATTERN ", 10}, //Line pattern (bit pattern in a DWORD)
{"VXRENDERSTATE_ZWRITEENABLE ", 14}, //Enable z writes (TRUE/FALSE)
{"VXRENDERSTATE_ALPHATESTENABLE ", 15}, //Enable alpha tests (TRUE/FALSE)
{"VXRENDERSTATE_SRCBLEND ", 19}, //Blend factor for source (VXBLEND_MODE)
{"VXRENDERSTATE_DESTBLEND ", 20}, //Blend factor for destination (VXBLEND_MODE)
{"VXRENDERSTATE_CULLMODE ", 22}, //Back-face culling mode (VXCULL)
{"VXRENDERSTATE_ZFUNC ", 23}, //Z-comparison function (VXCMPFUNC)
{"VXRENDERSTATE_ALPHAREF ", 24}, //Reference alpha value (DWORD (0..255) )
{"VXRENDERSTATE_ALPHAFUNC ", 25}, //Alpha-comparison function (VXCMPFUNC)
{"VXRENDERSTATE_DITHERENABLE ", 26}, //Enable dithering (TRUE/FALSE)
{"VXRENDERSTATE_ALPHABLENDENABLE ", 27}, //Enable alpha blending (TRUE/FALSE)
{"VXRENDERSTATE_FOGENABLE ", 28}, //Enable fog (TRUE/FALSE)
{"VXRENDERSTATE_SPECULARENABLE ", 29}, //Enable specular highlights (TRUE/FALSE)
{"VXRENDERSTATE_FOGCOLOR ", 34}, //Fog color (DWORD ARGB)
{"VXRENDERSTATE_FOGPIXELMODE ", 35}, //Fog mode for per pixel fog (VXFOG_MODE)
{"VXRENDERSTATE_FOGSTART ", 36}, //Fog start (for both vertex and pixel fog)
{"VXRENDERSTATE_FOGEND ", 37}, //Fog end (for both vertex and pixel fog)
{"VXRENDERSTATE_FOGDENSITY ", 38}, //Fog density (for both vertex and pixel fog)
{"VXRENDERSTATE_EDGEANTIALIAS ", 40}, //Antialias edges (TRUE/FALSE)
{"VXRENDERSTATE_ZBIAS ", 47}, //Z-bias (DWORD 0..16)
{"VXRENDERSTATE_RANGEFOGENABLE ", 48}, //Enables range-based fog
{"VXRENDERSTATE_STENCILENABLE ", 52}, //Enable or disable stenciling (TRUE/FALSE)
{"VXRENDERSTATE_STENCILFAIL ", 53}, //Stencil operation (VXSTENCILOP)
{"VXRENDERSTATE_STENCILZFAIL ", 54}, //Stencil operation (VXSTENCILOP)
{"VXRENDERSTATE_STENCILPASS ", 55}, //Stencil operation (VXSTENCILOP)
{"VXRENDERSTATE_STENCILFUNC ", 56}, //Stencil comparison function (VXCMPFUNC)
{"VXRENDERSTATE_STENCILREF ", 57}, //Reference value for stencil test (DWORD (0..255))
{"VXRENDERSTATE_STENCILMASK ", 58}, //Mask value used in stencil test (DWORD (0..255))
{"VXRENDERSTATE_STENCILWRITEMASK ", 59}, //Stencil buffer write mask
{"VXRENDERSTATE_TEXTUREFACTOR ", 60}, //Texture factor
{"VXRENDERSTATE_WRAP0 ", 128}, // Wrap flags for 1st texture coord set (VXWRAP_MODE)
{"VXRENDERSTATE_WRAP1 ", 129}, // Wrap flags for 2nd texture coord set (VXWRAP_MODE)
{"VXRENDERSTATE_WRAP2 ", 130}, // Wrap flags for 3rd texture coord set (VXWRAP_MODE)
{"VXRENDERSTATE_WRAP3 ", 131}, // Wrap flags for 4th texture coord set (VXWRAP_MODE)
{"VXRENDERSTATE_WRAP4 ", 132}, // Wrap flags for 5th texture coord set (VXWRAP_MODE)
{"VXRENDERSTATE_WRAP5 ", 133}, // Wrap flags for 6th texture coord set (VXWRAP_MODE)
{"VXRENDERSTATE_WRAP6 ", 134}, // Wrap flags for 7th texture coord set (VXWRAP_MODE)
{"VXRENDERSTATE_WRAP7 ", 135}, // Wrap flags for last texture coord set
{"VXRENDERSTATE_CLIPPING ", 136}, //Enable or disable primitive clipping (TRUE/FALSE)
{"VXRENDERSTATE_LIGHTING ", 137}, //Enable or disable lighting (TRUE/FALSE)
{"VXRENDERSTATE_AMBIENT ", 139}, //Ambient color for scene (DWORD ARGB)
{"VXRENDERSTATE_FOGVERTEXMODE ", 140}, //Fog mode for per vertex fog (VXFOG_MODE)
{"VXRENDERSTATE_COLORVERTEX ", 141}, //Enable or disable per-vertex color
{"VXRENDERSTATE_LOCALVIEWER ", 142}, //Camera relative specular highlights (TRUE/FALSE)
{"VXRENDERSTATE_NORMALIZENORMALS ", 143}, //Enable automatic normalization of vertex normals
{"VXRENDERSTATE_DIFFUSEFROMVERTEX ", 145}, //If VXRENDERSTATE_COLORVERTEX is TRUE this flags indicate whether diffuse color is taken from the vertex color (TRUE) or from the currently set material (FALSE)
{"VXRENDERSTATE_SPECULARFROMVERTEX ", 146}, //If VXRENDERSTATE_COLORVERTEX is TRUE this flags indicate whether specular color is taken from the vertex color (2) or from the currently set material (0)
{"VXRENDERSTATE_AMBIENTFROMVERTEX ", 147}, //If VXRENDERSTATE_COLORVERTEX is TRUE this flags indicate whether ambient color is taken from the vertex color (TRUE) or from the currently set material (FALSE)
{"VXRENDERSTATE_EMISSIVEFROMVERTEX ", 148}, //If VXRENDERSTATE_COLORVERTEX is TRUE this flags indicate whether emissive color is taken from the vertex color (TRUE) or from the currently set material (FALSE)
{"VXRENDERSTATE_VERTEXBLEND ", 151}, //Enable vertex blending and set the number of matrices to use (VXVERTEXBLENDFLAGS)
{"VXRENDERSTATE_SOFTWAREVPROCESSING", 153}, //When using a T&L driver in mixed mode}, for the usage of software processing
{"VXRENDERSTATE_POINTSIZE ", 154}, //Size of point when drawing point sprites. This value is in screen space units if VXRENDERSTATE_POINTSCALEENABLE is FALSE; otherwise this value is in world space units.
{"VXRENDERSTATE_POINTSIZE_MIN ", 155}, //Specifies the minimum size of point primitives. If below 1 the points drawn will disappear when smaller than a pixel
{"VXRENDERSTATE_POINTSIZE_MAX ", 166}, //Specifies the maximum size of point primitives. If below 1 the points drawn will disappear when smaller than a pixel
{"VXRENDERSTATE_POINTSPRITEENABLE ", 156}, //
{"VXRENDERSTATE_POINTSCALEENABLE ", 157}, //If true the size of point will be attenuated according to distance:
//Size , pointSize * sqrt(1/ (a + b*dist + c * dist*dist)) where dist
//is the distance from viewpoint to point.
{"VXRENDERSTATE_POINTSCALE_A ", 158}, // constant attenuation factor for point size computation (see VXRENDERSTATE_POINTSCALEENABLE)
{"VXRENDERSTATE_POINTSCALE_B ", 159}, // linear attenuation factor for point size computation (see VXRENDERSTATE_POINTSCALEENABLE)
{"VXRENDERSTATE_POINTSCALE_C ", 160}, // quadratic attenuation factor for point size computation (see VXRENDERSTATE_POINTSCALEENABLE)
{"VXRENDERSTATE_CLIPPLANEENABLE ", 152}, //Enable one or more user-defined clipping planes ( DWORD mask of planes)
{"VXRENDERSTATE_INDEXVBLENDENABLE ", 167}, //Enable indexed vertex blending (to use with VXRENDERSTATE_VERTEXBLEND)
{"VXRENDERSTATE_BLENDOP ", 171}, //Set blending operation VXBLENDOP
{"VXRENDERSTATE_LOCKMATERIALSTATES ", 252}, // if Enabled}, subsequent calls to CKRasterizerContext::SetMaterial are ignored
{"VXRENDERSTATE_TEXTURETARGET ", 253}, // Hint: context is used to render on a texture
{"VXRENDERSTATE_INVERSEWINDING ", 254}, // Invert Cull CW and cull CCW (TRUE/FALSE)
};
OutputDebugString("==================================================================\n");
for (int k = 0; k < sizeofarray(stateNames); ++k)
{
rc->InvalidateStateCache((VXRENDERSTATETYPE) stateNames[k].Value);
CKDWORD value;
if (rc->GetRenderState((VXRENDERSTATETYPE) stateNames[k].Value, &value))
{
char buf[512];
sprintf(buf, "%s = 0x%x\n", stateNames[k].Name, value);
OutputDebugString(buf);
}
}
OutputDebugString("==================================================================\n");
}
*/
}
//-----------------------------------------------------------------------------
static volatile bool UseStateCache = true;
//static volatile bool DumpAssgt = false;
//-----------------------------------------------------------------------------
void RCKShaderCG::ReplayStates(int rcIndex, CKRasterizerContext *rc, PassStateCache &passStateCache, bool doReset)
{
GLCHECK();
if (passStateCache.m_CallCGSetPassState || (!UseStateCache))
{
if (doReset)
{
GLCHECK();
cgResetPassState(m_CurrentActivePass[rcIndex][m_CurrentPassIndex]);
GLCHECK();
// Mark render states cache as potentially invalid (ideally, should set cg callback to use
// the state cache, but if we take this code path we're doomed to be slow anyway ...)
for (int k = 0; k < VXRENDERSTATE_MAXSTATE; ++k)
{
rc->InvalidateStateCache((VXRENDERSTATETYPE) k);
}
}
else
{
GLCHECK();
// clean the program cache, because we don't catch which programs are setup by the call
for (int domain = CG_FIRST_DOMAIN; domain < CG_FIRST_DOMAIN + NUMBER_OF_CG_DOMAIN; ++domain)
{
m_ShaderManager->DeactivateProgram((CGdomain) domain);
}
GLCHECK();
//cgGLSetManageTextureParameters(cgGetEffectContext(cgGetTechniqueEffect(cgGetPassTechnique((m_CurrentActivePass[rcIndex][m_CurrentPassIndex])))), CG_FALSE);
cgSetPassState(m_CurrentActivePass[rcIndex][m_CurrentPassIndex]);
// NB Nico V :
// Silently discard any GL error from CG here ...
// In some cases (setup of a 3D texture after a 2D texture), the cg runtime fails here ...
// (though we deactivated the sampler handling by cg through cgGLSetManageTextureParameters , it seem that is calls the GL texture function
// anyway ...)
glGetError();
/*
GLenum err = glGetError();
if (err != GL_NO_ERROR)
{
char buf[512];
sprintf(buf, "err = %x", err);
OutputDebugString(buf);
XASSERT(0);
}
*/
// Light setup may have been modified by the call, signal it
((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->InvalidateLightSetupCache();
GLCHECK();
}
}
else
{
GLCHECK();
for (int domain = 0; domain < NUMBER_OF_CG_DOMAIN; ++domain)
{
if (!passStateCache.m_ProgramEnabled[domain])
{
m_ShaderManager->DeactivateProgram((CGdomain) (domain + CG_FIRST_DOMAIN));
}
}
for (XClassArray<CachedRenderStateBase *>::Iterator it = passStateCache.m_RenderStateCacheArray.Begin(); it != passStateCache.m_RenderStateCacheArray.End(); ++it)
{
/*
if (DumpAssgt)
{
CGstate state = cgGetStateAssignmentState((*it)->StateAssignment);
OutputDebugString(cgGetStateName(state));
OutputDebugString(":");
CGtype type = cgGetStateType(state);
CGtype baseType = cgGetTypeBase(type);
switch(baseType)
{
case CG_BOOL:
{
int valueCount;
const CGbool *values = cgGetBoolStateAssignmentValues((*it)->StateAssignment, &valueCount);
for (int v = 0; v < valueCount; ++v)
{
OutputDebugString(values[v] ? "true" : "false");
}
}
break;
case CG_FLOAT:
{
int valueCount;
const float *values = cgGetFloatStateAssignmentValues((*it)->StateAssignment, &valueCount);
for (int v = 0; v < valueCount; ++v)
{
char buf[128];
sprintf(buf, "%f", values[v]);
OutputDebugString(buf);
}
}
break;
case CG_INT:
{
int valueCount;
const int *values = cgGetIntStateAssignmentValues((*it)->StateAssignment, &valueCount);
for (int v = 0; v < valueCount; ++v)
{
char buf[128];
sprintf(buf, "%d", values[v]);
OutputDebugString(buf);
}
}
break;
default:
break;
}
OutputDebugString(" ");
OutputDebugString("\n");
}
*/
(*it)->Apply(rc, doReset);
}
m_ShaderManager->ClearModifiedRenderStates(); // We applied all render state already so, clear the state that were marked as 'dirty'
// TODO : better design for this ...
//DumpStates(rc);
}
GLCHECK();
}
//-----------------------------------------------------------------------------
void RCKShaderCG::PassStateCache::RemoveConstantStores()
{
for (int domain = 0; domain < NUMBER_OF_CG_DOMAIN; ++domain)
{
delete m_ConstantStore[domain];
m_ConstantStore[domain] = NULL;
m_ProgramEnabled[domain] = false;
}
for (XArray<CachedRenderStateBase *>::Iterator it = m_RenderStateCacheArray.Begin(); it != m_RenderStateCacheArray.End(); ++it)
{
(*it)->m_ShaderConstantStore = NULL;
}
}
//-----------------------------------------------------------------------------
void RCKShaderCG::TechniqueStateCache::RemoveConstantStores()
{
for (int passIndex = 0; passIndex < m_Passes.Size(); ++passIndex)
{
m_Passes[passIndex]->RemoveConstantStores();
}
}
//-----------------------------------------------------------------------------
void RCKShaderCG::MarkSamplerStateConnectedParameters(CGeffect effect, ShaderDescriptorCG::ShaderCG *shaderCG)
{
int techniqueCount = ShaderManagerCG::GetCGEffectTechniqueCount(effect);
CGparameter currParam = cgGetFirstEffectParameter(effect);
while (currParam)
{
CGstateassignment sa = cgGetFirstSamplerStateAssignment(currParam);
while (sa)
{
int numConnectedParams = cgGetNumDependentStateAssignmentParameters(sa);
for (int paramIndex = 0; paramIndex < numConnectedParams; ++paramIndex)
{
CGparameter param = cgGetDependentStateAssignmentParameter(sa, paramIndex);
ShaderDescriptorCG::ShaderCG::CGParamToMeaningMap::Iterator it = shaderCG->m_CGParamToMeaning.Find(param);
if (it != shaderCG->m_CGParamToMeaning.End())
{
XASSERT((*it)->m_PerTechniquePerPassConstantSetup.Size() == techniqueCount);
// TODO : we could disambiguate sampler per technique here, but never seen it used
// anyway, so don't seem worth the trouble ...
for (int techIndex = 0; techIndex < techniqueCount; ++techIndex)
{
ShaderDescriptorCG::ParamMeaning::TechniqueConstantSetupInfo &tech = (*it)->m_PerTechniquePerPassConstantSetup[techIndex];
tech.m_ForceUseCGSetParameter = true; // we *must* call cgSetParameterxxx so that
// the dependent sampler states can be recomputed
tech.m_HasDependentSamplerStates = true;
}
}
}
sa = cgGetNextStateAssignment(sa);
}
currParam = cgGetNextParameter(currParam);
}
}
//-----------------------------------------------------------------------------f
void RCKShaderCG::RecordEffectStates(CGeffect effect, ShaderDescriptorCG::ShaderCG *shaderCG, EffectStateCache &effectStateCache)
{
XASSERT(!effectStateCache.m_StateCacheRecorded);
//
MarkSamplerStateConnectedParameters(effect, shaderCG);
// update state cache
//
int techIndex = 0;
for (CGtechnique tech = cgGetFirstTechnique(effect); tech; tech = cgGetNextTechnique(tech), ++techIndex)
{
int passIndex = 0;
bool unsupportedProfileFound = false;
TechniqueStateCache *tsc = new TechniqueStateCache;
for (CGpass pass = cgGetFirstPass(tech); pass; pass = cgGetNextPass(pass), ++passIndex)
{
const char *compiledPrograms[NUMBER_OF_CG_DOMAIN] = { NULL, NULL, NULL };
bool cstSetupSupportedPerDomain[NUMBER_OF_CG_DOMAIN] = { true, true, true }; // for each domain, true, if we support setup of
// constants for that profile
PassStateCache *psc = new PassStateCache;
for (int domainIndex = 0; domainIndex < NUMBER_OF_CG_DOMAIN; ++domainIndex)
{
psc->m_ProgramEnabled[domainIndex] = false;
}
psc->m_CallCGSetPassState = false;
psc->m_TextureStageBits = 0;
psc->m_LightPositionRenderState = NULL;
psc->m_LightSpotDirectionRenderState = NULL;
bool fragmentProgramFound = false;
//
XArray<CachedRenderStateBase *> cachedRenderStates;
//
#ifdef STATIC_FOR_MAYA // Maya export dll links with a cg that don't have
// cgGetTypeSizes -> link would fail
psc->m_CallCGSetPassState = true;
CGstateassignment sa; // dummy
XASSERT(0);
if (0)
#else
for (CGstateassignment sa = cgGetFirstStateAssignment(pass); sa; sa = cgGetNextStateAssignment(sa))
#endif
{
bool found = false;
CGstate state = cgGetStateAssignmentState(sa);
//
CGtype baseType;//cgGetTypeBase(type);
int nrows = 0, ncols = 0;
#ifndef STATIC_FOR_MAYA
CGtype type;//cgGetStateType(state);
type = cgGetStateType(state);
baseType = cgGetTypeBase(type);
cgGetTypeSizes(type, &nrows, &ncols);
#else
XASSERT(0); // shouldn't go here ...
#endif
if (nrows <= 1) // 0 for programs ...
{
switch(baseType)
{
//----------------------------------------------------------------------
case CG_BOOL:
{
CachedRenderStateBool *sc = new CachedRenderStateBool;
found = BuildStateAssignmentCache(m_ShaderManager,
sa,
*sc,
StateDescArrayBool,
sizeofarray(StateDescArrayBool)
);
if (found)
{
psc->m_RenderStateCacheArray.PushBack(sc);
cachedRenderStates.PushBack(sc);
// If this is texture enabled, mark the corresponding texture stage as 'used'
// we don't record the texture assignemnent state, because they
// are handled explicitly elsewhere (by ParamMeaning_Sampler)
if (sc->Callback == Texture1DEnable_CB ||
sc->Callback == Texture2DEnable_CB ||
sc->Callback == Texture3DEnable_CB ||
sc->Callback == TextureCubeMapEnable_CB ||
sc->Callback == TextureRectangleEnable_CB
)
{
psc->m_TextureStageBits |= (1 << cgGetStateAssignmentIndex(sa));
}
}
else
{
delete sc;
}
}
break;
//----------------------------------------------------------------------
case CG_INT:
{
CachedRenderStateInt *sc = new CachedRenderStateInt;
found = BuildStateAssignmentCache(m_ShaderManager,
sa,
*sc,
StateDescArrayInt,
sizeofarray(StateDescArrayInt)
);
if (found)
{
psc->m_RenderStateCacheArray.PushBack(sc);
cachedRenderStates.PushBack(sc);
}
else
{
delete sc;
}
}
break;
//----------------------------------------------------------------------
case CG_FLOAT:
{
CachedRenderStateFloat *sc = new CachedRenderStateFloat;
found = BuildStateAssignmentCache(m_ShaderManager,
sa,
*sc,
StateDescArrayFloat,
sizeofarray(StateDescArrayFloat)
);
if (found)
{
psc->m_RenderStateCacheArray.PushBack(sc);
cachedRenderStates.PushBack(sc);
if (sc->Callback == LightPosition_CB)
{
psc->m_LightPositionRenderState = sc;
}
if (sc->Callback == LightSpotDirection_CB)
{
psc->m_LightSpotDirectionRenderState = sc;
}
}
else
{
delete sc;
}
}
break;
//----------------------------------------------------------------------
case CG_PROGRAM_TYPE:
{
CGprogram prog = cgGetProgramStateAssignmentValue(sa);
if (prog)
{
GLCHECK();
if (!cgIsProgramCompiled(prog))
{
cgCompileProgram(prog);
}
GLCHECK();
if (!cgGLIsProgramLoaded(prog))
{
cgGLLoadProgram(prog);
GLCHECK();
cgSetPassProgramParameters(prog);
GLCHECK();
}
GLCHECK();
const char *compiledProgramString = NULL;
#ifndef STATIC_FOR_MAYA
GLCHECK();
compiledProgramString = cgGetProgramString(prog, CG_COMPILED_PROGRAM);
GLCHECK();
/*
OutputDebugString("=============================================\n");
OutputDebugString(compiledProgramString);
OutputDebugString("=============================================\n");
*/
GLCHECK();
CGprofile profile = cgGetProgramProfile(prog);
CGdomain domain = cgGetProfileDomain(profile);
switch (domain)
{
case CG_VERTEX_DOMAIN: compiledPrograms[0] = compiledProgramString; break;
case CG_FRAGMENT_DOMAIN: compiledPrograms[1] = compiledProgramString; break;
case CG_GEOMETRY_DOMAIN: compiledPrograms[2] = compiledProgramString; break;
default:
domain = CG_UNKNOWN_DOMAIN;
}
GLCHECK();
if (domain == CG_UNKNOWN_DOMAIN)
{
cachedRenderStates.PushBack(NULL);
found = true; // null assignment is valid, don't cancel the build of other states
break;
}
#endif
CachedRenderStateProgram *sc = new CachedRenderStateProgram;
found = BuildStateAssignmentCache(m_ShaderManager,
sa,
*sc,
StateDescArrayProgram,
sizeofarray(StateDescArrayProgram)
);
XASSERT(found);
psc->m_RenderStateCacheArray.PushBack(sc);
cachedRenderStates.PushBack(sc);
#ifndef STATIC_FOR_MAYA // Maya export dll links with a cg that don't have
// cgGetProfileDomain -> link would fail
XASSERT(domain < CG_FIRST_DOMAIN + NUMBER_OF_CG_DOMAIN);
psc->m_ProgramEnabled[domain - CG_FIRST_DOMAIN] = true;
// build constant store for that profile if supported
ShaderConstantStore *shCstStore = NULL;
if (prog && strlen(compiledProgramString)) //if compilation succesful
{
switch (profile)
{
case CG_PROFILE_ARBFP1:
shCstStore = new ShaderConstantStoreARBFP1;
break;
case CG_PROFILE_ARBVP1:
shCstStore = new ShaderConstantStoreARBVP1;
break;
//
case CG_PROFILE_FP20:
// GeForce3 NV_texture_shader & NV_register_combiners
// -> not worth handling yet ...
break;
case CG_PROFILE_FP30:
// not supported yet (constants are represented by name ...)
shCstStore = new ShaderConstantStoreFP30;
break;
case CG_PROFILE_FP40:
// not supported yet (constants are represented by name ...)
shCstStore = new ShaderConstantStoreFP40;
break;
//
case CG_PROFILE_VP20:
shCstStore = new ShaderConstantStoreVP20;
break;
case CG_PROFILE_VP30:
shCstStore = new ShaderConstantStoreVP30;
break;
case CG_PROFILE_VP40:
shCstStore = new ShaderConstantStoreVP40;
break;
//
}
}
if (shCstStore)
{
shCstStore->SetProgram(prog, compiledProgramString);
}
else
{
cstSetupSupportedPerDomain[domain - CG_FIRST_DOMAIN] = false;
unsupportedProfileFound = true;
}
psc->m_ConstantStore[domain - CG_FIRST_DOMAIN] = shCstStore;
sc->m_ShaderConstantStore = shCstStore;
//
if (cgGetProfileDomain(cgGetProgramProfile(prog)) == CG_FRAGMENT_DOMAIN)
{
fragmentProgramFound = true;
}
#endif
}
else
{
cachedRenderStates.PushBack(NULL);
found = true; // null assignment is valid, don't cancel the build of other states
}
}
break;
case CG_SAMPLER1D:
case CG_SAMPLER2D:
case CG_SAMPLER3D:
case CG_SAMPLERRECT:
case CG_SAMPLERCUBE:
{
found = true;
psc->m_TextureStageBits |= (1 << cgGetStateAssignmentIndex(sa));
cachedRenderStates.PushBack(NULL);
}
break;
default:
break;
}
}
if (!found)
{
/*
OutputDebugString("Unknown state : ");
OutputDebugString(cgGetStateName(state));
OutputDebugString("\n");
OutputDebugString(cgGetTypeString(cgGetStateType(state)));
OutputDebugString("\n");
*/
// Don't know this state ... we can't call CG default callback, so must
// do a full cgSetPassState as a callback
psc->m_CallCGSetPassState = true;
cachedRenderStates.PushBack(NULL);
}
}
if (!fragmentProgramFound)
{
/*
if (this != m_ShaderManager->m_DefaultShader)
{
// Fallback on cg runtime when no fragment program is found (don't no why, but incorrect
// material parameters on first frame else ... most of the time this won't be used, so a fallback is ok)
psc.m_CallCGSetPassState = true;
}
*/
}
if (psc->m_CallCGSetPassState)
{
psc->m_LightPositionRenderState = NULL;
psc->m_LightSpotDirectionRenderState = NULL;
// We don't know all render states ... must fallback to cgSetPassState for that pass
psc->ClearRenderStateCache();
psc->RemoveConstantStores();
for (int domain = 0; domain < NUMBER_OF_CG_DOMAIN; ++ domain)
{
cstSetupSupportedPerDomain[domain] = FALSE;
}
}
#ifndef STATIC_FOR_MAYA
{
// For each render states, see which parameters are needed to compute them
CGpass currPass = cgGetFirstPass(tech);
int cachedRenderStateIndex = 0;
CGstateassignment sa = cgGetFirstStateAssignment(pass);
while (sa)
{
if (cachedRenderStates[cachedRenderStateIndex])
{
int numDependentParameters = cgGetNumDependentStateAssignmentParameters(sa);
for (int paramIndex = 0; paramIndex < numDependentParameters; ++paramIndex)
{
CGparameter param = cgGetDependentStateAssignmentParameter(sa, paramIndex);
ShaderDescriptorCG::ShaderCG::CGParamToMeaningMap::Iterator it = shaderCG->m_CGParamToMeaning.Find(param);
if (it != shaderCG->m_CGParamToMeaning.End())
{
ShaderDescriptorCG::ParamMeaning::TechniqueConstantSetupInfo &tech = (*it)->m_PerTechniquePerPassConstantSetup[techIndex];
/*char buf[512];
sprintf(buf, "%s depends on %s\n", cgGetStateName(cgGetStateAssignmentState(sa)), cgGetParameterName(param));
OutputDebugString(buf);*/
if (!psc->m_CallCGSetPassState)
{
tech.m_DependentRenderStates.PushBack(cachedRenderStates[cachedRenderStateIndex]);
}
tech.m_ForceUseCGSetParameter = true; // we *must* call cgSetParameterxxx so that
// the dependent render state can be recomputed
}
}
}
sa = cgGetNextStateAssignment(sa);
++cachedRenderStateIndex;
}
XASSERT(cachedRenderStateIndex == cachedRenderStates.Size());
// now, setup the constants setup info for each meaning
shaderCG->InitConstantSetupInfo(techIndex, passIndex, compiledPrograms, psc->m_ConstantStore);
// Compute the number of constant needed by each program domain
for (int domain = 0; domain < NUMBER_OF_CG_DOMAIN; ++ domain)
{
if (compiledPrograms[domain] &&
cstSetupSupportedPerDomain[domain] &&
psc->m_ConstantStore[domain] &&
!psc->m_ConstantStore[domain]->UsesNamedConstant()
)
{
XASSERT(psc->m_ConstantStore[domain]);
if (!psc->m_ConstantStore[domain]->UsesNamedConstant())
{
int constantCount = shaderCG->ComputeMaxParamMeaningCstIndex(techIndex, passIndex, (CGdomain) (domain + CG_FIRST_DOMAIN)) + 1;
if (constantCount > 0)
{
psc->m_ConstantStore[domain]->EnsureSize(constantCount);
}
}
}
}
}
#endif
tsc->m_Passes.PushBack(psc);
// end of pass
}
effectStateCache.m_TechniquesStateCache.PushBack(tsc);
// for this technique
bool invalidateTechniqueConstantWrap = false;
if (unsupportedProfileFound)
{
// Note 1 : Invalidate the whole technique !!! Even if some profile are supported
// calling setCGParameter for a parameter may set constant in other pass or domain that we support
// (example : mixing fp20 with vp20). However, some supported profiles (e.g those we know how to set constants into)
// do not have local constants (e.g vp 20) -> require a call to cgGLBindProgram to bind *all* the constant for real! (so conflict with our constant
// store that do the whole setup at the end as well ... we can't mix the 2 -> we must invalidate the whole technique...)
// We could have a finer granularity than that, but discard the whole thing for simplicity...
invalidateTechniqueConstantWrap = true;
}
else
{
// If a parameter has both dependent render states (or sampler states), and set constants in some profile
// (very unlikely and do not seem useful, but can be done ...)
// then the call to cgSetParameter (we require it since is it needed to eval the new render state value from cg)
// may conflict with our constant wrapper (see Note 1 above to see an example where this situation happens)
// NB 1 : when we support wrapping for a profile, then *all* constants are wrapped, thus, call to cgSetParameter
// only happen when an effect parameter has a dependent render state and set no constants ...
for (XArray<ShaderDescriptorCG::ParamMeaning*>::Iterator it = shaderCG->GetParamMeanings().Begin(); it != shaderCG->GetParamMeanings().End() && !invalidateTechniqueConstantWrap; ++it)
{
if ((*it)->HasDependentStates(techIndex))
{
if ((*it)->HasDependentProgramConstants(techIndex))
{
invalidateTechniqueConstantWrap = true;
}
}
}
for (XArray<ShaderDescriptorCG::ParamMeaning*>::Iterator it = shaderCG->GetPerPassParamMeanings().Begin(); it != shaderCG->GetPerPassParamMeanings().End() && !invalidateTechniqueConstantWrap; ++it)
{
if ((*it)->HasDependentStates(techIndex))
{
if ((*it)->HasDependentProgramConstants(techIndex))
{
invalidateTechniqueConstantWrap = true;
}
}
}
for (XArray<ShaderDescriptorCG::ExposedParamMeaning*>::Iterator it = shaderCG->GetExposedParamMeanings().Begin(); it != shaderCG->GetExposedParamMeanings().End() && !invalidateTechniqueConstantWrap; ++it)
{
if ((*it)->HasDependentStates(techIndex))
{
if ((*it)->HasDependentProgramConstants(techIndex))
{
invalidateTechniqueConstantWrap = true;
}
}
}
}
if (invalidateTechniqueConstantWrap)
{
tsc->RemoveConstantStores();
shaderCG->DisableProgramConstantsWrapping(techIndex);
}
// end of technique
}
//
shaderCG->m_CGParamToMeaning.Clear(); // the hash map was only necessary for the build, get rid of it.
//
effectStateCache.m_StateCacheRecorded = true;
}
//-----------------------------------------------------------------------------
void RCKShaderCG::BeginPass( CKDWORD Num, CKRenderContext* rc )
{
GLCHECK();
const int rcIndex = m_ShaderManager->_GetRenderContextIndex(rc);
EffectStateCache &efsc = *m_EffectStateCachePerContext[rcIndex];
XASSERT(efsc.m_StateCacheRecorded);
/*if (!efsc.m_StateCacheRecorded)
{
RecordEffectStates(m_Effect[rcIndex], m_ShaderDescriptor[rcIndex], efsc);
}*/
m_CurrentPassIndex = Num;
int currentTechniqueIndex = m_CurrentTechniqueIndex[rcIndex];
PassStateCache &psc = *(efsc.m_TechniquesStateCache[currentTechniqueIndex]->m_Passes[m_CurrentPassIndex]);
ReplayStates(rcIndex, rc->GetRasterizerContext(), psc, false /* doReset */);
// if this is a fixed fragment program, then unbound all unused texture stages
if (!psc.m_ProgramEnabled[CG_FRAGMENT_DOMAIN])
{
m_ShaderManager->DisableTextureStages(rc->GetRasterizerContext(), psc.m_TextureStageBits);
}
GLCHECK();
}
//-----------------------------------------------------------------------------
void RCKShaderCG::EndPass( CKRenderContext* rc )
{
GLCHECK();
const int rcIndex = m_ShaderManager->_GetRenderContextIndex(rc);
//
EffectStateCache &efsc = *m_EffectStateCachePerContext[rcIndex];
XASSERT(efsc.m_StateCacheRecorded);
//
int currentTechniqueIndex = m_CurrentTechniqueIndex[rcIndex];
PassStateCache &psc = *(efsc.m_TechniquesStateCache[currentTechniqueIndex]->m_Passes[m_CurrentPassIndex]);
ReplayStates(rcIndex, rc->GetRasterizerContext(), psc, true /* doReset */);
++ m_CurrentPassIndex; // Necessary to increase the pass index because some meaning setup
// happen before the call to BeginPass, and require the current pass index
if (m_CurrentPassIndex == m_CurrentPassCount)
{
m_CurrentPassIndex = 0; // reset for next shader invocation
}
m_ShaderManager->ClearModifiedRenderStates(); // for safety
GLCHECK();
}
//-----------------------------------------------------------------------------
void RCKShaderCG::CommitChanges( CKRenderContext* rc )
{
const int rcIndex = m_ShaderManager->_GetRenderContextIndex(rc);
EffectStateCache &efsc = *m_EffectStateCachePerContext[rcIndex];
XASSERT(efsc.m_StateCacheRecorded);
//
int currentTechniqueIndex = m_CurrentTechniqueIndex[rcIndex];
PassStateCache &psc = *(efsc.m_TechniquesStateCache[currentTechniqueIndex]->m_Passes[m_CurrentPassIndex]);
if (psc.m_CallCGSetPassState || (!UseStateCache))
{
// fallback when some render state are unknown (should use the optimized path instead of this most of the time)
cgSetPassState(m_CurrentActivePass[rcIndex][m_CurrentPassIndex]);
}
else
{
m_ShaderManager->FlushModifiedRenderStates(m_CurrentPassIndex, rc->GetRasterizerContext());
// if this is a fixed fragment program, then unbound all unused texture stages
if (!psc.m_ProgramEnabled[CG_FRAGMENT_DOMAIN])
{
m_ShaderManager->DisableTextureStages(rc->GetRasterizerContext(), psc.m_TextureStageBits);
}
// flush program constants
for (int domain = 0; domain < NUMBER_OF_CG_DOMAIN; ++domain)
{
if (psc.m_ConstantStore[domain])
{
psc.m_ConstantStore[domain]->Flush(rc->GetRasterizerContext());
}
}
}
GLCHECK();
}
//-----------------------------------------------------------------------------
void RCKShaderCG::End( CKRenderContext* rc )
{
GLCHECK();
}
//-----------------------------------------------------------------------------
void RCKShaderCG::SetTechnique( const XString& iTechName )
{
const int rcCount = m_Effect.Size();
for( int rcIndex=0 ; rcIndex<rcCount ; ++rcIndex )
{
m_CurrentTechnique[rcIndex] = cgGetNamedTechnique( m_Effect[rcIndex], iTechName.CStr() );
int techIndex = 0;
CGtechnique currTech = cgGetFirstTechnique(m_Effect[rcIndex]);
while (currTech != m_CurrentTechnique[rcIndex])
{
++ techIndex;
currTech = cgGetNextTechnique(currTech);
assert(currTech != NULL); // should find the technique inside the list ...
}
m_CurrentTechniqueIndex[rcIndex] = techIndex;
}
// int techIndex = -1;
// if( !GetTechIndexByName( iTechName, techIndex ) ) return;
//
// SetTechnique( techIndex );
}
//-----------------------------------------------------------------------------
void RCKShaderCG::SetTechnique( int iTechIndex )
{
// if(m_CurrTechniqueIndex == iTechIndex)
// return;
#pragma todo ("RCKShaderCG::SetTechnique : optimize the technique selection -> fill the technique array at compilation time, whith the shader descriptor")
m_CurrTechniqueIndex = iTechIndex;
const int rcCount = m_Effect.Size();
for( int rcIndex=0 ; rcIndex<rcCount ; ++rcIndex ){
CGtechnique tech = cgGetFirstTechnique(m_Effect[rcIndex]);
int techCount = 0;
while (techCount < iTechIndex) {
tech = cgGetNextTechnique(tech);
if(!tech) break;
++techCount;
}
assert(tech);
m_CurrentTechnique[rcIndex] = tech;
m_CurrentTechniqueIndex[rcIndex] = iTechIndex;
}
}
//-----------------------------------------------------------------------------
int
RCKShaderCG::GetTechniquesCount() const
{
//--- Same count for all render context
if( !m_ShaderDescriptor.Size() ) return 0;
return m_ShaderDescriptor[0]->GetTechMeanings().Size();
}
//-----------------------------------------------------------------------------
bool
RCKShaderCG::GetTechIndexByName( const XString& iTechName, int& oPos ) const
{
//--- Tech Name Should be the same for all Render Contexts
if( !m_ShaderDescriptor.Size() ) return false;
oPos = m_ShaderDescriptor[0]->GetTechIndexByName( iTechName );
if( oPos == -1 ) return false;
return true;
}
//-----------------------------------------------------------------------------
void
RCKShaderCG::GetTechniqueInfo( int iTechIndex, TechniqueInfo& oTechInfo ) const
{
if( !m_ShaderDescriptor.Size() ) return;
XArray<ShaderDescriptorCG::TechMeaning*>& techMeanings = m_ShaderDescriptor[0]->GetTechMeanings();
ShaderDescriptorCG::TechMeaning& techMeaning = *techMeanings[ iTechIndex ];
oTechInfo.name = XString(cgGetTechniqueName(techMeaning.m_TechDesc));
oTechInfo.desc = techMeaning.m_DescStr;
oTechInfo.isValid = techMeaning.m_Validated;
}
//-----------------------------------------------------------------------------
bool RCKShaderCG::FindNextValidTechnique( int& ioTechIndex, XString* oTechName ) const
{
if( !m_ShaderDescriptor.Size() ) return false;
//--- Use Shader Descriptor of Render Context 0 (validation should be the same for all RC)
ShaderDescriptorCG::ShaderCG& shaderDescriptor = *m_ShaderDescriptor[0];
//--- Parse all technique from the given one
TechniqueInfo techInfo;
int techIndex = ioTechIndex;
if( techIndex == -1 ) techIndex = 0;
const int techCount = GetTechniquesCount();
for( ; techIndex<techCount ; ++techIndex ){
GetTechniqueInfo( techIndex, techInfo );
if( techInfo.isValid ){
ioTechIndex = techIndex;
if( oTechName != NULL ) *oTechName = techInfo.name;
return true;
}
}
return false;
}
//-----------------------------------------------------------------------------
int
RCKShaderCG::GetTechniqueEnumValue( const XString& iTechName ) const
{
int techIndex = -1;
if( !GetTechIndexByName( iTechName, techIndex ) ) return 0;
return techIndex;
}
//-----------------------------------------------------------------------------
void
RCKShaderCG::GetTechniqueEnumString( int num, XString& oName ) const
{
TechniqueInfo techInfo;
GetTechniqueInfo( num, techInfo );
oName = techInfo.name;
}
//-----------------------------------------------------------------------------
int
RCKShaderCG::GetPassCount( int iTechIndex ) const
{
if( (CKShader*)this == m_ShaderManager->GetDefaultShader() ) return 1;
if( !m_ShaderDescriptor.Size() ) return 0;
XArray<ShaderDescriptorCG::TechMeaning*>& techMeanings = m_ShaderDescriptor[0]->GetTechMeanings();
ShaderDescriptorCG::TechMeaning& techMeaning = *techMeanings[ iTechIndex ];
return techMeaning.m_Passes.Size();
}
//-----------------------------------------------------------------------------
void
RCKShaderCG::GetPassInfo( int iTechIndex, int iPassIndex, PassInfo& oPassInfo ) const
{
if( !m_ShaderDescriptor.Size() ) return;
//--- Should be the same for RC0 than for other RC
XArray<ShaderDescriptorCG::TechMeaning*>& techMeanings = m_ShaderDescriptor[0]->GetTechMeanings();
ShaderDescriptorCG::TechMeaning& techMeaning = *techMeanings[ iTechIndex ];
ShaderDescriptorCG::PassMeaning& passMeaning = *techMeaning.m_Passes[ iPassIndex ];
oPassInfo.name = XString(cgGetPassName(passMeaning.m_PassDesc));
oPassInfo.desc = passMeaning.m_DescStr;
}
//-----------------------------------------------------------------------------
bool
RCKShaderCG::GetPassIndexByName( int iTechIndex, const char* iPassName, int& oPos ) const
{
if( !m_ShaderDescriptor.Size() ) return false;
//--- Should be the same for RC0 than for other RC
XArray<ShaderDescriptorCG::TechMeaning*>& techMeanings = m_ShaderDescriptor[0]->GetTechMeanings();
ShaderDescriptorCG::TechMeaning& techMeaning = *techMeanings[ iTechIndex ];
//--- Find index of given technique
int passIndex = techMeaning.GetPassIndexByName( iPassName );
//--- Cannot find the given pass
if( passIndex == -1 ) return false;
oPos = passIndex;
return true;
}
//-----------------------------------------------------------------------------
// Effect parameters feature
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Execute Exposed Params Meanings
void RCKShaderCG::SetParameters(const XArray<CKParameterLocal*>& params)
{
GLCHECK();
CKRenderManager* rm = m_ShaderManager->m_Context->GetRenderManager();
const int rcCount = m_Effect.Size();
for( int rcIndex=0 ; rcIndex<rcCount ; ++rcIndex ){
CKRenderContext* rc = m_ShaderManager->m_rcList[rcIndex];
int techIndex = m_CurrentTechniqueIndex[rcIndex];
XASSERT(m_EffectStateCachePerContext[rcIndex]->m_StateCacheRecorded);
TechniqueStateCache *tsc = m_EffectStateCachePerContext[rcIndex]->m_TechniquesStateCache[techIndex];
//
ShaderDescriptorCG::MeaningProcessingInfo
MPI( NULL, NULL, m_Effect[rcIndex], rc, NULL, m_ShaderDescriptor[rcIndex], NULL, m_CurrentTechniqueIndex[rcIndex], false /* per pass meaning */, tsc);
for (int i = 0; i < params.Size(); ++i)
{
GLCHECK();
CKParameterLocal* param = params[i];
ShaderDescriptorCG::ExposedParamMeaning* exposedParamMeaning =
m_ShaderManager->_GetRegisteredParamMeaning( param, rcIndex );
if( !exposedParamMeaning ) continue;
MPI.param = param;
exposedParamMeaning->ProcessCallBack( MPI );
GLCHECK();
}
}
GLCHECK();
}
//-----------------------------------------------------------------------------
// Execute Params Meanings (non-exposed)
// called by SetValuesOfUsedAutomatics()
//
void RCKShaderCG::ExecuteMeanings( CK3dEntity* iEnt, CKMaterial* iMat, CKMaterialShader* iMatShader, CKRenderContext* iRC )
{
const int rcIndex = m_ShaderManager->_GetRenderContextIndex( iRC );
int techIndex = m_CurrentTechniqueIndex[rcIndex];
XASSERT(m_EffectStateCachePerContext[rcIndex]->m_StateCacheRecorded);
TechniqueStateCache *tsc = m_EffectStateCachePerContext[rcIndex]->m_TechniquesStateCache[techIndex];
ShaderDescriptorCG::MeaningProcessingInfo mpi( iEnt, iMat, m_Effect[rcIndex], iRC, iMatShader, m_ShaderDescriptor[rcIndex], NULL, techIndex, false /* per pass meaning */, tsc);
m_ShaderDescriptor[rcIndex]->ExecuteMeanings( mpi );
int currentTechniqueIndex = m_CurrentTechniqueIndex[rcIndex];
EffectStateCache &efsc = *m_EffectStateCachePerContext[rcIndex];
if (efsc.m_TechniquesStateCache.Size() != 0)
{
XClassArray<PassStateCache *>& passes = efsc.m_TechniquesStateCache[currentTechniqueIndex]->m_Passes;
if (passes.Size() != 0)
{
PassStateCache &psc = *passes[m_CurrentPassIndex];
if ((!psc.m_CallCGSetPassState) && UseStateCache)
{
// the matrix of the object is setup prior to the call of that method by SetValueOfUsedAutomatics -> force to update light position & direction here at the next CommitChanges
// (OpenGL stores light position & direction in eye space so the matrix of the object needs to be set before a
// call to glLight)
// -> done twice with beginPass, but at least it works in all cases, because "ExecuteMeanings' is sometimes called
// before beginPass, sometime after ... maybe is it the real problem ...??
if (psc.m_LightPositionRenderState)
{
m_ShaderManager->AddPassModifiedRenderState(m_CurrentPassIndex, psc.m_LightPositionRenderState);
}
if (psc.m_LightSpotDirectionRenderState)
{
m_ShaderManager->AddPassModifiedRenderState(m_CurrentPassIndex, psc.m_LightSpotDirectionRenderState);
}
}
}
}
}
//-----------------------------------------------------------------------------
void RCKShaderCG::ExecutePerPassMeanings( CK3dEntity* iEnt, CKMaterial* iMat, CKMaterialShader* iMatShader, CKRenderContext* iRC )
{
const int rcIndex = m_ShaderManager->_GetRenderContextIndex( iRC );
int techIndex = m_CurrentTechniqueIndex[rcIndex];
XASSERT(m_EffectStateCachePerContext[rcIndex]->m_StateCacheRecorded);
TechniqueStateCache *tsc = m_EffectStateCachePerContext[rcIndex]->m_TechniquesStateCache[techIndex];
ShaderDescriptorCG::MeaningProcessingInfo mpi( iEnt, iMat, m_Effect[rcIndex], iRC, iMatShader, m_ShaderDescriptor[rcIndex], NULL, techIndex, true /* per pass meaning */, tsc);
m_ShaderDescriptor[rcIndex]->ExecutePerPassMeanings( mpi );
}
//-----------------------------------------------------------------------------
int RCKShaderCG::GetAutoParameterCount( CKRenderContext* rc )
{
const int rcIndex = m_ShaderManager->_GetRenderContextIndex(rc);
if( !m_ShaderDescriptor[rcIndex] ) return 0;
return m_ShaderDescriptor[rcIndex]->GetParamMeanings().Size();
}
//-----------------------------------------------------------------------------
int RCKShaderCG::GetExposedParameterCount( CKRenderContext* rc )
{
const int rcIndex = m_ShaderManager->_GetRenderContextIndex(rc);
if( !m_ShaderDescriptor[rcIndex] ) return 0;
return m_ShaderDescriptor[rcIndex]->GetExposedParamMeanings().Size();
}
//-----------------------------------------------------------------------------
void RCKShaderCG::GetAutoParameterInfo( int paramIndex, ParamInfo& paramInfo, CKRenderContext* rc )
{
const int rcIndex = m_ShaderManager->_GetRenderContextIndex(rc);
if( !m_ShaderDescriptor[rcIndex] ) return;
XArray<ShaderDescriptorCG::ParamMeaning*>& paramMeanings
= m_ShaderDescriptor[rcIndex]->GetParamMeanings();
paramInfo.name = XString(cgGetParameterName(paramMeanings[paramIndex]->m_ParamDesc));
}
//-----------------------------------------------------------------------------
void RCKShaderCG::GetExposedParameterInfo( int paramIndex, ParamInfo& paramInfo, CKRenderContext* rc )
{
const int rcIndex = m_ShaderManager->_GetRenderContextIndex(rc);
if( !m_ShaderDescriptor[rcIndex] ) return;
XArray<ShaderDescriptorCG::ExposedParamMeaning*>& exposedParamMeanings
= m_ShaderDescriptor[rcIndex]->GetExposedParamMeanings();
paramInfo.name = XString(cgGetParameterName(exposedParamMeanings[paramIndex]->m_ParamDesc));
paramInfo.guid = exposedParamMeanings[paramIndex]->m_Guid;
}
//-----------------------------------------------------------------------------
bool RCKShaderCG::LinkParameters(int& CompID, XArray<CKParameterLocal*>& params, CKBOOL cleanup)
{
//--- If comes from the same compilation, nothing to do.
if( CompID == m_CompID ) return false;
//--- Updates the compilation id.
CompID = m_CompID;
CKRenderManager* rm = m_ShaderManager->m_Context->GetRenderManager();
const int rcCount = m_Effect.Size();
for( int rcIndex=0 ; rcIndex<rcCount ; ++rcIndex ){
if( !m_Effect[rcIndex] ) return false;
//--- Set index of the CKParam* to the corresponding ExposedParamMeaning*,
///// and remove CKParam* that doesn't appear anymore in the shader code.
ParamInfo pInfo;
int ckParamCount = params.Size();
for( int ip=0; ip<ckParamCount ; ++ip )
{
CKParameterLocal* p = params[ip];
if( !p ) continue;
const char* name = params[ip]->GetName();
ShaderDescriptorCG::ExposedParamMeaning* paramMeaning
= m_ShaderDescriptor[rcIndex]->GetParamMeaningByName( name );
//--- If parameter is found...
if( paramMeaning ){
CKGUID prevGUID = p->GetGUID();
//--- If its guid has changed (for example because its annotation has changed)
///// then change its type
if( !paramMeaning->m_Guid.IsValid() ||
prevGUID != paramMeaning->m_Guid )
{
p->SetGUID( paramMeaning->m_Guid );
}
//--- Kindly update UI for FLOATSLIDER because update UIMin and UIMax
///// may have changed in the shader code
if( paramMeaning->m_Guid == CKPGUID_FLOATSLIDER ){
float valueToKeep = *(float*)p->GetWriteDataPtr();
ShaderDescriptorCG::MeaningProcessingInfo
mpi( NULL, NULL, m_Effect[rcIndex], NULL, NULL, NULL, p, -1, false /* per pass meanings */, NULL);
paramMeaning->CopyDefaultValueFromShaderToParamCB( mpi );
//--- UIMin and UIMax have been change, but we don't want the Value
///// to change so restore the previous one
*(float*)p->GetWriteDataPtr() = valueToKeep;
}
//--- Link the ExposedMeaning* this name-matching CKParam*
m_ShaderManager->_RegisterExposedParameterMeaning( params[ip], paramMeaning, rcIndex );
} else {
//--- Destroy params which name does not match
///// any Exposed Meaning, and remove them from input list
m_ShaderManager->m_Context->DestroyObject( p, CK_DESTROY_NONOTIFY );
m_ShaderManager->_UnregisterExposedParameter( p );
params.RemoveAt(ip);
--ip;
--ckParamCount;
}
}
//--- Now parse all ExposedMeaning* and create new CKParam*
///// if there wasn't any CKParam* associated with the ExposedMeaning*
XArray<ShaderDescriptorCG::ExposedParamMeaning*>& exposedMeanings =
m_ShaderDescriptor[rcIndex]->GetExposedParamMeanings();
const int exposedMeaningCount = exposedMeanings.Size();
for( int exposedMeaningIndex=0 ; exposedMeaningIndex<exposedMeaningCount ; ++exposedMeaningIndex ){
ShaderDescriptorCG::ExposedParamMeaning* exposedMeaning
= exposedMeanings[exposedMeaningIndex];
//--- Find one of the CKParam* that is already linked to this ExposedMeaning*
bool found = false;
ckParamCount = params.Size();
for( int paramIndex=0 ; paramIndex<ckParamCount ; ++paramIndex )
{
CKParameterLocal* p = params[paramIndex];
if( m_ShaderManager->_GetRegisteredParamMeaning( p, rcIndex ) == exposedMeaning )
{
found=true;
//--- Ensure parameter is located at the natural position
if( paramIndex != exposedMeaningIndex ){
//--- And if not, then move it to the desired position
params.Move( &params[exposedMeaningIndex], &params[paramIndex] );
}
break;
}
}
//--- No CKParam* linked to the ExposedMeaning*, so create one
if( !found ){
//--- So let's create a new CKParameter
CKParameterLocal* p =
m_ShaderManager->m_Context->CreateCKParameterLocal(
(char*)cgGetParameterName(exposedMeaning->m_ParamDesc), exposedMeaning->m_Guid );
//--- Insert it in the CKParameter array at the natural position if possible
if( params.Size() > exposedMeaningIndex ){
params.Insert( exposedMeaningIndex, p );
} else {
params.PushBack(p);
}
m_ShaderManager->_RegisterExposedParameterMeaning( p, exposedMeaning, rcIndex );
//--- We must register the parameter for the others handles
///// of all other render context, to make sure no other local param
///// will be created (as we must have only 1 ckparam for all RCs)
for( int otherRCIndex=0 ; otherRCIndex<rcCount ; ++otherRCIndex ){
if( otherRCIndex==rcIndex ) continue;
XArray<ShaderDescriptorCG::ExposedParamMeaning*>& exposedMeaningsOfOtherRC =
m_ShaderDescriptor[otherRCIndex]->GetExposedParamMeanings();
ShaderDescriptorCG::ExposedParamMeaning* meaningOfOtherRC =
exposedMeaningsOfOtherRC[ exposedMeaningIndex ];
m_ShaderManager->_RegisterExposedParameterMeaning( p, meaningOfOtherRC, otherRCIndex );
}
//--- While we are at it, tries to give the brand new parameter
///// the same value as the one in the shader.
///// Note: In principle, for the CopyDefaultValue callback we only need
///// to provide the FX and the CKParam
ShaderDescriptorCG::MeaningProcessingInfo
mpi( NULL, NULL, m_Effect[rcIndex], NULL, NULL, NULL, p, -1, false/* per pass meanings */, NULL);
exposedMeaning->CopyDefaultValueFromShaderToParamCB( mpi );
}
}
}
return true;
}
//-----------------------------------------------------------------------------
bool
RCKShaderCG::LinkTechnique( int& CompID, const XString& iTechName, BOOL iFNVT, int& oTechIndex )
{
//--- If comes from the same compilation, nothing to do.
if( CompID == m_CompID ) return false;
//--- Updates the compilation id.
CompID = m_CompID;
//--- Retrieves Technique index From Name
if( !GetTechIndexByName( iTechName, oTechIndex ) ) return false;
//--- Finds the next valid technique.
if( iFNVT ){
return FindNextValidTechnique( oTechIndex );
}
return true;
}
//-----------------------------------------------------------------------------
void RCKShaderCG::ClearStateCache()
{
int contextCount = m_EffectStateCachePerContext.Size();
for (int contextIndex = 0; contextIndex < contextCount; ++contextIndex)
{
m_EffectStateCachePerContext[contextIndex]->Clear();
}
}
//-----------------------------------------------------------------------------
void RCKShaderCG::RecordStates()
{
ClearStateCache();
int contextCount = m_EffectStateCachePerContext.Size();
for (int contextIndex = 0; contextIndex < contextCount; ++contextIndex)
{
m_EffectStateCachePerContext[contextIndex]->Clear();
EffectStateCache &efsc = *m_EffectStateCachePerContext[contextCount];
XASSERT(!efsc.m_StateCacheRecorded);
RecordEffectStates(m_Effect[contextIndex], m_ShaderDescriptor[contextIndex], efsc);
}
}
//-----------------------------------------------------------------------------
// Compiling
//-----------------------------------------------------------------------------
void RCKShaderCG::Compile(CKContext* Context)
{
XClassArray<XString> output;
m_ShaderManager->CompileShader(this, output);
RecordStates();
}
//-----------------------------------------------------------------------------
void RCKShaderCG::_AddRenderContextSlot()
{
//--- Add a Effect slot
m_Effect.PushBack( NULL );
m_CurrentTechnique.PushBack( NULL );
m_CurrentTechniqueIndex.PushBack(0);
m_EffectStateCachePerContext.PushBack(new EffectStateCache());
passArray p;
m_CurrentActivePass.PushBack(p);
///// Also add a ShaderDescriptorCG slot
ShaderDescriptorCG::ShaderCG* shaderDescriptorForThisRenderContext = new ShaderDescriptorCG::ShaderCG;
m_ShaderDescriptor.PushBack( shaderDescriptorForThisRenderContext );
}
//-----------------------------------------------------------------------------
void RCKShaderCG::_RemoveRenderContextSlot( int iRCIndex )
{
//--- Remove dxEffect for this rcIndex
XArray<CGeffect>& dxEffectArray = m_Effect;
dxEffectArray.RemoveAt( iRCIndex );
m_CurrentTechnique.RemoveAt( iRCIndex );
m_CurrentTechniqueIndex.RemoveAt( iRCIndex );
delete m_EffectStateCachePerContext[iRCIndex];
m_EffectStateCachePerContext.RemoveAt(iRCIndex);
m_CurrentActivePass.RemoveAt(iRCIndex);
//--- Remove also the ShaderDescriptorCG
delete m_ShaderDescriptor[iRCIndex];
m_ShaderDescriptor.RemoveAt( iRCIndex );
}
//-----------------------------------------------------------------------------
// Registering
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
CKSTRING RCKShaderCG::GetClassName()
{
return "Shader";
}
//-----------------------------------------------------------------------------
// Render state caches
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------------
void CachedRenderStateBool::Apply(CKRasterizerContext *rc, bool doReset)
{
if (doReset)
{
Callback(rc, *this, &DefaultValue[0], true);
}
else
{
if (NeedReeval)
{
int valueCount;
const CGbool *values = cgGetBoolStateAssignmentValues(StateAssignment, &valueCount);
if (valueCount <= sizeofarray(StaticValue))
{
for (int i = 0; i < valueCount; ++i)
{
StaticValue[i] = values[i];
}
NeedReeval = false;
}
else
{
// can't store value ... just pass through
Callback(rc, *this, values, false);
return;
}
}
// callback for that state
Callback(rc, *this, &StaticValue[0], false);
}
}
//-----------------------------------------------------------------------------------
void CachedRenderStateInt::Apply(CKRasterizerContext *rc, bool doReset)
{
if (doReset)
{
Callback(rc, *this, &DefaultValue[0], true);
}
else
{
if (NeedReeval)
{
int valueCount;
const int *values = cgGetIntStateAssignmentValues(StateAssignment, &valueCount);
if (valueCount <= sizeofarray(StaticValue))
{
for (int i = 0; i < valueCount; ++i)
{
StaticValue[i] = values[i];
}
NeedReeval = false;
}
else
{
// can't store value ... just pass through
Callback(rc, *this, values, false);
return;
}
}
// callback for that state
Callback(rc, *this, &StaticValue[0], false);
}
}
//-----------------------------------------------------------------------------------
void CachedRenderStateFloat::Apply(CKRasterizerContext *rc, bool doReset)
{
if (doReset)
{
Callback(rc, *this, &DefaultValue[0], true);
}
else
{
if (NeedReeval)
{
int valueCount;
const float *values = cgGetFloatStateAssignmentValues(StateAssignment, &valueCount);
if (valueCount <= sizeofarray(StaticValue))
{
for (int i = 0; i < valueCount; ++i)
{
StaticValue[i] = values[i];
}
NeedReeval = false;
}
else
{
// can't store value ... just pass through
Callback(rc, *this, values, false);
return;
}
}
// callback for that state
Callback(rc, *this, &StaticValue[0], false);
}
}
//-----------------------------------------------------------------------------------
void CachedRenderStateProgram::Apply(CKRasterizerContext *rc, bool doReset)
{
if (doReset)
{
Callback(rc, *this, &DefaultValue[0], true);
}
else
{
if (NeedReeval)
{
CGprogram prog = cgGetProgramStateAssignmentValue(StateAssignment);
StaticValue[0] = prog;
}
// callback for that state
Callback(rc, *this, &StaticValue[0], false);
}
}