1163 lines
31 KiB
C++
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 );
|
|
}
|
|
|
|
|