deargui-vpl/ref/virtools/Samples/Behaviors/Shader/Sources/ShaderManager.cpp

1480 lines
41 KiB
C++

#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<MaxChannelCount ; i++) {
m_PseudoChannelTexture[i] = NULL;
}
}
//-----------------------------------------------------------------------------
ShaderManager::~ShaderManager()
{
#if DIRECT3D_VERSION>=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<XString>&
ShaderManager::GetSemanticOriginalNames()
{
return m_ShaderDescriptorManager.GetSemanticOriginalNames();
}
//-----------------------------------------------------------------------------
void
ShaderManager::GetSemanticDesc( int iSemIndex, XString*& oSemDesc )
{
m_ShaderDescriptorManager.GetSemanticDesc( iSemIndex, oSemDesc );
}
//-----------------------------------------------------------------------------
#if DIRECT3D_VERSION>=0x0900
const XClassArray<XString>&
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<shaderCount ; ++a ){
CompileShader( m_AllShaders[a], m_Output );
}
}
//-----------------------------------------------------------------------------
void ShaderManager::OnDestroyDevice( CKRenderContext* rc )
{
int rcIndex = _GetRenderContextIndex(rc);
XASSERT( rcIndex>=0 );
const int shaderCount = m_AllShaders.Size();
for( int a=0 ; a<shaderCount ; ++a ){
RCKShader* shader = (RCKShader*)m_AllShaders[a];
if( !shader ) continue;
//--- Release d3deffect for this rcIndex
XArray<ID3DXEffect*>& 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<rcCount ; ++rcIndex ){
m_paramMeaningLinker[rcIndex].Clear();
}
#if !defined(MULTIPLESHADERMANAGER)
return CKShaderManager::PreClearAll();
#else
return CK_OK;
#endif
}
//-----------------------------------------------------------------------------
CKERROR ShaderManager::PostClearAll()
{
m_RenderOptionsBeforePlay = CK_RENDER_USECURRENTSETTINGS;
#if DIRECT3D_VERSION>=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<XString> &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 ; rcIndex<rcCount ; ++rcIndex ){
CKRenderContext* rc = m_rcList[rcIndex];
VxDirectXData* dx = rc->GetDirectXInfo();
#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<XString> &output, XArray<char>& 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<CKShader*> toBeCompiledShaders;
// Check the version
int version = chunk->ReadInt();
// Check the flags
int flags = chunk->ReadInt();
// Read Shaders
int num_Shaders = chunk->ReadInt();
int chunkid = FIRSTSHADER_CHUNKID;
for (int i = 0; i < num_Shaders; ++i)
{
CKBOOL notEndOfChunk = chunk->SeekIdentifier(chunkid);
++chunkid;
if( !notEndOfChunk ){
continue;
}
//--- If Version < 1 there's a BOOL "isDefaultFx"
if( version < 2 ){
//--- Is it the default effect then don't read content
CKBOOL isDefaultFx = chunk->ReadInt();
if( isDefaultFx ) continue;
}
//--- Read Shader Name and Text
XString fxName = chunk->ReadString();
XString fxText;// = chunk->ReadString();
//--- Retrieves 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;index<marksSize;++index)
fx->m_F2Marks[index]=marksBuffer[index];
#endif
CKDeletePointer(marksBuffer);
}
}
//--- Compile all loaded shaders
if( IsSupportedAndWarnIfNot() ){
//--- Compile every loaded Shader except the default Shader
///// as it has already been compiled (cf: just above)
const int loadedShaderCount = toBeCompiledShaders.Size();
for( int i=0 ; i<loadedShaderCount ; ++i ){
CKShader* const fx = toBeCompiledShaders[i];
if( fx == m_DefaultShader ) continue;
CompileShader( fx, m_Output );
}
#if defined(_XBOX) && defined(_DEBUG)
for(XString* it = m_Output.Begin();it!=m_Output.End();it++){
OutputDebugString(it->CStr());
OutputDebugString("\n");
}
m_Output.Clear();
#endif
}
}
chunk->CloseChunk();
return CK_OK;
}
//-----------------------------------------------------------------------------
#define VIRTOOLS_SCRIPT_DOT_EXTENSION ".nms"
#define VIRTOOLS_OBJECT_DOT_EXTENSION ".nmo"
CKStateChunk* 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<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 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<char> &s) const
{
//--- Read XString from file.
VxFile f;
if( !f.Open(filename.CStr()) ) return FALSE;
int size = f.Size();
s.Resize( size+1);
f.Read( s.Begin(), size );
s[size] = '\0';
f.Close();
return TRUE;
}
//-----------------------------------------------------------------------------
BOOL 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<CKSTRING>(command.CStr()), // Command line.
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
FALSE, // Set handle inheritance to FALSE.
CREATE_NO_WINDOW, // No creation flags.
NULL, // Use parent's environment block.
NULL, // Use parent's starting directory.
&si, // Pointer to STARTUPINFO structure.
&pi ) // Pointer to PROCESS_INFORMATION structure.
)
return FALSE;
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, 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<rcCount ; ++rcIndex ){
m_paramMeaningLinker[rcIndex].RemoveAt(paramIndex);
}
//--- Remove reference to this param in the hash table
///// and shift every parameter index beyond the removed one
XHashTable<int, CKParameterLocal*>::Iterator it = m_hashParamIndex.Begin();
while (it != m_hashParamIndex.End()) {
if( *it > paramIndex ){
--(*it);
}
++it;
}
m_hashParamIndex.Remove( p );
}
//-----------------------------------------------------------------------------
void 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<rcCount ; ++a ){
if( m_rcList[a] == rc ) return a;
}
return -1;
}
/*******************************************************************
Summary: Called when a RenderContext gets created or destroyed
to update the Shader Manager's inner list of render contexts
*******************************************************************/
//-----------------------------------------------------------------------------
void ShaderManager::OnRenderContextCreated( CKRenderContext* rc )
{
int rcIndex = m_rcList.Size();
m_rcList.PushBack( rc );
//--- Add a RenderContext Slot for all Exposed Parameters
_AddRCForExposedParameters();
//--- Add RenderContext Slot for all RCKShaders
const int shaderCount = m_AllShaders.Size();
for( int a=0 ; a<shaderCount ; ++a ){
RCKShader* shader = (RCKShader*)m_AllShaders[a];
if( !shader ) continue;
shader->_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<m_AllShaders.Size(); ++a ){
RCKShader* shader = (RCKShader*)m_AllShaders[a];
if( !shader ) continue;
shader->_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