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

1163 lines
31 KiB
C++

/////////////////////////////////////////////////////
// ShaderManagerDX8
/////////////////////////////////////////////////////
#include "stdafx.h"
#include "RTView.h"
#include "ShaderManagerDX8.h"
#include "default_fxDX8.cpp"
#include "CKRasterizer.h"
#ifndef _XBOX
#include "mCppLib.h"
#endif
#ifdef _XBOX
#undef CompileShader
#endif
// need to Get The symbol D3DXCreateEffect for DX8
// Since we cannot link against D3DX8 and 9 Libs
void FourCC2XString(XString& xs,DWORD fcc);
DWORD XString2FourCC(XString& xs);
IDirect3DDevice8* DeviceFromRC(CKRenderContext* rc){
IDirect3DDevice8*ret = NULL;
VxDirectXData* dx = rc->GetDirectXInfo();
#ifdef _XBOX
ret = (IDirect3DDevice8*) dx->D3DDevice;
ret->AddRef();
#else
((IUnknown*)dx->D3DDevice)->QueryInterface(IID_IDirect3DDevice8,(LPVOID*)&ret);
#endif
return ret;
}
//-----------------------------------------------------------------------------
ShaderManagerDX8::ShaderManagerDX8(CKContext *Context) :
CKShaderManager(Context,ShaderManagerGUID,"Shader Manager DX8"),
m_NextCompID(1)
{
Context->RegisterNewManager(this);
#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";
m_FXPCommand = filename;
m_FXPCommand += "\\fxp.exe";
m_XBECCommand = filename;
m_XBECCommand += "\\xbec.exe";
#endif
}
//-----------------------------------------------------------------------------
ShaderManagerDX8::~ShaderManagerDX8()
{
}
CKERROR ShaderManagerDX8::OnCKEnd(){
return CK_OK;
}
//-----------------------------------------------------------------------------
D3DXHANDLE ShaderManagerDX8::_FindAutomaticParameter( CKShader& rfx,
ShaderAutomaticParameter index, CKRenderContext* rc )
{
RCKShaderDX8& nrfx = (RCKShaderDX8&) rfx;
int rcIndex = _GetRenderContextIndex(rc);
assert( rcIndex>=0 );
assert( nrfx.m_DXEffect[rcIndex] );
ShaderAutomaticInfoDX8& sai = GetRegAutomaticInfo( index );
D3DXPARAMETER_DESC desc;
#ifdef _XBOX
// No search By Name on XBOX need
// Try With dName ?
// Otherwise Iterate on all parameters to find the good one
int count = rfx.GetParameterCount(rc);
HRESULT res = E_FAIL;
for(int i=0;i<count;i++){
res = nrfx.m_DXEffect[rcIndex]->GetParameterDesc(i,&desc);
if(res == S_OK){
if(desc.Name == sai.m_dName){
break;
}
}
res = E_FAIL;
}
#else
HRESULT res = nrfx.m_DXEffect[rcIndex]->GetParameterDesc(sai.m_name.CStr(),&desc);
#endif
if(res == S_OK){
if (desc.Type != sai.m_d3dType){
m_Context->OutputToConsoleEx("Error : The parameter with %4s "
"semantic has an incorrect type.", &sai.m_name);
}else{
#ifdef _XBOX
return desc.Name;
#else
return sai.m_name.CStr();
#endif
}
}
return NULL;
}
//-----------------------------------------------------------------------------
void ShaderManagerDX8::BeginShaders(CKRenderContext* rc)
{
assert(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);
IDirect3DDevice8* dev = DeviceFromRC(rc);
if(dev){
dev->SetVertexShader(D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_NORMAL|D3DFVF_TEX0);
dev->SetPixelShader(NULL);
dev->Release();
}
}
//-----------------------------------------------------------------------------
void ShaderManagerDX8::EndShaders(CKRenderContext* rc)
{
m_DefaultShader->End(rc);
// Tell the rasterizer context we're in not shader mode
rc->GetRasterizerContext()->m_ShaderInUse = FALSE;
rc->GetRasterizerContext()->FlushCaches();
rc->GetRasterizerContext()->DisableAllTextureStages();
IDirect3DDevice8* dev = DeviceFromRC(rc);
if(dev){
dev->SetVertexShaderInputDirect(NULL,0,NULL);
dev->SetVertexShader(D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_NORMAL|D3DFVF_TEX0);
dev->SetPixelShader(NULL);
dev->Release();
}
}
//-----------------------------------------------------------------------------
void ShaderManagerDX8::_RegisterAutomatics(){
//--- Add here the information of the new register automatics
///// Automatics standard
_SetRegAutomaticInfo( FXAP_WVP, "mWVP",
D3DXPT_MATRIX, sizeof(VxMatrix),
"World View Projection" );
_SetRegAutomaticInfo( FXAP_WORLD, "mWOR",
D3DXPT_MATRIX, sizeof(VxMatrix),
"World Matrix" );
_SetRegAutomaticInfo( FXAP_VIEW, "mVIE",
D3DXPT_MATRIX, sizeof(VxMatrix),
"View Matrix" );
_SetRegAutomaticInfo( FXAP_WORLDVIEW, "mWVI",
D3DXPT_MATRIX, sizeof(VxMatrix),
"WorldView Matrix" );
_SetRegAutomaticInfo( FXAP_VIEWPROJ, "mVPR",
D3DXPT_MATRIX, sizeof(VxMatrix),
"ViewProj Matrix" );
_SetRegAutomaticInfo( FXAP_PROJECTION,"mPRO",
D3DXPT_MATRIX, sizeof(VxMatrix),
"Projection Matrix" );
_SetRegAutomaticInfo( FXAP_EYEPOS, "vEPO",
D3DXPT_VECTOR, sizeof(VxVector),
"Virtools camera position" );
///// Automatics for 3dentity
_SetRegAutomaticInfo( FXAP_OBJECTPOS, "vPOS",
D3DXPT_VECTOR, sizeof(VxVector),
"Virtools object's position" );
///// Automatics for materials
_SetRegAutomaticInfo( FXAP_DIFFUSE, "vDIF",
D3DXPT_VECTOR, sizeof(VxColor),
"- as a Virtools semantic: Virtools material's diffuse color\n"
"- as render state: renderstate enum standing for diffuse stage\n"
"- as a Vertex Shader Input semantic: the input vertex diffuse color"
);
_SetRegAutomaticInfo( FXAP_EMISSIVE, "vEMI",
D3DXPT_VECTOR, sizeof(VxColor),
"Virtools material's emissive color"
);
_SetRegAutomaticInfo( FXAP_SPECULAR, "vSPE",
D3DXPT_VECTOR, sizeof(VxColor),
"- as a Virtools semantic: Virtools material's specular color\n"
"- as a VS input semantic: the input vertex specular color"
);
_SetRegAutomaticInfo( FXAP_AMBIENT, "vAMB",
D3DXPT_VECTOR, sizeof(VxColor),
"Virtools material's ambient color"
);
_SetRegAutomaticInfo( FXAP_POWER, "fPOW",
D3DXPT_FLOAT, sizeof(float),
"Virtools material's power\n"
);
_SetRegAutomaticInfo( FXAP_TEXTURE, "tTEX",
D3DXPT_TEXTURE, 0,
"- as a Virtools semantic: Virtools material's texture\n"
"- as render state: renderstate enum standing for texture stage"
);
///// Automatics for global stuff
_SetRegAutomaticInfo( FXAP_TIME, "fTIM",
D3DXPT_VECTOR, 4*sizeof(float),
"x = Seconds elapsed since Virtools play event occured ( in seconds)\n"
"y = sin(x)\n"
"z = cos(x)\n"
"w = 1"
);
//--- Channel's Automatic
char SemanticName[16];
char SemanticDesc[128];
for( int a=0 ; a<4 ; ++a ){
sprintf( SemanticName, "TEX%d", a );
sprintf( SemanticDesc, "Virtools texture of channel %d of current mesh", a);
_SetRegAutomaticInfo( (ShaderAutomaticParameter)(FXAP_TEXTURE0+a),
SemanticName,
D3DXPT_TEXTURE, 0,
SemanticDesc
);
}
_SetRegAutomaticInfo( FXAP_PASSCOUNT, "PASC",
D3DXPT_FLOAT, sizeof(float),
"shader's pass count."
);
_SetRegAutomaticInfo( FXAP_PASSINDEX, "PASI",
D3DXPT_FLOAT, sizeof(float),
"Current rendering pass index."
);
_SetRegAutomaticInfo( FXAP_BONES, "mBON",
D3DXPT_DWORD, sizeof(int),
"First Register index that can be used to store bones matrices."
);
_SetRegAutomaticInfo( FXAP_TBONES, "mTBO",
D3DXPT_DWORD, sizeof(int),
"First Register index that can be used to store transformed bones matrices."
);
_SetRegAutomaticInfo( FXAP_BONESINDEXCONSTANT, "vBIC",
D3DXPT_DWORD, sizeof(int),
"Constant needed to convert D3DColor packed bones index to index."
);
/*
_SetRegAutomaticInfo( FXAP_VIEWPORTOFFSET, "vVOF",
D3DXPT_VECTOR, sizeof(VxVector4),
"Viewport Offset."
);
_SetRegAutomaticInfo( FXAP_VIEWPORTSCALE, "vVSC",
D3DXPT_VECTOR, sizeof(VxVector4),
"Viewport Scale."
);
*/
}
void ShaderManagerDX8::SetRegAutomaticName(
ShaderAutomaticParameter index,
const XString& iName )
{
m_RegisteredAutomatics[index].m_name = iName;
}
XString& ShaderManagerDX8::GetRegAutomaticName( ShaderAutomaticParameter index, int NameIndex )
{
static XString unregistred("");
if(0 ==NameIndex)
return m_RegisteredAutomatics[index].m_name;
else
return unregistred;
}
XString& ShaderManagerDX8::GetRegAutomaticDesc( ShaderAutomaticParameter index )
{
static XString empty("");
#ifdef _XBOX
return empty;
#else
return m_RegisteredAutomatics[index].m_desc;
#endif
}
void ShaderManagerDX8::_SetRegAutomaticInfo(
ShaderAutomaticParameter index,
const XString& iName,
D3DXPARAMETERTYPE iD3DType,
int iTypeSize,
const char* iDesc )
{
//--- Init all relevant members
m_RegisteredAutomatics[index].m_name = iName;
m_RegisteredAutomatics[index].m_d3dType = iD3DType;
#ifdef _XBOX
m_RegisteredAutomatics[index].m_dName = XString2FourCC(m_RegisteredAutomatics[index].m_name);
#else
m_RegisteredAutomatics[index].m_typeSize = iTypeSize;
m_RegisteredAutomatics[index].m_desc = iDesc;
#endif
}
void ShaderManagerDX8::_SetRegAutomaticInfo(
ShaderAutomaticParameter index,
const ShaderAutomaticInfoDX8& iSai )
{
m_RegisteredAutomatics[index] = iSai;
}
ShaderAutomaticInfoDX8& ShaderManagerDX8::GetRegAutomaticInfo( ShaderAutomaticParameter index )
{
return m_RegisteredAutomatics[index];
}
BOOL ShaderManagerDX8::IsAutomatic( const D3DXPARAMETER_DESC& desc ) const
{
for( int a=0 ; a<FXAP_MAXSIZE ; ++a ){
#ifdef _XBOX
if(m_RegisteredAutomatics[a].m_dName == desc.Name)
#else
if( !strcmp( m_RegisteredAutomatics[a].m_name.CStr(), desc.Name ) )
#endif
{
return TRUE;
}
}
return FALSE;
}
//-----------------------------------------------------------------------------
CKERROR ShaderManagerDX8::OnCKInit()
{
_RegisterAutomatics();
return CK_OK;
}
//-----------------------------------------------------------------------------
CKERROR ShaderManagerDX8::OnRasterizerEvent(CKRST_EVENTS Event, CKRenderContext* dev)
{
switch (Event)
{
case CKRST_EVENT_CREATE:
OnCreateDevice(dev);
break;
case CKRST_EVENT_DESTROY:
OnDestroyDevice(dev);
break;
case CKRST_EVENT_RESIZING:
case CKRST_EVENT_LOST:
OnLostDevice(dev);
break;
case CKRST_EVENT_RESET:
OnResetDevice(dev);
break;
};
return CK_OK;
}
//-----------------------------------------------------------------------------
void ShaderManagerDX8::OnCreateDevice(CKRenderContext* rc)
{
//--- Compile all shaders for all devices
int rcIndex = _GetRenderContextIndex(rc);
assert( rcIndex>=0 );
for (int i = 0; i < m_AllShaders.Size(); ++i)
{
CompileShader(m_AllShaders[i], m_Output);
}
}
//-----------------------------------------------------------------------------
void ShaderManagerDX8::OnDestroyDevice(CKRenderContext* rc)
{
int rcIndex = _GetRenderContextIndex(rc);
if ( rcIndex>=0 ) {
for (int i = 0; i < m_AllShaders.Size(); ++i)
{
((RCKShaderDX8*)m_AllShaders[i])->ReleaseDxEffect(rcIndex);
}
}
}
//-----------------------------------------------------------------------------
void ShaderManagerDX8::OnLostDevice(CKRenderContext* rc)
{
// No device lost on Xbox
#ifndef _XBOX
int rcIndex = _GetRenderContextIndex(rc);
for (int i = 0; i < m_AllShaders.Size(); ++i)
if (((RCKShaderDX8*)m_AllShaders[i])->m_DXEffect[rcIndex])
{
HRESULT hr = ((RCKShaderDX8*)m_AllShaders[i])->m_DXEffect[rcIndex]->OnLostDevice();
assert(SUCCEEDED(hr));
}
#endif
}
//-----------------------------------------------------------------------------
void ShaderManagerDX8::OnResetDevice(CKRenderContext* rc)
{
// No Reset Device On Xbox
#ifndef _XBOX
int rcIndex = _GetRenderContextIndex(rc);
for (int i = 0; i < m_AllShaders.Size(); ++i)
if (((RCKShaderDX8*)m_AllShaders[i])->m_DXEffect[rcIndex])
{
HRESULT hr = ((RCKShaderDX8*)m_AllShaders[i])->m_DXEffect[rcIndex]->OnResetDevice();
assert(SUCCEEDED(hr));
}
#endif
}
//-----------------------------------------------------------------------------
CKERROR ShaderManagerDX8::PreClearAll()
{
CKShaderManager::PreClearAll();
for (int i = 0; i < m_AllShaders.Size(); ++i)
delete m_AllShaders[i];
m_AllShaders.Clear();
m_DefaultShader = NULL;
return CK_OK;
}
//-----------------------------------------------------------------------------
CKERROR ShaderManagerDX8::PostClearAll()
{
return CK_OK;
}
//-----------------------------------------------------------------------------
CKShader* ShaderManagerDX8::CreateShader(
const XString* name, const XString* text, BOOL uniqueName )
{
RCKShaderDX8* fx = new RCKShaderDX8(this);
//--- Make Shader Fx name unique. This is needed because for example,
///// the material combo box gets the shader fx 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* ShaderManagerDX8::CreateShaderFromFile(const CKSTRING filename)
{
VxFile f;
if (f.Open(filename, VxFile::TEXTREADONLY))
{
int size = f.Size();
XString s;
s.Resize(size);
int sread = 0;
while (sread < size)
{
f.Read(&s[sread], 1024);
sread += 1024;
}
// 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 ShaderManagerDX8::SaveShaderToFile(const XString& filename, CKShader* fx)
{
_WriteStringToFile(filename, fx->GetText());
return true;
}
//-----------------------------------------------------------------------------
CKBOOL ShaderManagerDX8::IsSupported() const
{
CKRenderManager* rm = m_Context->GetRenderManager();
CKRenderContext* rc = rm->GetRenderContext(0);
VxDirectXData* dx = rc->GetDirectXInfo();
// Check Direct X Version
if (dx && dx->DxVersion >= 0x0800 && dx->DxVersion < 0x0900)
return TRUE;
return FALSE;
}
CKBOOL ShaderManagerDX8::IsSupportedAndWarnIfNot()
{
const CKBOOL isSupported = IsSupported();
if( !isSupported ){
m_Output.PushBack("Rasterizer does not support Shader FXs (use DirectX 8 or better)");
}
return isSupported;
}
//-----------------------------------------------------------------------------
void ShaderManagerDX8::GetVSPSVersion(float& vs, float& ps) const
{
#ifdef _XBOX
vs = 1.1f;
ps = 1.1f;
#else
CKRenderManager* rm = m_Context->GetRenderManager();
CKRenderContext* rc = rm->GetRenderContext(0);
VxDirectXData* dx = rc->GetDirectXInfo();
// Check Direct X Version
if (dx && dx->DxVersion >= 0x0800 && dx->DxVersion < 0x0900)
{
D3DCAPS8 caps;
memset(&caps,0,sizeof(caps));
IDirect3DDevice8* dev8 = NULL;
((IUnknown*)dx->D3DDevice)->QueryInterface(IID_IDirect3DDevice8,(LPVOID*)&dev8);
XASSERT(dev8);
dev8->GetDeviceCaps(&caps);
dev8->Release();
DWORD Major = (caps.VertexShaderVersion & 0xFF00) >> 8;
DWORD Minor = (caps.VertexShaderVersion & 0xFF);
if (Minor <= 10) Minor *= 10;
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;
if (Minor <= 10) Minor *= 10;
ps = (float)Major + (float)Minor * 0.01f;
}
#endif
}
//-----------------------------------------------------------------------------
CKShader* ShaderManagerDX8::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 ShaderManagerDX8::GetNumShaders() const
{
return m_AllShaders.Size();
}
//-----------------------------------------------------------------------------
CKShader* ShaderManagerDX8::GetShader(int pos)
{
return m_AllShaders[pos];
}
//-----------------------------------------------------------------------------
void ShaderManagerDX8::DeleteShader(CKShader* fx)
{
m_AllShaders.Remove(fx);
if (fx == m_DefaultShader)
m_DefaultShader = NULL;
delete fx;
}
//-----------------------------------------------------------------------------
bool ShaderManagerDX8::CompileShader(CKShader* fx, XClassArray<XString> &output)
{
RCKShaderDX8& rfx = *(RCKShaderDX8*)fx;
CKRenderManager* rm = m_Context->GetRenderManager();
const int rcCount = m_rcList.Size();
for( int rcIndex=0 ; rcIndex<rcCount ; ++rcIndex ){
// Check Direct X Version
CKRenderContext* rc = m_rcList[rcIndex];
VxDirectXData* dx = rc->GetDirectXInfo();
if (dx && dx->DxVersion >= 0x0800 && dx->DxVersion < 0x0900)
{
ID3DXBuffer* Error = NULL;
const XString& Text = rfx.GetText();
ID3DXEffect* oldfx = rfx.m_DXEffect[rcIndex];
// Creates a simple Shader
#ifdef _XBOX
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();
if (Error != NULL && Error->GetBufferSize()){
XStringTokenizer tokizer((char*)Error->GetBufferPointer(), "\n");
const char *tok = NULL;
while ((tok = tokizer.NextToken(tok)) != NULL){
if(strlen(tok) < 12)
continue;
output.PushBack(rfx.GetName() + XString(tok));
}
}
if(Error)
Error->Release();
#else
IDirect3DDevice8* dev8 = NULL;
((IUnknown*)dx->D3DDevice)->QueryInterface(IID_IDirect3DDevice8,(LPVOID*)&dev8);
XASSERT(dev8);
// Do Preprocesing Stuff.
//mCppLib_Define("D3DX_VERSION","0x0801");
//mCppLib_Define("DIRECT3D_VERSION","0x0801");
XString PreProcessed;
XString PreProcErr;
HRESULT hr = mCppLib_PreProcess(Text,"-D D3DX_VERSION=0x0801 -D DIRECT3D_VERSION=0x0801"
,PreProcessed,PreProcErr);
if(hr && PreProcErr.Length()){
// an error occurred during preprocessing
XStringTokenizer tokizer(PreProcErr.CStr(), "\n");
const char *tok = NULL;
while ((tok = tokizer.NextToken(tok)) != NULL)
output.PushBack(rfx.GetName() + XString(" ") + XString(tok));
}else{
hr = D3DXCreateEffect(dev8,PreProcessed.CStr(), PreProcessed.Length(),&rfx.m_DXEffect[rcIndex], &Error);
}
dev8->Release();
if (Error != NULL && Error->GetBufferSize()){
XStringTokenizer tokizer((char*)Error->GetBufferPointer(), "\n");
const char *tok = NULL;
while ((tok = tokizer.NextToken(tok)) != NULL)
output.PushBack(rfx.GetName() + XString(tok));
}
if(Error)
Error->Release();
#endif
//--- Replace the old Shader with the new one
if (FAILED(hr)){
rfx.m_DXEffect[rcIndex] = oldfx;
output.PushBack(rfx.GetName() +
": Shader Fx compilation failed.");
return FALSE;
} else {
output.PushBack(rfx.GetName() +
": Shader Fx compilation successfull.");
if (oldfx)
oldfx->Release();
rfx.m_CompID = m_NextCompID++;
rfx._RetrieveTechniques(rc);
//--- We don't consider automatics for the default shader.
///// In fact the default shader contain automatics just to show the
///// user how to use them
if( fx != m_DefaultShader ){
for( int a=0 ; a<FXAP_MAXSIZE ; ++a ){
rfx.m_AutomaticHandle[a] =
_FindAutomaticParameter( rfx, (ShaderAutomaticParameter)a,m_rcList[rcIndex]);
}
//--- And just for security, if it's the default shader,
///// we fill its automatics handle with NULL
} else {
for( int a=0 ; a<FXAP_MAXSIZE ; ++a ){
rfx.m_AutomaticHandle[a] = NULL;
}
}
}
}
}
return TRUE;
}
//-----------------------------------------------------------------------------
bool ShaderManagerDX8::CompileShaderOutput(CKShader* fx, const CKSTRING funcname,
const CKSTRING target, XClassArray<XString> &output, XArray<char>& text)
{
CKRenderManager* rm = m_Context->GetRenderManager();
CKRenderContext* rc = rm->GetRenderContext(0);
VxDirectXData* dx = rc->GetDirectXInfo();
assert(fx != NULL);
#ifndef _XBOX
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 >= 0x0800 && 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 Fx file.");
return FALSE;
}
XString outfile;
outfile.Format("%sfxcout.txt", tmp);
XString cmd;
cmd.Format("\"%s\" /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;
}
}
#endif
return TRUE;
}
//-----------------------------------------------------------------------------
CKShader* ShaderManagerDX8::GetDefaultShader()
{
return GetDefaultShaderI();
}
//-----------------------------------------------------------------------------
CKShader* ShaderManagerDX8::GetDefaultShaderI()
{
if( !m_DefaultShader )
{
#if 0
//#ifdef _XBOX
VxFile f;
f.Open("d:\\media\\default.fx");
XASSERT(f.IsValid());
VxScratch tmp(f.Size()+1);
char *txt = (char*) tmp.Mem();
f.Read(txt,f.Size());
txt[f.Size()] = '\0';
m_DefaultShader = ShaderManagerDX8::CreateShader(&XString("- default -"), &XString(txt));
#else
m_DefaultShader = ShaderManagerDX8::CreateShader(&XString("- default -"), &XString(g_default));
#endif
CompileShader(m_DefaultShader, m_Output);
}
return m_DefaultShader;
}
//-----------------------------------------------------------------------------
CKERROR ShaderManagerDX8::LoadData(CKStateChunk *chunk,CKFile* LoadedFile)
{
assert(LoadedFile != 0);
if (!chunk)
return CKERR_INVALIDPARAMETER;
chunk->StartRead();
if (chunk->SeekIdentifier(SHADERMANAGER_CHUNKID))
{
// Check the version
int version = chunk->ReadInt();
/* ?... I don't get the point of this...
if (version != ShaderManagerDX8_SAVE_VERSION)
{
m_Context->OutputToConsole("Shader manager load data error : bad version");
return CK_OK;
}
*/
// 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)
{
chunk->SeekIdentifier(chunkid);
++chunkid;
//--- 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();
CKShader* sameNameEffect;
BOOL shaderMustBeCreated = TRUE;
while( sameNameEffect = GetShaderByName( fxName ) ){
//--- Skip this effect if text is the same
if( !fxText.Compare( sameNameEffect->GetText()) ){
shaderMustBeCreated = FALSE;
break;
}
//--- Otherwise rename the new effect
int extCount = 1;
XString originalFxName = fxName;
fxName.Format( "%s %.3d", originalFxName.CStr(), extCount );
++extCount;
}
if( !shaderMustBeCreated ) continue;
RCKShaderDX8* fx = new RCKShaderDX8(this);
fx->SetName( fxName );
fx->SetText( fxText );
m_AllShaders.PushBack(fx);
m_Context->OutputToConsoleEx("Loaded Shader Fx %s.", fx->GetName().CStr());
}
}
//--- If the Default Shader doesn't exist GetDefaultShader will create it
m_DefaultShader = GetDefaultShaderI();
if( IsSupportedAndWarnIfNot() ){
//--- Compile every loaded Shader except the default Shader
///// as it has already been compiled (cf: just above)
for (int i = 0; i < m_AllShaders.Size(); ++i){
CKShader* const fx = m_AllShaders[i];
if( fx == m_DefaultShader ) continue;
CompileShader( fx, m_Output );
}
}
chunk->CloseChunk();
return CK_OK;
}
//-----------------------------------------------------------------------------
CKStateChunk* ShaderManagerDX8::SaveData(CKFile* SavedFile)
{
assert(SavedFile != 0);
//--- If there's only one shader it's certainly the default shader Shader
///// and so it's not even needed to save any ShaderManagerDX8 Chunk
const int toSaveCount = m_AllShaders.Size()-1;
if( toSaveCount<1 ) return NULL;
// 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;
for (int i = 0; i < m_AllShaders.Size(); ++i)
{
CKShader* const fx = m_AllShaders[i];
//--- Is it the default effect then don't write it
if( fx == m_DefaultShader ) continue;
chunk->WriteIdentifier(chunkid);
++chunkid;
/* --- old Version ( < 2 )
// store if it's the default Shader (this becomes obsolete...)
chunk->WriteInt(m_AllShaders[i] == m_DefaultShader ? TRUE : FALSE);
*/
// store name
chunk->WriteString(m_AllShaders[i]->GetName().CStr());
// store text
#ifndef _XBOX
if(m_SavePreProcessed){
XString PreProcessed;
XString PreProcErr;
HRESULT hr = mCppLib_PreProcess(m_AllShaders[i]->GetText(),m_SavePreprocessedOptions.CStr(),PreProcessed,PreProcErr);
if(S_OK == hr)
chunk->WriteString(PreProcessed.CStr());
else
chunk->WriteString(m_AllShaders[i]->GetText().CStr());
}else
#endif
{
// Need to do some pre-processing to match the target
chunk->WriteString(m_AllShaders[i]->GetText().CStr());
}
}
chunk->CloseChunk();
return chunk;
}
//-----------------------------------------------------------------------------
BOOL ShaderManagerDX8::_ReadStringFromFile(const XString& filename, XString &s) const
{
//--- Read XString from file.
VxFile f;
if( !f.Open(filename.CStr()) ) return FALSE;
int size = f.Size();
s.Resize( size );
f.Read( s.Str(), size );
f.Close();
return TRUE;
}
//-----------------------------------------------------------------------------
BOOL ShaderManagerDX8::_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 _WinExec(const XString& command)
{
#ifdef _XBOX
return FALSE;
#else
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line).
const_cast<CKSTRING>(command.CStr()), // Command line.
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
FALSE, // Set handle inheritance to FALSE.
CREATE_NO_WINDOW, // No creation flags.
NULL, // Use parent's environment block.
NULL, // Use parent's starting directory.
&si, // Pointer to STARTUPINFO structure.
&pi ) // Pointer to PROCESS_INFORMATION structure.
)
return FALSE;
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
DWORD code = 0;
GetExitCodeProcess( pi.hProcess, &code );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
return code == 0;
#endif
}
int ShaderManagerDX8::_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 ShaderManagerDX8::OnRenderContextCreated( CKRenderContext* rc )
{
int rcIndex = m_rcList.Size();
m_rcList.PushBack( rc );
//--- Register the Render Context
_AddRCForExposedParameters();
//--- Don't forget to add also a slot in the DXEffect array of all Shaders !
const int shaderCount = m_AllShaders.Size();
for( int a=0 ; a<shaderCount ; ++a ){
((RCKShaderDX8*)m_AllShaders[a])->m_DXEffect.PushBack(NULL);
}
}
void ShaderManagerDX8::OnRenderContextDestroyed( CKRenderContext* rc )
{
int rcIndex = _GetRenderContextIndex(rc);
assert( rcIndex>=0 );
//--- UnRegister the Render Context
_RemoveRCForExposedParameters( rcIndex );
//--- Release d3deffects for this device
for(int a=0; a<m_AllShaders.Size(); ++a ){
XArray<ID3DXEffect*>& dxEffectArray = ((RCKShaderDX8*)m_AllShaders[a])->m_DXEffect;
if( dxEffectArray[rcIndex] ){
dxEffectArray[rcIndex]->Release();
}
dxEffectArray.RemoveAt(rcIndex);
}
//--- Remove the RC from our managed list (hash) of RCs
m_rcList.Remove( rc );
}
void ShaderManagerDX8::_AddRCForExposedParameters()
{
const int endIndex = m_paramLinker.Size();
//--- Add one rc
m_paramLinker.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_paramLinker[endIndex].Resize( registeredParamCount );
m_paramLinker[endIndex].Fill( (D3DXHANDLE)0 );
}
void ShaderManagerDX8::_RemoveRCForExposedParameters( int rcIndex )
{
//--- Remove the rc
///// Note: as it's a class array, it will remove also all d3dhandles fo the rc
m_paramLinker.RemoveAt( rcIndex );
}