#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 ; iRegisterNewManager(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& ShaderManagerWrapper::GetSemanticOriginalNames() { return m_CurrentShaderManager->GetSemanticOriginalNames(); } //----------------------------------------------------------------------------- void ShaderManagerWrapper::GetSemanticDesc( int iSemIndex, XString*& oSemDesc ) { m_CurrentShaderManager->GetSemanticDesc( iSemIndex, oSemDesc ); } //----------------------------------------------------------------------------- const XClassArray& 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 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 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 &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 &output, XArray& 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 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 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 marksBufferArray; XHashTable marksSizeArray; XHashTable fxTextArray; XArray hides; XClassArray 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(seekPosSeekIdentifier(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(seekPosSeekIdentifier(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(seekPosSeekIdentifier(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::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 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;indexGetF2Marks())[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::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 ; iCStr()); 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 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 ; am_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); } }