#include "stdafx.h" #include "ShaderManager.h" #ifdef XBOX1 #include "default_fxDX8.cpp" #else #include "default_fx.cpp" #endif #include "shadow_fx.cpp" #ifndef _XBOX #if defined(MULTIPLESHADERMANAGER) unsigned int mCppLib_PreProcess(const XString& xsIn,const char *opt,XString& xsOut,XString& PreProcErr); BOOL DoWinExec(const XString& command); #else #include "mCppLib.h" #endif #endif /*************************************************************************** ____ _ _ __ __ / ___|| |__ __ _ __| | ___ _ __ | \/ | __ _ _ __ __ _ __ _ ___ _ __ \___ \| '_ \ / _` |/ _` |/ _ \ '__| | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__| ___) | | | | (_| | (_| | __/ | | | | | (_| | | | | (_| | (_| | __/ | |____/|_| |_|\__,_|\__,_|\___|_| |_| |_|\__,_|_| |_|\__,_|\__, |\___|_| |___/ ***************************************************************************/ //----------------------------------------------------------------------------- ShaderManager::ShaderManager(CKContext *Context) : #if defined(MULTIPLESHADERMANAGER) ShaderManagerInterface(Context), m_NextCompID(NULL), #else CKShaderManager(Context,ShaderManagerGUID,"Shader Manager"), m_NextCompID(1), #endif #if DIRECT3D_VERSION>=0x0900 m_Pool(0), #endif m_ReplacementMode( ShaderReplacementMode_RenameNew ), m_NMOSavingMode( ShaderNMOSavingMode_SaveOnlyUsedShaders ), m_TangentSpaceCreationMode( ShaderTSCreationMode_DontWeldTangentSpaces ) { #if !defined(MULTIPLESHADERMANAGER) Context->RegisterNewManager(this); #endif #ifndef _XBOX 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 += "\\fxc.exe"; #endif m_CurrentPassCount = 0; m_CurrentPassIndex = 0; for (int i = 0 ; i=0x0900 if (m_Pool) { m_Pool->Release(); m_Pool = NULL; } #endif } //----------------------------------------------------------------------------- void ShaderManager::BeginShaders( CKRenderContext* rc ) { PIXE_RENDER_L2("ShaderManager::BeginShaders"); XASSERT(IsSupported()); // Tell the rasterizer context we're in shader mode rc->GetRasterizerContext()->m_ShaderInUse = TRUE; m_DefaultShader = GetDefaultShaderI(); m_DefaultShader->Begin( rc ); m_DefaultShader->BeginPass( 0, rc ); m_DefaultShader->EndPass(rc ); } //----------------------------------------------------------------------------- void ShaderManager::EndShaders( CKRenderContext* rc ) { m_DefaultShader->End( rc ); //--- Flush Rasterizer Cache to make sure all states are reset CKRasterizerContext* rstc = rc->GetRasterizerContext(); if( !rstc ) return; // Tell the rasterizer context we're in not shader mode rc->GetRasterizerContext()->m_ShaderInUse = FALSE; rstc->FlushCaches(); rstc->DisableAllTextureStages(); #if defined(_XBOX) #if _XBOX_VER<200 D3DDevice::SetVertexShaderInputDirect(NULL,0,NULL); D3DDevice::SetVertexShader(D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_NORMAL|D3DFVF_TEX0); D3DDevice::SetPixelShader(NULL); #else rstc->SetTexture(0,0); rstc->SetTexture(0,1); rstc->SetTexture(0,2); rstc->SetTexture(0,3); rstc->SetTexture(0,4); rstc->SetTexture(0,5); rstc->SetTexture(0,6); rstc->SetTexture(0,7); #endif #endif } //----------------------------------------------------------------------------- #if DIRECT3D_VERSION<0x0900 int ShaderManager::GetSemanticIndexFromFourCC( DWORD iFcc) { return m_ShaderDescriptorManager.GetSemanticIndexFromFourCC( iFcc ); } #else int ShaderManager::GetSemanticIndexFromString( XString& iStr ) { return m_ShaderDescriptorManager.GetSemanticIndexFromString( iStr ); } #endif //----------------------------------------------------------------------------- const XClassArray& ShaderManager::GetSemanticOriginalNames() { return m_ShaderDescriptorManager.GetSemanticOriginalNames(); } //----------------------------------------------------------------------------- void ShaderManager::GetSemanticDesc( int iSemIndex, XString*& oSemDesc ) { m_ShaderDescriptorManager.GetSemanticDesc( iSemIndex, oSemDesc ); } //----------------------------------------------------------------------------- #if DIRECT3D_VERSION>=0x0900 const XClassArray& ShaderManager::GetAnnotationOriginalNames() { return m_ShaderDescriptorManager.GetAnnotationOriginalNames(); } #endif //----------------------------------------------------------------------------- CKERROR ShaderManager::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 ShaderManager::OnCKInit() { #if DIRECT3D_VERSION>=0x0900 D3DXCreateEffectPool(&m_Pool); m_IncludeManager.Init( this ); #endif #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 ShaderManager 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 ShaderDescriptor m_ShaderDescriptorManager.Init( m_Context ); return CK_OK; } //----------------------------------------------------------------------------- CKERROR ShaderManager::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; } //----------------------------------------------------------------------------- void ShaderManager::OnCreateDevice(CKRenderContext* rc) { //--- Compile all shaders for all devices int rcIndex = _GetRenderContextIndex(rc); XASSERT( rcIndex>=0 ); const int shaderCount = m_AllShaders.Size(); for( int a=0 ; a=0 ); const int shaderCount = m_AllShaders.Size(); for( int a=0 ; a& dxEffectArray = shader->m_DXEffect; ID3DXEffect*& dxEffect = dxEffectArray[rcIndex]; if( !dxEffect ) continue; dxEffect->Release(); dxEffect = NULL; } } //----------------------------------------------------------------------------- void ShaderManager::OnLostDevice(CKRenderContext* rc) { #ifndef _XBOX int rcIndex = _GetRenderContextIndex(rc); XASSERT( rcIndex>=0 ); for (int i = 0; i < m_AllShaders.Size(); ++i){ if (((RCKShader*)m_AllShaders[i])->m_DXEffect[rcIndex]) { HRESULT hr = ((RCKShader*)m_AllShaders[i])->m_DXEffect[rcIndex]->OnLostDevice(); XASSERT(SUCCEEDED(hr)); } } #endif // _XBOX } //----------------------------------------------------------------------------- void ShaderManager::OnResetDevice(CKRenderContext* rc) { #ifndef _XBOX int rcIndex = _GetRenderContextIndex(rc); XASSERT( rcIndex>=0 ); for (int i = 0; i < m_AllShaders.Size(); ++i){ if (((RCKShader*)m_AllShaders[i])->m_DXEffect[rcIndex]) { HRESULT hr = ((RCKShader*)m_AllShaders[i])->m_DXEffect[rcIndex]->OnResetDevice(); XASSERT(SUCCEEDED(hr)); } } #endif } //----------------------------------------------------------------------------- CKERROR ShaderManager::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 ShaderManager::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; #if DIRECT3D_VERSION>=0x0900 if (m_Pool) { m_Pool->Release(); m_Pool = NULL; } #endif // _XBOX //--- Clear Exposed Parameters Management Arrays m_hashParamIndex.Clear(); const int rcCount = m_paramMeaningLinker.Size(); for( int rcIndex=0 ; rcIndex=0x0900 D3DXCreateEffectPool(&m_Pool); #endif // _XBOX return CK_OK; } //----------------------------------------------------------------------------- CKShader* ShaderManager::CreateShader( const XString* name, const XString* text, BOOL uniqueName ) { RCKShader* fx = new RCKShader(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* ShaderManager::CreateShaderFromFiles(const CKSTRING HLSLfilename, const CKSTRING CgFXfilename) { if (HLSLfilename != NULL) return CreateShaderFromFile(HLSLfilename); else return CreateShaderFromFile(CgFXfilename); } //----------------------------------------------------------------------------- CKShader* ShaderManager::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 ShaderManager::SaveShaderToFile(const XString& filename, CKShader* fx) { #ifndef _XBOX return _WriteStringToFile(filename, fx->GetText()) ? true:false; #else return false; #endif // _XBOX } //----------------------------------------------------------------------------- CKBOOL ShaderManager::IsSupported() const { #ifdef _XBOX return TRUE; #else CKRenderManager* rm = m_Context->GetRenderManager(); if( rm ){ CKRenderContext* rc = rm->GetRenderContext(0); if( rc ){ VxDirectXData* dx = rc->GetDirectXInfo(); // Check Direct X Version if (dx && dx->DxVersion >= 0x0900) return TRUE; } } return FALSE; #endif } CKBOOL ShaderManager::IsSupportedAndWarnIfNot() { const CKBOOL isSupported = IsSupported(); if( !isSupported ){ m_Output.PushBack("Rasterizer does not support Shaders (use DirectX 9 or better)"); } return isSupported; } //----------------------------------------------------------------------------- void ShaderManager::GetVSPSVersion(float& vs, float& ps) const { CKRenderManager* rm = m_Context->GetRenderManager(); CKRenderContext* rc = rm->GetRenderContext(0); VxDirectXData* dx = rc->GetDirectXInfo(); // Check Direct X Version #if DIRECT3D_VERSION<0x0900 #define Direct3DDevice IDirect3DDevice8 #define D3DCAPS D3DCAPS8 #else #define Direct3DDevice IDirect3DDevice9 #define D3DCAPS D3DCAPS9 #endif // When compiling for XBox DIRECT3D_VERSION will be 0x0800, for D3D9 0x0900 // if (dx && dx->DxVersion >= DIRECT3D_VERSION) { D3DCAPS caps; ((Direct3DDevice*)dx->D3DDevice)->GetDeviceCaps(&caps); DWORD Major = (caps.VertexShaderVersion & 0xFF00) >> 8; DWORD Minor = (caps.VertexShaderVersion & 0xFF); if (Minor <= 10) Minor *= 10; vs = (float)Major + (float)Minor * 0.01f; Major = (caps.PixelShaderVersion & 0xFF00) >> 8; Minor = (caps.PixelShaderVersion & 0xFF); if (Minor <= 10) Minor *= 10; ps = (float)Major + (float)Minor * 0.01f; } } //----------------------------------------------------------------------------- CKShader* ShaderManager::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 ShaderManager::GetNumShaders() const { return m_AllShaders.Size(); } //----------------------------------------------------------------------------- CKShader* ShaderManager::GetShader(int pos) { return m_AllShaders[pos]; } //----------------------------------------------------------------------------- void ShaderManager::DeleteShader(CKShader* fx) { m_AllShaders.Remove(fx); if (fx == m_DefaultShader) m_DefaultShader = NULL; delete fx; } //----------------------------------------------------------------------------- bool ShaderManager::CompileShader(CKShader* fx, XClassArray &output) { RCKShader& rfx = *(RCKShader*)fx; //CKRenderManager* rm = m_Context->GetRenderManager(); // Check Direct X Version //--- We must compile for all created render context const int rcCount = m_rcList.Size(); for( int rcIndex=0 ; rcIndexGetDirectXInfo(); #ifndef _XBOX if( !dx || dx->DxVersion<0x0900 ) return FALSE; #endif ID3DXBuffer* Error = NULL; const XString& Text = rfx.GetTextInternal(); ID3DXEffect* oldfx = rfx.m_DXEffect[rcIndex]; // Creates a simple Shader #if DIRECT3D_VERSION>=0x0900 XASSERT(m_Pool != NULL); #endif int drvidx = rc->GetDriverIndex(); CKRenderManager *rman = rc->GetCKContext()->GetRenderManager(); VxDriverDesc* desc = rman->GetRenderDriverDescription(drvidx); #if DIRECT3D_VERSION<0x0900 ID3DXBuffer* compiledEffect = NULL; HRESULT hr = E_FAIL; try{ hr = D3DXCompileEffect(Text.CStr(), Text.Length(),&compiledEffect,&Error); } catch(...){ } if(hr == D3D_OK){ hr = D3DXCreateEffect((IDirect3DDevice8*)dx->D3DDevice, compiledEffect->GetBufferPointer(),compiledEffect->GetBufferSize(),0, &rfx.m_DXEffect[rcIndex]); } if(compiledEffect) compiledEffect->Release(); #else DWORD flags = (desc->IsHardware) ? 0 : D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION; HRESULT hr; //--- For Hardware Support if(flags){ #ifndef _XBOX #if _MSC_VER >= 1400 // 1310 = Visual Studio 7.1 1400 = Visual Studio 8 flags |= D3DXSHADER_USE_LEGACY_D3DX9_31_DLL; #endif #endif XString tmp = VxGetTempPath(); tmp<< fx->GetName(); tmp << ".fx"; VxFile vf; vf.Open(tmp.CStr(),VxFile::WRITEONLY); vf.Write(Text.CStr(), Text.Length()); vf.Close(); hr = D3DXCreateEffectFromFile( (IDirect3DDevice9*)dx->D3DDevice,tmp.CStr(),NULL, &m_IncludeManager, flags, m_Pool, &rfx.m_DXEffect[rcIndex], &Error ); }else { #ifndef _XBOX #if _MSC_VER >= 1400 // 1310 = Visual Studio 7.1 1400 = Visual Studio 8 flags |= D3DXSHADER_USE_LEGACY_D3DX9_31_DLL; #endif #endif hr = D3DXCreateEffect( (IDirect3DDevice9*)dx->D3DDevice, Text.CStr(), Text.Length(), NULL, &m_IncludeManager, flags, m_Pool, &rfx.m_DXEffect[rcIndex], &Error); } #endif if (Error != NULL){ XStringTokenizer tokizer((char*)Error->GetBufferPointer(), "\n"); const char *tok = NULL; while ((tok = tokizer.NextToken(tok)) != NULL) output.PushBack(rfx.GetName() + XString(tok)); Error->Release(); } //--- Replace the old Shader with the new one if (FAILED(hr)){ rfx.m_DXEffect[rcIndex] = oldfx; output.PushBack(rfx.GetName() + ": Shader compilation failed."); } else { //--- Init the Shader Descriptor for this Shader if( fx != m_DefaultShader ){ rfx.m_ShaderDescriptor[rcIndex]->Init( &m_ShaderDescriptorManager, rfx.m_DXEffect[rcIndex], rc, &rfx ); } if (oldfx) oldfx->Release(); #if defined(MULTIPLESHADERMANAGER) rfx.m_CompID = (*m_NextCompID)++; #else rfx.m_CompID = m_NextCompID++; #endif //rfx._RetrieveTechniques( rc ); //--- Output "Compilation successful" message output.PushBack(rfx.GetName() + ": Shader compilation successful."); } } return TRUE; } //----------------------------------------------------------------------------- bool ShaderManager::CompileShaderOutput(CKShader* fx, const CKSTRING funcname, const CKSTRING target, XClassArray &output, XArray& text) { #ifdef _XBOX return false; #else CKRenderManager* rm = m_Context->GetRenderManager(); CKRenderContext* rc = rm->GetRenderContext(0); VxDirectXData* dx = rc->GetDirectXInfo(); XASSERT(fx != NULL); if (!(VxFile::GetFileMode(m_FXCCommand.CStr()) & VxFile::REGULAR_FILE)) { output.PushBack("No path to fxc.exe HLSL Compiler."); return FALSE; } // Check Direct X Version if (dx && dx->DxVersion >= 0x0900) { char tmp[1024]; GetTempPath(1024, tmp); // 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; if(strcmp(target,"fx_2_0")==0){ cmd.Format("\"%s\" /nologo /Zi /T%s /Fc%s %s", m_FXCCommand.CStr(), target, outfile.CStr(), infile.CStr()); }else if(strcmp(target,"fx_2_0 No PreShader")==0){ cmd.Format("\"%s\" /nologo /Zi /Op /T%s /Fc%s %s", m_FXCCommand.CStr(), "fx_2_0", outfile.CStr(), infile.CStr()); }else{ cmd.Reserve( 1024+strlen(funcname) ); cmd.Format( "\"%s\" /nologo /Zi /T%s /E%s /Fc%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; #endif // _XBOX } //----------------------------------------------------------------------------- CKShader* ShaderManager::GetDefaultShader() { return GetDefaultShaderI(); } //----------------------------------------------------------------------------- CKShader* ShaderManager::GetDefaultShaderI() { if( !m_DefaultShader ) { m_DefaultShader = ShaderManager::CreateShader(&XString("- default -"), &XString(g_default)); CompileShader(m_DefaultShader, m_Output); } return m_DefaultShader; } //----------------------------------------------------------------------------- CKShader* ShaderManager::GetShadowShader() { if( !this->m_ShadowShader) { XString sh; // TMP TMP : load from external file for tests /*#pragma todo("remove this part when finished") FILE *f = fopen("c:\\shader\\shadow.fx", "rb"); XString sh; if (f) { for (;;) { char next; if (fread(&next, 1, 1, f) != 1) break; sh += next; } fclose(f); } else*/ { sh = g_shadow; } m_ShadowShader = ShaderManager::CreateShader(&XString("- builtin shadows -"), &sh); CompileShader(m_ShadowShader, m_Output); } return m_ShadowShader; } //----------------------------------------------------------------------------- CKERROR ShaderManager::LoadData(CKStateChunk *chunk,CKFile* LoadedFile) { //--- If the Default Shader doesn't exist GetDefaultShader will create it m_DefaultShader = GetDefaultShaderI(); XASSERT(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(); //--- Retrieves HLSL text version of a shader bool needToExit = false; int* marksBuffer = NULL; int marksSize = 0; do{ fxText = chunk->ReadString(); if (fxText.Compare("HLSL") == 0){ fxText = chunk->ReadString(); needToExit = true; } else if (fxText.Compare("CGFX") == 0){ chunk->ReadString(); fxText = ""; } else if (fxText.Compare("_END_") == 0){ fxText = ""; needToExit = true; break; } else { //--- pre Dev 4.0 (only HLSL) needToExit = true; } // 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 RCKShader* fx = new RCKShader(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;indexm_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 ; 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* ShaderManager::SaveData(CKFile* SavedFile) { XASSERT(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) { ++ 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 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; 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("HLSL"); chunk->WriteString( shader->GetText().CStr()); } }else #endif // _XBOX { chunk->WriteString("HLSL"); 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 ShaderManager::_ReadStringFromFile(const XString& filename, XArray &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 ShaderManager::_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 ShaderManager::_WinExec(const XString& command) { 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(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, 15000 ); DWORD code = 0; GetExitCodeProcess( pi.hProcess, &code ); if(code == STILL_ACTIVE){ TerminateProcess(pi.hProcess,-1); } // Close process and thread handles. CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); return code==0; } #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 ShaderManager::_RegisterExposedParameterMeaning( CKParameterLocal* p, ShaderDescriptor::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 ShaderManager::_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::Iterator it = m_hashParamIndex.Begin(); while (it != m_hashParamIndex.End()) { if( *it > paramIndex ){ --(*it); } ++it; } m_hashParamIndex.Remove( p ); } //----------------------------------------------------------------------------- void ShaderManager::_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( (ShaderDescriptor::ExposedParamMeaning*)0 ); } //----------------------------------------------------------------------------- void ShaderManager::_RemoveRCForExposedParameters( int rcIndex ) { //--- Remove the rc ///// Note: as it's a class array, it will remove also all d3dhandles fo the rc m_paramMeaningLinker.RemoveAt( rcIndex ); } //----------------------------------------------------------------------------- ShaderDescriptor::ExposedParamMeaning* ShaderManager::_GetRegisteredParamMeaning( CKParameterLocal* p, int rcIndex ) { //--- Check if parameter is registered int* paramIndexPtr = m_hashParamIndex.FindPtr(p); if( !paramIndexPtr ) return (ShaderDescriptor::ExposedParamMeaning*)(-1); int paramIndex = *paramIndexPtr; return m_paramMeaningLinker[rcIndex][paramIndex]; } //----------------------------------------------------------------------------- int ShaderManager::_GetRenderContextIndex( CKRenderContext* rc ) { const int rcCount = m_rcList.Size(); for( int a=0 ; a_AddRenderContextSlot(); } } //----------------------------------------------------------------------------- void ShaderManager::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_RemoveRenderContextSlot( rcIndex ); } //--- Remove the RC from our managed list of RCs m_rcList.Remove( rc ); } } /*************************************************************************** ___ _ _ __ __ |_ _|_ __ ___| |_ _ __| | ___ | \/ | __ _ _ __ __ _ __ _ ___ _ __ | || '_ \ / __| | | | |/ _` |/ _ \ | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__| | || | | | (__| | |_| | (_| | __/ | | | | (_| | | | | (_| | (_| | __/ | |___|_| |_|\___|_|\__,_|\__,_|\___| |_| |_|\__,_|_| |_|\__,_|\__, |\___|_| |___/ ***************************************************************************/ #if DIRECT3D_VERSION>=0x0900 //----------------------------------------------------------------------------- HRESULT ShaderManager::IncludeManager ::Open(D3DXINCLUDE_TYPE IncludeType, LPCSTR pName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes #if (_XBOX_VER>=200) ,LPSTR pFullPath,DWORD cbFullPath #endif ) { 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 ShaderManager::IncludeManager ::Close(LPCVOID pData) { if( pData ) delete[] (BYTE*)pData; return S_OK; } #endif