1725 lines
49 KiB
C++
1725 lines
49 KiB
C++
#include "stdafx.h"
|
|
#include "ShaderManagerCG.h"
|
|
#include "CKGL15RasterizerContext.h"
|
|
#include "ShaderDescriptorCG.h"
|
|
#include "default_fxCG.cpp"
|
|
|
|
#include <Cg/cgGL.h>
|
|
|
|
#if defined(MULTIPLESHADERMANAGER)
|
|
unsigned int mCppLib_PreProcess(const XString& xsIn,const char *opt,XString& xsOut,XString& PreProcErr);
|
|
BOOL DoWinExec(const XString& command);
|
|
#else
|
|
#ifndef macintosh
|
|
#include "mCppLib.h"
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
____ _ _ __ __
|
|
/ ___|| |__ __ _ __| | ___ _ __ | \/ | __ _ _ __ __ _ __ _ ___ _ __
|
|
\___ \| '_ \ / _` |/ _` |/ _ \ '__| | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
|
___) | | | | (_| | (_| | __/ | | | | | (_| | | | | (_| | (_| | __/ |
|
|
|____/|_| |_|\__,_|\__,_|\___|_| |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
|
|___/
|
|
***************************************************************************/
|
|
|
|
XArray<ShaderManagerCG::CGContextToRasterizer> ShaderManagerCG::m_CGContextToRasterizer;
|
|
|
|
#ifdef _DEBUG
|
|
static void errorCallback()
|
|
{
|
|
static bool already_called = false;
|
|
if (already_called) {
|
|
return;
|
|
}
|
|
already_called = true;
|
|
theShaderManager->m_Context->OutputToConsole((char*)cgGetErrorString(cgGetError()));
|
|
if (theShaderManager->m_CgContext.Size()) {
|
|
const char* listing = cgGetLastListing(theShaderManager->m_CgContext[0]);
|
|
if (listing)
|
|
theShaderManager->m_Context->OutputToConsole((char*)listing);
|
|
}
|
|
already_called = false;
|
|
}
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
ShaderManagerCG::ShaderManagerCG(CKContext *Context) :
|
|
#if defined(MULTIPLESHADERMANAGER)
|
|
ShaderManagerInterface(Context),
|
|
m_NextCompID(NULL),
|
|
#else
|
|
CKShaderManager(Context,ShaderManagerGUID,"Shader Manager"),
|
|
m_NextCompID(1),
|
|
#endif
|
|
m_ReplacementMode( ShaderReplacementMode_RenameNew ),
|
|
m_NMOSavingMode( ShaderNMOSavingMode_SaveOnlyUsedShaders ),
|
|
m_TangentSpaceCreationMode( ShaderTSCreationMode_DontWeldTangentSpaces )
|
|
{
|
|
#if !defined(MULTIPLESHADERMANAGER)
|
|
Context->RegisterNewManager(this);
|
|
#endif
|
|
|
|
#ifdef macintosh
|
|
#warning mac must compile external file ?
|
|
#else
|
|
char filename[512];
|
|
GetModuleFileName(NULL, filename, 512);
|
|
int c = strlen(filename);
|
|
while (c >= 0 && filename[c] != '\\')
|
|
--c;
|
|
filename[c] = '\0';
|
|
m_FXCCommand = filename;
|
|
m_FXCCommand += "\\cgc.exe";
|
|
#endif
|
|
m_CurrentPassCount = 0;
|
|
m_CurrentPassIndex = 0;
|
|
|
|
for (int i = 0 ; i<MaxChannelCount ; i++) {
|
|
m_PseudoChannelTexture[i] = NULL;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
theShaderManager = this;
|
|
cgSetErrorCallback(errorCallback);
|
|
#endif
|
|
for (int domain = 0; domain < NUMBER_OF_CG_DOMAIN; ++domain)
|
|
{
|
|
m_CurrentCGProgram[domain] = NULL;
|
|
m_CurrentProfile[domain] = CG_PROFILE_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
ShaderManagerCG::~ShaderManagerCG()
|
|
{
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
inline VCKGL15Rasterizer::CKGLRasterizerContext *ShaderManagerCG::GetRasterizerFromCGContext(CGcontext cgContext)
|
|
{
|
|
int contextCount = m_CGContextToRasterizer.Size();
|
|
for (int contextIndex = 0; contextIndex != contextCount; ++contextIndex)
|
|
{
|
|
if (m_CGContextToRasterizer[contextIndex].cgContext == cgContext)
|
|
{
|
|
return m_CGContextToRasterizer[contextIndex].glRasterizerContext;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::RegisterCGContext(CGcontext cgContext, VCKGL15Rasterizer::CKGLRasterizerContext *glRasterizerContext)
|
|
{
|
|
XASSERT(!GetRasterizerFromCGContext(cgContext));
|
|
XASSERT(cgContext);
|
|
XASSERT(glRasterizerContext);
|
|
//
|
|
CGContextToRasterizer ctr;
|
|
ctr.cgContext = cgContext;
|
|
ctr.glRasterizerContext = glRasterizerContext;
|
|
m_CGContextToRasterizer.PushBack(ctr);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::UnregisterCGContext(CGcontext cgContext)
|
|
{
|
|
int contextCount = m_CGContextToRasterizer.Size();
|
|
for (int contextIndex = 0; contextIndex != contextCount; ++contextIndex)
|
|
{
|
|
if (m_CGContextToRasterizer[contextIndex].cgContext == cgContext)
|
|
{
|
|
m_CGContextToRasterizer.EraseAt(contextIndex);
|
|
XASSERT(!GetRasterizerFromCGContext(cgContext));
|
|
return;
|
|
}
|
|
}
|
|
XASSERT(0);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::BeginShaders( CKRenderContext* rc )
|
|
{
|
|
assert(IsSupported());
|
|
|
|
if (rc->GetRasterizerContext()->m_ShaderInUse)
|
|
{
|
|
return;
|
|
}
|
|
|
|
rc->GetRasterizerContext()->DisableAllTextureStages();
|
|
m_UsedTextureStageBits = 0;
|
|
|
|
#ifdef _DEBUG
|
|
for (int domain = 0; domain < NUMBER_OF_CG_DOMAIN; ++domain)
|
|
{
|
|
XASSERT(m_CurrentCGProgram[domain] == NULL);
|
|
XASSERT(m_CurrentProfile[domain] == CG_PROFILE_UNKNOWN);
|
|
}
|
|
#endif
|
|
CKRasterizerContext *rstc = rc->GetRasterizerContext();
|
|
|
|
rstc->SetTextureStageState(0, CKRST_TSS_OP, CKRST_TOP_MODULATE);
|
|
rstc->SetTextureStageState(0, CKRST_TSS_ARG1, CKRST_TA_TEXTURE);
|
|
rstc->SetTextureStageState(0, CKRST_TSS_ARG2, CKRST_TA_CURRENT);
|
|
rstc->SetTextureStageState(0, CKRST_TSS_AOP, CKRST_TOP_SELECTARG1);
|
|
rstc->SetTextureStageState(0, CKRST_TSS_AARG1, CKRST_TA_TEXTURE);
|
|
rstc->SetTextureStageState(0, CKRST_TSS_AARG2, CKRST_TA_CURRENT);
|
|
|
|
((VCKGL15Rasterizer::CKGLRasterizerContext*) rstc)->BackupLightSetup();
|
|
|
|
// Tell the rasterizer context we're in shader mode
|
|
rstc->m_ShaderInUse = TRUE;
|
|
|
|
m_DefaultShader = GetDefaultShaderI();
|
|
m_DefaultShader->Begin( rc );
|
|
m_DefaultShader->BeginPass( 0, rc );
|
|
|
|
|
|
|
|
//rc->GetRasterizerContext()->DisableAllTextureStages();
|
|
// m_DefaultShader->EndPass( rc );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::EndShaders( CKRenderContext* rc )
|
|
{
|
|
//--- Flush Rasterizer Cache to make sure all states are reset
|
|
CKRasterizerContext* rstc = rc->GetRasterizerContext();
|
|
if (!rstc)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!rstc->m_ShaderInUse)
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_DefaultShader->EndPass( rc );
|
|
m_DefaultShader->End( rc );
|
|
|
|
ClearModifiedRenderStates(); // for safety
|
|
|
|
DeactivateProgram(CG_VERTEX_DOMAIN);
|
|
DeactivateProgram(CG_FRAGMENT_DOMAIN);
|
|
DeactivateProgram(CG_GEOMETRY_DOMAIN);
|
|
|
|
|
|
|
|
// Tell the rasterizer context we're in not shader mode
|
|
rstc->m_ShaderInUse = FALSE;
|
|
|
|
|
|
DisableTextureStages(rstc, 0);
|
|
rstc->FlushCaches();
|
|
rstc->DisableAllTextureStages();
|
|
|
|
((VCKGL15Rasterizer::CKGLRasterizerContext*) rstc)->RestoreLightSetup();
|
|
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int
|
|
ShaderManagerCG::GetSemanticIndexFromString( XString& iStr )
|
|
{
|
|
return m_ShaderDescriptorManager.GetSemanticIndexFromString( iStr );
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
const XClassArray<XString>&
|
|
ShaderManagerCG::GetSemanticOriginalNames()
|
|
{
|
|
return m_ShaderDescriptorManager.GetSemanticOriginalNames();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
ShaderManagerCG::GetSemanticDesc( int iSemIndex, XString*& oSemDesc )
|
|
{
|
|
m_ShaderDescriptorManager.GetSemanticDesc( iSemIndex, oSemDesc );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
const XClassArray<XString>&
|
|
ShaderManagerCG::GetAnnotationOriginalNames()
|
|
{
|
|
return m_ShaderDescriptorManager.GetAnnotationOriginalNames();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKERROR ShaderManagerCG::OnCKEnd()
|
|
{
|
|
CKVariableManager* vm = m_Context->GetVariableManager();
|
|
if( vm ){
|
|
vm->UnBind( "Shader/When Loading Shader With Same Name" );
|
|
vm->UnBind( "Shader/When Saving a NMO" );
|
|
vm->UnBind( "Shader/When Building Tangent Spaces" );
|
|
}
|
|
return CK_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKERROR ShaderManagerCG::OnCKInit()
|
|
{
|
|
#if !defined(MULTIPLESHADERMANAGER)
|
|
//--- Register Shader Global Variables to the Variable Manager
|
|
CKVariableManager* vm = m_Context->GetVariableManager();
|
|
|
|
vm->Bind(
|
|
"Shader/When Loading Shader With Same Name", &m_ReplacementMode, ShaderReplacementMode_RenameNew,
|
|
VxVar::COMPOSITIONBOUND,
|
|
"enum:0=Rename New;1=Replace Old By New;2=Keep Old And Dont Use New",
|
|
"When loading a shader which name matches an existing one but content don't, then this variable is used to tell the Shader Manager what to do.");
|
|
|
|
vm->Bind(
|
|
"Shader/When Saving a NMO", &m_NMOSavingMode, ShaderNMOSavingMode_SaveOnlyUsedShaders,
|
|
VxVar::COMPOSITIONBOUND,
|
|
"enum:0=Save All Shaders;1=Save Only Used Shaders;2=Don't Save Any Shader",
|
|
"When saving a NMO file this variable tells the Shader Manager what to do with existing shaders.\nNote: a shader is considered as being used if it is used by a material, or referenced by a parameter.\nNote: When saving the composition (CMO) all shaders are saved.");
|
|
|
|
vm->Bind(
|
|
"Shader/When Building Tangent Spaces", &m_TangentSpaceCreationMode, ShaderTSCreationMode_DontWeldTangentSpaces,
|
|
VxVar::COMPOSITIONBOUND,
|
|
"enum:0=Dont Weld Tangent Spaces;1=Weld Tangent Spaces;",
|
|
"When tangent spaces are built on a mesh this variable tells the Shader Manager how tangent spaces should be generated\nNote: if one is using Normal Maps generated with 3dsmax 7 then Welding Tangent Spaces should be used.");
|
|
#endif // MULTIPLESHADERMANAGER
|
|
|
|
//--- Render Options Used in PostClearAll
|
|
m_RenderOptionsBeforePlay = CK_RENDER_USECURRENTSETTINGS;
|
|
|
|
//--- Web player special case
|
|
///// If there's already a render context, it means
|
|
///// the sm->OnRenderContextCreated(this) hasn't been called
|
|
///// as the ShaderManagerCG was not created yet.
|
|
///// That's why we must call it here, if it already exist.
|
|
///// Note: that is the case when first downloading the shader.dll
|
|
///// in the web player
|
|
CKRenderManager* rm = m_Context->GetRenderManager();
|
|
if( !rm ) return CK_OK;
|
|
|
|
CKRenderContext* rc = rm->GetRenderContext(0);
|
|
if( rc ){
|
|
OnRenderContextCreated( rc );
|
|
OnRasterizerEvent( CKRST_EVENT_CREATE, rc );
|
|
}
|
|
|
|
//--- Register All Stuffs Needed for ShaderDescriptorCG
|
|
m_ShaderDescriptorManager.Init( m_Context );
|
|
|
|
return CK_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKERROR ShaderManagerCG::OnRasterizerEvent(CKRST_EVENTS Event, CKRenderContext* rc)
|
|
{
|
|
switch (Event)
|
|
{
|
|
case CKRST_EVENT_CREATE:
|
|
OnCreateDevice(rc);
|
|
break;
|
|
case CKRST_EVENT_DESTROY:
|
|
OnDestroyDevice(rc);
|
|
break;
|
|
case CKRST_EVENT_RESIZING:
|
|
case CKRST_EVENT_LOST:
|
|
OnLostDevice(rc);
|
|
break;
|
|
case CKRST_EVENT_RESET:
|
|
OnResetDevice(rc);
|
|
break;
|
|
};
|
|
return CK_OK;
|
|
}
|
|
|
|
CGbool CGFixFrontFaceCallback(CGstateassignment sa)
|
|
{
|
|
// TODO : use state cache
|
|
int valueCount;
|
|
const int *values = cgGetIntStateAssignmentValues(sa, &valueCount);
|
|
XASSERT(values);
|
|
CKBOOL ccw = (*values == GL_CCW) ? 1 : 0;
|
|
VCKGL15Rasterizer::CKGLRasterizerContext* ctx = ShaderManagerCG::GetRasterizerFromCGContext(cgGetEffectContext(cgGetTechniqueEffect(cgGetPassTechnique(cgGetStateAssignmentPass(sa)))));
|
|
XASSERT(ctx);
|
|
ccw = ccw ^ ctx->m_InverseWinding ^ ctx->m_TextureTarget;
|
|
glFrontFace(ccw ? GL_CCW : GL_CW);
|
|
return CG_TRUE;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::OnCreateDevice(CKRenderContext* rc)
|
|
{
|
|
//--- Compile all shaders for all devices
|
|
int rcIndex = _GetRenderContextIndex(rc);
|
|
assert( rcIndex>=0 );
|
|
|
|
|
|
|
|
#pragma todo ("Test if render context has been created")
|
|
|
|
CGcontext context = cgCreateContext();
|
|
XASSERT(context);
|
|
RegisterCGContext(context, (VCKGL15Rasterizer::CKGLRasterizerContext *) rc->GetRasterizerContext());
|
|
|
|
m_CgContext.Insert(rcIndex, context);
|
|
//cgGLSetManageTextureParameters(context, CG_FALSE); // we setup textures ourselves
|
|
cgGLRegisterStates(context);
|
|
CGstate frontFaceState = cgGetNamedState(context, "FrontFace");
|
|
if (frontFaceState)
|
|
{
|
|
cgSetStateCallbacks(frontFaceState, CGFixFrontFaceCallback, CGFixFrontFaceCallback, NULL);
|
|
}
|
|
const int shaderCount = m_AllShaders.Size();
|
|
for( int a=0 ; a<shaderCount ; ++a ){
|
|
CompileShader( m_AllShaders[a], m_Output );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::OnDestroyDevice( CKRenderContext* rc )
|
|
{
|
|
int rcIndex = _GetRenderContextIndex(rc);
|
|
assert( rcIndex>=0 );
|
|
const int shaderCount = m_AllShaders.Size();
|
|
for( int a=0 ; a<shaderCount ; ++a ){
|
|
|
|
RCKShaderCG* shader = (RCKShaderCG*)m_AllShaders[a];
|
|
if( !shader ) continue;
|
|
|
|
//--- Release effect for this rcIndex
|
|
CGeffect* effect = &(shader->m_Effect[rcIndex]);
|
|
|
|
if( !*effect ) continue;
|
|
|
|
cgDestroyEffect( *effect );
|
|
*effect = NULL;
|
|
|
|
shader->m_CurrentTechnique[rcIndex] = NULL;
|
|
}
|
|
|
|
if (m_CgContext.Size())
|
|
{
|
|
if (m_CgContext[rcIndex])
|
|
{
|
|
cgDestroyContext(m_CgContext[rcIndex]);
|
|
UnregisterCGContext(m_CgContext[rcIndex]);
|
|
}
|
|
}
|
|
|
|
m_CgContext[rcIndex] = NULL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::OnLostDevice(CKRenderContext* rc)
|
|
{
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::OnResetDevice(CKRenderContext* rc)
|
|
{
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKERROR ShaderManagerCG::OnCKPlay()
|
|
{
|
|
if( !m_Context->IsReseted() ) return CK_OK;
|
|
|
|
//--- Store rendering options
|
|
CKRenderContext* rc = m_Context->GetRenderManager()->GetRenderContext(0);
|
|
if( !rc ) return CK_OK;
|
|
|
|
m_RenderOptionsBeforePlay = rc->GetCurrentRenderOptions();
|
|
return CK_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKERROR ShaderManagerCG::PreClearAll()
|
|
{
|
|
|
|
#if !defined(MULTIPLESHADERMANAGER)
|
|
CKShaderManager::PreClearAll();
|
|
for (int i = 0; i < m_AllShaders.Size(); ++i)
|
|
delete m_AllShaders[i];
|
|
#endif
|
|
|
|
m_AllShaders.Clear();
|
|
m_DefaultShader = NULL;
|
|
m_ShadowShader = NULL;
|
|
|
|
//--- Clear Exposed Parameters Management Arrays
|
|
m_hashParamIndex.Clear();
|
|
const int rcCount = m_paramMeaningLinker.Size();
|
|
for( int rcIndex=0 ; rcIndex<rcCount ; ++rcIndex ){
|
|
m_paramMeaningLinker[rcIndex].Clear();
|
|
}
|
|
|
|
#if !defined(MULTIPLESHADERMANAGER)
|
|
return CKShaderManager::PreClearAll();
|
|
#else
|
|
return CK_OK;
|
|
#endif
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKERROR ShaderManagerCG::PostClearAll()
|
|
{
|
|
m_RenderOptionsBeforePlay = CK_RENDER_USECURRENTSETTINGS;
|
|
|
|
return CK_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKShader* ShaderManagerCG::CreateShader( const XString* name, const XString* text, BOOL uniqueName )
|
|
{
|
|
RCKShaderCG* fx = new RCKShaderCG(this);
|
|
|
|
//--- Make Shader name unique. This is needed because for example,
|
|
///// the material combo box gets the shader by its name.
|
|
XString wantedName = name? *name:"New Shader";
|
|
if( uniqueName ){
|
|
XString extName = "";
|
|
BOOL nameIsUnique = FALSE;
|
|
for( int a=1 ; ; ++a ){
|
|
CKShader* sameNameFx = GetShaderByName( wantedName+extName );
|
|
if( !sameNameFx ) break;
|
|
extName.Format( "%d", a );
|
|
}
|
|
wantedName += extName;
|
|
}
|
|
fx->SetName( wantedName );
|
|
|
|
//--- Set default text
|
|
fx->SetText(text ? *text : "technique tech\r\n{\r\n\tpass p\r\n\t{\r\n\t}\r\n}\r\n");
|
|
|
|
m_AllShaders.PushBack(fx);
|
|
return fx;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKShader* ShaderManagerCG::CreateShaderFromFiles(const CKSTRING HLSLfilename, const CKSTRING CgFXfilename)
|
|
{
|
|
if (CgFXfilename != NULL)
|
|
return CreateShaderFromFile(CgFXfilename);
|
|
else
|
|
return CreateShaderFromFile(HLSLfilename);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
CKShader* ShaderManagerCG::CreateShaderFromFile(const CKSTRING filename)
|
|
{
|
|
VxFile f;
|
|
|
|
if (f.Open(filename, VxFile::READONLY))
|
|
{
|
|
int size = f.Size();
|
|
XString s;
|
|
s.Resize( size );
|
|
int readCount = f.Read( s.Str(), size );
|
|
|
|
// Extract Shader name
|
|
int end = strlen(filename);
|
|
while (end > 0 && filename[end] != '.')
|
|
--end;
|
|
int start = strlen(filename);
|
|
while (start > 0 && filename[start] != '\\')
|
|
--start;
|
|
|
|
XString name;
|
|
if (start < end && end != 0)
|
|
{
|
|
if (start)
|
|
start++;
|
|
name.Resize(end - start);
|
|
strncpy(name.Str(), &filename[start], end - start);
|
|
}
|
|
else
|
|
name = filename;
|
|
|
|
// Creates the Shader.
|
|
CKShader* fx = CreateShader(&name, &s);
|
|
return fx;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool ShaderManagerCG::SaveShaderToFile(const XString& filename, CKShader* fx)
|
|
{
|
|
return _WriteStringToFile(filename, fx->GetText()) ? true:false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKBOOL ShaderManagerCG::IsSupported() const
|
|
{
|
|
CKRenderManager* rm = m_Context->GetRenderManager();
|
|
if( rm ){
|
|
CKRenderContext* rc = rm->GetRenderContext(0);
|
|
if( rc ){
|
|
CKRasterizerContext* rCtx = rc->GetRasterizerContext();
|
|
|
|
// Check rasterizer capability
|
|
if (rCtx->m_Driver->m_3DCaps.CKRasterizerSpecificCaps & CKRST_SPECIFICCAPS_SUPPORTSHADERS &&
|
|
rCtx->m_Driver->m_2DCaps.Family == CKRST_OPENGL)
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
CKBOOL ShaderManagerCG::IsSupportedAndWarnIfNot()
|
|
{
|
|
const CKBOOL isSupported = IsSupported();
|
|
if( !isSupported ){
|
|
m_Output.PushBack("Rasterizer does not support Shaders (use OpenGL Shader Compatible Card)");
|
|
}
|
|
return isSupported;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::GetVSPSVersion(float& vs, float& ps) const
|
|
{
|
|
CGprofile vsProf = cgGLGetLatestProfile(CG_GL_VERTEX);
|
|
CGprofile psProf = cgGLGetLatestProfile(CG_GL_FRAGMENT);
|
|
//CG_PROFILE_GLSLC //GLSLCombined
|
|
|
|
switch(vsProf) {
|
|
case CG_PROFILE_ARBVP1:
|
|
vs = 2.1f;
|
|
break;
|
|
case CG_PROFILE_GLSLV:
|
|
vs = 2.2f;
|
|
break;
|
|
case CG_PROFILE_VP20:
|
|
vs = 1.1f;
|
|
break;
|
|
case CG_PROFILE_VP30:
|
|
vs = 2.0f;
|
|
break;
|
|
case CG_PROFILE_VP40:
|
|
vs = 3.0f;
|
|
break;
|
|
case CG_PROFILE_UNKNOWN:
|
|
vs = 0.0f;
|
|
break;
|
|
default:
|
|
vs = 1.1f;
|
|
XASSERT(vsProf == CG_PROFILE_ARBVP1);
|
|
break;
|
|
}
|
|
|
|
switch(psProf) {
|
|
case CG_PROFILE_ARBFP1:
|
|
ps = 2.1f;
|
|
break;
|
|
case CG_PROFILE_GLSLF:
|
|
ps = 2.2f;
|
|
break;
|
|
case CG_PROFILE_FP20:
|
|
ps = 1.1f;
|
|
break;
|
|
case CG_PROFILE_FP30:
|
|
ps = 2.0f;
|
|
break;
|
|
case CG_PROFILE_FP40:
|
|
ps = 3.0f;
|
|
break;
|
|
case CG_PROFILE_UNKNOWN:
|
|
ps = 0.0f;
|
|
break;
|
|
default:
|
|
ps = 1.1f;
|
|
XASSERT(psProf == CG_PROFILE_ARBFP1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKShader* ShaderManagerCG::GetShaderByName(const XBaseString& name)
|
|
{
|
|
for (int i = 0; i < m_AllShaders.Size(); ++i)
|
|
if (m_AllShaders[i]->GetName() == name)
|
|
return m_AllShaders[i];
|
|
return NULL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int ShaderManagerCG::GetNumShaders() const
|
|
{
|
|
return m_AllShaders.Size();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKShader* ShaderManagerCG::GetShader(int pos)
|
|
{
|
|
return m_AllShaders[pos];
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::DeleteShader(CKShader* fx)
|
|
{
|
|
m_AllShaders.Remove(fx);
|
|
if (fx == m_DefaultShader)
|
|
m_DefaultShader = NULL;
|
|
delete fx;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool ShaderManagerCG::CompileShader(CKShader* fx, XClassArray<XString> &output)
|
|
{
|
|
RCKShaderCG& rfx = *(RCKShaderCG*)fx;
|
|
|
|
|
|
|
|
//--- We must compile for all created render context
|
|
const int rcCount = m_rcList.Size();
|
|
for( int rcIndex=0 ; rcIndex<rcCount ; ++rcIndex ){
|
|
|
|
CKRenderContext* rc = m_rcList[rcIndex];
|
|
CKRasterizerContext* rCtx = rc->GetRasterizerContext();
|
|
// NB : nicov : CG supports fixed pipeline setup as well, so permit it (same behavior than with Direct3D)
|
|
if (!(/*rCtx->m_Driver->m_3DCaps.CKRasterizerSpecificCaps & CKRST_SPECIFICCAPS_SUPPORTSHADERS && */
|
|
rCtx->m_Driver->m_2DCaps.Family == CKRST_OPENGL))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
rfx.m_EffectStateCachePerContext[rcIndex]->Clear();
|
|
|
|
const XString& Text = rfx.GetText();
|
|
if (!Text.Length()) {
|
|
output.PushBack(rfx.GetName() + ": Empty shader : shader compilation failed.");
|
|
rfx.RecordEffectStates(rfx.m_Effect[rcIndex], rfx.m_ShaderDescriptor[rcIndex], *rfx.m_EffectStateCachePerContext[rcIndex]);
|
|
continue;
|
|
}
|
|
|
|
CGeffect oldfx = rfx.m_Effect[rcIndex];
|
|
|
|
// Creates and compile a simple Shader
|
|
rfx.m_Effect[rcIndex] = cgCreateEffect(m_CgContext[rcIndex],Text.CStr(),NULL);
|
|
|
|
|
|
//--- Retrieves compilation errors
|
|
CGerror err = cgGetError();
|
|
if ( err != CG_NO_ERROR) {
|
|
XStringTokenizer tokizer(cgGetErrorString(err), "\n");
|
|
const char *tok = NULL;
|
|
while ((tok = tokizer.NextToken(tok)) != NULL)
|
|
output.PushBack(rfx.GetName() + ": "+ XString(tok));
|
|
}
|
|
|
|
const char* listing = cgGetLastListing(m_CgContext[rcIndex]);
|
|
if (listing) {
|
|
XStringTokenizer tokizer(listing, "\n");
|
|
const char *tok = NULL;
|
|
while ((tok = tokizer.NextToken(tok)) != NULL)
|
|
output.PushBack(rfx.GetName() + ": " + XString(tok));
|
|
}
|
|
|
|
//--- Find Valid Technique in effect file
|
|
CGtechnique tech = cgGetFirstTechnique(rfx.m_Effect[rcIndex]);
|
|
BOOL valideTechFind = FALSE;
|
|
while (tech) {
|
|
if (cgValidateTechnique(tech) == CG_FALSE)
|
|
{
|
|
output.PushBack(rfx.GetName() + ": Technique "+ cgGetTechniqueName(tech) +" not validated.");
|
|
listing = cgGetLastListing(m_CgContext[rcIndex]);
|
|
if (listing) {
|
|
XStringTokenizer tokizer(listing, "\n");
|
|
const char *tok = NULL;
|
|
while ((tok = tokizer.NextToken(tok)) != NULL)
|
|
output.PushBack(rfx.GetName() + ": " + XString(tok));
|
|
}
|
|
}
|
|
else
|
|
valideTechFind = TRUE;
|
|
tech = cgGetNextTechnique(tech);
|
|
}
|
|
if (!valideTechFind)
|
|
output.PushBack(rfx.GetName() + ": No valid technique found.");
|
|
#if (defined(macintosh) && defined(__i386__))
|
|
// Intel GMA 950 Hack.
|
|
// this graphical chipset does not support pixel shader longger than 62 instructions.
|
|
if (strstr((char *) glGetString(GL_VENDOR),"intel")!=NULL)
|
|
{
|
|
CGprogram program;
|
|
for (program=cgGetFirstProgram(m_CgContext[rcIndex]);program;program=cgGetNextProgram(program))
|
|
{
|
|
if (cgIsProgramCompiled(program))
|
|
{
|
|
XString shader(cgGetProgramString(program,CG_COMPILED_PROGRAM));
|
|
int indice= shader.Find("END");
|
|
char* ptr = shader.Str()+indice+strlen("END\\n#");
|
|
int nbinstruction = atoi(ptr);
|
|
if (nbinstruction>62)
|
|
{
|
|
rfx.m_Effect[rcIndex] = NULL;
|
|
output.PushBack(rfx.GetName() + ": Shader compilation failed.");
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
//--- Replace the old Shader with the new one
|
|
if (!rfx.m_Effect[rcIndex] || (listing!=NULL && strstr(listing, "error")) && oldfx){
|
|
rfx.m_Effect[rcIndex] = oldfx;
|
|
output.PushBack(rfx.GetName() + ": Shader compilation failed.");
|
|
rfx.RecordEffectStates(rfx.m_Effect[rcIndex], rfx.m_ShaderDescriptor[rcIndex], *rfx.m_EffectStateCachePerContext[rcIndex]);
|
|
} else {
|
|
|
|
//--- Init the Shader Descriptor for this Shader
|
|
if( fx != m_DefaultShader ){
|
|
rfx.m_ShaderDescriptor[rcIndex]->Init( &m_ShaderDescriptorManager, rfx.m_Effect[rcIndex], rc, &rfx );
|
|
}
|
|
|
|
if (oldfx) {
|
|
cgDestroyEffect(oldfx);
|
|
rfx.m_CurrentTechnique[rcIndex]=NULL;
|
|
}
|
|
|
|
#if defined(MULTIPLESHADERMANAGER)
|
|
rfx.m_CompID = (*m_NextCompID)++;
|
|
#else
|
|
rfx.m_CompID = m_NextCompID++;
|
|
#endif
|
|
|
|
//--- Output "Compilation successful" message
|
|
output.PushBack(rfx.GetName() +
|
|
": Shader compilation successful.");
|
|
rfx.RecordEffectStates(rfx.m_Effect[rcIndex], rfx.m_ShaderDescriptor[rcIndex], *rfx.m_EffectStateCachePerContext[rcIndex]);
|
|
|
|
}
|
|
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool ShaderManagerCG::CompileShaderOutput(CKShader* fx, const CKSTRING funcname,
|
|
const CKSTRING target, XClassArray<XString> &output, XArray<char>& text)
|
|
{
|
|
assert(fx != NULL);
|
|
|
|
if (!(VxFile::GetFileMode(m_FXCCommand.CStr()) & VxFile::REGULAR_FILE))
|
|
{
|
|
output.PushBack("No path to cgc.exe CGFX Compiler.");
|
|
return FALSE;
|
|
}
|
|
// Check Direct X Version
|
|
// if (dx && dx->DxVersion >= 0x0900)
|
|
{
|
|
#ifdef macintosh
|
|
char *tmp=(char *)VxGetTempPath().CStr();
|
|
#else
|
|
char tmp[1024];
|
|
GetTempPath(1024, tmp);
|
|
#endif
|
|
// Create an input file.
|
|
XString infile;
|
|
infile.Format("%sfxcin.fx", tmp);
|
|
|
|
// Write XString to file.
|
|
if (!_WriteStringToFile(infile, fx->GetText()))
|
|
{
|
|
output.PushBack("Cannot write temporary Shader file.");
|
|
return FALSE;
|
|
}
|
|
|
|
XString outfile;
|
|
outfile.Format("%sfxcout.txt", tmp);
|
|
|
|
XString cmd;
|
|
|
|
cmd.Reserve( 1024+strlen(funcname) );
|
|
cmd.Format( "\"%s\" -profile %s -entry %s -o %s %s", m_FXCCommand.CStr(), target,
|
|
funcname, outfile.CStr(), infile.CStr());
|
|
|
|
if (!_WinExec(cmd.CStr()))
|
|
{
|
|
output.PushBack(XString("Command execution has failed : ") + cmd);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!_ReadStringFromFile(outfile, text))
|
|
{
|
|
output.PushBack("Cannot read compiled output file.");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKShader* ShaderManagerCG::GetDefaultShader()
|
|
{
|
|
return GetDefaultShaderI();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKShader* ShaderManagerCG::GetDefaultShaderI()
|
|
{
|
|
if( !m_DefaultShader )
|
|
{
|
|
XString defaultShader("- default -");
|
|
XString g_defaultShader(g_default);
|
|
m_DefaultShader = ShaderManagerCG::CreateShader(&defaultShader, &g_defaultShader);
|
|
CompileShader(m_DefaultShader, m_Output);
|
|
}
|
|
return m_DefaultShader;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKShader* ShaderManagerCG::GetShadowShader()
|
|
{
|
|
if( !m_ShadowShader)
|
|
{
|
|
XString shadowShader("- builtin shadows -");
|
|
XString g_shadowShader(g_default); // TMP : not implemented, return default shader
|
|
m_ShadowShader = ShaderManagerCG::CreateShader(&shadowShader, &g_shadowShader);
|
|
CompileShader(m_ShadowShader, m_Output);
|
|
}
|
|
return m_ShadowShader;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKERROR ShaderManagerCG::LoadData(CKStateChunk *chunk,CKFile* LoadedFile)
|
|
{
|
|
//--- If the Default Shader doesn't exist GetDefaultShader will create it
|
|
m_DefaultShader = GetDefaultShaderI();
|
|
|
|
assert(LoadedFile != 0);
|
|
if (!chunk)
|
|
return CKERR_INVALIDPARAMETER;
|
|
|
|
chunk->StartRead();
|
|
|
|
if (chunk->SeekIdentifier(SHADERMANAGER_CHUNKID))
|
|
{
|
|
XArray<CKShader*> toBeCompiledShaders;
|
|
|
|
// Check the version
|
|
int version = chunk->ReadInt();
|
|
|
|
// Check the flags
|
|
int flags = chunk->ReadInt();
|
|
// Read Shaders
|
|
int num_Shaders = chunk->ReadInt();
|
|
int chunkid = FIRSTSHADER_CHUNKID;
|
|
for (int i = 0; i < num_Shaders; ++i)
|
|
{
|
|
CKBOOL notEndOfChunk = chunk->SeekIdentifier(chunkid);
|
|
++chunkid;
|
|
|
|
if( !notEndOfChunk ){
|
|
continue;
|
|
}
|
|
|
|
//--- If Version < 1 there's a BOOL "isDefaultFx"
|
|
if( version < 2 ){
|
|
//--- Is it the default effect then don't read content
|
|
CKBOOL isDefaultFx = chunk->ReadInt();
|
|
if( isDefaultFx ) continue;
|
|
}
|
|
|
|
//--- Read Shader Name and Text
|
|
XString fxName = chunk->ReadString();
|
|
XString fxText;// = chunk->ReadString();
|
|
|
|
//--- Retrieves CgFX text version of a shader
|
|
bool needToExit = false;
|
|
int* marksBuffer = NULL;
|
|
int marksSize = 0;
|
|
do{
|
|
fxText = chunk->ReadString();
|
|
|
|
if (fxText.Compare("HLSL") == 0) {
|
|
chunk->ReadString();
|
|
fxText = "";
|
|
}
|
|
else if (fxText.Compare("CGFX") == 0){
|
|
fxText = chunk->ReadString();
|
|
needToExit = true;
|
|
}
|
|
else if (fxText.Compare("_END_") == 0){
|
|
fxText = "";
|
|
needToExit = true;
|
|
break;
|
|
}
|
|
else { //--- pre Dev 4.0 (only HLSL)
|
|
fxText = "";
|
|
needToExit = true;
|
|
break;
|
|
}
|
|
|
|
// Read Marks
|
|
if (version>=3) {
|
|
if (marksBuffer != NULL) {
|
|
CKDeletePointer(marksBuffer);
|
|
marksBuffer = NULL;
|
|
}
|
|
marksSize = chunk->ReadBuffer((void**)&marksBuffer) / sizeof(int);
|
|
}
|
|
|
|
} while (needToExit == false);
|
|
|
|
|
|
CKShader* sameNameEffect;
|
|
BOOL shaderMustBeCreated = TRUE;
|
|
int extCount = 0;
|
|
while( (sameNameEffect=GetShaderByName( fxName )) && shaderMustBeCreated ){
|
|
|
|
//--- Skip this effect if text is the same
|
|
if( !fxText.Compare( sameNameEffect->GetText() ) ){
|
|
shaderMustBeCreated = FALSE;
|
|
break;
|
|
}
|
|
|
|
//--- Otherwise ...
|
|
switch( m_ReplacementMode ){
|
|
|
|
case ShaderReplacementMode_ReplaceOldByNew:
|
|
|
|
//--- Replace Old Shader By New Shader
|
|
{
|
|
sameNameEffect->SetText( fxText );
|
|
shaderMustBeCreated = FALSE;
|
|
toBeCompiledShaders.PushBack( sameNameEffect );
|
|
}
|
|
break;
|
|
|
|
case ShaderReplacementMode_KeepOldAndDontUseNew:
|
|
|
|
//--- Keep Old Shader And Dont Use New Shader
|
|
{
|
|
shaderMustBeCreated = FALSE;
|
|
}
|
|
break;
|
|
|
|
case ShaderReplacementMode_RenameNew:
|
|
default:
|
|
|
|
//--- Rename New Shader
|
|
{
|
|
//--- Find Existing Extension Number
|
|
XString originalFxName = fxName;
|
|
int fxNameLength = fxName.Length();
|
|
if( fxNameLength > 4 ){
|
|
if( fxName[ fxNameLength-4 ] == '_' ){
|
|
XString extStr = fxName.Substring( fxNameLength-3 );
|
|
extCount = extStr.ToInt();
|
|
originalFxName = fxName.Substring( 0, fxNameLength-4 );
|
|
}
|
|
}
|
|
//--- Replace extension number by Incremented Extension Number
|
|
++extCount;
|
|
fxName.Format( "%s_%.3d", originalFxName.CStr(), extCount );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( !shaderMustBeCreated ) continue;
|
|
|
|
//--- Create new shader
|
|
RCKShaderCG* fx = new RCKShaderCG(this);
|
|
fx->SetName( fxName );
|
|
fx->SetText( fxText );
|
|
|
|
m_AllShaders.PushBack( fx );
|
|
toBeCompiledShaders.PushBack( fx );
|
|
|
|
// Read Marks
|
|
if (version>=3)
|
|
{
|
|
#ifndef VIRTOOLS_RUNTIME_VERSION
|
|
fx->m_F2Marks.Resize(marksSize);
|
|
for (int index=0;index<marksSize;++index)
|
|
fx->m_F2Marks[index]=marksBuffer[index];
|
|
#endif
|
|
CKDeletePointer(marksBuffer);
|
|
}
|
|
}
|
|
|
|
//--- Compile all loaded shaders
|
|
if( IsSupportedAndWarnIfNot() ){
|
|
|
|
//--- Compile every loaded Shader except the default Shader
|
|
///// as it has already been compiled (cf: just above)
|
|
const int loadedShaderCount = toBeCompiledShaders.Size();
|
|
for( int i=0 ; i<loadedShaderCount ; ++i ){
|
|
|
|
CKShader* const fx = toBeCompiledShaders[i];
|
|
if( fx == m_DefaultShader ) continue;
|
|
|
|
CompileShader( fx, m_Output );
|
|
}
|
|
|
|
#if defined(_XBOX) && defined(_DEBUG)
|
|
for(XString* it = m_Output.Begin();it!=m_Output.End();it++){
|
|
OutputDebugString(it->CStr());
|
|
OutputDebugString("\n");
|
|
}
|
|
m_Output.Clear();
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
chunk->CloseChunk();
|
|
|
|
return CK_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
#define VIRTOOLS_SCRIPT_DOT_EXTENSION ".nms"
|
|
#define VIRTOOLS_OBJECT_DOT_EXTENSION ".nmo"
|
|
|
|
CKStateChunk* ShaderManagerCG::SaveData(CKFile* SavedFile)
|
|
{
|
|
assert(SavedFile != 0);
|
|
|
|
//--- If there's only one shader it's certainly the default shader Shader
|
|
///// and so it's not even needed to save any ShaderManagerCG Chunk
|
|
int toSaveCount = 0;
|
|
for (int shIndex = 0; shIndex < m_AllShaders.Size(); ++shIndex)
|
|
{
|
|
if (m_AllShaders[shIndex] != m_DefaultShader && m_AllShaders[shIndex] != m_ShadowShader)
|
|
{
|
|
++ toSaveCount;
|
|
}
|
|
}
|
|
if (toSaveCount == 0) return NULL;
|
|
|
|
XHashTable<bool, XString> shaderThatCanBeSavedFromName;
|
|
bool checkIfShaderMustBeSaved = false;
|
|
|
|
//--- Check file extension
|
|
CKSTRING fileName = SavedFile->m_FileName;
|
|
const int fileNameLength = strlen(fileName);
|
|
if( fileNameLength >= 4 ){
|
|
|
|
char* extension = fileName + fileNameLength - 4;
|
|
|
|
//--- Saving .NMS
|
|
if( stricmp( extension, VIRTOOLS_SCRIPT_DOT_EXTENSION ) == 0 ){
|
|
|
|
//--- Don't save any Shaders with an .NMS
|
|
return NULL;
|
|
}
|
|
//--- Saving .NMO
|
|
if( stricmp( extension, VIRTOOLS_OBJECT_DOT_EXTENSION ) == 0 ){
|
|
|
|
//--- If User asked not to save any Shader with NMO, then Exit
|
|
if( m_NMOSavingMode == ShaderNMOSavingMode_DontSaveAnyShader ) return NULL;
|
|
|
|
//--- If User asked to save Only Used Shaders, then find references to shaders
|
|
if( m_NMOSavingMode == ShaderNMOSavingMode_SaveOnlyUsedShaders ){
|
|
|
|
checkIfShaderMustBeSaved = true;
|
|
toSaveCount = 0;
|
|
|
|
CKParameterManager* pm = m_Context->GetParameterManager();
|
|
CKParameterType shaderParamType = pm->ParameterGuidToType( CKPGUID_SHADER );
|
|
|
|
const int count = SavedFile->m_FileObjects.Size();
|
|
for( int a=0 ; a<count ; a++ ){
|
|
|
|
const CKFileObject& objSaved = SavedFile->m_FileObjects[a];
|
|
|
|
//--- If it's a material..
|
|
if( CKIsChildClassOf(objSaved.ObjectCid, CKCID_MATERIAL) ){
|
|
|
|
CKMaterial* mat = (CKMaterial*)objSaved.ObjPtr;
|
|
if( !mat ) continue;
|
|
|
|
CKMaterialShader* mfx = mat->GetMaterialShader();
|
|
if( !mfx ) continue;
|
|
|
|
//--- If there's a Shader on this Material
|
|
CKShader* shader = mfx->m_Shader;
|
|
|
|
if( !shader ) continue;
|
|
XASSERT(shader!=m_DefaultShader); // this shouldn't happen
|
|
XASSERT(shader!=m_ShadowShader); // this shouldn't happen
|
|
|
|
//--- If this ShaderName isn't yet supposed to be saved
|
|
const XString& shaderName = shader->GetName();
|
|
if( shaderThatCanBeSavedFromName.FindPtr( shaderName ) ) continue;
|
|
|
|
//--- Then add it to the list of ShaderNames to be saved
|
|
shaderThatCanBeSavedFromName.Insert( shaderName, true );
|
|
++toSaveCount;
|
|
}
|
|
//--- If it's a Parameter
|
|
else if( CKIsChildClassOf(objSaved.ObjectCid, CKCID_PARAMETERLOCAL) ){
|
|
|
|
CKParameter* param = (CKParameter*)objSaved.ObjPtr;
|
|
if( !param ) continue;
|
|
|
|
//--- if this parameter is a CKPGUID_SHADER
|
|
if( param->GetType() != shaderParamType ) continue;
|
|
|
|
const char* shaderName = (char*)param->GetReadDataPtr(FALSE);
|
|
if( !shaderName ) continue;
|
|
|
|
//--- We shouldn't, but if we ever parse a shader param string == None then do nothing
|
|
if( strcmp( shaderName, "-- None --" ) == 0 ) continue;
|
|
|
|
//--- If this ShaderName isn't yet supposed to be saved
|
|
if( shaderThatCanBeSavedFromName.FindPtr( shaderName ) ) continue;
|
|
|
|
//--- Then add it to the list of ShaderNames to be saved
|
|
shaderThatCanBeSavedFromName.Insert( shaderName, true );
|
|
++toSaveCount;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
// Writes chunk information
|
|
CKStateChunk *chunk = CreateCKStateChunk(SHADERMANAGER_CHUNKID, SavedFile);
|
|
if (!chunk)
|
|
return NULL;
|
|
chunk->StartWrite();
|
|
chunk->WriteIdentifier(SHADERMANAGER_CHUNKID);
|
|
chunk->WriteInt(SHADERMANAGER_SAVE_VERSION);
|
|
chunk->WriteInt(SHADERMANAGER_FLAGS);
|
|
|
|
// Writes all Shaders we want to save.
|
|
chunk->WriteInt( toSaveCount ); //--- Minus the default Shader
|
|
int chunkid = FIRSTSHADER_CHUNKID;
|
|
const int shaderCount = m_AllShaders.Size();
|
|
for (int i = 0; i < shaderCount; ++i)
|
|
{
|
|
CKShader* shader = m_AllShaders[i];
|
|
if( !shader ) continue;
|
|
|
|
//--- Is it the default effect then don't write it (same for builtin shadows)
|
|
if( shader == m_DefaultShader ) continue;
|
|
if( shader == m_ShadowShader ) continue;
|
|
|
|
//--- If extension is .NMO, filter Only Used Shaders
|
|
if( checkIfShaderMustBeSaved ){
|
|
if( !shaderThatCanBeSavedFromName.FindPtr( shader->GetName() ) ) continue;
|
|
}
|
|
|
|
chunk->WriteIdentifier(chunkid);
|
|
++chunkid;
|
|
|
|
// store name
|
|
chunk->WriteString( shader->GetName().CStr() );
|
|
// store text
|
|
|
|
#ifndef _XBOX
|
|
#ifndef macintosh
|
|
if(m_SavePreProcessed){
|
|
|
|
XString PreProcessed;
|
|
XString PreProcErr;
|
|
|
|
HRESULT hr = mCppLib_PreProcess( shader->GetText(),m_SavePreprocessedOptions.CStr(),PreProcessed,PreProcErr);
|
|
if(S_OK == hr){
|
|
chunk->WriteString(PreProcessed.CStr());
|
|
}else{
|
|
m_Context->OutputToConsoleExBeep("Error Preprocessing Shader : %s",PreProcErr.CStr());
|
|
chunk->WriteString("CGFX");
|
|
chunk->WriteString( shader->GetText().CStr());
|
|
}
|
|
}else
|
|
#endif // macintosh
|
|
#endif // _XBOX
|
|
{
|
|
chunk->WriteString("CGFX");
|
|
chunk->WriteString( shader->GetText().CStr());
|
|
}
|
|
|
|
// Write F2 Marks
|
|
#ifdef VIRTOOLS_RUNTIME_VERSION
|
|
chunk->WriteBuffer(0,0);
|
|
#else
|
|
chunk->WriteBuffer(shader->GetF2Marks()->Size()*sizeof(int),shader->GetF2Marks()->Begin());
|
|
#endif
|
|
chunk->WriteString("_END_");
|
|
}
|
|
chunk->CloseChunk();
|
|
return chunk;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#ifndef _XBOX
|
|
|
|
//-----------------------------------------------------------------------------
|
|
BOOL ShaderManagerCG::_ReadStringFromFile(const XString& filename, XArray<char> &s) const
|
|
{
|
|
//--- Read XString from file.
|
|
VxFile f;
|
|
if( !f.Open(filename.CStr()) ) return FALSE;
|
|
|
|
int size = f.Size();
|
|
s.Resize( size+1);
|
|
f.Read( s.Begin(), size );
|
|
s[size] = '\0';
|
|
f.Close();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
BOOL ShaderManagerCG::_WriteStringToFile(const XString& filename, const XString &s) const
|
|
{
|
|
VxFile f;
|
|
|
|
if (!f.Open(filename.CStr(), VxFile::WRITEONLY))
|
|
return FALSE;
|
|
|
|
f.Write(s.CStr(), s.Length());
|
|
f.Close();
|
|
return TRUE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
BOOL ShaderManagerCG::_WinExec(const XString& command)
|
|
{
|
|
#ifdef macintosh
|
|
return (system(command.CStr())!=-1);
|
|
#else
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
|
|
ZeroMemory( &si, sizeof(si) );
|
|
si.cb = sizeof(si);
|
|
ZeroMemory( &pi, sizeof(pi) );
|
|
|
|
// Start the child process.
|
|
if( !CreateProcess( NULL, // No module name (use command line).
|
|
const_cast<CKSTRING>(command.CStr()), // Command line.
|
|
NULL, // Process handle not inheritable.
|
|
NULL, // Thread handle not inheritable.
|
|
FALSE, // Set handle inheritance to FALSE.
|
|
CREATE_NO_WINDOW, // No creation flags.
|
|
NULL, // Use parent's environment block.
|
|
NULL, // Use parent's starting directory.
|
|
&si, // Pointer to STARTUPINFO structure.
|
|
&pi ) // Pointer to PROCESS_INFORMATION structure.
|
|
)
|
|
return FALSE;
|
|
|
|
|
|
// Wait until child process exits.
|
|
WaitForSingleObject( pi.hProcess, INFINITE );
|
|
|
|
DWORD code = 0;
|
|
GetExitCodeProcess( pi.hProcess, &code );
|
|
|
|
// Close process and thread handles.
|
|
CloseHandle( pi.hProcess );
|
|
CloseHandle( pi.hThread );
|
|
|
|
return code==0;
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------//
|
|
// Exposed Parameters Management
|
|
//
|
|
// m_hashParamIndex: a hash table for retrieving the index of store CKParams
|
|
// m_paramMeaningLinker: array of ExposedLoclalParamsPerRC indexed per RC index.
|
|
// ExposedLocalParamsPerRC:
|
|
//-----------------------------------------------------------------------//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::_RegisterExposedParameterMeaning( CKParameterLocal* p, ShaderDescriptorCG::ExposedParamMeaning* paramMeaning, int rcIndex )
|
|
{
|
|
//--- Check if parameter has already been registered
|
|
int* paramIndexPtr = m_hashParamIndex.FindPtr(p);
|
|
|
|
int registeredParamCount = m_hashParamIndex.Size();
|
|
int paramIndex = registeredParamCount;
|
|
|
|
//--- If the paramater has not yet been registered then add it
|
|
if( !paramIndexPtr ){
|
|
m_hashParamIndex.Insert( p, paramIndex );
|
|
m_paramMeaningLinker[rcIndex].PushBack( paramMeaning );
|
|
//--- Otherwise use the param's index
|
|
} else {
|
|
//--- If parameter has already been registered for another rc, but not for this one
|
|
if( *paramIndexPtr >= m_paramMeaningLinker[rcIndex].Size() ){
|
|
m_paramMeaningLinker[rcIndex].Resize( *paramIndexPtr+1 );
|
|
}
|
|
m_paramMeaningLinker[rcIndex][*paramIndexPtr] = paramMeaning;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::_UnregisterExposedParameter( CKParameterLocal* p )
|
|
{
|
|
//--- Check if parameter is registered
|
|
int* paramIndexPtr = m_hashParamIndex.FindPtr(p);
|
|
if( !paramIndexPtr ) return;
|
|
|
|
int paramIndex = *paramIndexPtr;
|
|
|
|
//--- Parse all rc and remove d3dhandle for the found param index
|
|
const int rcCount = m_paramMeaningLinker.Size();
|
|
for( int rcIndex=0 ; rcIndex<rcCount ; ++rcIndex ){
|
|
m_paramMeaningLinker[rcIndex].RemoveAt(paramIndex);
|
|
}
|
|
//--- Remove reference to this param in the hash table
|
|
///// and shift every parameter index beyond the removed one
|
|
XHashTable<int, CKParameterLocal*>::Iterator it = m_hashParamIndex.Begin();
|
|
while (it != m_hashParamIndex.End()) {
|
|
if( *it > paramIndex ){
|
|
--(*it);
|
|
}
|
|
++it;
|
|
}
|
|
m_hashParamIndex.Remove( p );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::_AddRCForExposedParameters()
|
|
{
|
|
const int endIndex = m_paramMeaningLinker.Size();
|
|
|
|
//--- Add one rc
|
|
m_paramMeaningLinker.Expand(1);
|
|
|
|
//--- Set as many params for this rc as there's params defined in the hash table
|
|
const int registeredParamCount = m_hashParamIndex.Size();
|
|
m_paramMeaningLinker[endIndex].Resize( registeredParamCount );
|
|
m_paramMeaningLinker[endIndex].Fill( (ShaderDescriptorCG::ExposedParamMeaning*)0 );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::_RemoveRCForExposedParameters( int rcIndex )
|
|
{
|
|
//--- Remove the rc
|
|
///// Note: as it's a class array, it will remove also all d3dhandles for the rc
|
|
m_paramMeaningLinker.RemoveAt( rcIndex );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
ShaderDescriptorCG::ExposedParamMeaning*
|
|
ShaderManagerCG::_GetRegisteredParamMeaning( CKParameterLocal* p, int rcIndex )
|
|
{
|
|
//--- Check if parameter is registered
|
|
int* paramIndexPtr = m_hashParamIndex.FindPtr(p);
|
|
if( !paramIndexPtr ) return (ShaderDescriptorCG::ExposedParamMeaning*)(-1);
|
|
|
|
int paramIndex = *paramIndexPtr;
|
|
|
|
return m_paramMeaningLinker[rcIndex][paramIndex];
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int ShaderManagerCG::_GetRenderContextIndex( CKRenderContext* rc )
|
|
{
|
|
const int rcCount = m_rcList.Size();
|
|
for( int a=0 ; a<rcCount ; ++a ){
|
|
if( m_rcList[a] == rc ) return a;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*******************************************************************
|
|
Summary: Called when a RenderContext gets created or destroyed
|
|
to update the Shader Manager's inner list of render contexts
|
|
*******************************************************************/
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::OnRenderContextCreated( CKRenderContext* rc )
|
|
{
|
|
int rcIndex = m_rcList.Size();
|
|
m_rcList.PushBack( rc );
|
|
|
|
//--- Add a RenderContext Slot for all Exposed Parameters
|
|
_AddRCForExposedParameters();
|
|
|
|
//--- Add RenderContext Slot for all RCKShaders
|
|
const int shaderCount = m_AllShaders.Size();
|
|
for( int a=0 ; a<shaderCount ; ++a ){
|
|
|
|
RCKShaderCG* shader = (RCKShaderCG*)m_AllShaders[a];
|
|
if( !shader ) continue;
|
|
|
|
shader->_AddRenderContextSlot();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::OnRenderContextDestroyed( CKRenderContext* rc )
|
|
{
|
|
int rcIndex = _GetRenderContextIndex(rc);
|
|
if( rcIndex >= 0 ){
|
|
|
|
//--- Remove a RenderContext Slot for all Exposed Parameters
|
|
_RemoveRCForExposedParameters( rcIndex );
|
|
|
|
//--- Remove a RenderContext Slot for all RCKShaders
|
|
for(int a=0; a<m_AllShaders.Size(); ++a ){
|
|
|
|
RCKShaderCG* shader = (RCKShaderCG*)m_AllShaders[a];
|
|
if( !shader ) continue;
|
|
|
|
shader->_RemoveRenderContextSlot( rcIndex );
|
|
}
|
|
//--- Remove the RC from our managed list of RCs
|
|
m_rcList.Remove( rc );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::EnableProgram(CKRasterizerContext* rc, ShaderConstantStore *cstStore)
|
|
{
|
|
XASSERT(cstStore);
|
|
CGprofile profile = cstStore->GetProfile();
|
|
CGdomain domain = cstStore->GetDomain();
|
|
EnableProfile(domain, profile);
|
|
CGprogram cgProg = cstStore->GetCGProgram();
|
|
XASSERT(cgProg != 0);
|
|
XASSERT(cstStore->GetGLProgramID()); // If program failed to compile, then we shouldn't have built a ShaderConstantStore from it
|
|
if (cgProg != m_CurrentCGProgram[domain - CG_FIRST_DOMAIN])
|
|
{
|
|
cstStore->BindProgramIntoGL(rc);
|
|
m_CurrentCGProgram[domain - CG_FIRST_DOMAIN] = cgProg;
|
|
}
|
|
cstStore->Flush(rc);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::EnableProgram(CGprogram prog)
|
|
{
|
|
#ifndef STATIC_FOR_MAYA // Maya export dll links with a cg that don't have
|
|
// cgGetProfileDomain -> link would fail
|
|
GLCHECK();
|
|
XASSERT(prog);
|
|
//
|
|
CGprofile profile = cgGetProgramProfile(prog);
|
|
CGdomain domain = cgGetProfileDomain(profile);
|
|
XASSERT(domain < CG_FIRST_DOMAIN + NUMBER_OF_CG_DOMAIN);
|
|
if (prog != m_CurrentCGProgram[domain - CG_FIRST_DOMAIN])
|
|
{
|
|
EnableProfile(domain, profile);
|
|
cgGLBindProgram(prog);
|
|
m_CurrentCGProgram[domain - CG_FIRST_DOMAIN] = prog;
|
|
|
|
if (profile == CG_PROFILE_FP20)
|
|
{
|
|
cgSetPassProgramParameters(prog); // no local parameters for that profile
|
|
// (GeForce 3 pixel shaders via NV_TEXTURE_SHADER ... must set them up)
|
|
}
|
|
}
|
|
GLCHECK();
|
|
#else
|
|
XASSERT(0); // not supposed to be called
|
|
#endif
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::EnableProfile(CGdomain domain, CGprofile profile)
|
|
{
|
|
XASSERT(domain < CG_FIRST_DOMAIN + NUMBER_OF_CG_DOMAIN);
|
|
GLCHECK();
|
|
if (m_CurrentProfile[domain - CG_FIRST_DOMAIN] != profile)
|
|
{
|
|
if (m_CurrentProfile[domain - CG_FIRST_DOMAIN] != CG_PROFILE_UNKNOWN)
|
|
{
|
|
cgGLDisableProfile(m_CurrentProfile[domain - CG_FIRST_DOMAIN]);
|
|
}
|
|
if (profile != CG_PROFILE_UNKNOWN)
|
|
{
|
|
cgGLEnableProfile(profile);
|
|
}
|
|
m_CurrentProfile[domain - CG_FIRST_DOMAIN] = profile;
|
|
}
|
|
GLCHECK();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::DeactivateProgram(CGdomain domain)
|
|
{
|
|
XASSERT(domain < CG_FIRST_DOMAIN + NUMBER_OF_CG_DOMAIN);
|
|
GLCHECK();
|
|
if (m_CurrentCGProgram[domain - CG_FIRST_DOMAIN])
|
|
{
|
|
XASSERT(m_CurrentProfile[domain - CG_FIRST_DOMAIN] != CG_PROFILE_UNKNOWN);
|
|
cgGLUnbindProgram(m_CurrentProfile[domain - CG_FIRST_DOMAIN]);
|
|
EnableProfile(domain, CG_PROFILE_UNKNOWN);
|
|
m_CurrentCGProgram[domain - CG_FIRST_DOMAIN] = NULL;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
XASSERT(m_CurrentProfile[domain - CG_FIRST_DOMAIN] == CG_PROFILE_UNKNOWN);
|
|
#endif
|
|
GLCHECK();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::FlushModifiedRenderStates(int passIndex, CKRasterizerContext* rc)
|
|
{
|
|
if (passIndex >= m_PerPassModifiedRenderStates.Size())
|
|
{
|
|
m_PerPassModifiedRenderStates.Resize(passIndex + 1);
|
|
}
|
|
PerPassModifiedRenderStates &flushedPass = m_PerPassModifiedRenderStates[passIndex];
|
|
int stateCount = flushedPass.RenderStates.Size();
|
|
for (int stateIndex =0 ; stateIndex < stateCount; ++stateIndex)
|
|
{
|
|
flushedPass.RenderStates[stateIndex]->Apply(rc, false /* do reset */);
|
|
}
|
|
flushedPass.RenderStates.Resize(0); // don't do a clear here : want to keep memory for future reuse
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::ClearModifiedRenderStates()
|
|
{
|
|
int passCount = m_PerPassModifiedRenderStates.Size();
|
|
for (int passIndex = 0; passIndex < passCount; ++passIndex)
|
|
{
|
|
m_PerPassModifiedRenderStates[passIndex].RenderStates.Resize(0);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::SignalTextureStageUsed(int stage, GLenum textureTarget)
|
|
{
|
|
XASSERT(stage >= 0 && stage < 32);
|
|
m_UsedTextureStageBits |= (1 << stage);
|
|
m_TextureStageTargets[stage] = textureTarget;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerCG::DisableTextureStages(CKRasterizerContext *rc, CKDWORD stagesMask)
|
|
{
|
|
GLCHECK();
|
|
CKDWORD toDisableBits = (~stagesMask) & m_UsedTextureStageBits;
|
|
int currentStage = 0;
|
|
VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc;
|
|
XASSERT(ogRC->m_glActiveTextureARB);
|
|
|
|
|
|
while (toDisableBits)
|
|
{
|
|
if (toDisableBits & 1)
|
|
{
|
|
ogRC->m_glActiveTextureARB(GL_TEXTURE0_ARB + currentStage);
|
|
ogRC->DisableGLCurrentStageTexturing();
|
|
}
|
|
toDisableBits >>= 1;
|
|
++ currentStage;
|
|
}
|
|
ogRC->m_glActiveTextureARB(GL_TEXTURE0_ARB);
|
|
m_UsedTextureStageBits &= stagesMask;
|
|
GLCHECK();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int ShaderManagerCG::GetCGEffectTechniqueCount(CGeffect effect)
|
|
{
|
|
if (!effect) return NULL;
|
|
int techCount = 0;
|
|
for (CGtechnique currTech = cgGetFirstTechnique(effect); currTech != NULL; currTech = cgGetNextTechnique(currTech), ++ techCount)
|
|
{
|
|
}
|
|
return techCount;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
___ _ _ __ __
|
|
|_ _|_ __ ___| |_ _ __| | ___ | \/ | __ _ _ __ __ _ __ _ ___ _ __
|
|
| || '_ \ / __| | | | |/ _` |/ _ \ | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
|
| || | | | (__| | |_| | (_| | __/ | | | | (_| | | | | (_| | (_| | __/ |
|
|
|___|_| |_|\___|_|\__,_|\__,_|\___| |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
|
|___/
|
|
***************************************************************************/
|
|
#if DIRECT3D_VERSION>=0x0900
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//HRESULT
|
|
//ShaderManagerCG::IncludeManager
|
|
//::Open(D3DXINCLUDE_TYPE IncludeType, LPCSTR pName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes)
|
|
//{
|
|
//
|
|
// bool foundError = TRUE;
|
|
// do {
|
|
//
|
|
// XString includeFileName( pName );
|
|
// CKERROR err = m_ShaderManager->m_Context->GetPathManager()->ResolveFileName( includeFileName, DATA_PATH_IDX );
|
|
// if( err!=CK_OK ){
|
|
// m_ShaderManager->m_Context->GetPathManager()->ResolveFileName( includeFileName, BITMAP_PATH_IDX );
|
|
// if( err!=CK_OK ) break;
|
|
// }
|
|
// VxFile file;
|
|
// if( !file.Open( includeFileName.CStr() ) ) break;
|
|
//
|
|
// DWORD size = file.Size();
|
|
//
|
|
// BYTE* pData = new BYTE[size];
|
|
// if( pData == NULL ) return E_OUTOFMEMORY;
|
|
//
|
|
// file.Read( pData, size );
|
|
//
|
|
// *ppData = pData;
|
|
// *pBytes = size;
|
|
//
|
|
// foundError = FALSE;
|
|
//
|
|
// } while(0);
|
|
//
|
|
// //--- If an Error Occured
|
|
// if( foundError ){
|
|
// XString errStr = "Warning: Can't include file \"";
|
|
// errStr += pName;
|
|
// errStr += "\"";
|
|
// m_ShaderManager->m_Output.PushBack( errStr );
|
|
// return E_FAIL;
|
|
// }
|
|
// return S_OK;
|
|
//}
|
|
//
|
|
////-----------------------------------------------------------------------------
|
|
//HRESULT
|
|
//ShaderManagerCG::IncludeManager
|
|
//::Close(LPCVOID pData)
|
|
//{
|
|
// if( pData ) delete[] (BYTE*)pData;
|
|
// return S_OK;
|
|
//}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|