1172 lines
33 KiB
C++
1172 lines
33 KiB
C++
#include "stdafx.h"
|
|
#include "ShaderManagerWrapper.h"
|
|
|
|
#include "mCppLib.h"
|
|
|
|
/***************************************************************************
|
|
____ _ _ __ __
|
|
/ ___|| |__ __ _ __| | ___ _ __ | \/ | __ _ _ __ __ _ __ _ ___ _ __
|
|
\___ \| '_ \ / _` |/ _` |/ _ \ '__| | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
|
___) | | | | (_| | (_| | __/ | | | | | (_| | | | | (_| | (_| | __/ |
|
|
|____/|_| |_|\__,_|\__,_|\___|_| |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
|
|___/
|
|
***************************************************************************/
|
|
|
|
//-----------------------------------------------------------------------------
|
|
ShaderManagerWrapper::ShaderManagerWrapper(CKContext *Context) :
|
|
CKShaderManager(Context,ShaderManagerGUID,"Shader Manager"),
|
|
m_PreCleared(FALSE),
|
|
m_NextCompID(1),
|
|
m_ReplacementMode( ShaderReplacementMode_RenameNew ),
|
|
m_NMOSavingMode( ShaderNMOSavingMode_SaveOnlyUsedShaders ),
|
|
m_TangentSpaceCreationMode( ShaderTSCreationMode_DontWeldTangentSpaces )
|
|
{
|
|
//--- init and load all the Shader Managers
|
|
ShaderManagerInterface* sm = NULL;
|
|
m_CurrentShaderManager = NULL;
|
|
|
|
sm = (ShaderManagerInterface*) new ShaderManager(Context);
|
|
((ShaderManager*)sm)->m_NextCompID = &m_NextCompID;
|
|
sm->m_Type = CKSM_HLSL;
|
|
m_ShaderManagerArray.PushBack(sm);
|
|
|
|
//--- Set HLSL shader manager as default shader manager
|
|
//--- if no rasterizer context are created
|
|
m_CurrentShaderManager = sm;
|
|
|
|
sm = (ShaderManagerInterface*) new ShaderManagerCG(Context);
|
|
((ShaderManagerCG*)sm)->m_NextCompID = &m_NextCompID;
|
|
sm->m_Type = CKSM_CGFX;
|
|
m_ShaderManagerArray.PushBack(sm);
|
|
|
|
m_CurrentPassCount = 0;
|
|
m_CurrentPassIndex = 0;
|
|
|
|
for (int i = 0 ; i<MaxChannelCount ; i++) {
|
|
m_PseudoChannelTexture[i] = NULL;
|
|
}
|
|
|
|
Context->RegisterNewManager(this);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
ShaderManagerWrapper::~ShaderManagerWrapper()
|
|
{
|
|
//--- Destroy all shader managers
|
|
int smNum = m_ShaderManagerArray.Size();
|
|
for (int i = 0 ; i < smNum ; i++) {
|
|
ShaderManagerInterface* smTmp = m_ShaderManagerArray[i];
|
|
switch(smTmp->m_Type)
|
|
{
|
|
case CKSM_HLSL:
|
|
delete (ShaderManager*)smTmp;
|
|
break;
|
|
case CKSM_CGFX:
|
|
delete (ShaderManagerCG*)smTmp;
|
|
break;
|
|
default:
|
|
XASSERT(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerWrapper::BeginShaders( CKRenderContext* rc )
|
|
{
|
|
PIXE("ShaderManagerWrapper::BeginShaders");
|
|
m_DefaultShader = GetDefaultShaderI();
|
|
m_CurrentShaderManager->BeginShaders(rc);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerWrapper::EndShaders( CKRenderContext* rc )
|
|
{
|
|
m_CurrentShaderManager->EndShaders(rc);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int
|
|
ShaderManagerWrapper::GetSemanticIndexFromString( XString& iStr )
|
|
{
|
|
return m_CurrentShaderManager->GetSemanticIndexFromString(iStr);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
const XClassArray<XString>&
|
|
ShaderManagerWrapper::GetSemanticOriginalNames()
|
|
{
|
|
return m_CurrentShaderManager->GetSemanticOriginalNames();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
ShaderManagerWrapper::GetSemanticDesc( int iSemIndex, XString*& oSemDesc )
|
|
{
|
|
m_CurrentShaderManager->GetSemanticDesc( iSemIndex, oSemDesc );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
const XClassArray<XString>&
|
|
ShaderManagerWrapper::GetAnnotationOriginalNames()
|
|
{
|
|
return m_CurrentShaderManager->GetAnnotationOriginalNames();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKERROR ShaderManagerWrapper::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 ShaderManagerWrapper::OnCKInit()
|
|
{
|
|
|
|
//--- 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.");
|
|
|
|
//--- Render Options Used in PostClearAll
|
|
m_RenderOptionsBeforePlay = CK_RENDER_USECURRENTSETTINGS;
|
|
|
|
|
|
int smNum = m_ShaderManagerArray.Size();
|
|
for (int i = 0 ; i < smNum ; i++) {
|
|
m_ShaderManagerArray[i]->OnCKInit();
|
|
}
|
|
|
|
|
|
return CK_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKERROR ShaderManagerWrapper::OnRasterizerEvent(CKRST_EVENTS Event, CKRenderContext* rc)
|
|
{
|
|
switch (Event)
|
|
{
|
|
case CKRST_EVENT_CREATE:
|
|
{ // set the current shader manager depending to current rasterizer
|
|
CKRasterizerContext* rCtx = rc->GetRasterizerContext();
|
|
|
|
if (rCtx->m_Driver->m_2DCaps.Family == CKRST_DIRECTX) {
|
|
m_CurrentShaderManager = GetShaderManagerByType(CKSM_HLSL);
|
|
}
|
|
else if (rCtx->m_Driver->m_2DCaps.Family == CKRST_OPENGL) {
|
|
m_CurrentShaderManager = GetShaderManagerByType(CKSM_CGFX);
|
|
}
|
|
|
|
for (int i =0 ; i < m_AllShaders.Size(); i++) {
|
|
((RCKShaderWrapper*)m_AllShaders[i])->m_CurrentShaderManager = m_CurrentShaderManager;
|
|
((RCKShaderWrapper*)m_AllShaders[i])->m_CurrentRCKShader = m_CurrentShaderManager->m_AllShaders[i];
|
|
}
|
|
}
|
|
m_CurrentShaderManager->OnCreateDevice(rc);
|
|
break;
|
|
case CKRST_EVENT_DESTROY:
|
|
m_CurrentShaderManager->OnDestroyDevice(rc);
|
|
break;
|
|
case CKRST_EVENT_RESIZING:
|
|
case CKRST_EVENT_LOST:
|
|
m_CurrentShaderManager->OnLostDevice(rc);
|
|
break;
|
|
case CKRST_EVENT_RESET:
|
|
m_CurrentShaderManager->OnResetDevice(rc);
|
|
break;
|
|
};
|
|
|
|
// int smNum = m_ShaderManagerArray.Size();
|
|
// for (int i = 0 ; i < smNum ; i++) {
|
|
// m_ShaderManagerArray[i]->OnRasterizerEvent(Event, rc);
|
|
// }
|
|
|
|
return CK_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerWrapper::OnCreateDevice(CKRenderContext* rc)
|
|
{
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerWrapper::OnDestroyDevice( CKRenderContext* rc )
|
|
{
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerWrapper::OnLostDevice(CKRenderContext* rc)
|
|
{
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerWrapper::OnResetDevice(CKRenderContext* rc)
|
|
{
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKERROR ShaderManagerWrapper::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 ShaderManagerWrapper::PreClearAll()
|
|
{
|
|
|
|
CKShaderManager::PreClearAll();
|
|
|
|
for (int i = 0; i < m_AllShaders.Size(); ++i)
|
|
delete m_AllShaders[i];
|
|
m_AllShaders.Clear();
|
|
m_DefaultShader = NULL;
|
|
m_ShadowShader = NULL;
|
|
|
|
int smNum = m_ShaderManagerArray.Size();
|
|
for (int i = 0 ; i < smNum ; i++) {
|
|
m_ShaderManagerArray[i]->PreClearAll();
|
|
}
|
|
|
|
CKERROR err = CKShaderManager::PreClearAll();
|
|
m_PreCleared = TRUE;
|
|
return err;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKERROR ShaderManagerWrapper::PostClearAll()
|
|
{
|
|
m_PreCleared = FALSE;
|
|
m_RenderOptionsBeforePlay = CK_RENDER_USECURRENTSETTINGS;
|
|
|
|
int smNum = m_ShaderManagerArray.Size();
|
|
for (int i = 0 ; i < smNum ; i++) {
|
|
m_ShaderManagerArray[i]->PostClearAll();
|
|
}
|
|
|
|
return CK_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKShader* ShaderManagerWrapper::CreateShader(
|
|
const XString* name, const XString* text, BOOL uniqueName )
|
|
{
|
|
int smNum = m_ShaderManagerArray.Size();
|
|
XArray<WCKShader> CKShaderArray;
|
|
|
|
for (int i = 0 ; i < smNum ; i++) {
|
|
WCKShader wShader;
|
|
if (m_CurrentShaderManager == m_ShaderManagerArray[i])
|
|
wShader.shader = m_ShaderManagerArray[i]->CreateShader(name, text, FALSE);
|
|
else
|
|
wShader.shader = m_ShaderManagerArray[i]->CreateShader(name, &XString(""), FALSE);
|
|
wShader.type = m_ShaderManagerArray[i]->m_Type;
|
|
CKShaderArray.PushBack(wShader);
|
|
}
|
|
|
|
RCKShaderWrapper* fx = new RCKShaderWrapper(this, CKShaderArray);
|
|
|
|
//--- 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 );
|
|
|
|
m_AllShaders.PushBack(fx);
|
|
return fx;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKShader* ShaderManagerWrapper::CreateShaderFromFiles(const CKSTRING HLSLfilename, const CKSTRING CgFXfilename)
|
|
{
|
|
VxFile f;
|
|
|
|
ShaderManagerInterface** begin = m_ShaderManagerArray.Begin();
|
|
ShaderManagerInterface** end = m_ShaderManagerArray.End();
|
|
XArray<WCKShader> CKShaderArray;
|
|
|
|
RCKShaderWrapper* fx = NULL;
|
|
|
|
XString name;
|
|
XString HLSLtext;
|
|
XString CgFXtext;
|
|
XString* text;
|
|
CKBOOL isLoaded = FALSE;
|
|
|
|
while(begin != end) {
|
|
|
|
CKSTRING filename = NULL;
|
|
text = NULL;
|
|
|
|
if( ((*begin)->m_Type == CKSM_HLSL)) {
|
|
filename = HLSLfilename;
|
|
text = &HLSLtext;
|
|
}
|
|
else {
|
|
filename = CgFXfilename;
|
|
text = &CgFXtext;
|
|
}
|
|
|
|
if (filename && f.Open(filename, VxFile::READONLY))
|
|
{
|
|
isLoaded = TRUE;
|
|
|
|
int size = f.Size();
|
|
text->Resize( size );
|
|
int readCount = f.Read( text->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;
|
|
|
|
if (start < end && end != 0)
|
|
{
|
|
if (start)
|
|
start++;
|
|
name.Resize(end - start);
|
|
strncpy(name.Str(), &filename[start], end - start);
|
|
}
|
|
else
|
|
// We take the name of the first(HLSL) Shader
|
|
if (name.Length() == 0)
|
|
name = filename;
|
|
}
|
|
|
|
++begin;
|
|
}
|
|
|
|
if (isLoaded) {
|
|
begin = m_ShaderManagerArray.Begin();
|
|
while(begin != end) {
|
|
text = NULL;
|
|
if( ((*begin)->m_Type == CKSM_HLSL))
|
|
text = &HLSLtext/*.Length() ? &HLSLtext : NULL*/;
|
|
else
|
|
text = &CgFXtext/*.Length() ? &CgFXtext : NULL*/;
|
|
|
|
WCKShader wShader;
|
|
wShader.shader = (*begin)->CreateShader(&name, text, FALSE);
|
|
wShader.type = (*begin)->m_Type;
|
|
CKShaderArray.PushBack(wShader);
|
|
|
|
++begin;
|
|
}
|
|
fx = new RCKShaderWrapper(this, CKShaderArray);
|
|
fx->SetName( name );
|
|
m_AllShaders.PushBack(fx);
|
|
}
|
|
|
|
return fx;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKShader* ShaderManagerWrapper::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 ShaderManagerWrapper::SaveShaderToFile(const XString& filename, CKShader* fx)
|
|
{
|
|
return _WriteStringToFile(filename, fx->GetText()) ? true:false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKBOOL ShaderManagerWrapper::IsSupported() const
|
|
{
|
|
return m_CurrentShaderManager->IsSupported();
|
|
}
|
|
|
|
CKBOOL ShaderManagerWrapper::IsSupportedAndWarnIfNot()
|
|
{
|
|
const CKBOOL isSupported = IsSupported();
|
|
if( !isSupported ){
|
|
m_Output.PushBack("Rasterizer does not support Shaders");
|
|
}
|
|
return isSupported;
|
|
}
|
|
|
|
CKBOOL ShaderManagerWrapper::IsPreCleared() const
|
|
{
|
|
return m_PreCleared;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerWrapper::GetVSPSVersion(float& vs, float& ps) const
|
|
{
|
|
m_CurrentShaderManager->GetVSPSVersion(vs, ps);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKShader* ShaderManagerWrapper::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 ShaderManagerWrapper::GetNumShaders() const
|
|
{
|
|
return m_AllShaders.Size();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKShader* ShaderManagerWrapper::GetShader(int pos)
|
|
{
|
|
return m_AllShaders[pos];
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerWrapper::DeleteShader(CKShader* fx)
|
|
{
|
|
XASSERT(fx);
|
|
m_AllShaders.Remove(fx);
|
|
|
|
RCKShaderWrapper* fxw = (RCKShaderWrapper*)fx;
|
|
WCKShader* begin = fxw->m_WCKShaderArray.Begin();
|
|
WCKShader* end = fxw->m_WCKShaderArray.End();
|
|
|
|
while (begin != end) {
|
|
GetShaderManagerByType(begin->type)->DeleteShader(begin->shader);
|
|
++begin;
|
|
}
|
|
fxw->m_WCKShaderArray.Clear();
|
|
|
|
|
|
if (fx == m_DefaultShader)
|
|
m_DefaultShader = NULL;
|
|
delete fx;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool ShaderManagerWrapper::CompileShader(CKShader* fx, XClassArray<XString> &output)
|
|
{
|
|
RCKShaderWrapper& wfx = *(RCKShaderWrapper*)fx;
|
|
CKShader* cfx = wfx.m_CurrentRCKShader;
|
|
return m_CurrentShaderManager->CompileShader(cfx, output);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool ShaderManagerWrapper::CompileShaderOutput(CKShader* fx, const CKSTRING funcname,
|
|
const CKSTRING target, XClassArray<XString> &output, XArray<char>& text)
|
|
{
|
|
RCKShaderWrapper& wfx = *(RCKShaderWrapper*)fx;
|
|
CKShader* cfx = wfx.m_CurrentRCKShader;
|
|
return m_CurrentShaderManager->CompileShaderOutput(cfx, funcname, target, output, text);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKShader* ShaderManagerWrapper::GetDefaultShader()
|
|
{
|
|
return GetDefaultShaderI();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKShader* ShaderManagerWrapper::NewBuiltInShader(const char *name, CKShader *(ShaderManagerInterface::*buildFun) ())
|
|
{
|
|
int smNum = m_ShaderManagerArray.Size();
|
|
XArray<WCKShader> CKShaderArray;
|
|
|
|
for (int i = 0 ; i < smNum ; i++) {
|
|
WCKShader wShader;
|
|
wShader.shader = (m_ShaderManagerArray[i]->*buildFun)();
|
|
wShader.type = m_ShaderManagerArray[i]->m_Type;
|
|
CKShaderArray.PushBack(wShader);
|
|
}
|
|
|
|
CKShader *shader = new RCKShaderWrapper(this,CKShaderArray);
|
|
shader->SetName(name);
|
|
m_AllShaders.PushBack(shader);
|
|
return shader;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKShader* ShaderManagerWrapper::GetDefaultShaderI()
|
|
{
|
|
if( !m_DefaultShader )
|
|
{
|
|
m_DefaultShader = NewBuiltInShader( "- default -" , &ShaderManagerInterface::GetDefaultShaderI);
|
|
}
|
|
return m_DefaultShader;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKShader* ShaderManagerWrapper::GetShadowShader()
|
|
{
|
|
if( !m_ShadowShader )
|
|
{
|
|
m_ShadowShader = NewBuiltInShader( "- builtin shadows -" , &ShaderManagerInterface::GetShadowShader);
|
|
}
|
|
return m_ShadowShader;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CKERROR ShaderManagerWrapper::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();
|
|
|
|
CK_SHADER_MANAGER_TYPE sType;
|
|
bool needToExit = false;
|
|
|
|
BOOL shaderMustBeCreated = TRUE;
|
|
|
|
XHashTable<int*, CK_SHADER_MANAGER_TYPE> marksBufferArray;
|
|
XHashTable<int, CK_SHADER_MANAGER_TYPE> marksSizeArray;
|
|
XHashTable<XString, CK_SHADER_MANAGER_TYPE> fxTextArray;
|
|
|
|
XArray<int> hides;
|
|
XClassArray<XString> protects;
|
|
|
|
int hide = -1; XString protect;
|
|
|
|
int seekPos = -1;
|
|
|
|
//--- Retrieves all text version of a shader
|
|
do{
|
|
int* marksBuffer = NULL;
|
|
int marksSize = 0;
|
|
|
|
XString fxText = chunk->ReadString();
|
|
|
|
if (fxText.Compare("HLSL") == 0){
|
|
|
|
int currentPos = chunk->GetCurrentPos();
|
|
if(seekPos<currentPos+2)
|
|
{
|
|
if(chunk->SeekIdentifier(HideChunkID))
|
|
seekPos = chunk->GetCurrentPos();
|
|
}
|
|
|
|
if(seekPos==currentPos+2) {
|
|
chunk->Goto(seekPos);
|
|
hide = chunk->ReadInt();
|
|
protect = chunk->ReadString();
|
|
hides.PushBack(hide);
|
|
protects.PushBack(protect);
|
|
}
|
|
else {
|
|
chunk->Goto(currentPos);
|
|
hides.PushBack(-1);
|
|
protects.PushBack("");
|
|
}
|
|
|
|
sType = CKSM_HLSL;
|
|
fxText = chunk->ReadString();
|
|
fxTextArray.Insert(sType, fxText);
|
|
}
|
|
else if (fxText.Compare("CGFX") == 0){
|
|
|
|
int currentPos = chunk->GetCurrentPos();
|
|
if(seekPos<currentPos+2)
|
|
{
|
|
if(chunk->SeekIdentifier(HideChunkID))
|
|
seekPos = chunk->GetCurrentPos();
|
|
}
|
|
|
|
if(seekPos==currentPos+2) {
|
|
chunk->Goto(seekPos);
|
|
hide = chunk->ReadInt();
|
|
protect = chunk->ReadString();
|
|
hides.PushBack(hide);
|
|
protects.PushBack(protect);
|
|
}
|
|
else {
|
|
chunk->Goto(currentPos);
|
|
hides.PushBack(-1);
|
|
protects.PushBack("");
|
|
}
|
|
|
|
sType = CKSM_CGFX;
|
|
fxText = chunk->ReadString();
|
|
fxTextArray.Insert(sType, fxText);
|
|
}
|
|
else if (fxText.Compare("_END_") == 0){
|
|
needToExit = true;
|
|
break;
|
|
}
|
|
else { //--- pre Dev 4.0 (only HLSL)
|
|
|
|
int currentPos = chunk->GetCurrentPos();
|
|
if(seekPos<currentPos+2)
|
|
{
|
|
if(chunk->SeekIdentifier(HideChunkID))
|
|
seekPos = chunk->GetCurrentPos();
|
|
}
|
|
|
|
if(seekPos==currentPos+2) {
|
|
chunk->Goto(seekPos);
|
|
hide = chunk->ReadInt();
|
|
protect = chunk->ReadString();
|
|
hides.PushBack(hide);
|
|
protects.PushBack(protect);
|
|
}
|
|
else {
|
|
chunk->Goto(currentPos);
|
|
hides.PushBack(-1);
|
|
protects.PushBack("");
|
|
}
|
|
|
|
sType = CKSM_HLSL;
|
|
fxTextArray.Insert(sType, fxText);
|
|
needToExit = true;
|
|
}
|
|
|
|
// Read Marks
|
|
if (version>=3) {
|
|
marksSize = chunk->ReadBuffer((void**)&marksBuffer) / sizeof(int);
|
|
marksBufferArray.Insert(sType, marksBuffer);
|
|
marksSizeArray.Insert(sType, marksSize);
|
|
}
|
|
|
|
} while (needToExit == false);
|
|
|
|
XHashTable<XString, CK_SHADER_MANAGER_TYPE>::Iterator It = fxTextArray.Begin();
|
|
|
|
//--- Test if the shader already exist
|
|
CKShader* sameNameEffect;
|
|
int extCount = 0;
|
|
while( (sameNameEffect=GetShaderByName( fxName )) && shaderMustBeCreated ){
|
|
|
|
//--- Skip this effect if all text are the same
|
|
CKBOOL sameText = TRUE;
|
|
while(It != fxTextArray.End())
|
|
{
|
|
if( (*It).Compare( sameNameEffect->GetText(It.GetKey()) ) ){
|
|
sameText = FALSE;
|
|
}
|
|
++It;
|
|
}
|
|
if (sameText) {
|
|
shaderMustBeCreated = FALSE;
|
|
break;
|
|
}
|
|
|
|
//--- Otherwise ...
|
|
switch( m_ReplacementMode ){
|
|
|
|
case ShaderReplacementMode_ReplaceOldByNew:
|
|
|
|
//--- Replace Old Shader By New Shader
|
|
{
|
|
It = fxTextArray.Begin();
|
|
int count = 0;
|
|
while(It != fxTextArray.End()) {
|
|
if(hides.Size()>count) {
|
|
if(hides[count]!=-1) {
|
|
CKProtectable* protectable = sameNameEffect->GetProtectable();
|
|
if (protectable) protectable->ReadProtectable(&hides[count], &protects[count]);
|
|
}
|
|
}
|
|
sameNameEffect->SetText( *It, It.GetKey() );
|
|
++It;
|
|
++count;
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
|
|
//--- Create new shader
|
|
if( shaderMustBeCreated ) {
|
|
XArray<WCKShader> CKShaderArray;
|
|
|
|
for (int i = 0 ; i < m_ShaderManagerArray.Size() ; i++)
|
|
{
|
|
WCKShader wShader;
|
|
wShader.type = m_ShaderManagerArray[i]->m_Type;
|
|
XString* sText = &fxTextArray[wShader.type]/*.Length() ? &fxTextArray[wShader.type] : NULL*/;
|
|
wShader.shader = m_ShaderManagerArray[i]->CreateShader(&fxName, sText, FALSE);
|
|
CKShaderArray.PushBack(wShader);
|
|
// Read Marks
|
|
#ifndef VIRTOOLS_RUNTIME_VERSION
|
|
wShader.shader->GetF2Marks()->Resize(marksSizeArray[wShader.type]);
|
|
for (int index=0;index<marksSizeArray[wShader.type];++index)
|
|
(*wShader.shader->GetF2Marks())[index]=marksBufferArray[wShader.type][index];
|
|
#endif
|
|
|
|
if(hides.Size()>i) {
|
|
if(hides[i]!=-1) {
|
|
CKProtectable* protectable = wShader.shader->GetProtectable();
|
|
if (protectable) protectable->ReadProtectable(&hides[i], &protects[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
RCKShaderWrapper* fx = new RCKShaderWrapper(this,CKShaderArray);
|
|
fx->SetName( fxName );
|
|
|
|
m_AllShaders.PushBack( fx );
|
|
toBeCompiledShaders.PushBack( fx );
|
|
}
|
|
|
|
//--- Delete F2Marks buffers
|
|
XHashTable<int*, CK_SHADER_MANAGER_TYPE>::Iterator ItBuff = marksBufferArray.Begin();
|
|
while (ItBuff != marksBufferArray.End()) {
|
|
if (*ItBuff)
|
|
CKDeletePointer(*ItBuff);
|
|
++ItBuff;
|
|
}
|
|
|
|
}
|
|
|
|
//--- 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* ShaderManagerWrapper::SaveData(CKFile* SavedFile)
|
|
{
|
|
assert(SavedFile != 0);
|
|
|
|
// count number of shader to save (do not include shadow and default shader)
|
|
int toSaveCount = 0;
|
|
for (int shIndex = 0; shIndex < m_AllShaders.Size(); ++shIndex)
|
|
{
|
|
if (m_AllShaders[shIndex] != m_DefaultShader &&
|
|
m_AllShaders[shIndex] != m_ShadowShader &&
|
|
m_AllShaders[shIndex]->GetSaveFlag()
|
|
)
|
|
{
|
|
++ 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
|
|
if( shader == m_DefaultShader ) continue;
|
|
if( shader == m_ShadowShader ) continue;
|
|
if (!shader->GetSaveFlag()) 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
|
|
if(m_SavePreProcessed){
|
|
|
|
XString PreProcessed;
|
|
XString PreProcErr;
|
|
#pragma todo ("Handle preprocess while saving")
|
|
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( shader->GetText().CStr());
|
|
RCKShaderWrapper* sw = (RCKShaderWrapper*)shader;
|
|
CKShader* shader = NULL;
|
|
for (int i = 0 ; i < sw->m_WCKShaderArray.Size() ; i++) {
|
|
switch(sw->m_WCKShaderArray[i].type) {
|
|
case CKSM_HLSL:
|
|
chunk->WriteString("HLSL");
|
|
break;
|
|
case CKSM_CGFX:
|
|
chunk->WriteString("CGFX");
|
|
break;
|
|
default:
|
|
XASSERT(sw->m_WCKShaderArray[i].type == CKSM_HLSL || sw->m_WCKShaderArray[i].type == CKSM_CGFX);
|
|
break;
|
|
}
|
|
shader = sw->m_WCKShaderArray[i].shader;
|
|
|
|
CKProtectable* protectable = shader->GetProtectable();
|
|
|
|
if(protectable->GetHideFlag()) {
|
|
chunk->WriteIdentifier(HideChunkID);
|
|
int hide; XString protect;
|
|
protectable->ReadProtectable(&hide, &protect);
|
|
chunk->WriteInt(hide);
|
|
chunk->WriteString(protect.CStr());
|
|
}
|
|
|
|
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_");
|
|
}
|
|
}else
|
|
#endif // _XBOX
|
|
{
|
|
RCKShaderWrapper* sw = (RCKShaderWrapper*)shader;
|
|
CKShader* shader = NULL;
|
|
for (int i = 0 ; i < sw->m_WCKShaderArray.Size() ; i++) {
|
|
switch(sw->m_WCKShaderArray[i].type) {
|
|
case CKSM_HLSL:
|
|
chunk->WriteString("HLSL");
|
|
break;
|
|
case CKSM_CGFX:
|
|
chunk->WriteString("CGFX");
|
|
break;
|
|
default:
|
|
XASSERT(sw->m_WCKShaderArray[i].type == CKSM_HLSL || sw->m_WCKShaderArray[i].type == CKSM_CGFX);
|
|
break;
|
|
}
|
|
shader = sw->m_WCKShaderArray[i].shader;
|
|
|
|
CKProtectable* protectable = shader->GetProtectable();
|
|
|
|
if(protectable->GetHideFlag()) {
|
|
int currentPost = chunk->GetCurrentPos();
|
|
chunk->WriteIdentifier(HideChunkID);
|
|
int hide; XString protect;
|
|
protectable->WriteProtectable(&hide, &protect);
|
|
chunk->WriteInt(hide);
|
|
chunk->WriteString(protect.CStr());
|
|
}
|
|
|
|
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 ShaderManagerWrapper::_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;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
Summary: Called when a RenderContext gets created or destroyed
|
|
to update the Shader Manager's inner list of render contexts
|
|
*******************************************************************/
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerWrapper::OnRenderContextCreated( CKRenderContext* rc )
|
|
{
|
|
int smNum = m_ShaderManagerArray.Size();
|
|
for (int i = 0 ; i < smNum ; i++) {
|
|
m_ShaderManagerArray[i]->OnRenderContextCreated(rc);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void ShaderManagerWrapper::OnRenderContextDestroyed( CKRenderContext* rc )
|
|
{
|
|
int smNum = m_ShaderManagerArray.Size();
|
|
for (int i = 0 ; i < smNum ; i++) {
|
|
m_ShaderManagerArray[i]->OnRenderContextDestroyed(rc);
|
|
}
|
|
}
|
|
|