2734 lines
96 KiB
C++
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( ¶ms[exposedMeaningIndex], ¶ms[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);
|
|
}
|
|
}
|
|
|
|
|