Use bSNES-style XML-based .shader files for both OpenGL and Direct3D

.shader files are parsed with MSXML. A wrapper-class would be nice,
but it does its job.
This commit is contained in:
OV2 2010-11-13 20:41:38 +01:00
parent 1c3d31828c
commit f8fcdcbd72
2 changed files with 136 additions and 26 deletions

View File

@ -320,6 +320,14 @@ bool CDirect3D::SetShader(const TCHAR *file)
TCHAR folder[MAX_PATH]; TCHAR folder[MAX_PATH];
TCHAR rubyLUTfileName[MAX_PATH]; TCHAR rubyLUTfileName[MAX_PATH];
TCHAR *slash; TCHAR *slash;
char *shaderText = NULL;
TCHAR errorMsg[MAX_PATH + 50];
IXMLDOMDocument * pXMLDoc = NULL;
IXMLDOMElement * pXDE = NULL;
IXMLDOMNode * pXDN = NULL;
BSTR queryString, nodeContent;
HRESULT hr; HRESULT hr;
@ -341,6 +349,100 @@ bool CDirect3D::SetShader(const TCHAR *file)
if (file == NULL || *file==TEXT('\0')) if (file == NULL || *file==TEXT('\0'))
return true; return true;
hr = CoCreateInstance(CLSID_DOMDocument,NULL,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&pXMLDoc));
if(FAILED(hr)) {
MessageBox(NULL, TEXT("Error creating XML Parser"), TEXT("Shader Loading Error"),
MB_OK|MB_ICONEXCLAMATION);
return false;
}
VARIANT fileName;
VARIANT_BOOL ret;
fileName.vt = VT_BSTR;
#ifdef UNICODE
fileName.bstrVal = SysAllocString(file);
#else
wchar_t tempfilename[MAX_PATH];
MultiByteToWideChar(CP_UTF8,0,file,-1,tempfilename,MAX_PATH);
fileName.bstrVal = SysAllocString(tempfilename);
#endif
hr = pXMLDoc->load(fileName,&ret);
SysFreeString(fileName.bstrVal);
if(FAILED(hr) || hr==S_FALSE) {
_stprintf(errorMsg,TEXT("Error loading HLSL shader file:\n%s"),file);
MessageBox(NULL, errorMsg, TEXT("Shader Loading Error"), MB_OK|MB_ICONEXCLAMATION);
pXMLDoc->Release();
return false;
}
VARIANT attributeValue;
BSTR attributeName;
hr = pXMLDoc->get_documentElement(&pXDE);
if(FAILED(hr) || hr==S_FALSE) {
_stprintf(errorMsg,TEXT("Error loading root element from file:\n%s"),file);
MessageBox(NULL, errorMsg, TEXT("Shader Loading Error"), MB_OK|MB_ICONEXCLAMATION);
pXMLDoc->Release();
return false;
}
attributeName=SysAllocString(L"language");
pXDE->getAttribute(attributeName,&attributeValue);
SysFreeString(attributeName);
pXDE->Release();
if(attributeValue.vt!=VT_BSTR || lstrcmpiW(attributeValue.bstrVal,L"hlsl")) {
_stprintf(errorMsg,TEXT("Shader language is <%s>, expected <HLSL> in file:\n%s"),attributeValue.bstrVal,file);
MessageBox(NULL, errorMsg, TEXT("Shader Loading Error"), MB_OK|MB_ICONEXCLAMATION);
if(attributeValue.vt==VT_BSTR) SysFreeString(attributeValue.bstrVal);
pXMLDoc->Release();
return false;
}
if(attributeValue.vt==VT_BSTR) SysFreeString(attributeValue.bstrVal);
queryString=SysAllocString(L"/shader/source");
hr = pXMLDoc->selectSingleNode(queryString,&pXDN);
SysFreeString(queryString);
if(hr == S_OK) {
hr = pXDN->get_text(&nodeContent);
if(hr == S_OK) {
int requiredChars = WideCharToMultiByte(CP_ACP,0,nodeContent,-1,shaderText,0,NULL,NULL);
shaderText = new char[requiredChars];
WideCharToMultiByte(CP_UTF8,0,nodeContent,-1,shaderText,requiredChars,NULL,NULL);
}
SysFreeString(nodeContent);
pXDN->Release();
pXDN = NULL;
}
pXMLDoc->Release();
if(!shaderText) {
_stprintf(errorMsg,TEXT("No HLSL shader program in file:\n%s"),file);
MessageBox(NULL, errorMsg, TEXT("Shader Loading Error"),
MB_OK|MB_ICONEXCLAMATION);
return false;
}
LPD3DXBUFFER pBufferErrors = NULL;
hr = D3DXCreateEffect( pDevice,shaderText,strlen(shaderText),NULL, NULL,
D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY, NULL, &effect,
&pBufferErrors );
delete[] shaderText;
if( FAILED(hr) ) {
_stprintf(errorMsg,TEXT("Error parsing HLSL shader file:\n%s"),file);
MessageBox(NULL, errorMsg, TEXT("Shader Loading Error"), MB_OK|MB_ICONEXCLAMATION);
if(pBufferErrors) {
LPVOID pCompilErrors = pBufferErrors->GetBufferPointer();
MessageBox(NULL, (const TCHAR*)pCompilErrors, TEXT("FX Compile Error"),
MB_OK|MB_ICONEXCLAMATION);
}
return false;
}
lstrcpy(folder,file); lstrcpy(folder,file);
slash = _tcsrchr(folder,TEXT('\\')); slash = _tcsrchr(folder,TEXT('\\'));
if(slash) if(slash)
@ -357,22 +459,6 @@ bool CDirect3D::SetShader(const TCHAR *file)
} }
} }
LPD3DXBUFFER pBufferErrors = NULL;
hr = D3DXCreateEffectFromFile( pDevice,file,NULL, NULL,
D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY, NULL, &effect,
&pBufferErrors );
if( FAILED(hr) ) {
TCHAR errorMsg[MAX_PATH + 50];
_stprintf(errorMsg,TEXT("Error loading HLSL effect file:\n%s"),file);
MessageBox(NULL, errorMsg, TEXT("Shader Loading Error"),
MB_OK|MB_ICONEXCLAMATION);
if(pBufferErrors) {
LPVOID pCompilErrors = pBufferErrors->GetBufferPointer();
MessageBox(NULL, (const TCHAR*)pCompilErrors, TEXT("FX Compile Error"),
MB_OK|MB_ICONEXCLAMATION);
}
return false;
}
D3DXHANDLE hTech; D3DXHANDLE hTech;
effect->FindNextValidTechnique(NULL,&hTech); effect->FindNextValidTechnique(NULL,&hTech);
effect->SetTechnique( hTech ); effect->SetTechnique( hTech );

View File

@ -257,19 +257,19 @@ void COpenGL::Render(SSurface Src)
if (shaderCompiled) { if (shaderCompiled) {
GLint location; GLint location;
float inputSize[2] = { afterRenderWidth, afterRenderHeight }; float inputSize[2] = { (float)afterRenderWidth, (float)afterRenderHeight };
location = glGetUniformLocation (shaderProgram, "rubyInputSize"); location = glGetUniformLocation (shaderProgram, "rubyInputSize");
glUniform2fv (location, 1, inputSize); glUniform2fv (location, 1, inputSize);
RECT windowSize; RECT windowSize;
GetClientRect(hWnd,&windowSize); GetClientRect(hWnd,&windowSize);
float outputSize[2] = {GUI.Stretch?windowSize.right:afterRenderWidth, float outputSize[2] = {(float)(GUI.Stretch?windowSize.right:afterRenderWidth),
GUI.Stretch?windowSize.bottom:afterRenderHeight }; (float)(GUI.Stretch?windowSize.bottom:afterRenderHeight) };
location = glGetUniformLocation (shaderProgram, "rubyOutputSize"); location = glGetUniformLocation (shaderProgram, "rubyOutputSize");
glUniform2fv (location, 1, outputSize); glUniform2fv (location, 1, outputSize);
float textureSize[2] = { quadTextureSize, quadTextureSize }; float textureSize[2] = { (float)quadTextureSize, (float)quadTextureSize };
location = glGetUniformLocation (shaderProgram, "rubyTextureSize"); location = glGetUniformLocation (shaderProgram, "rubyTextureSize");
glUniform2fv (location, 1, textureSize); glUniform2fv (location, 1, textureSize);
} }
@ -485,10 +485,13 @@ bool COpenGL::SetShaders(const TCHAR *glslFileName)
{ {
char *fragment=NULL, *vertex=NULL; char *fragment=NULL, *vertex=NULL;
IXMLDOMDocument * pXMLDoc = NULL; IXMLDOMDocument * pXMLDoc = NULL;
IXMLDOMElement * pXDE = NULL;
IXMLDOMNode * pXDN = NULL; IXMLDOMNode * pXDN = NULL;
HRESULT hr; HRESULT hr;
BSTR queryString, nodeContent; BSTR queryString, nodeContent;
TCHAR errorMsg[MAX_PATH + 50];
shaderCompiled = false; shaderCompiled = false;
if(fragmentShader) { if(fragmentShader) {
@ -538,14 +541,37 @@ bool COpenGL::SetShaders(const TCHAR *glslFileName)
SysFreeString(fileName.bstrVal); SysFreeString(fileName.bstrVal);
if(FAILED(hr) || hr==S_FALSE) { if(FAILED(hr) || hr==S_FALSE) {
TCHAR errorMsg[MAX_PATH + 50];
_stprintf(errorMsg,TEXT("Error loading GLSL shader file:\n%s"),glslFileName); _stprintf(errorMsg,TEXT("Error loading GLSL shader file:\n%s"),glslFileName);
MessageBox(NULL, errorMsg, TEXT("Shader Loading Error"), MessageBox(NULL, errorMsg, TEXT("Shader Loading Error"), MB_OK|MB_ICONEXCLAMATION);
MB_OK|MB_ICONEXCLAMATION);
pXMLDoc->Release(); pXMLDoc->Release();
return false; return false;
} }
VARIANT attributeValue;
BSTR attributeName;
hr = pXMLDoc->get_documentElement(&pXDE);
if(FAILED(hr) || hr==S_FALSE) {
_stprintf(errorMsg,TEXT("Error loading root element from file:\n%s"),glslFileName);
MessageBox(NULL, errorMsg, TEXT("Shader Loading Error"), MB_OK|MB_ICONEXCLAMATION);
pXMLDoc->Release();
return false;
}
attributeName=SysAllocString(L"language");
pXDE->getAttribute(attributeName,&attributeValue);
SysFreeString(attributeName);
pXDE->Release();
if(attributeValue.vt!=VT_BSTR || lstrcmpiW(attributeValue.bstrVal,L"glsl")) {
_stprintf(errorMsg,TEXT("Shader language is <%s>, expected <GLSL> in file:\n%s"),attributeValue.bstrVal,glslFileName);
MessageBox(NULL, errorMsg, TEXT("Shader Loading Error"), MB_OK|MB_ICONEXCLAMATION);
if(attributeValue.vt==VT_BSTR) SysFreeString(attributeValue.bstrVal);
pXMLDoc->Release();
return false;
}
if(attributeValue.vt==VT_BSTR) SysFreeString(attributeValue.bstrVal);
queryString=SysAllocString(L"/shader/fragment"); queryString=SysAllocString(L"/shader/fragment");
hr = pXMLDoc->selectSingleNode(queryString,&pXDN); hr = pXMLDoc->selectSingleNode(queryString,&pXDN);
SysFreeString(queryString); SysFreeString(queryString);
@ -581,10 +607,8 @@ bool COpenGL::SetShaders(const TCHAR *glslFileName)
pXMLDoc->Release(); pXMLDoc->Release();
if(!fragment && !vertex) { if(!fragment && !vertex) {
TCHAR errorMsg[MAX_PATH + 50];
_stprintf(errorMsg,TEXT("No vertex or fragment program in file:\n%s"),glslFileName); _stprintf(errorMsg,TEXT("No vertex or fragment program in file:\n%s"),glslFileName);
MessageBox(NULL, errorMsg, TEXT("Shader Loading Error"), MessageBox(NULL, errorMsg, TEXT("Shader Loading Error"), MB_OK|MB_ICONEXCLAMATION);
MB_OK|MB_ICONEXCLAMATION);
return false; return false;
} }