DOSBox Direct3D (threaded) patch. From: gulikoza Adds direct3d output option. Supports shaders. Author: gulikoza (http://vogons.zetafleet.com/viewtopic.php?t=9255) Changes (2013/03/26): - add inputDims to shader - support forceUpdating the screen (alphablend shaders, use "FORCEUPDATE" in the shader fx) - support forcing shaders ("forced" keyword) - fix crash when the shader does not compile (LOG_MSG limit) - support dynamically changing pixelshader= option from cli - fix pixelshader=none crash - fix a possible win8 crash Version (2011/09/01): - clear texture to black on init TODO: - support rubyFrameCount equivalent (?) --- configure.ac | 37 + include/render.h | 1 src/gui/Makefile.am | 3 src/gui/ScalingEffect.cpp | 660 +++++++++++++++++++ src/gui/ScalingEffect.h | 104 +++ src/gui/direct3d.cpp | 1435 +++++++++++++++++++++++++++++++++++++++++ src/gui/direct3d.h | 257 +++++++ src/gui/hq2x_d3d.cpp | 205 ++++++ src/gui/hq2x_d3d.h | 294 ++++++++ src/gui/render.cpp | 12 src/gui/sdlmain.cpp | 200 ++++++ src/platform/visualc/config.h | 6 12 files changed, 3212 insertions(+), 2 deletions(-) create mode 100644 src/gui/ScalingEffect.cpp create mode 100644 src/gui/ScalingEffect.h create mode 100644 src/gui/direct3d.cpp create mode 100644 src/gui/direct3d.h create mode 100644 src/gui/hq2x_d3d.cpp create mode 100644 src/gui/hq2x_d3d.h diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -460,7 +460,44 @@ dnl Some target detection and actions for them case "$host" in *-*-cygwin* | *-*-mingw32*) LIBS="$LIBS -lwinmm -lshlwapi -lws2_32" + AH_TEMPLATE(C_D3DSHADERS,[Define to 1 to use Direct3D shaders, requires d3d9.h and libd3dx9]) + AC_ARG_WITH(dx-headers,[ --with-dx-headers=DIR DirectX include files location], + dx_headers="$withval", dx_headers="") + AC_ARG_WITH(dx-libs,[ --with-dx-libs=DIR DirectX library location], + dx_libs="$withval", dx_libs="") + ac_save_CPPFLAGS=$CPPFLAGS + if test x$dx_headers != x ; then + CPPFLAGS="$CPPFLAGS -I$dx_headers" + fi + AC_LANG(C++) AC_CHECK_HEADERS(ddraw.h) + AC_CHECK_HEADERS(d3d9.h,have_d3d9_h=yes,) + AC_MSG_CHECKING(whether direct3d display output will be enabled) + if test x$have_d3d9_h = xyes ; then + AC_MSG_RESULT(yes) + AC_ARG_ENABLE(shaders,AC_HELP_STRING([--disable-shaders],[Disable d3d pixelshader support (which requires libd3dx9)]),,[ + AC_MSG_CHECKING(whether direct3d pixelshaders will be enabled) + ac_save_LIBS=$LIBS + if test x$dx_libs != x ; then + dx_libs=" -L$dx_libs" + fi + LIBS="$LIBS$dx_libs -ld3dx9" + AC_TRY_LINK([#include + #include + extern "C" int main();],D3DXCreateEffect(0, 0, 0, 0, 0, 0, 0, 0, 0), have_d3dx9_lib=yes,) + if test x$have_d3dx9_lib = xyes ; then + AC_MSG_RESULT(yes) + AC_DEFINE(C_D3DSHADERS,1) + else + LIBS=$ac_save_LIBS + AC_MSG_RESULT(no) + AC_MSG_WARN([Can't find libd3dx9, pixelshader support disabled]) + fi + ],) + else + CPPFLAGS=$ac_save_CPPFLAGS + AC_MSG_RESULT(no) + fi AC_DEFINE(C_DIRECTSERIAL, 1, [ Define to 1 if you want serial passthrough support (Win32, Posix and OS/2 only).]) if test x$have_sdl_net_lib = xyes -a x$have_sdl_net_h = xyes ; then LIBS="$LIBS -lws2_32" diff --git a/include/render.h b/include/render.h --- a/include/render.h +++ b/include/render.h @@ -85,6 +85,7 @@ typedef struct { bool active; bool aspect; bool fullFrame; + bool forceUpdate; } Render_t; extern Render_t render; diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -7,5 +7,6 @@ libgui_a_SOURCES = sdlmain.cpp sdl_mapper.cpp dosbox_logo.h \ render_templates_sai.h render_templates_hq.h \ render_templates_hq2x.h render_templates_hq3x.h \ midi.cpp midi_win32.h midi_oss.h midi_coreaudio.h midi_alsa.h \ - midi_coremidi.h sdl_gui.cpp dosbox_splash.h + midi_coremidi.h sdl_gui.cpp dosbox_splash.h direct3d.cpp direct3d.h \ + ScalingEffect.cpp ScalingEffect.h hq2x_d3d.cpp hq2x_d3d.h diff --git a/src/gui/ScalingEffect.cpp b/src/gui/ScalingEffect.cpp new file mode 100644 --- /dev/null +++ b/src/gui/ScalingEffect.cpp @@ -0,0 +1,660 @@ +/* +Copyright (C) 2003 Ryan A. Nunn + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "dosbox.h" + +#if (HAVE_D3D9_H) && (C_D3DSHADERS) && defined(WIN32) + +#include "ScalingEffect.h" + +ScalingEffect::ScalingEffect(LPDIRECT3DDEVICE9 pd3dDevice) : + m_scale(0.0f), m_forceupdate(false), m_pd3dDevice(pd3dDevice), m_pEffect(0) +{ + m_iDim[0] = m_iDim[1] = 256.0f; // Some sane default + m_strName = "Unnamed"; + KillThis(); +} + +ScalingEffect::~ScalingEffect(void) +{ + KillThis(); +} + +void ScalingEffect::KillThis() +{ + SAFE_RELEASE(m_pEffect); + m_strErrors.clear(); + m_strName = "Unnamed"; + + m_MatWorldEffectHandle = 0; + m_MatViewEffectHandle = 0; + m_MatProjEffectHandle = 0; + m_MatWorldViewEffectHandle = 0; + m_MatViewProjEffectHandle = 0; + m_MatWorldViewProjEffectHandle = 0; + + // Source Texture Handles + m_SourceDimsEffectHandle = 0; + m_TexelSizeEffectHandle = 0; + m_SourceTextureEffectHandle = 0; + m_WorkingTexture1EffectHandle = 0; + m_WorkingTexture2EffectHandle = 0; + m_Hq2xLookupTextureHandle = 0; + + // Technique stuff + m_PreprocessTechnique1EffectHandle = 0; + m_PreprocessTechnique2EffectHandle = 0; + m_CombineTechniqueEffectHandle = 0; +} + +HRESULT ScalingEffect::LoadEffect(const TCHAR *filename) +{ + KillThis(); + + LPD3DXBUFFER lpBufferEffect = 0; + LPD3DXBUFFER lpErrors = 0; + LPD3DXEFFECTCOMPILER lpEffectCompiler = 0; + + m_strErrors += filename; + m_strErrors += ":\n"; + + // First create an effect compiler + HRESULT hr = D3DXCreateEffectCompilerFromFile(filename, NULL, NULL, 0, + &lpEffectCompiler, &lpErrors); + + // Errors... + if(FAILED(hr)) { + if(lpErrors) { + m_strErrors += (char*) lpErrors->GetBufferPointer(); + SAFE_RELEASE(lpErrors); + } + + m_strErrors += "Unable to create effect compiler from "; + m_strErrors += filename; + } + + if(SUCCEEDED(hr)) { +#ifdef C_D3DSHADERS_COMPILE_WITH_DEBUG + hr = lpEffectCompiler->CompileEffect(D3DXSHADER_DEBUG, &lpBufferEffect, &lpErrors); +#else + hr = lpEffectCompiler->CompileEffect(0, &lpBufferEffect, &lpErrors); +#endif + + // Errors... + if(FAILED(hr)) { + if(lpErrors) { + m_strErrors += (char*) lpErrors->GetBufferPointer(); + SAFE_RELEASE(lpErrors); + } + + m_strErrors += "Unable to compile effect from "; + m_strErrors += filename; + } + } + + if(SUCCEEDED(hr)) { + hr = D3DXCreateEffect(m_pd3dDevice, + lpBufferEffect->GetBufferPointer(), + lpBufferEffect->GetBufferSize(), + NULL, NULL, + 0, + NULL, &m_pEffect, &lpErrors); + + // Errors... + if(FAILED(hr)) { + if(lpErrors) { + m_strErrors += (char*) lpErrors->GetBufferPointer(); + SAFE_RELEASE(lpErrors); + } + + m_strErrors += "Unable to create effect from compiled "; + m_strErrors += filename; + } + } + + if(SUCCEEDED(hr)) { + m_pEffect->GetDesc(&m_EffectDesc); + hr = ParseParameters(lpEffectCompiler); + } + + SAFE_RELEASE(lpErrors); + SAFE_RELEASE(lpBufferEffect); + SAFE_RELEASE(lpEffectCompiler); + return hr; +} + +HRESULT ScalingEffect::ParseParameters(LPD3DXEFFECTCOMPILER lpEffectCompiler) +{ + HRESULT hr = S_OK; + + if(m_pEffect == NULL) + return E_FAIL; + + // Look at parameters for semantics and annotations that we know how to interpret + D3DXPARAMETER_DESC ParamDesc; + D3DXPARAMETER_DESC AnnotDesc; + D3DXHANDLE hParam; + D3DXHANDLE hAnnot; + LPDIRECT3DBASETEXTURE9 pTex = NULL; + + for(UINT iParam = 0; iParam < m_EffectDesc.Parameters; iParam++) { + LPCSTR pstrName = NULL; + LPCSTR pstrFunction = NULL; + LPCSTR pstrTarget = NULL; + LPCSTR pstrTextureType = NULL; + INT Width = D3DX_DEFAULT; + INT Height= D3DX_DEFAULT; + INT Depth = D3DX_DEFAULT; + + hParam = m_pEffect->GetParameter(NULL, iParam); + m_pEffect->GetParameterDesc(hParam, &ParamDesc); + + if(ParamDesc.Semantic != NULL) { + if(ParamDesc.Class == D3DXPC_MATRIX_ROWS || ParamDesc.Class == D3DXPC_MATRIX_COLUMNS) { + if(strcmpi(ParamDesc.Semantic, "world") == 0) + m_MatWorldEffectHandle = hParam; + else if(strcmpi(ParamDesc.Semantic, "view") == 0) + m_MatViewEffectHandle = hParam; + else if(strcmpi(ParamDesc.Semantic, "projection") == 0) + m_MatProjEffectHandle = hParam; + else if(strcmpi(ParamDesc.Semantic, "worldview") == 0) + m_MatWorldViewEffectHandle = hParam; + else if(strcmpi(ParamDesc.Semantic, "viewprojection") == 0) + m_MatViewProjEffectHandle = hParam; + else if(strcmpi(ParamDesc.Semantic, "worldviewprojection") == 0) + m_MatWorldViewProjEffectHandle = hParam; + } + + else if(ParamDesc.Class == D3DXPC_VECTOR && ParamDesc.Type == D3DXPT_FLOAT) { + if(strcmpi(ParamDesc.Semantic, "sourcedims") == 0) + m_SourceDimsEffectHandle = hParam; + else if(strcmpi(ParamDesc.Semantic, "texelsize") == 0) + m_TexelSizeEffectHandle = hParam; + else if(strcmpi(ParamDesc.Semantic, "inputdims") == 0) { + if(m_iDim[0] && m_iDim[1] && ((hr = m_pEffect->SetFloatArray(hParam, m_iDim, 2)) != D3D_OK)) { + m_strErrors += "Could not set inputdims parameter!"; + return hr; + } + } + } + + else if(ParamDesc.Class == D3DXPC_SCALAR && ParamDesc.Type == D3DXPT_FLOAT) { + if(strcmpi(ParamDesc.Semantic, "SCALING") == 0) + m_pEffect->GetFloat(hParam, &m_scale); + } + + else if(ParamDesc.Class == D3DXPC_SCALAR && ParamDesc.Type == D3DXPT_BOOL) { + if(strcmpi(ParamDesc.Semantic, "FORCEUPDATE") == 0) + m_pEffect->GetBool(hParam, &m_forceupdate); + } + + else if(ParamDesc.Class == D3DXPC_OBJECT && ParamDesc.Type == D3DXPT_TEXTURE) { + if(strcmpi(ParamDesc.Semantic, "SOURCETEXTURE") == 0) + m_SourceTextureEffectHandle = hParam; + if(strcmpi(ParamDesc.Semantic, "WORKINGTEXTURE") == 0) + m_WorkingTexture1EffectHandle = hParam; + if(strcmpi(ParamDesc.Semantic, "WORKINGTEXTURE1") == 0) + m_WorkingTexture2EffectHandle = hParam; + if(strcmpi(ParamDesc.Semantic, "HQ2XLOOKUPTEXTURE") == 0) + m_Hq2xLookupTextureHandle = hParam; + } + + else if(ParamDesc.Class == D3DXPC_OBJECT && ParamDesc.Type == D3DXPT_STRING) { + LPCSTR pstrTechnique = NULL; + + if(strcmpi(ParamDesc.Semantic, "COMBINETECHNIQUE") == 0) { + m_pEffect->GetString(hParam, &pstrTechnique); + m_CombineTechniqueEffectHandle = m_pEffect->GetTechniqueByName(pstrTechnique); + } + else if(strcmpi(ParamDesc.Semantic, "PREPROCESSTECHNIQUE") == 0) { + m_pEffect->GetString(hParam, &pstrTechnique); + m_PreprocessTechnique1EffectHandle = m_pEffect->GetTechniqueByName(pstrTechnique); + } + else if(strcmpi(ParamDesc.Semantic, "PREPROCESSTECHNIQUE1") == 0) { + m_pEffect->GetString(hParam, &pstrTechnique); + m_PreprocessTechnique2EffectHandle = m_pEffect->GetTechniqueByName(pstrTechnique); + } + else if(strcmpi(ParamDesc.Semantic, "NAME") == 0) + m_pEffect->GetString(hParam, &m_strName); + + } + + + } + + for(UINT iAnnot = 0; iAnnot < ParamDesc.Annotations; iAnnot++) { + hAnnot = m_pEffect->GetAnnotation (hParam, iAnnot); + m_pEffect->GetParameterDesc(hAnnot, &AnnotDesc); + if(strcmpi(AnnotDesc.Name, "name") == 0) + m_pEffect->GetString(hAnnot, &pstrName); + else if(strcmpi(AnnotDesc.Name, "function") == 0) + m_pEffect->GetString(hAnnot, &pstrFunction); + else if(strcmpi(AnnotDesc.Name, "target") == 0) + m_pEffect->GetString(hAnnot, &pstrTarget); + else if(strcmpi(AnnotDesc.Name, "width") == 0) + m_pEffect->GetInt(hAnnot, &Width); + else if(strcmpi(AnnotDesc.Name, "height") == 0) + m_pEffect->GetInt(hAnnot, &Height); + else if(strcmpi(AnnotDesc.Name, "depth") == 0) + m_pEffect->GetInt(hAnnot, &Depth); + else if(strcmpi(AnnotDesc.Name, "type") == 0) + m_pEffect->GetString(hAnnot, &pstrTextureType); + + } + + // Not used in DOSBox +/* if(pstrName != NULL) { + pTex = NULL; + DXUtil_ConvertAnsiStringToGenericCch(strPath, pstrName, MAX_PATH); + if(pstrTextureType != NULL) { + if(strcmpi(pstrTextureType, "volume") == 0) { + LPDIRECT3DVOLUMETEXTURE9 pVolumeTex = NULL; + if(SUCCEEDED(hr = D3DXCreateVolumeTextureFromFileEx(m_pd3dDevice, strPath, + Width, Height, Depth, 1, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, + D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &pVolumeTex))) { + pTex = pVolumeTex; + } + else { + m_strErrors += "Could not load volume texture "; + m_strErrors += pstrName; + } + } + else if(strcmpi(pstrTextureType, "cube") == 0) { + LPDIRECT3DCUBETEXTURE9 pCubeTex = NULL; + if(SUCCEEDED(hr = D3DXCreateCubeTextureFromFileEx(m_pd3dDevice, strPath, + Width, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, + D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &pCubeTex))) { + pTex = pCubeTex; + } + else { + m_strErrors += "Could not load cube texture "; + m_strErrors += pstrName; + } + } + } + else { + LPDIRECT3DTEXTURE9 p2DTex = NULL; + if(SUCCEEDED(hr = D3DXCreateTextureFromFileEx(m_pd3dDevice, strPath, + Width, Height, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, + D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &p2DTex))) { + pTex = p2DTex; + } + else { + m_strErrors += "Could not load texture "; + m_strErrors += pstrName; + m_strErrors += "\n"; + } + } + + // Apply successfully loaded texture to effect + if(SUCCEEDED(hr) && pTex != NULL) { + m_pEffect->SetTexture(m_pEffect->GetParameter(NULL, iParam), pTex); + SAFE_RELEASE(pTex); + } + } + else */ + if(pstrFunction != NULL) { + LPD3DXBUFFER pTextureShader = NULL; + LPD3DXBUFFER lpErrors = 0; + + if(pstrTarget == NULL || strcmp(pstrTarget,"tx_1_1")) + pstrTarget = "tx_1_0"; + + if(SUCCEEDED(hr = lpEffectCompiler->CompileShader( + pstrFunction, pstrTarget, + 0, &pTextureShader, &lpErrors, NULL))) { + SAFE_RELEASE(lpErrors); + + if(Width == D3DX_DEFAULT) + Width = 64; + if(Height == D3DX_DEFAULT) + Height = 64; + if(Depth == D3DX_DEFAULT) + Depth = 64; + +#if D3DX_SDK_VERSION >= 22 + LPD3DXTEXTURESHADER ppTextureShader; + D3DXCreateTextureShader((DWORD *)pTextureShader->GetBufferPointer(), &ppTextureShader); +#endif + + if(pstrTextureType != NULL) { + if(strcmpi(pstrTextureType, "volume") == 0) { + LPDIRECT3DVOLUMETEXTURE9 pVolumeTex = NULL; + if(SUCCEEDED(hr = D3DXCreateVolumeTexture(m_pd3dDevice, + Width, Height, Depth, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &pVolumeTex))) { +#if D3DX_SDK_VERSION >= 22 + if(SUCCEEDED(hr = D3DXFillVolumeTextureTX(pVolumeTex, ppTextureShader))) { +#else + if(SUCCEEDED(hr = D3DXFillVolumeTextureTX(pVolumeTex, + (DWORD *)pTextureShader->GetBufferPointer(), NULL, 0))) { +#endif + pTex = pVolumeTex; + } + } + } else if(strcmpi(pstrTextureType, "cube") == 0) { + LPDIRECT3DCUBETEXTURE9 pCubeTex = NULL; + if(SUCCEEDED(hr = D3DXCreateCubeTexture(m_pd3dDevice, + Width, D3DX_DEFAULT, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &pCubeTex))) { +#if D3DX_SDK_VERSION >= 22 + if(SUCCEEDED(hr = D3DXFillCubeTextureTX(pCubeTex, ppTextureShader))) { +#else + if(SUCCEEDED(hr = D3DXFillCubeTextureTX(pCubeTex, + (DWORD *)pTextureShader->GetBufferPointer(), NULL, 0))) { +#endif + pTex = pCubeTex; + } + } + } + } else { + LPDIRECT3DTEXTURE9 p2DTex = NULL; + if(SUCCEEDED(hr = D3DXCreateTexture(m_pd3dDevice, Width, Height, + D3DX_DEFAULT, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &p2DTex))) { +#if D3DX_SDK_VERSION >= 22 + if(SUCCEEDED(hr = D3DXFillTextureTX(p2DTex, ppTextureShader))) { +#else + if(SUCCEEDED(hr = D3DXFillTextureTX(p2DTex, + (DWORD *)pTextureShader->GetBufferPointer(), NULL, 0))) { +#endif + pTex = p2DTex; + } + } + } + m_pEffect->SetTexture(m_pEffect->GetParameter(NULL, iParam), pTex); + SAFE_RELEASE(pTex); + SAFE_RELEASE(pTextureShader); +#if D3DX_SDK_VERSION >= 22 + SAFE_RELEASE(ppTextureShader); +#endif + } else { + if(lpErrors) { + m_strErrors += (char*) lpErrors->GetBufferPointer(); + } + + m_strErrors += "Could not compile texture shader "; + m_strErrors += pstrFunction; + + SAFE_RELEASE(lpErrors); + return hr; + } + } + } + + return S_OK; +} + +// Set Source texture +HRESULT ScalingEffect::SetTextures(LPDIRECT3DTEXTURE9 lpSource, LPDIRECT3DTEXTURE9 lpWorking1, + LPDIRECT3DTEXTURE9 lpWorking2, LPDIRECT3DVOLUMETEXTURE9 lpHq2xLookupTexture) +{ + if(!m_SourceTextureEffectHandle) { + m_strErrors += "Texture with SOURCETEXTURE semantic not found"; + return E_FAIL; + } + + HRESULT hr = m_pEffect->SetTexture(m_SourceTextureEffectHandle, lpSource); + + if(FAILED(hr)) { + m_strErrors += "Unable to set SOURCETEXTURE"; + return hr; + } + + if(m_WorkingTexture1EffectHandle) { + hr = m_pEffect->SetTexture(m_WorkingTexture1EffectHandle, lpWorking1); + + if(FAILED(hr)) { + m_strErrors += "Unable to set WORKINGTEXTURE"; + return hr; + } + } + + if(m_WorkingTexture2EffectHandle) { + hr = m_pEffect->SetTexture(m_WorkingTexture2EffectHandle, lpWorking2); + + if(FAILED(hr)) { + m_strErrors += "Unable to set WORKINGTEXTURE1"; + return hr; + } + } + + if(m_Hq2xLookupTextureHandle) { + hr = m_pEffect->SetTexture(m_Hq2xLookupTextureHandle, lpHq2xLookupTexture); + + if(FAILED(hr)) { + m_strErrors += "Unable to set HQ2XLOOKUPTEXTURE"; + return hr; + } + } + + D3DXVECTOR4 fDims(256,256,1,1), fTexelSize(1,1,1,1); + + if(lpSource) { + D3DSURFACE_DESC Desc; + lpSource->GetLevelDesc(0, &Desc); + fDims[0] = (FLOAT) Desc.Width; + fDims[1] = (FLOAT) Desc.Height; + } + + fTexelSize[0] = 1.0/fDims[0]; + fTexelSize[1] = 1.0/fDims[1]; + + if(m_SourceDimsEffectHandle) { + hr = m_pEffect->SetVector(m_SourceDimsEffectHandle, &fDims); + + if(FAILED(hr)) { + m_strErrors += "Unable to set SOURCEDIMS"; + return hr; + } + } + + if(m_TexelSizeEffectHandle) { + hr = m_pEffect->SetVector(m_TexelSizeEffectHandle, &fTexelSize); + + if(FAILED(hr)) { + m_strErrors += "Unable to set TEXELSIZE"; + return hr; + } + } + + return hr; +} + +// Set the Matrices for this frame +HRESULT ScalingEffect::SetMatrices(D3DXMATRIX &matProj, D3DXMATRIX &matView, D3DXMATRIX &matWorld) +{ + HRESULT hr = S_OK; + + if(m_MatWorldEffectHandle != NULL) { + hr = m_pEffect->SetMatrix(m_MatWorldEffectHandle, &matWorld); + if(FAILED(hr)) { + m_strErrors += "Unable to set WORLD matrix"; + return hr; + } + } + + if(m_MatViewEffectHandle != NULL) { + hr = m_pEffect->SetMatrix(m_MatViewEffectHandle, &matView); + if(FAILED(hr)) { + m_strErrors += "Unable to set VIEW matrix"; + return hr; + } + } + + if(m_MatProjEffectHandle != NULL) { + hr = m_pEffect->SetMatrix(m_MatProjEffectHandle, &matProj); + if(FAILED(hr)) { + m_strErrors += "Unable to set PROJECTION matrix"; + return hr; + } + } + + if(m_MatWorldViewEffectHandle != NULL) { + D3DXMATRIX matWorldView = matWorld * matView; + hr = m_pEffect->SetMatrix(m_MatWorldViewEffectHandle, &matWorldView); + if(FAILED(hr)) { + m_strErrors += "Unable to set WORLDVIEW matrix"; + return hr; + } + } + + if(m_MatViewProjEffectHandle != NULL) { + D3DXMATRIX matViewProj = matView * matProj; + hr = m_pEffect->SetMatrix(m_MatViewProjEffectHandle, &matViewProj); + if(FAILED(hr)) { + m_strErrors += "Unable to set VIEWPROJECTION matrix"; + return hr; + } + } + + if(m_MatWorldViewProjEffectHandle != NULL) { + D3DXMATRIX matWorldViewProj = matWorld * matView * matProj; + hr = m_pEffect->SetMatrix(m_MatWorldViewProjEffectHandle, &matWorldViewProj); + if(FAILED(hr)) { + m_strErrors += "Unable to set WORLDVIEWPROJECTION matrix"; + return hr; + } + } + + return hr; +} + + +// Returns Number of passes for this technique +HRESULT ScalingEffect::Begin(Pass pass, UINT* pPasses) +{ + HRESULT hr = S_OK; + + switch (pass) { + case Preprocess1: + hr = m_pEffect->SetTechnique(m_PreprocessTechnique1EffectHandle); + break; + case Preprocess2: + hr = m_pEffect->SetTechnique(m_PreprocessTechnique2EffectHandle); + break; + case Combine: + hr = m_pEffect->SetTechnique(m_CombineTechniqueEffectHandle); + break; + } + + if(FAILED(hr)) { + m_strErrors += "SetTechnique failed"; + return E_FAIL; + } + + return m_pEffect->Begin(pPasses, D3DXFX_DONOTSAVESTATE|D3DXFX_DONOTSAVESHADERSTATE); +} + +// Render Pass in technique +HRESULT ScalingEffect::BeginPass(UINT Pass) +{ +#if D3DX_SDK_VERSION >= 22 + return m_pEffect->BeginPass(Pass); +#else + return m_pEffect->Pass(Pass); +#endif +} + +// End Pass of this technique +HRESULT ScalingEffect::EndPass() +{ +#if D3DX_SDK_VERSION >= 22 + return m_pEffect->EndPass(); +#else + return S_OK; +#endif +} + +// End rendering of this technique +HRESULT ScalingEffect::End() +{ + return m_pEffect->End(); +} + +// Validates the effect +HRESULT ScalingEffect::Validate() +{ + HRESULT hr; + + // Now we check to see if they all exist + if(!m_MatWorldEffectHandle || !m_MatWorldViewEffectHandle || + !m_MatWorldViewProjEffectHandle) { + m_strErrors += "Effect doesn't have any world matrix handles"; + return E_FAIL; + } + + if(!m_MatViewEffectHandle || !m_MatWorldViewEffectHandle || + !m_MatViewProjEffectHandle || !m_MatWorldViewProjEffectHandle) { + m_strErrors += "Effect doesn't have any view matrix handles"; + return E_FAIL; + } + + if(!m_MatProjEffectHandle || !m_MatViewProjEffectHandle || + !m_MatWorldViewProjEffectHandle) { + m_strErrors += "Effect doesn't have any projection matrix handles"; + return E_FAIL; + } + + if(!m_SourceTextureEffectHandle) { + m_strErrors += "Effect doesn't have a SOURCETEXTURE handle"; + return E_FAIL; + } + + if(!m_CombineTechniqueEffectHandle) { + m_strErrors += "Effect doesn't have a COMBINETECHNIQUE handle"; + return E_FAIL; + } + + if(!m_WorkingTexture1EffectHandle && m_PreprocessTechnique1EffectHandle) { + m_strErrors += "Effect doesn't have a WORKINGTEXTURE handle but uses preprocess steps"; + return E_FAIL; + } + + if(!m_WorkingTexture2EffectHandle && m_PreprocessTechnique2EffectHandle) { + m_strErrors += "Effect doesn't have a WORKINGTEXTURE1 handle but uses 2 preprocess steps"; + return E_FAIL; + } + + // Validate this + if(m_PreprocessTechnique1EffectHandle) { + hr = m_pEffect->ValidateTechnique(m_PreprocessTechnique1EffectHandle); + + if(FAILED(hr)) { + m_strErrors += "ValidateTechnique for PREPROCESSTECHNIQUE failed"; + return hr; + } + } + + if(m_PreprocessTechnique2EffectHandle) { + hr = m_pEffect->ValidateTechnique(m_PreprocessTechnique2EffectHandle); + + if(FAILED(hr)) { + m_strErrors += "ValidateTechnique for PREPROCESSTECHNIQUE1 failed"; + return hr; + } + } + + hr = m_pEffect->ValidateTechnique(m_CombineTechniqueEffectHandle); + + if(FAILED(hr)) { + m_strErrors += "ValidateTechnique for COMBINETECHNIQUE failed"; + return hr; + } + + return S_OK; +} + +#endif // C_D3DSHADERS diff --git a/src/gui/ScalingEffect.h b/src/gui/ScalingEffect.h new file mode 100644 --- /dev/null +++ b/src/gui/ScalingEffect.h @@ -0,0 +1,104 @@ +/* +Copyright (C) 2003 Ryan A. Nunn + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#pragma once + +#include +#include +#include + +#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } + +class ScalingEffect +{ + float m_scale; + float m_iDim[2]; + BOOL m_forceupdate; + LPCSTR m_strName; + std::string m_strErrors; + LPDIRECT3DDEVICE9 m_pd3dDevice; + + LPD3DXEFFECT m_pEffect; + D3DXEFFECT_DESC m_EffectDesc; + + // Matrix Handles + D3DXHANDLE m_MatWorldEffectHandle; + D3DXHANDLE m_MatViewEffectHandle; + D3DXHANDLE m_MatProjEffectHandle; + D3DXHANDLE m_MatWorldViewEffectHandle; + D3DXHANDLE m_MatViewProjEffectHandle; + D3DXHANDLE m_MatWorldViewProjEffectHandle; + + // Texture Handles + D3DXHANDLE m_SourceDimsEffectHandle; + D3DXHANDLE m_TexelSizeEffectHandle; + D3DXHANDLE m_SourceTextureEffectHandle; + D3DXHANDLE m_WorkingTexture1EffectHandle; + D3DXHANDLE m_WorkingTexture2EffectHandle; + D3DXHANDLE m_Hq2xLookupTextureHandle; + + // Technique stuff + D3DXHANDLE m_PreprocessTechnique1EffectHandle; + D3DXHANDLE m_PreprocessTechnique2EffectHandle; + D3DXHANDLE m_CombineTechniqueEffectHandle; + +public: + enum Pass { Preprocess1, Preprocess2, Combine }; + + ScalingEffect(LPDIRECT3DDEVICE9 pd3dDevice); + ~ScalingEffect(void); + + void KillThis(); + + HRESULT LoadEffect(const TCHAR *filename); + + const char *getErrors() { return m_strErrors.c_str(); } + + LPCSTR getName() { return m_strName; } + float getScale() { return m_scale; } + bool getForceUpdate() { return m_forceupdate != FALSE; } + void setinputDim(float w, float h) { m_iDim[0] = w; m_iDim[1] = h; } + + // Does it have a preprocess step + BOOL hasPreprocess() { return m_PreprocessTechnique1EffectHandle!=0; } + BOOL hasPreprocess2() { return m_PreprocessTechnique2EffectHandle!=0; } + + // Set The Textures + HRESULT SetTextures( LPDIRECT3DTEXTURE9 lpSource, LPDIRECT3DTEXTURE9 lpWorking1, + LPDIRECT3DTEXTURE9 lpWorking2, LPDIRECT3DVOLUMETEXTURE9 lpHq2xLookupTexture ); + + // Set the Matrices for this frame + HRESULT SetMatrices( D3DXMATRIX &matProj, D3DXMATRIX &matView, D3DXMATRIX &matWorld ); + + // Begin the technique + // Returns Number of passes for this technique + HRESULT Begin(Pass pass, UINT* pPasses); + + // Render Pass in technique + HRESULT BeginPass(UINT Pass); + HRESULT EndPass(); + + // End rendering of this technique + HRESULT End(); + + // Validates the effect + HRESULT Validate(); + +private: + HRESULT ParseParameters(LPD3DXEFFECTCOMPILER lpEffectCompiler); +}; diff --git a/src/gui/direct3d.cpp b/src/gui/direct3d.cpp new file mode 100644 --- /dev/null +++ b/src/gui/direct3d.cpp @@ -0,0 +1,1435 @@ +/* + * Direct3D rendering code by gulikoza + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "dosbox.h" + +#if (HAVE_D3D9_H) && defined(WIN32) + +#include "direct3d.h" +#include + +#if LOG_D3D && D3D_THREAD +#define EnterCriticalSection(x) EnterLOGCriticalSection(x, __LINE__) + +void CDirect3D::EnterLOGCriticalSection(LPCRITICAL_SECTION lpCriticalSection, int line) +{ + Bitu i = 0; + static int oldline = -1; + while(!TryEnterCriticalSection(lpCriticalSection)) { + i++; Sleep(0); + if(!(i&0xFFF)) { + LOG_MSG("D3D:Possible deadlock in %u (line: %d, oldline: %d, active command: %d)", SDL_ThreadID(), line, oldline, thread_command); + } + } + if(i) LOG_MSG("D3D:Thread %u waited %u to enter critical section (line: %d, oldline: %d, active command: %d)", SDL_ThreadID(), i, line, oldline, thread_command); + oldline = line; +} +#endif + +HRESULT CDirect3D::InitializeDX(HWND wnd, bool triplebuf) +{ +#if LOG_D3D + LOG_MSG("D3D:Starting Direct3D"); +#endif + + // Check for display window + if(!wnd) { + MessageBox(wnd, "No display window set!", "Error", MB_OK | MB_ICONERROR); + return E_FAIL; + } + + hwnd = wnd; + + mhmodDX9 = LoadLibrary("d3d9.dll"); + if(!mhmodDX9) + return E_FAIL; + + // Set the presentation parameters + ZeroMemory(&d3dpp, sizeof(d3dpp)); + d3dpp.BackBufferWidth = dwWidth; + d3dpp.BackBufferHeight = dwHeight; + d3dpp.BackBufferCount = 1; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.Windowed = true; + d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // */D3DPRESENT_INTERVAL_DEFAULT; //VSync(); + + if(triplebuf) { + LOG_MSG("D3D:Using triple buffering"); + d3dpp.BackBufferCount = 2; + } + + // Init Direct3D + if(FAILED(InitD3D())) { + DestroyD3D(); + MessageBox(hwnd, "Unable to initialize DirectX9!", "Error", MB_OK | MB_ICONERROR); + return E_FAIL; + } + +#if D3D_THREAD +#if LOG_D3D + LOG_MSG("D3D:Starting worker thread from thread: %u", SDL_ThreadID()); +#endif + + thread_run = true; + thread_command = D3D_IDLE; + thread = SDL_CreateThread(EntryPoint, this); + SDL_SemWait(thread_ack); +#endif + + return S_OK; +} + +#if D3D_THREAD +// Wait for D3D to finish processing and return the result +HRESULT CDirect3D::Wait(bool unlock) { + HRESULT res; + + EnterCriticalSection(&cs); + while(thread_command != D3D_IDLE) { + wait = true; + LeaveCriticalSection(&cs); +#if LOG_D3D + LOG_MSG("D3D:Waiting for D3D thread to finish processing...(command: %d)", thread_command); +#endif + SDL_SemWait(thread_ack); + EnterCriticalSection(&cs); + wait = false; + } + +#if LOG_D3D + if(SDL_SemValue(thread_ack)) LOG_MSG("D3D:Semaphore has value: %d!", SDL_SemValue(thread_ack)); +#endif + + res = thread_hr; + if(unlock) LeaveCriticalSection(&cs); + return res; +} +#endif + +#if D3D_THREAD +int CDirect3D::Start(void) +{ +#if LOG_D3D + LOG_MSG("D3D:Worker thread %u starting", SDL_ThreadID()); +#endif + + SDL_SemPost(thread_ack); + + EnterCriticalSection(&cs); + while(thread_run) { + + HRESULT hr; + D3D_state tmp = thread_command; + LeaveCriticalSection(&cs); + + if(tmp == D3D_IDLE) { + SDL_SemWait(thread_sem); + EnterCriticalSection(&cs); + continue; + } + + switch(tmp) { + case D3D_LOADPS: hr = LoadPixelShader(); break; + case D3D_LOCK: hr = LockTexture(); break; + case D3D_UNLOCK: (UnlockTexture() ? hr = S_OK : hr = E_FAIL); break; + default: hr = S_OK; break; + } + + EnterCriticalSection(&cs); + thread_hr = hr; + thread_command = D3D_IDLE; + if(wait) { + LeaveCriticalSection(&cs); + SDL_SemPost(thread_ack); + EnterCriticalSection(&cs); + } + } + +#if LOG_D3D + LOG_MSG("D3D:Thread %u is finishing...", SDL_ThreadID()); +#endif + LeaveCriticalSection(&cs); + + return 0; +} +#endif + +bool CDirect3D::LockTexture(Bit8u * & pixels,Bitu & pitch) +{ +#if D3D_THREAD + Wait(false); + + // Locks take a bit, waiting for the worker thread to do it will most certainly + // take us waiting in the kernel mode...try to lock the texture directly... + if(FAILED(LockTexture())) { + + // OK, let the worker thread do it... + thread_command = D3D_LOCK; + LeaveCriticalSection(&cs); + SDL_SemPost(thread_sem); + + if(FAILED(Wait(false))) { + LeaveCriticalSection(&cs); + LOG_MSG("D3D:No texture to draw to!?"); + return false; + } + } + LeaveCriticalSection(&cs); +#else + if(FAILED(LockTexture())) { + LOG_MSG("D3D:No texture to draw to!?"); + return false; + } +#endif + + pixels=(Bit8u *)d3dlr.pBits; + pitch=d3dlr.Pitch; + return true; +} + +HRESULT CDirect3D::LockTexture(void) +{ + // Lock the surface and write the pixels + static DWORD d3dflags = D3DLOCK_NO_DIRTY_UPDATE; +lock_texture: + if(GCC_UNLIKELY(!lpTexture || deviceLost)) { + // Try to reset the device, but only when running main thread +#if D3D_THREAD + if((SDL_ThreadID() != SDL_GetThreadID(thread))) +#endif + { + Resize3DEnvironment(); + } + if(GCC_UNLIKELY(!lpTexture || deviceLost)) { + LOG_MSG("D3D:Device is lost, locktexture() failed..."); + return E_FAIL; + } + // Success, continue as planned... + } + if(GCC_UNLIKELY(lpTexture->LockRect(0, &d3dlr, NULL, d3dflags) != D3D_OK)) { + if(d3dflags) { + d3dflags = 0; + LOG_MSG("D3D:Cannot lock texture, fallback to compatible mode"); + goto lock_texture; + } else { + LOG_MSG("D3D:Failed to lock texture!"); + } + return E_FAIL; + } + + return S_OK; +} + +bool CDirect3D::UnlockTexture(const Bit16u *changed) +{ + changedLines = changed; +#if D3D_THREAD + Wait(false); + thread_command = D3D_UNLOCK; + LeaveCriticalSection(&cs); + + SDL_SemPost(thread_sem); + return true; +#else + return UnlockTexture(); +#endif +} + +bool CDirect3D::UnlockTexture(void) +{ + if(GCC_UNLIKELY(deviceLost)) return false; + // Support EndUpdate without new data...needed by some shaders + if(GCC_UNLIKELY(!d3dlr.pBits)) return D3DSwapBuffers(); + lpTexture->UnlockRect(0); + d3dlr.pBits = NULL; + RECT rect; + rect.left = 0; + rect.right = dwWidth; + if(!dynamic && changedLines) { + Bitu y = 0, index = 0; + while(y < dwHeight) { + if(!(index & 1)) { + y += changedLines[index]; + } else { + rect.top = y; + rect.bottom = y + changedLines[index]; + lpTexture->AddDirtyRect(&rect); + y += changedLines[index]; + } + index++; + } + } else { + rect.top = 0; rect.bottom = dwHeight; + lpTexture->AddDirtyRect(&rect); + } + + return D3DSwapBuffers(); +} + +HRESULT CDirect3D::InitD3D(void) +{ + IDirect3D9 *(APIENTRY *pDirect3DCreate9)(UINT) = (IDirect3D9 *(APIENTRY *)(UINT))GetProcAddress(mhmodDX9, "Direct3DCreate9"); + if(!pDirect3DCreate9) + return E_FAIL; + + // create the IDirect3D9 object + pD3D9 = pDirect3DCreate9(D3D_SDK_VERSION); + if(pD3D9 == NULL) + return E_FAIL; + + D3DCAPS9 d3dCaps; + // get device capabilities + ZeroMemory(&d3dCaps, sizeof(d3dCaps)); + if(FAILED(pD3D9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps))) + return E_FAIL; + + // get the display mode + D3DDISPLAYMODE d3ddm; + pD3D9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm); + d3dpp.BackBufferFormat = d3ddm.Format; + + HRESULT hr; + + // Check if hardware vertex processing is available + if(d3dCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) { + // Create device with hardware vertex processing + hr = pD3D9->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL, hwnd, + D3DCREATE_HARDWARE_VERTEXPROCESSING|0x00000800L|D3DCREATE_FPU_PRESERVE, &d3dpp, &pD3DDevice9); + } else { + // Create device with software vertex processing + hr = pD3D9->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL, hwnd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING|0x00000800L|D3DCREATE_FPU_PRESERVE, &d3dpp, &pD3DDevice9); + } + + // Make sure device was created + if(FAILED(hr)) { + LOG_MSG("D3D:Unable to create D3D device!"); + return E_FAIL; + } + + if(FAILED(pD3D9->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3ddm.Format, + 0, D3DRTYPE_TEXTURE, D3DFMT_X8R8G8B8))) { + if(FAILED(pD3D9->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3ddm.Format, + 0, D3DRTYPE_TEXTURE, D3DFMT_R5G6B5))) { + DestroyD3D(); + MessageBox(hwnd, "Cannot find a working texture color format!", "Error", MB_OK | MB_ICONERROR); + return E_FAIL; + } + + bpp16 = true; + LOG_MSG("D3D:Running in 16-bit color mode"); + } + + if(d3dCaps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) { +#if LOG_D3D + LOG_MSG("D3D:Square-only textures"); +#endif + square = true; + } else { +#if LOG_D3D + LOG_MSG("D3D:Non-square textures"); +#endif + square = false; + } + + if(d3dCaps.TextureCaps & D3DPTEXTURECAPS_POW2) { + if(d3dCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) { +#if LOG_D3D + LOG_MSG("D3D:Conditional non-pow2 texture size support"); +#endif + pow2 = false; + } else { +#if LOG_D3D + LOG_MSG("D3D:Textures must be a power of 2 in size"); +#endif + pow2 = true; + } + } else { +#if LOG_D3D + LOG_MSG("D3D:Textures do not need to be a power of 2 in size"); +#endif + pow2 = false; + } + + if(d3dCaps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) { +#if LOG_D3D + LOG_MSG("D3D:Dynamic textures supported"); +#endif + dynamic = true; + } else { + LOG_MSG("D3D:Dynamic textures NOT supported. Performance will suffer!"); + dynamic = false; + } + +#if LOG_D3D + LOG_MSG("D3D:Max texture width: %d", d3dCaps.MaxTextureWidth); + LOG_MSG("D3D:Max texture height: %d", d3dCaps.MaxTextureHeight); +#endif + + if((d3dCaps.MaxTextureWidth < 1024) || (d3dCaps.MaxTextureHeight < 1024)) { + DestroyD3D(); + MessageBox(hwnd, "Your card does not support large textures!", "Error", MB_OK | MB_ICONERROR); + return E_FAIL; + } + +#if C_D3DSHADERS + // allow scale2x_ps14.fx with 1.4 shaders, everything else requires 2.0 + if(d3dCaps.PixelShaderVersion >= D3DPS_VERSION(1,4)) { +#if LOG_D3D + LOG_MSG("D3D:Hardware PS version %d.%d", D3DSHADER_VERSION_MAJOR(d3dCaps.PixelShaderVersion), + D3DSHADER_VERSION_MINOR(d3dCaps.PixelShaderVersion)); +#endif + if(d3dCaps.PixelShaderVersion == D3DPS_VERSION(1,4)) + LOG_MSG("D3D:Hardware PS version 1.4 detected. Most shaders probably won't work..."); + if((d3dCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) && (dynamic)) { + psEnabled = true; + square = true; + pow2 = true; // pow2 texture size has to be enabled as well + } else { + LOG_MSG("D3D:Error when initializing pixel shader support. Disabling shaders."); + psEnabled = false; + } + } + else { + LOG_MSG("D3D:Hardware PS version too low. Disabling support for shaders."); + psEnabled = false; + } +#endif + + DWORD dwNumAdapterModes; + D3DDISPLAYMODE DisplayMode; + DWORD m; + + dwNumModes = 0; + + if(bpp16) + dwNumAdapterModes = pD3D9->GetAdapterModeCount(D3DADAPTER_DEFAULT, D3DFMT_R5G6B5); + else + dwNumAdapterModes = pD3D9->GetAdapterModeCount(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8); + + if(dwNumAdapterModes == 0) { + LOG_MSG("D3D:No display modes found"); + return E_FAIL; + } + +#if LOG_D3D + LOG_MSG("D3D:Found %d display modes", dwNumAdapterModes); +#endif + modes = (D3DDISPLAYMODE*)malloc(sizeof(D3DDISPLAYMODE)*dwNumAdapterModes); + + if(!modes) { + LOG_MSG("D3D:Error allocating memory!"); + DestroyD3D(); + return E_FAIL; + } + + for(iMode=0;iModeEnumAdapterModes(D3DADAPTER_DEFAULT, D3DFMT_R5G6B5, iMode, &DisplayMode); + else + pD3D9->EnumAdapterModes(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8, iMode, &DisplayMode); + + // Check if the mode already exists + for(m=0;m0) { + if(((modes[m - 1].Width == DisplayMode.Width) && (modes[m - 1].Height > DisplayMode.Height)) || + (modes[m - 1].Width > DisplayMode.Width)) { + modes[m].Width = modes[m - 1].Width; + modes[m].Height = modes[m - 1].Height; + modes[m].Format = modes[m - 1].Format; + m--; + } + } + + modes[m].Width = DisplayMode.Width; + modes[m].Height = DisplayMode.Height; + modes[m].Format = DisplayMode.Format; + modes[m].RefreshRate = 0; + ++dwNumModes; + } + } + + // Free some unused memory + modes = (D3DDISPLAYMODE*)realloc(modes, sizeof(D3DDISPLAYMODE)*dwNumModes); + + if(!modes) { + LOG_MSG("D3D:Error allocating memory!"); + DestroyD3D(); + return E_FAIL; + } + + dwTexHeight = 0; + dwTexWidth = 0; + + return S_OK; +} + +void CDirect3D::DestroyD3D(void) +{ +#if D3D_THREAD + // Kill child thread + if(thread != NULL) { + Wait(false); + thread_run = false; + thread_command = D3D_IDLE; + LeaveCriticalSection(&cs); + SDL_SemPost(thread_sem); + SDL_WaitThread(thread, NULL); + thread = NULL; + } +#endif + + InvalidateDeviceObjects(); + + // Delete D3D device + SAFE_RELEASE(pD3DDevice9); + SAFE_RELEASE(pD3D9); + + if(modes) { + free(modes); + modes = NULL; + } +} + +// Draw a textured quad on the back-buffer +bool CDirect3D::D3DSwapBuffers(void) +{ + HRESULT hr; + UINT uPasses; + + // begin rendering + pD3DDevice9->BeginScene(); + +#if C_D3DSHADERS + /* PS 2.0 path */ + if(psActive) { + + if(preProcess) { + + // Set preprocess matrices + if(FAILED(psEffect->SetMatrices(m_matPreProj, m_matPreView, m_matPreWorld))) { + LOG_MSG("D3D:Set matrices failed."); + return false; + } + + // Save render target + LPDIRECT3DSURFACE9 lpRenderTarget; + pD3DDevice9->GetRenderTarget(0, &lpRenderTarget); + LPDIRECT3DTEXTURE9 lpWorkTexture = lpWorkTexture1; +pass2: + // Change the render target + LPDIRECT3DSURFACE9 lpNewRenderTarget; + lpWorkTexture->GetSurfaceLevel(0, &lpNewRenderTarget); + + if(FAILED(pD3DDevice9->SetRenderTarget(0, lpNewRenderTarget))) { + LOG_MSG("D3D:Failed to set render target"); + return false; + } + + SAFE_RELEASE(lpNewRenderTarget); + + uPasses = 0; + if(FAILED(psEffect->Begin((lpWorkTexture==lpWorkTexture1) ? + (ScalingEffect::Preprocess1):(ScalingEffect::Preprocess2), &uPasses))) { + LOG_MSG("D3D:Failed to begin PS"); + return false; + } + + for(UINT uPass=0;uPassBeginPass(uPass); + if(FAILED(hr)) { + LOG_MSG("D3D:Failed to begin pass %d", uPass); + return false; + } + + // Render the vertex buffer contents + pD3DDevice9->DrawPrimitive(D3DPT_TRIANGLESTRIP, 4, 2); + psEffect->EndPass(); + } + + if(FAILED(psEffect->End())) { + LOG_MSG("D3D:Failed to end effect"); + return false; + } + +#if DEBUG_PS + // Save rendertarget data + LPDIRECT3DSURFACE9 lpTexRenderTarget; + lpWorkTexture->GetSurfaceLevel(0, &lpTexRenderTarget); + lpDebugTexture->GetSurfaceLevel(0, &lpNewRenderTarget); + if(FAILED(hr=pD3DDevice9->GetRenderTargetData(lpTexRenderTarget, lpNewRenderTarget))) { + LOG_MSG("D3D:Unable to get render target data: 0x%x", hr); + SAFE_RELEASE(lpTexRenderTarget); + SAFE_RELEASE(lpNewRenderTarget); + } else { + SAFE_RELEASE(lpTexRenderTarget); + SAFE_RELEASE(lpNewRenderTarget); + LOG_MSG("D3D:Got render target data, writing debug file (%dx%d)", dwTexWidth, dwTexHeight); + if(lpDebugTexture->LockRect(0, &d3dlr, NULL, D3DLOCK_READONLY) == D3D_OK) { + FILE * debug = fopen(((lpWorkTexture==lpWorkTexture1)?"pass1.raw":"pass2.raw"), "wb"); + if(debug == NULL) { + LOG_MSG("D3D:Unable to create file!"); + } else { + for(int i = 0; i < dwTexHeight; i++) { + Bit8u * ptr = (Bit8u*)d3dlr.pBits; + for(int j = 0; j < dwTexWidth; j++) { + fwrite(ptr, 3, sizeof(char), debug); + ptr += 4; + } + d3dlr.pBits = (Bit8u*)d3dlr.pBits + d3dlr.Pitch; + } + fclose(debug); + } + lpDebugTexture->UnlockRect(0); + } + d3dlr.pBits = NULL; + } +#endif + + if((psEffect->hasPreprocess2()) && (lpWorkTexture == lpWorkTexture1)) { + lpWorkTexture = lpWorkTexture2; + goto pass2; + } + + // Reset the rendertarget + pD3DDevice9->SetRenderTarget(0, lpRenderTarget); + SAFE_RELEASE(lpRenderTarget); + + // Set matrices for final pass + if(FAILED(psEffect->SetMatrices(m_matProj, m_matView, m_matWorld))) { + LOG_MSG("D3D:Set matrices failed."); + return false; + } + } + + uPasses = 0; + + if(FAILED(psEffect->Begin(ScalingEffect::Combine, &uPasses))) { + LOG_MSG("D3D:Failed to begin PS"); + return false; + } + + for(UINT uPass=0;uPassBeginPass(uPass); + if(FAILED(hr)) { + LOG_MSG("D3D:Failed to begin pass %d", uPass); + return false; + } + + // Render the vertex buffer contents + pD3DDevice9->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + psEffect->EndPass(); + } + + if(FAILED(psEffect->End())) { + LOG_MSG("D3D:Failed to end effect"); + return false; + } + + } else +#endif + { + // Normal path + pD3DDevice9->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + } + + // end rendering + pD3DDevice9->EndScene(); + + if(GCC_UNLIKELY(hr=pD3DDevice9->Present(NULL, NULL, NULL, NULL)) != D3D_OK) { + switch(hr) { + case D3DERR_DEVICELOST: + // This will be handled when SDL catches alt-tab and resets GFX + return true; + break; + case D3DERR_DRIVERINTERNALERROR: + LOG_MSG("D3D:Driver internal error"); + return false; + break; + case D3DERR_INVALIDCALL: + default: + LOG_MSG("D3D:Invalid call"); + return false; + break; + } + } + + return true; +} + +HRESULT CDirect3D::InvalidateDeviceObjects(void) +{ + SAFE_RELEASE(lpTexture); +#if C_D3DSHADERS + SAFE_RELEASE(lpWorkTexture1); + SAFE_RELEASE(lpWorkTexture2); + SAFE_RELEASE(lpHq2xLookupTexture); +#if LOG_D3D + SAFE_RELEASE(lpDebugTexture); +#endif + + // Delete pixel shader + if(psEffect) { + delete psEffect; + psEffect = NULL; + } +#endif + + // clear stream source + if(pD3DDevice9) + pD3DDevice9->SetStreamSource(0, NULL, 0, 0); + + SAFE_RELEASE(vertexBuffer); + + return S_OK; +} + +HRESULT CDirect3D::RestoreDeviceObjects(void) +{ + unsigned int vertexbuffersize = sizeof(TLVERTEX) * 4; + preProcess = false; + +#if C_D3DSHADERS + if(psActive) { + // Set up pixel shaders + LoadPixelShader(); + + if(psEffect && psEffect->hasPreprocess()) { +#if LOG_D3D + LOG_MSG("D3D:Pixel shader preprocess active"); +#endif + preProcess = true; + vertexbuffersize = sizeof(TLVERTEX) * 8; + } + } +#endif + // Initialize vertex + pD3DDevice9->SetFVF(D3DFVF_TLVERTEX); + + // Create vertex buffer + if(FAILED(pD3DDevice9->CreateVertexBuffer(vertexbuffersize, D3DUSAGE_WRITEONLY, + D3DFVF_TLVERTEX, D3DPOOL_MANAGED, &vertexBuffer, NULL))) { + LOG_MSG("D3D:Failed to create Vertex Buffer"); + return E_FAIL; + } + + // Lock vertex buffer and set vertices + CreateVertex(); + + pD3DDevice9->SetStreamSource(0, vertexBuffer, 0, sizeof(TLVERTEX)); + + // Turn off culling + pD3DDevice9->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + + // Turn off D3D lighting + pD3DDevice9->SetRenderState(D3DRS_LIGHTING, false); + + // Turn off the zbuffer + pD3DDevice9->SetRenderState(D3DRS_ZENABLE, false); + + CreateDisplayTexture(); + SetupSceneScaled(); + + if(!psActive) { + pD3DDevice9->SetTexture(0, lpTexture); + + // Disable Shaders + pD3DDevice9->SetVertexShader(0); + pD3DDevice9->SetPixelShader(0); + + pD3DDevice9->SetTransform(D3DTS_PROJECTION, &m_matProj); + pD3DDevice9->SetTransform(D3DTS_VIEW, &m_matView); + pD3DDevice9->SetTransform(D3DTS_WORLD, &m_matWorld); + } +#if C_D3DSHADERS + else if(psEffect) { + if(preProcess) { + // Projection is (0,0,0) -> (1,1,1) + D3DXMatrixOrthoOffCenterLH(&m_matPreProj, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f); + + // Align texels with pixels + D3DXMatrixTranslation(&m_matPreView, -0.5f/dwTexWidth, 0.5f/dwTexHeight, 0.0f); + + // Identity for world + D3DXMatrixIdentity(&m_matPreWorld); + + } else if(FAILED(psEffect->SetMatrices(m_matProj, m_matView, m_matWorld))) { + LOG_MSG("D3D:Set matrices failed."); + InvalidateDeviceObjects(); + return E_FAIL; + } + } +#endif + + return S_OK; +} + +extern void RENDER_SetForceUpdate(bool); +HRESULT CDirect3D::LoadPixelShader(const char * shader, double scalex, double scaley, bool forced) +{ + if(!psEnabled) { + RENDER_SetForceUpdate(false); + psActive = false; + return E_FAIL; + } + +#if C_D3DSHADERS + // See if the shader is already running + if((!psEffect) || (strcmp(pshader+8, shader))) { + + // This is called in main thread to test if pixelshader needs to be changed + if((scalex == 0) && (scaley == 0)) return S_OK; + + RENDER_SetForceUpdate(false); + strncpy(pshader+8, shader, 22); pshader[29] = '\0'; +#if D3D_THREAD + Wait(false); + thread_command = D3D_LOADPS; + LeaveCriticalSection(&cs); + SDL_SemPost(thread_sem); + + if(FAILED(Wait(true))) return E_FAIL; +#else + if(FAILED(LoadPixelShader())) return E_FAIL; +#endif + + } else { +#if LOG_D3D + LOG_MSG("D3D:Shader %s is already loaded", shader); +#endif + return E_FAIL; + } + + if (psEffect) { +#if LOG_D3D + LOG_MSG("D3D:Shader scale: %.2f", psEffect->getScale()); +#endif + // Compare optimal scaling factor + bool dblgfx=((scalex < scaley ? scalex : scaley) >= psEffect->getScale()); + + if(dblgfx || forced) { + LOG_MSG("D3D:Pixel shader %s active", shader); + RENDER_SetForceUpdate(psEffect->getForceUpdate()); + psActive = true; + return S_OK; + } else { + LOG_MSG("D3D:Pixel shader not needed"); + psActive = false; + return E_FAIL; + } + } else psActive = false; + +#endif // C_D3DSHADERS + + return S_OK; +} + +HRESULT CDirect3D::LoadPixelShader(void) +{ +#if C_D3DSHADERS + // Load new shader + if(psEffect) { + delete psEffect; + psEffect = NULL; + } + + if(!strcmp(pshader+8, "none")) { + // Returns E_FAIL so that further shader processing is disabled + psActive = false; + return E_FAIL; + } + + psEffect = new ScalingEffect(pD3DDevice9); + if (psEffect == NULL) { + LOG_MSG("D3D:Error creating shader object!"); + psActive = false; + return E_FAIL; + } + +#if LOG_D3D + LOG_MSG("D3D:Loading pixel shader from %s", pshader); +#endif + + psEffect->setinputDim(dwWidth, dwHeight); + if(FAILED(psEffect->LoadEffect(pshader)) || FAILED(psEffect->Validate())) { + LOG_MSG("D3D:Pixel shader error:"); + + // The resulting string can exceed 512 char LOG_MSG limit, split on newlines + std::stringstream ss(psEffect->getErrors()); + std::string line; + while(std::getline(ss, line)) { + LOG_MSG(" %s", line.c_str()); + } + + LOG_MSG("D3D:Pixel shader output disabled"); + delete psEffect; + psEffect = NULL; + psActive = false; + pshader[8] = '\0'; + return E_FAIL; + } + +#endif // C_D3DSHADERS + + return S_OK; +} + +HRESULT CDirect3D::Resize3DEnvironment(Bitu width, Bitu height, Bitu rwidth, Bitu rheight, bool fullscreen) +{ +#if LOG_D3D + LOG_MSG("D3D:Resizing D3D screen..."); +#endif + +#if D3D_THREAD + Wait(false); +#endif + + // set the presentation parameters + d3dpp.BackBufferWidth = width; + d3dpp.BackBufferHeight = height; + + if(fullscreen) { + // Find correct display mode + bool fullscreen_ok = false; + + for(iMode=0;iMode= width) && (modes[iMode].Height >= height)) { + d3dpp.BackBufferWidth = modes[iMode].Width; + d3dpp.BackBufferHeight = modes[iMode].Height; + fullscreen_ok = true; + + // Some cards no longer support 320xXXX resolutions, + // even if they list them as supported. In this case + // the card will silently switch to 640xXXX, leaving black + // borders around displayed picture. Using hardware scaling + // to 640xXXX doesn't cost anything in this case and should + // look exactly the same as 320xXXX. + if(d3dpp.BackBufferWidth < 512) { + d3dpp.BackBufferWidth *= 2; + d3dpp.BackBufferHeight *= 2; + width *= 2; height *= 2; + } + break; + } + } + + if(!fullscreen_ok) { + LOG_MSG("D3D:No suitable fullscreen mode found!"); + //d3dpp.Windowed = !d3dpp.Windowed; + } + } + + dwScaledWidth = width; + dwScaledHeight = height; + + dwWidth = rwidth; + dwHeight = rheight; + +#if LOG_D3D + LOG_MSG("D3D:Resolution set to %dx%d%s", d3dpp.BackBufferWidth, d3dpp.BackBufferHeight, fullscreen ? ", fullscreen" : ""); +#endif + + HRESULT hr = Resize3DEnvironment(); + +#if D3D_THREAD + LeaveCriticalSection(&cs); +#endif + return hr; +} + +HRESULT CDirect3D::Resize3DEnvironment(void) +{ + // Release all vidmem objects + HRESULT hr; + +#if LOG_D3D + LOG_MSG("D3D:Resize3DEnvironment() called"); +#endif + + if(FAILED(hr=InvalidateDeviceObjects())) { + LOG_MSG("D3D:Failed to invalidate objects"); + return hr; + } + + // Reset the device +reset_device: + Bitu i = 20; + // Don't bother too much, when device is already lost + if(deviceLost) i = 5; + deviceLost = false; + + if(FAILED(hr=pD3DDevice9->Reset(&d3dpp))) { + if(hr==D3DERR_DEVICELOST) { + while((hr=pD3DDevice9->TestCooperativeLevel()) != D3DERR_DEVICENOTRESET) { + if(hr==D3DERR_DRIVERINTERNALERROR) { + LOG_MSG("D3D:Driver internal error when resetting device!"); + return hr; + } +#if LOG_D3D + LOG_MSG("D3D:Wait for D3D device to become available..."); +#endif + Sleep(50); i--; + if(i == 0) { + deviceLost = true; +#if LOG_D3D + LOG_MSG("D3D:Giving up on D3D wait..."); +#endif + // Return ok or dosbox will quit, we'll try to reset the device later + return S_OK; + } + } +#if LOG_D3D + LOG_MSG("D3D:Performing another reset..."); +#endif + goto reset_device; + } else { + LOG_MSG("D3D:Failed to reset device!"); + return hr; + } + } + + // Clear all backbuffers + pD3DDevice9->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); + + pD3DDevice9->Present(NULL, NULL, NULL, NULL); + pD3DDevice9->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); + + if(d3dpp.BackBufferCount == 2) { + pD3DDevice9->Present(NULL, NULL, NULL, NULL); + pD3DDevice9->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); + } + +#if LOG_D3D + LOG_MSG("D3D:Mode: %dx%d (x %.2fx%.2f) --> scaled size: %dx%d", dwWidth, dwHeight, + (float)dwScaledWidth/dwWidth, (float)dwScaledHeight/dwHeight, dwScaledWidth, dwScaledHeight); +#endif + + return RestoreDeviceObjects(); +} + +HRESULT CDirect3D::CreateDisplayTexture(void) +{ + SAFE_RELEASE(lpTexture); + + if((dwTexWidth == 0) || (dwTexHeight == 0)) + return S_OK; + +#if LOG_D3D + LOG_MSG("D3D:Creating Textures: %dx%d", dwTexWidth, dwTexHeight); +#endif + + HRESULT hr; + + D3DFORMAT d3dtexformat; + + if(bpp16) + d3dtexformat = D3DFMT_R5G6B5; + else + d3dtexformat = D3DFMT_X8R8G8B8; + + if(!dynamic) { + hr = pD3DDevice9->CreateTexture(dwTexWidth, dwTexHeight, 1, 0, d3dtexformat, + D3DPOOL_MANAGED, &lpTexture, NULL); + + } else { + hr = pD3DDevice9->CreateTexture(dwTexWidth, dwTexHeight, 1, D3DUSAGE_DYNAMIC, d3dtexformat, + D3DPOOL_DEFAULT, &lpTexture, NULL); + } + + if(FAILED(hr)) { + LOG_MSG("D3D:Failed to create %stexture: 0x%x", (dynamic ? "dynamic " : ""), hr); + + switch(hr) { + case D3DERR_INVALIDCALL: + LOG_MSG("D3D:Invalid call"); + break; + case D3DERR_OUTOFVIDEOMEMORY: + LOG_MSG("D3D:D3DERR_OUTOFVIDEOMEMORY"); + break; + case E_OUTOFMEMORY: + LOG_MSG("D3D:E_OUTOFMEMORY"); + break; + default: + LOG_MSG("D3D:E_UNKNOWN"); + } + return E_FAIL; + } + + // Initialize texture to black + if(LockTexture() == S_OK) { + Bit8u * pixels = (Bit8u *)d3dlr.pBits; + + for(Bitu lines = dwTexHeight; lines; lines--) { + memset(pixels, 0, (dwTexWidth<<2)>>bpp16); + pixels += d3dlr.Pitch; + } + + lpTexture->UnlockRect(0); + } + + d3dlr.pBits = NULL; + RECT rect; + + rect.left = rect.top = 0; + rect.right = dwTexWidth; rect.bottom = dwTexHeight; + lpTexture->AddDirtyRect(&rect); + +#if C_D3DSHADERS + if(psActive) { + // Working textures for pixel shader + if(FAILED(hr=pD3DDevice9->CreateTexture(dwTexWidth, dwTexHeight, 1, D3DUSAGE_RENDERTARGET, + D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &lpWorkTexture1, NULL))) { + LOG_MSG("D3D:Failed to create working texture: 0x%x", hr); + + switch(hr) { + case D3DERR_INVALIDCALL: + LOG_MSG("D3D:Invalid call"); + break; + case D3DERR_OUTOFVIDEOMEMORY: + LOG_MSG("D3D:D3DERR_OUTOFVIDEOMEMORY"); + break; + case E_OUTOFMEMORY: + LOG_MSG("D3D:E_OUTOFMEMORY"); + break; + default: + LOG_MSG("D3D:E_UNKNOWN"); + } + return E_FAIL; + } + + if(FAILED(hr=pD3DDevice9->CreateTexture(dwTexWidth, dwTexHeight, 1, D3DUSAGE_RENDERTARGET, + D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &lpWorkTexture2, NULL))) { + LOG_MSG("D3D:Failed to create working texture: 0x%x", hr); + + switch(hr) { + case D3DERR_INVALIDCALL: + LOG_MSG("D3D:Invalid call"); + break; + case D3DERR_OUTOFVIDEOMEMORY: + LOG_MSG("D3D:D3DERR_OUTOFVIDEOMEMORY"); + break; + case E_OUTOFMEMORY: + LOG_MSG("D3D:E_OUTOFMEMORY"); + break; + default: + LOG_MSG("D3D:E_UNKNOWN"); + } + return E_FAIL; + } + + if(FAILED(hr=pD3DDevice9->CreateVolumeTexture(256, 16, 256, 1, 0, D3DFMT_A8R8G8B8, + D3DPOOL_MANAGED, &lpHq2xLookupTexture, NULL))) { + LOG_MSG("D3D:Failed to create volume texture: 0x%x", hr); + + switch(hr) { + case D3DERR_INVALIDCALL: + LOG_MSG("D3D:Invalid call"); + break; + case D3DERR_OUTOFVIDEOMEMORY: + LOG_MSG("D3D:D3DERR_OUTOFVIDEOMEMORY"); + break; + case E_OUTOFMEMORY: + LOG_MSG("D3D:E_OUTOFMEMORY"); + break; + default: + LOG_MSG("D3D:E_UNKNOWN"); + } + return E_FAIL; + } + + // build lookup table + D3DLOCKED_BOX lockedBox; + + if(FAILED(hr = lpHq2xLookupTexture->LockBox(0, &lockedBox, NULL, 0))) { + LOG_MSG("D3D:Failed to lock box of volume texture: 0x%x", hr); + + switch(hr) { + case D3DERR_INVALIDCALL: + LOG_MSG("D3D:Invalid call"); + break; + default: + LOG_MSG("D3D:E_UNKNOWN"); + } + return E_FAIL; + } + + BuildHq2xLookupTexture(dwScaledWidth, dwScaledHeight, dwWidth, dwHeight, (Bit8u *)lockedBox.pBits); + +#if LOG_D3D + // Debug: Write look-up texture to file + int fd = _open("hq2xLookupTexture.pam",_O_WRONLY|_O_CREAT|_O_TRUNC|_O_BINARY,0666); + unsigned char table[4096] = HQ2X_D3D_TABLE_DATA; + sprintf((char *)table,"P7\nWIDTH %i\nHEIGHT %i\nMAXVAL 255\nDEPTH 4\nTUPLTYPE RGB_ALPHA\nENDHDR\n",16*HQ2X_RESOLUTION,4096/16*HQ2X_RESOLUTION); + write(fd,table,strlen((char *)table)); + write(fd, lockedBox.pBits, HQ2X_RESOLUTION * HQ2X_RESOLUTION * 4096 * 4); + _close(fd); +#endif + + if(FAILED(hr = lpHq2xLookupTexture->UnlockBox(0))) { + LOG_MSG("D3D:Failed to unlock box of volume texture: 0x%x", hr); + + switch(hr) { + case D3DERR_INVALIDCALL: + LOG_MSG("D3D:Invalid call"); + break; + default: + LOG_MSG("D3D:E_UNKNOWN"); + } + return E_FAIL; + } + +#if LOG_D3D + // Debug texture for pixel shader + if(FAILED(hr=pD3DDevice9->CreateTexture(dwTexWidth, dwTexHeight, 1, 0, D3DFMT_A8R8G8B8, + D3DPOOL_SYSTEMMEM, &lpDebugTexture, NULL))) { + LOG_MSG("D3D:Failed to create debug texture: 0x%x", hr); + + switch(hr) { + case D3DERR_INVALIDCALL: + LOG_MSG("D3D:Invalid call"); + break; + case D3DERR_OUTOFVIDEOMEMORY: + LOG_MSG("D3D:D3DERR_OUTOFVIDEOMEMORY"); + break; + case E_OUTOFMEMORY: + LOG_MSG("D3D:E_OUTOFMEMORY"); + break; + default: + LOG_MSG("D3D:E_UNKNOWN"); + } + return E_FAIL; + } +#endif // LOG_D3D + + // Set textures + if(FAILED(psEffect->SetTextures(lpTexture, lpWorkTexture1, lpWorkTexture2, lpHq2xLookupTexture))) { + LOG_MSG("D3D:Failed to set PS textures"); + return false; + } + + } +#endif // C_D3DSHADERS + + return S_OK; +} + +HRESULT CDirect3D::CreateVertex(void) +{ + TLVERTEX* vertices; + + // Texture coordinates + float sizex=1.0f, sizey=1.0f; + + // If texture is larger than DOSBox FB + if(dwTexWidth != dwWidth) + sizex = (float)dwWidth/dwTexWidth; + if(dwTexHeight != dwHeight) + sizey = (float)dwHeight/dwTexHeight; + +#if LOG_D3D + LOG_MSG("D3D:Quad size: %dx%d, tex. coord.: 0,0-->%.2f,%.2f", dwWidth, dwHeight, sizex, sizey); +#endif + + // Lock the vertex buffer + vertexBuffer->Lock(0, 0, (void**)&vertices, 0); + + //Setup vertices + vertices[0].position = D3DXVECTOR3(-0.5f, -0.5f, 0.0f); + vertices[0].diffuse = 0xFFFFFFFF; + vertices[0].texcoord = D3DXVECTOR2( 0.0f, sizey); + vertices[1].position = D3DXVECTOR3(-0.5f, 0.5f, 0.0f); + vertices[1].diffuse = 0xFFFFFFFF; + vertices[1].texcoord = D3DXVECTOR2( 0.0f, 0.0f); + vertices[2].position = D3DXVECTOR3( 0.5f, -0.5f, 0.0f); + vertices[2].diffuse = 0xFFFFFFFF; + vertices[2].texcoord = D3DXVECTOR2( sizex, sizey); + vertices[3].position = D3DXVECTOR3( 0.5f, 0.5f, 0.0f); + vertices[3].diffuse = 0xFFFFFFFF; + vertices[3].texcoord = D3DXVECTOR2( sizex, 0.0f); + + // Additional vertices required for some PS effects + if(preProcess) { + vertices[4].position = D3DXVECTOR3( 0.0f, 0.0f, 0.0f); + vertices[4].diffuse = 0xFFFFFF00; + vertices[4].texcoord = D3DXVECTOR2( 0.0f, 1.0f); + vertices[5].position = D3DXVECTOR3( 0.0f, 1.0f, 0.0f); + vertices[5].diffuse = 0xFFFFFF00; + vertices[5].texcoord = D3DXVECTOR2( 0.0f, 0.0f); + vertices[6].position = D3DXVECTOR3( 1.0f, 0.0f, 0.0f); + vertices[6].diffuse = 0xFFFFFF00; + vertices[6].texcoord = D3DXVECTOR2( 1.0f, 1.0f); + vertices[7].position = D3DXVECTOR3( 1.0f, 1.0f, 0.0f); + vertices[7].diffuse = 0xFFFFFF00; + vertices[7].texcoord = D3DXVECTOR2( 1.0f, 0.0f); + } + + // Unlock the vertex buffer + vertexBuffer->Unlock(); + + return S_OK; +} + +void CDirect3D::SetupSceneScaled(void) +{ + unsigned char x=1, y=1; + double sizex,sizey,ratio; + + pD3DDevice9->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + pD3DDevice9->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + pD3DDevice9->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + pD3DDevice9->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + pD3DDevice9->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + pD3DDevice9->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + pD3DDevice9->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + pD3DDevice9->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + pD3DDevice9->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + + D3DVIEWPORT9 Viewport; + pD3DDevice9->GetViewport(&Viewport); + + // Projection is screenspace coords + D3DXMatrixOrthoOffCenterLH(&m_matProj, 0.0f, (float)Viewport.Width, 0.0f, (float)Viewport.Height, 0.0f, 1.0f); + + // View matrix does offset + // A -0.5f modifier is applied to vertex coordinates to match texture + // and screen coords. Some drivers may compensate for this + // automatically, but on others texture alignment errors are introduced + // More information on this can be found in the Direct3D 9 documentation + D3DXMatrixTranslation(&m_matView, (float)Viewport.Width/2-0.5f, (float)Viewport.Height/2+0.5f, 0.0f); + + // World View does scaling + sizex = dwScaledWidth; + sizey = dwScaledHeight; + + // aspect = -1 when in window mode + if((aspect > -1) && (dwWidth > 0) && (dwHeight > 0)) { + if(aspect == 0) { + + // Do only integer scaling to avoid blurring + x = (Bitu)dwScaledWidth/dwWidth; + y = (Bitu)dwScaledHeight/dwHeight; + + ratio = (double)(dwWidth*x)/(dwHeight*y); +#if LOG_D3D + LOG_MSG("D3D:Image aspect ratio is: %f (%dx%d)", ratio, x, y); +#endif + + // Ajdust width + sizey = 4.0/3.0; + while(x > 1) { + sizex = (double)(dwWidth*(x-1))/(dwHeight*y); + if(fabs(sizex - sizey) > fabs(ratio - sizey)) { + break; + } else { + x--; + ratio = sizex; + } +#if LOG_D3D + LOG_MSG("D3D:X adjust, new aspect ratio is: %f (%dx%d)", ratio, x, y); +#endif + } + + // Adjust height + while(y > 1) { + sizex = (double)(dwWidth*x)/(dwHeight*(y-1)); + if(fabs(sizex - sizey) > fabs(ratio - sizey)) { + break; + } else { + y--; + ratio = sizex; + } +#if LOG_D3D + LOG_MSG("D3D:Y adjust, new aspect ratio is: %f (%dx%d)", ratio, x, y); +#endif + } + + sizex = dwWidth*x; + sizey = dwHeight*y; + + } else if(aspect == 1) { + + // We'll try to make the image as close as possible to 4:3 + // (square pixels assumed (as in lcd not crt)) +#if LOG_D3D + LOG_MSG("D3D:Scaling image to 4:3"); +#endif + ratio = 4.0/3.0; + + if(sizex*3 > sizey*4) + sizex = sizey*ratio; + else if(sizex*3 < sizey*4) + sizey = sizex/ratio; + + } + } + +#if LOG_D3D + LOG_MSG("D3D:Scaled resolution: %.1fx%.1f, factor: %dx%d", sizex, sizey, x, y); +#endif + + D3DXMatrixScaling(&m_matWorld, sizex, sizey, 1.0f); +} + +#if !(C_D3DSHADERS) + +D3DXMATRIX* CDirect3D::MatrixOrthoOffCenterLH(D3DXMATRIX *pOut, float l, float r, float b, float t, float zn, float zf) +{ + pOut->_11=2.0f/r; pOut->_12=0.0f; pOut->_13=0.0f; pOut->_14=0.0f; + pOut->_21=0.0f; pOut->_22=2.0f/t; pOut->_23=0.0f; pOut->_24=0.0f; + pOut->_31=0.0f; pOut->_32=0.0f; pOut->_33=1.0f; pOut->_34=0.0f; + pOut->_41=-1.0f; pOut->_42=-1.0f; pOut->_43=0.0f; pOut->_44=1.0f; + + return pOut; +} + +D3DXMATRIX* CDirect3D::MatrixScaling(D3DXMATRIX *pOut, float sx, float sy, float sz) +{ + pOut->_11=sx; pOut->_12=0.0f; pOut->_13=0.0f; pOut->_14=0.0f; + pOut->_21=0.0f; pOut->_22=sy; pOut->_23=0.0f; pOut->_24=0.0f; + pOut->_31=0.0f; pOut->_32=0.0f; pOut->_33=sz; pOut->_34=0.0f; + pOut->_41=0.0f; pOut->_42=0.0f; pOut->_43=0.0f; pOut->_44=1.0f; + + return pOut; +} + +D3DXMATRIX* CDirect3D::MatrixTranslation(D3DXMATRIX *pOut, float tx, float ty, float tz) +{ + pOut->_11=1.0f; pOut->_12=0.0f; pOut->_13=0.0f; pOut->_14=0.0f; + pOut->_21=0.0f; pOut->_22=1.0f; pOut->_23=0.0f; pOut->_24=0.0f; + pOut->_31=0.0f; pOut->_32=0.0f; pOut->_33=1.0f; pOut->_34=0.0f; + pOut->_41=tx; pOut->_42=ty; pOut->_43=tz; pOut->_44=1.0f; + + return pOut; +} + +#endif // !(C_D3DSHADERS) + +#endif // (HAVE_D3D9_H) diff --git a/src/gui/direct3d.h b/src/gui/direct3d.h new file mode 100644 --- /dev/null +++ b/src/gui/direct3d.h @@ -0,0 +1,257 @@ +/* + * Direct3D rendering code by gulikoza + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __DIRECT3D_H_ +#define __DIRECT3D_H_ + +#include +#include "dosbox.h" +#include "hq2x_d3d.h" + +#define LOG_D3D 0 // Set this to 1 to enable D3D debug messages +#define D3D_THREAD 1 // Set this to 1 to thread Direct3D + +#if LOG_D3D +#include +#include +#include +#endif + +#if D3D_THREAD +#include "SDL_thread.h" +#endif + +#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } + +#if defined (_MSC_VER) /* MS Visual C++ */ +#define strcasecmp(a,b) stricmp(a,b) +#endif + +// Vertex format +#define D3DFVF_TLVERTEX D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1 + +#if C_D3DSHADERS +#include "ScalingEffect.h" +#else +#define D3DXMATRIX D3DMATRIX +#define D3DXVECTOR3 vec3f +#define D3DXVECTOR2 vec2f +#define D3DXMatrixOrthoOffCenterLH MatrixOrthoOffCenterLH +#define D3DXMatrixTranslation MatrixTranslation +#define D3DXMatrixScaling MatrixScaling + +struct vec3f { + float x, y, z; + vec3f() { } + vec3f(float vx, float vy, float vz) + : x(vx), y(vy), z(vz) { } +}; + +struct vec2f { + float x, y; + vec2f() { } + vec2f(float vx, float vy) + : x(vx), y(vy) { } +}; + +#endif + +class CDirect3D { +private: + + // globals + HMODULE mhmodDX9; + IDirect3D9* pD3D9; + IDirect3DDevice9* pD3DDevice9; + + D3DPRESENT_PARAMETERS d3dpp; // Present parameters + D3DLOCKED_RECT d3dlr; // Texture lock rectangle + + HWND hwnd; // DOSBow window + DWORD dwWidth, dwHeight; // DOSBox framebuffer size + DWORD dwScaledWidth, dwScaledHeight; // D3D backbuffer size + const Bit16u* changedLines; + + // display modes + D3DDISPLAYMODE* modes; + unsigned int iMode; + DWORD dwNumModes; + + bool deviceLost; + + // vertex stuff + IDirect3DVertexBuffer9* vertexBuffer; // VertexBuffer + + // Custom vertex + struct TLVERTEX { + D3DXVECTOR3 position; // vertex position + D3DCOLOR diffuse; + D3DXVECTOR2 texcoord; // texture coords + }; + + // Projection matrices + D3DXMATRIX m_matProj; + D3DXMATRIX m_matWorld; + D3DXMATRIX m_matView; + +#if C_D3DSHADERS + D3DXMATRIX m_matPreProj; + D3DXMATRIX m_matPreView; + D3DXMATRIX m_matPreWorld; + + // Pixel shader + char pshader[30]; + ScalingEffect* psEffect; + LPDIRECT3DTEXTURE9 lpWorkTexture1; + LPDIRECT3DTEXTURE9 lpWorkTexture2; + LPDIRECT3DVOLUMETEXTURE9 lpHq2xLookupTexture; +#if LOG_D3D + LPDIRECT3DTEXTURE9 lpDebugTexture; +#endif +#endif + LPDIRECT3DTEXTURE9 lpTexture; // D3D texture + bool psEnabled; + bool preProcess; + + // function declarations + HRESULT InitD3D(void); + + HRESULT RestoreDeviceObjects(void); + HRESULT InvalidateDeviceObjects(void); + HRESULT CreateDisplayTexture(void); + HRESULT CreateVertex(void); +#if !(C_D3DSHADERS) + D3DXMATRIX* MatrixOrthoOffCenterLH(D3DXMATRIX*, float, float, float, float, float, float); + D3DXMATRIX* MatrixScaling(D3DXMATRIX*, float, float, float); + D3DXMATRIX* MatrixTranslation(D3DXMATRIX*, float, float, float); +#endif + + void SetupSceneScaled(void); + bool D3DSwapBuffers(void); + +#if D3D_THREAD + // Thread entry point must be static + static int EntryPoint(void * pthis) { CDirect3D * pt = (CDirect3D *)pthis; return pt->Start(); } + HRESULT Wait(bool unlock = true); + int Start(void); + + SDL_Thread *thread; + CRITICAL_SECTION cs; + SDL_semaphore *thread_sem, *thread_ack; + + volatile enum D3D_state { D3D_IDLE = 0, D3D_LOADPS, D3D_LOCK, D3D_UNLOCK } thread_command; + volatile bool thread_run, wait; + volatile HRESULT thread_hr; +#if LOG_D3D + void EnterLOGCriticalSection(LPCRITICAL_SECTION lpCriticalSection, int); +#endif +#endif + + HRESULT LoadPixelShader(void); + HRESULT Resize3DEnvironment(void); + HRESULT LockTexture(void); + bool UnlockTexture(void); + void DestroyD3D(void); + +public: + + // texture stuff + DWORD dwTexHeight, dwTexWidth; + + bool square, pow2, dynamic, bpp16; // Texture limitations + Bit8s aspect; + + // Pixel shader status + bool psActive; + + // function declarations + HRESULT InitializeDX(HWND, bool); + HRESULT LoadPixelShader(const char*, double, double, bool forced=false); + HRESULT Resize3DEnvironment(Bitu, Bitu, Bitu, Bitu, bool fullscreen=false); + bool LockTexture(Bit8u * & pixels,Bitu & pitch); + bool UnlockTexture(const Bit16u *changed); + + CDirect3D(Bitu width = 640, Bitu height = 400):dwWidth(width),dwHeight(height) { + mhmodDX9 = NULL; + pD3D9 = NULL; + pD3DDevice9 = NULL; + modes = NULL; + vertexBuffer = NULL; + + deviceLost = false; + + bpp16 = false; + aspect = 0; + lpTexture = NULL; + + psEnabled = false; + psActive = false; + preProcess = false; + +#if C_D3DSHADERS + lpWorkTexture1 = NULL; + lpWorkTexture2 = NULL; + lpHq2xLookupTexture = NULL; +#if LOG_D3D + lpDebugTexture = NULL; +#endif + strcpy(pshader, "shaders\\"); + psEffect = NULL; +#endif + +#if D3D_THREAD + thread = NULL; + wait = false; + thread_run = false; + thread_command = D3D_IDLE; + + InitializeCriticalSection(&cs); + thread_sem = SDL_CreateSemaphore(0); + thread_ack = SDL_CreateSemaphore(0); +#endif + + } + + bool getForceUpdate(void) { +#if C_D3DSHADERS + if (psEffect) return psEffect->getForceUpdate(); +#endif + return false; + } + + ~CDirect3D() { +#if LOG_D3D + LOG_MSG("D3D:Shutting down Direct3D"); +#endif + DestroyD3D(); + +#if D3D_THREAD + DeleteCriticalSection(&cs); + SDL_DestroySemaphore(thread_sem); + SDL_DestroySemaphore(thread_ack); +#endif + + // Unload d3d9.dll + if (mhmodDX9) { + FreeLibrary(mhmodDX9); + mhmodDX9 = NULL; + } + } +}; + +#endif // __DIRECT3D_H_ diff --git a/src/gui/hq2x_d3d.cpp b/src/gui/hq2x_d3d.cpp new file mode 100644 --- /dev/null +++ b/src/gui/hq2x_d3d.cpp @@ -0,0 +1,205 @@ +/* + * Hq2x scaler pixel shader version support code by Mitja Gros (Mitja.Gros@gmail.com) + * + * Original OpenGL-HQ rendering code + * Copyright (C) 2004-2005 Jörg Walter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "hq2x_d3d.h" + +#if C_D3DSHADERS + +#define fmax(x,y) ((x)>(y)?(x):(y)) +#define fmin(x,y) ((x)<(y)?(x):(y)) +#define R 1 +#define T 2 +#define RT 4 +#define RT2 8 +#define L 16 +#define LB2 32 +#define LT2 64 +#define LT 128 +#define LB 256 +#define B 512 +#define RB2 1024 +#define RB 2048 + +#define NODIAG 0x90 +#define H 1 +#define V 2 +#define D 4 + +#define hmirror(p) swap_bits(swap_bits(swap_bits(swap_bits(swap_bits(p,R,L),RT,LT),RT2,LT2),RB,LB),RB2,LB2) +#define vmirror(p) swap_bits(swap_bits(swap_bits(swap_bits(swap_bits(p,T,B),RT,RB),RT2,RB2),LT,LB),LT2,LB2) +#define NO_BORDER(x) ((b&(x)) == 0) +#define IS_BORDER(x) ((b&(x)) == (x)) +#define SETINTERP(percentage_inside) setinterp(xcenter,ycenter,percentage_inside, \ + NO_BORDER(R),NO_BORDER(T),NO_BORDER(RT), \ + IS_BORDER(R),IS_BORDER(T),IS_BORDER(RT), \ + texture+((x+(border%16)*HQ2X_RESOLUTION+y*16*HQ2X_RESOLUTION+(border&~15)*HQ2X_RESOLUTION*HQ2X_RESOLUTION)*4)) + +static double sign(double a) { + return (a < 0?-1:1); +} + +/* + This function calculates what percentage of a rectangle intersected by a line lies near the center of the + cordinate system. It is mathematically exact, and well-tested for xcenter > 0 and ycenter > 0 (it's only + used that way). It should be correct for other cases as well, but well... famous last words :) +*/ +static double intersect_any(double xcenter, double ycenter, double xsize, double ysize, double yoffset, double gradient) { + double g = fabs(gradient)*xsize/ysize; + double o = -((yoffset-ycenter) + gradient*xcenter)/ysize*sign(ycenter)*sign(yoffset)-g*0.5+0.5; + double yl = o, yr = o+g, xb = -o/g, xt = (1-o)/g; + double area = 1.0; + + if (yl >= 1.0) xt = xb = area = 0.0; + else if (yl > 0.0) { + area = 1.0-yl; + xb = 0.0; + } + else if (yr <= 0.0) yl = yr = area = 1.0; + else yl = o+xb*g; + + if (xt <= 0.0) yr = yl = area = 0.0; + else if (xt < 1.0) { + area *= xt; + yr = 1.0; + } + else if (xb >= 1.0) xb = xt = area = 1.0; + else xt = (yr-o)/g; + + area -= (xt-xb)*(yr-yl)/2; + + return area; +} + +static double intersect_h(double xcenter, double ycenter, double xsize, double ysize) { + return fmax(0.0,fmin(1.0,(.55-fabs(xcenter)+xsize/2.0)/xsize)); +} + +static double intersect_any_h(double xcenter, double ycenter, double xsize, double ysize, double yoffset, double gradient) { + double hinside = intersect_h(xcenter,ycenter,xsize,ysize); + return hinside*hinside*intersect_any(xcenter,ycenter,xsize,ysize,yoffset,gradient); +} + +static double intersect_v(double xcenter, double ycenter, double xsize, double ysize) { + return fmax(0.0,fmin(1.0,(.55-fabs(ycenter)+ysize/2.0)/ysize)); +} + +static double intersect_any_v(double xcenter, double ycenter, double xsize, double ysize, double yoffset, double gradient) { + double vinside = intersect_v(xcenter,ycenter,xsize,ysize); + return vinside*vinside*intersect_any(xcenter,ycenter,xsize,ysize,yoffset,gradient); +} + +static double intersect_hv(double xcenter, double ycenter, double xsize, double ysize) { + double hinside = intersect_h(xcenter,ycenter,xsize,ysize); + double vinside = intersect_v(xcenter,ycenter,xsize,ysize); + return (1-hinside)*(1-vinside)+hinside*vinside; +} + +/* FIXME: not sure if this is correct, but it is rare enough and most likely near enough. fixes welcome :) */ +static double intersect_any_hv(double xcenter, double ycenter, double xsize, double ysize, double yoffset, double gradient) { + double hvinside = intersect_hv(xcenter,ycenter,xsize,ysize); + return hvinside*hvinside*intersect_any(xcenter,ycenter,xsize,ysize,yoffset,gradient); +} + +static double intersect_hvd(double xcenter, double ycenter, double xsize, double ysize) { + return intersect_h(xcenter,ycenter,xsize,ysize)*intersect_v(xcenter,ycenter,xsize,ysize); +} + +static void setinterp(double xcenter, double ycenter, double percentage_inside, int i1, int i2, int i3, int o1, int o2, int o3, unsigned char *factors) { + double d0, d1, d2, d3, percentage_outside, totaldistance_i, totaldistance_o; + xcenter = fabs(xcenter); + ycenter = fabs(ycenter); + d0 = (1-xcenter)*(1-ycenter); + d1 = xcenter*(1-ycenter); + d2 = (1-xcenter)*ycenter; + d3 = xcenter*ycenter; + if (i1 && i2) i3 = 0; + if (o1 && o2) o3 = 0; + percentage_outside = 1.0-percentage_inside; + totaldistance_i = d0+i1*d1+i2*d2+i3*d3; + totaldistance_o = o1*d1+o2*d2+o3*d3+1e-12; /* +1e-12: prevent division by zero */ + + factors[1] = (unsigned char)(((d1/totaldistance_i*percentage_inside*i1)+(d1/totaldistance_o*percentage_outside*o1))*255+.5); + factors[2] = (unsigned char)(((d2/totaldistance_i*percentage_inside*i2)+(d2/totaldistance_o*percentage_outside*o2))*255+.5); + factors[3] = (unsigned char)(((d3/totaldistance_i*percentage_inside*i3)+(d3/totaldistance_o*percentage_outside*o3))*255+.5); + factors[0] = 255-factors[1]-factors[2]-factors[3];/*(unsigned char)((d0/totaldistance_i*percentage_inside)*255+.5);*/ +} + +/* Wanna have gcc fun? #define this as a macro, get a fast machine and go fetch a coffe or two. See how it is used to get an idea why. + I aborted compilation after 5 minutes of CPU time on an Athlon64 3700+. */ +static int swap_bits(int num, int bit1, int bit2) { + return ((num & ~(bit1|bit2))|((num&bit1)?bit2:0)|((num&bit2)?bit1:0)); +} + + +// width, height == rwidth, rheight +// outwidth, outheight == width, height +void BuildHq2xLookupTexture(Bitu outWidth, Bitu outHeight, Bitu rwidth, Bitu rheight, Bit8u* texture) +{ + double xsize, ysize; + unsigned char table[4096] = HQ2X_D3D_TABLE_DATA; + + xsize = (double)rwidth / (double)outWidth; + ysize = (double)rheight / (double)outHeight; + + for (int border = 0; border < 4096; border++) { + for (int y = 0; y < HQ2X_RESOLUTION; y++) { + for (int x = 0; x < HQ2X_RESOLUTION; x++) { + double xcenter = fabs((((double)x)+0.5) / (double)(HQ2X_RESOLUTION)-0.5)/0.958; + double ycenter = fabs((((double)y)+0.5) / (double)(HQ2X_RESOLUTION)-0.5)/0.958; + int sx = (x < HQ2X_RESOLUTION/2?-1:1); + int sy = (y < HQ2X_RESOLUTION/2?-1:1); + int b = (sy > 0?(sx > 0?border:hmirror(border)):(sx > 0?vmirror(border):vmirror(hmirror(border)))); + + if ((table[b] & NODIAG) == NODIAG) { + if (table[b] & H) { + if (table[b] & V) { + if (table[b] & D) SETINTERP(intersect_hvd(xcenter,ycenter,xsize,ysize)); + else SETINTERP(intersect_hv(xcenter,ycenter,xsize,ysize)); + } else { + SETINTERP(intersect_h(xcenter,ycenter,xsize,ysize)); + } + } else if (table[b] & V) { + SETINTERP(intersect_v(xcenter,ycenter,xsize,ysize)); + } else { + SETINTERP(1.0); + } + } else { + double yoff = (table[b]&4?1:-1)*(((table[b] >> 3) & 3) + 1)/4.0; + double grad = (table[b]&32?1:-1)*(((table[b] >> 6) & 3) + 1)/2.0; + if (table[b] & H) { + if (table[b] & V) { + SETINTERP(intersect_any_hv(xcenter,ycenter,xsize,ysize,yoff,grad)); + } else { + SETINTERP(intersect_any_h(xcenter,ycenter,xsize,ysize,yoff,grad)); + } + } else if (table[b] & V) { + SETINTERP(intersect_any_v(xcenter,ycenter,xsize,ysize,yoff,grad)); + } else { + SETINTERP(intersect_any(xcenter,ycenter,xsize,ysize,yoff,grad)); + } + } + + } + } + } +} + +#endif diff --git a/src/gui/hq2x_d3d.h b/src/gui/hq2x_d3d.h new file mode 100644 --- /dev/null +++ b/src/gui/hq2x_d3d.h @@ -0,0 +1,294 @@ +/* + * Hq2x scaler pixel shader version support code by Mitja Gros (Mitja.Gros@gmail.com) + * + * OpenGL-HQ rendering code Copyright (C) 2004-2005 Jörg Walter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __HQ2X_DIRECT3D_H_ +#define __HQ2X_DIRECT3D_H_ + +#include "config.h" +#include + +#if C_D3DSHADERS + +#define HQ2X_RESOLUTION 16 + +void BuildHq2xLookupTexture(Bitu width, Bitu height, Bitu rwidth, Bitu rheight, Bit8u* texture); + +#define HQ2X_D3D_TABLE_DATA { \ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x24,0x24,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x6c,0x93,0x94,0x91,0x24,0x24,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0x6c,0x94,0x91,0x6e,0x4c,0x90,0x91,0x6c,0x6c,0x94,0x91,0x24,0x24,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0x6c,0x94,0x91,0x6e,0x4c,0x90,0x91,0x6c,0x6c,0x94,0x91,0x24,0x24,\ +0x90,0x91,0x92,0x04,0x94,0x91,0x92,0x04,0x90,0x91,0x6c,0x93,0x94,0x91,0x96,0x97,\ +0x90,0x91,0x92,0x04,0x94,0x91,0x92,0x04,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x04,0x94,0x91,0x92,0x04,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x04,0x94,0x91,0x92,0x04,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0xec,0xec,0x94,0x91,0xec,0xec,0x90,0x91,0xec,0xec,0x94,0x91,0xec,0xec,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0x4c,0x94,0x91,0x6e,0x4c,0x90,0x91,0x6c,0x6c,0x94,0x91,0x6e,0x6c,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0x4c,0x94,0x91,0x6e,0x4c,0x90,0x91,0x6c,0x6c,0x94,0x91,0x92,0x6c,\ +0x90,0x91,0x92,0x04,0x94,0x91,0x92,0x04,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x4c,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x04,0x94,0x91,0x92,0x04,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x4c,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0xe8,0x92,0xe8,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0xe8,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x68,0x92,0x93,0x94,0xe8,0x92,0xe8,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0xe8,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0xe8,0x92,0xe8,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x4c,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0xe8,0x92,0xe8,\ +0x90,0x91,0x92,0x4c,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0xe8,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x6c,0x90,0x91,0x6c,0x93,0x94,0xe8,0x92,0xe8,\ +0x90,0x91,0x6c,0x6c,0x94,0x91,0x6c,0x4c,0x90,0x91,0x6c,0x93,0x94,0xe8,0x6c,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x6c,0x90,0x91,0x6c,0x93,0x94,0xe8,0x92,0xe8,\ +0x90,0x91,0x6c,0x6c,0x94,0x91,0x6e,0x4c,0x90,0x91,0x6c,0x93,0x94,0xe8,0x24,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x6c,0x90,0x91,0x6c,0x93,0x94,0xe8,0x92,0xe8,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x6c,0x04,0x90,0x91,0x92,0x93,0x94,0x91,0x6c,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x6c,0x93,0x94,0xe8,0x92,0xe8,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x04,0x90,0x91,0x92,0x93,0x94,0xe8,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x4c,0x48,0x48,0x48,0x93,0x48,0x48,0x48,0x97,\ +0x90,0x20,0x92,0x20,0x94,0x20,0x92,0x20,0x90,0x20,0x92,0x20,0x94,0x20,0x92,0x20,\ +0x90,0x20,0xec,0xec,0x94,0x20,0xec,0xec,0x90,0x20,0xec,0x93,0x94,0x20,0xec,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x4c,0x48,0x91,0x48,0x93,0x48,0x48,0x48,0x97,\ +0x90,0x20,0x92,0x93,0x94,0x20,0x92,0x4c,0x90,0x20,0x92,0x20,0x94,0x20,0x92,0x20,\ +0x90,0x20,0x92,0x20,0x94,0x20,0x92,0x4c,0x90,0x20,0x92,0x93,0x94,0x20,0x92,0x4c,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x48,0x48,0x6c,0x6c,0x48,0x48,0x6c,0x4c,0x48,0x48,0x6c,0x93,0x48,0x48,0x6c,0x97,\ +0x90,0x20,0x92,0x20,0x94,0x20,0x92,0x20,0x90,0x20,0x6c,0x20,0x94,0x20,0x92,0x20,\ +0x90,0x20,0x6c,0x20,0x94,0x20,0x6e,0x20,0x90,0x20,0x6c,0x93,0x94,0x20,0x6e,0x4c,\ +0x90,0x91,0x92,0x04,0x94,0x91,0x92,0x04,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x48,0x48,0x48,0x04,0x48,0x48,0x6c,0x04,0x48,0x68,0x48,0x93,0x48,0xec,0x6c,0x4c,\ +0x90,0x20,0x92,0x93,0x94,0x20,0x92,0x04,0x90,0x20,0x6c,0x20,0x94,0x20,0x92,0x20,\ +0x90,0x20,0x92,0x04,0x94,0x20,0x92,0x04,0x90,0x20,0x92,0x93,0x94,0x20,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x24,0x24,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x4c,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x24,0x24,\ +0x90,0x91,0x92,0x4c,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x4c,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0x6c,0x94,0x91,0x6e,0x4c,0x90,0x91,0x6c,0x6c,0x94,0x91,0x24,0x24,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0x68,0x94,0x91,0x6e,0x4c,0x90,0x91,0x6c,0x6c,0x94,0x91,0x24,0x24,\ +0x90,0x91,0x92,0x04,0x94,0x91,0x92,0x04,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x04,0x94,0x91,0x92,0x04,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x04,0x94,0x91,0x92,0x04,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x04,0x94,0x91,0x92,0x04,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0xec,0x93,0x94,0x91,0xec,0x4c,0x90,0x91,0xec,0xec,0x94,0x91,0xec,0xec,\ +0x90,0x91,0x92,0x4c,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x4c,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0x4c,0x94,0x91,0x6e,0x4c,0x90,0x91,0x6c,0x6c,0x94,0x91,0x6e,0x6c,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0x93,0x94,0x91,0x6e,0x4c,0x90,0x91,0x6c,0x68,0x94,0x91,0x6e,0x6c,\ +0x90,0x91,0x92,0x04,0x94,0x91,0x92,0x04,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x4c,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x04,0x94,0x91,0x92,0x04,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x04,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x97,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x4c,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x4c,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x4c,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x6c,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0x6c,0x94,0x91,0x6c,0x4c,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x6c,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0x6c,0x94,0x91,0x6e,0x4c,0x90,0x91,0x6c,0x93,0x94,0x91,0x24,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x04,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x6c,0x04,0x90,0x91,0x92,0x93,0x94,0x91,0x6c,0x97,\ +0x90,0x91,0x92,0x4c,0x94,0x91,0x92,0x04,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x04,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x4c,0x48,0x48,0x92,0x93,0x48,0x48,0x48,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0xec,0xec,0x94,0x91,0xec,0x4c,0x90,0x91,0xec,0x93,0x94,0x91,0xec,0x4c,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x48,0x48,0x48,0x4c,0x48,0x48,0x48,0x4c,0x48,0x48,0x48,0x93,0x48,0x48,0x48,0x97,\ +0x90,0x91,0x92,0x4c,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x4c,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x48,0x48,0x6c,0x6c,0x48,0x48,0x6c,0x4c,0x48,0x48,0x6c,0x93,0x48,0x48,0x96,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0x6c,0x94,0x91,0x6e,0x4c,0x90,0x91,0x6c,0x93,0x94,0x91,0x6e,0x97,\ +0x90,0x91,0x92,0x04,0x94,0x91,0x92,0x04,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x48,0x48,0x48,0x04,0x48,0x48,0x6c,0x04,0x48,0x48,0x48,0x93,0x48,0x48,0x6c,0x97,\ +0x90,0x91,0x92,0x04,0x94,0x91,0x92,0x04,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x04,0x94,0x91,0x92,0x04,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x6c,0x90,0x68,0x92,0x93,0x94,0x91,0x24,0x24,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x6c,0x90,0x68,0x92,0x93,0x94,0x91,0x24,0x24,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x6c,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x6c,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x68,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0x6c,0x94,0x91,0x6e,0x6c,0x90,0x68,0x6c,0x6c,0x94,0x91,0x24,0x24,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x68,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0x6c,0x94,0x91,0x6e,0x6c,0x90,0x68,0x6c,0x6c,0x94,0x91,0x24,0x24,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x68,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x6c,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x68,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x6c,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0xec,0xec,0x94,0x91,0xec,0xec,0x90,0x68,0xec,0xec,0x94,0x91,0xec,0xec,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x68,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0x6c,0x94,0x91,0x6e,0x6c,0x90,0x68,0x6c,0x6c,0x94,0x91,0x6e,0x6c,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x68,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0x6c,0x94,0x91,0x6e,0x6c,0x90,0x68,0x6c,0x6c,0x94,0x91,0x6e,0x6c,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x68,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x68,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x68,0x92,0x68,0x94,0x69,0x92,0x4c,0x90,0x68,0x92,0x68,0x94,0xe8,0x92,0xe8,\ +0x90,0x68,0x92,0x68,0x94,0x6c,0x92,0x4c,0x90,0x68,0x92,0x93,0x94,0x6c,0x24,0x97,\ +0x90,0x68,0x92,0x68,0x94,0x69,0x92,0x4c,0x90,0x68,0x92,0x68,0x94,0xe8,0x92,0xe8,\ +0x90,0x68,0x92,0x68,0x94,0x69,0x92,0x4c,0x90,0x68,0x92,0x93,0x94,0xe8,0x24,0x97,\ +0x90,0x68,0x92,0x68,0x94,0x69,0x92,0x4c,0x90,0x68,0x92,0x68,0x94,0xe8,0x92,0xe8,\ +0x90,0x68,0x92,0x68,0x94,0x6c,0x92,0x4c,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x68,0x92,0x6c,0x94,0x69,0x92,0x4c,0x90,0x68,0x92,0x68,0x94,0xe8,0x92,0xe8,\ +0x90,0x68,0x92,0x68,0x94,0x69,0x92,0x4c,0x90,0x68,0x92,0x93,0x94,0xe8,0x92,0x97,\ +0x90,0x68,0x92,0x68,0x94,0x69,0x92,0x6c,0x90,0x68,0x6c,0x68,0x94,0xe8,0x92,0xe8,\ +0x90,0x68,0x6c,0x90,0x94,0x69,0x6e,0x6c,0x90,0x68,0x6c,0x93,0x94,0xe8,0x24,0x97,\ +0x90,0x68,0x92,0x68,0x94,0x69,0x92,0x6c,0x90,0x68,0x6c,0x68,0x94,0xe8,0x92,0xe8,\ +0x90,0x68,0x6c,0x6c,0x94,0x69,0x6e,0x6c,0x90,0x68,0x6c,0x93,0x94,0xe8,0x24,0x97,\ +0x90,0x68,0x92,0x68,0x94,0x69,0x92,0x6c,0x90,0x68,0x6c,0x68,0x94,0xe8,0x92,0xe8,\ +0x90,0x68,0x92,0x68,0x94,0x69,0x92,0x68,0x90,0x68,0x92,0x90,0x94,0xe8,0x92,0x97,\ +0x90,0x68,0x92,0x68,0x94,0x69,0x92,0x97,0x90,0x68,0x6c,0x68,0x94,0xe8,0x92,0xe8,\ +0x90,0x68,0x92,0x90,0x94,0x69,0x92,0x68,0x90,0x68,0x92,0x93,0x94,0xe8,0x92,0x97,\ +0x90,0x68,0x92,0x4c,0x94,0x69,0x92,0x4c,0x90,0x68,0x92,0x68,0x94,0x69,0x92,0x68,\ +0x48,0x68,0x48,0x68,0x48,0x6c,0x48,0x4c,0x48,0x68,0x48,0x93,0x48,0x6c,0x48,0x97,\ +0x90,0x68,0x92,0x4c,0x94,0x69,0x92,0x4c,0x90,0x68,0x92,0x68,0x94,0x91,0x92,0x68,\ +0x90,0x68,0xec,0xec,0x94,0x69,0xec,0xec,0x90,0x68,0xec,0x93,0x94,0x69,0xec,0x4c,\ +0x90,0x68,0x92,0x4c,0x94,0x69,0x92,0x4c,0x90,0x68,0x92,0x68,0x94,0x69,0x92,0x68,\ +0x48,0x68,0x48,0x68,0x48,0x6c,0x48,0x4c,0x48,0x68,0x48,0x93,0x48,0x95,0x48,0x97,\ +0x90,0x68,0x92,0x93,0x94,0x69,0x92,0x4c,0x90,0x68,0x92,0x6c,0x94,0x69,0x92,0x68,\ +0x90,0x68,0x92,0x68,0x94,0x69,0x92,0x4c,0x90,0x68,0x92,0x93,0x94,0x69,0x92,0x97,\ +0x90,0x68,0x92,0x68,0x94,0x69,0x92,0x68,0x90,0x68,0x6c,0x68,0x94,0x69,0x92,0x68,\ +0x48,0x68,0x6c,0x6c,0x48,0x69,0x6e,0x90,0x48,0x68,0x6c,0x93,0x48,0x69,0x6e,0x97,\ +0x90,0x68,0x92,0x68,0x94,0x69,0x92,0x68,0x90,0x68,0x6c,0x68,0x94,0x69,0x92,0x68,\ +0x90,0x68,0x6c,0x6c,0x94,0x69,0x6e,0x6c,0x90,0x68,0x6c,0x93,0x94,0x69,0x6e,0x97,\ +0x90,0x68,0x92,0x68,0x94,0x69,0x92,0x68,0x90,0x68,0x6c,0x68,0x94,0x69,0x92,0x68,\ +0x48,0x68,0x48,0x68,0x48,0x69,0x48,0x68,0x48,0x68,0x48,0x93,0x48,0x91,0x48,0x97,\ +0x90,0x68,0x92,0x20,0x94,0x69,0x92,0x93,0x90,0x68,0x6c,0x20,0x94,0x69,0x92,0x68,\ +0x90,0x68,0x92,0x68,0x94,0x69,0x92,0x68,0x90,0x68,0x92,0x93,0x94,0x69,0x92,0x97,\ +0x90,0x91,0x92,0xcc,0x94,0x91,0x92,0xcc,0x90,0x68,0x92,0x93,0x94,0x95,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x6c,0x90,0x68,0x92,0x93,0x94,0x91,0x24,0x24,\ +0x90,0x91,0x92,0xcc,0x94,0x91,0x92,0xcc,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x4c,0x90,0x68,0x92,0x93,0x94,0x91,0x24,0x24,\ +0x90,0x91,0x92,0xcc,0x94,0x91,0x92,0xcc,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0xcc,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0xcc,0x94,0x91,0x92,0xcc,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x4c,0x94,0x91,0x92,0xcc,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x68,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0x6c,0x94,0x91,0x6e,0x6c,0x90,0x68,0x6c,0x6c,0x94,0x91,0x24,0x24,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x68,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0x6c,0x94,0x91,0x6e,0x97,0x90,0x68,0x6c,0x6c,0x94,0x91,0x24,0x24,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x68,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x68,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0xcc,0x94,0x91,0x92,0xcc,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0xcc,0x94,0x91,0x92,0xcc,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0xcc,0x94,0x91,0x92,0xcc,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0xec,0x93,0x94,0x91,0xec,0xcc,0x90,0x68,0xec,0xec,0x94,0x91,0xec,0xec,\ +0x90,0x91,0x92,0xcc,0x94,0x91,0x92,0xcc,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0xcc,0x94,0x91,0x92,0xcc,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0xcc,0x94,0x91,0x92,0xcc,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0xcc,0x94,0x91,0x92,0xcc,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x68,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0x6c,0x94,0x91,0x6e,0x6c,0x90,0x68,0x6c,0x6c,0x94,0x91,0x6e,0x6c,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x68,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0xec,0x94,0x91,0x6e,0x93,0x90,0x68,0x6c,0xec,0x94,0x91,0x6e,0x6c,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x68,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x68,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0xec,0x94,0x91,0x92,0xcc,0x90,0x68,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0xcc,0x94,0x91,0x92,0xcc,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x6c,0x92,0xcc,0x90,0x91,0x92,0x93,0x94,0x6c,0x92,0x97,\ +0x90,0x91,0x92,0xcc,0x94,0x91,0x92,0xcc,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0xcc,0x90,0x91,0x92,0x93,0x94,0x91,0x24,0x97,\ +0x90,0x91,0x92,0xcc,0x94,0x91,0x92,0xcc,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x6c,0x92,0xcc,0x90,0x91,0x92,0x93,0x94,0x6c,0x92,0x97,\ +0x90,0x91,0x92,0xcc,0x94,0x91,0x92,0xcc,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0xcc,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x6c,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0x6c,0x94,0x91,0x6e,0x6c,0x90,0x91,0x6c,0x90,0x94,0x91,0x24,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x6c,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0x90,0x94,0x91,0x6e,0x6c,0x90,0x91,0x6c,0x93,0x94,0x91,0x24,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x90,0x94,0x91,0x92,0x97,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x4c,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x48,0x48,0x48,0xcc,0x48,0x6c,0x48,0xcc,0x48,0x48,0x6c,0x93,0x48,0x6c,0x14,0x4c,\ +0x90,0x91,0x92,0x4c,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0xec,0xcc,0x94,0x91,0xec,0xcc,0x90,0x91,0xec,0x93,0x94,0x91,0xec,0x97,\ +0x90,0x91,0x92,0x4c,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x48,0x48,0x48,0xcc,0x48,0x6c,0x48,0xcc,0x48,0x48,0x48,0x93,0x48,0x6c,0x48,0x97,\ +0x90,0x91,0x92,0xcc,0x94,0x91,0x92,0x4c,0x90,0x91,0x92,0x97,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0xcc,0x94,0x91,0x92,0xcc,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x48,0x48,0x6c,0x6c,0x48,0x48,0x6e,0x6c,0x48,0x48,0x6c,0x93,0x48,0x48,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x6c,0x6c,0x94,0x91,0x6e,0x6c,0x90,0x91,0x6c,0x93,0x94,0x91,0x6e,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x48,0x48,0x48,0x97,0x48,0x48,0x48,0x97,0x48,0x48,0x48,0x93,0x48,0x48,0x48,0x97,\ +0x90,0x91,0x92,0x20,0x94,0x91,0x92,0x04,0x90,0x91,0x6c,0x93,0x94,0x91,0x92,0x97,\ +0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,0x90,0x91,0x92,0x93,0x94,0x91,0x92,0x97,\ +} + +#endif // C_D3DSHADERS + +#endif // __HQ2X_DIRECT3D_H_ diff --git a/src/gui/render.cpp b/src/gui/render.cpp --- a/src/gui/render.cpp +++ b/src/gui/render.cpp @@ -229,6 +229,9 @@ void RENDER_EndUpdate( bool abort ) { total += render.frameskip.hadSkip[i]; LOG_MSG( "Skipped frame %d %d", PIC_Ticks, (total * 100) / RENDER_SKIP_CACHE ); #endif + // Force output to update the screen even if nothing changed... + // works only with Direct3D output (GFX_StartUpdate() was probably not even called) + if (render.forceUpdate) GFX_EndUpdate( 0 ); } render.frameskip.index = (render.frameskip.index + 1) & (RENDER_SKIP_CACHE - 1); render.updating=false; @@ -563,6 +566,14 @@ static void ChangeScaler(bool pressed) { RENDER_CallBack( GFX_CallBackReset ); } */ +bool RENDER_GetAspect(void) { + return render.aspect; +} + +void RENDER_SetForceUpdate(bool f) { + render.forceUpdate = f; +} + void RENDER_Init(Section * sec) { Section_prop * section=static_cast(sec); @@ -578,6 +589,7 @@ void RENDER_Init(Section * sec) { render.aspect=section->Get_bool("aspect"); render.frameskip.max=section->Get_int("frameskip"); render.frameskip.count=0; + render.forceUpdate=false; std::string cline; std::string scaler; //Check for commandline paramters and parse them through the configclass so they get checked against allowed values diff --git a/src/gui/sdlmain.cpp b/src/gui/sdlmain.cpp --- a/src/gui/sdlmain.cpp +++ b/src/gui/sdlmain.cpp @@ -108,6 +108,12 @@ struct private_hwdata { }; #endif +#if (HAVE_D3D9_H) +#include "direct3d.h" + +CDirect3D* d3d = NULL; +#endif + #define STDOUT_FILE TEXT("stdout.txt") #define STDERR_FILE TEXT("stderr.txt") #define DEFAULT_CONFIG_FILE "/dosbox.conf" @@ -132,7 +138,8 @@ enum SCREEN_TYPES { SCREEN_SURFACE, SCREEN_SURFACE_DDRAW, SCREEN_OVERLAY, - SCREEN_OPENGL + SCREEN_OPENGL, + SCREEN_DIRECT3D }; enum PRIORITY_LEVELS { @@ -367,6 +374,15 @@ check_gotbpp: flags&=~(GFX_CAN_8|GFX_CAN_15|GFX_CAN_16); break; #endif +#if (HAVE_D3D9_H) && defined(WIN32) + case SCREEN_DIRECT3D: + flags|=GFX_SCALING; + if(GCC_UNLIKELY(d3d->bpp16)) + flags&=~(GFX_CAN_8|GFX_CAN_15|GFX_CAN_32); + else + flags&=~(GFX_CAN_8|GFX_CAN_15|GFX_CAN_16); + break; +#endif default: goto check_surface; break; @@ -459,6 +475,7 @@ void GFX_TearDown(void) { } } +extern bool RENDER_GetAspect(void); Bitu GFX_SetSize(Bitu width,Bitu height,Bitu flags,double scalex,double scaley,GFX_CallBack_t callback) { if (sdl.updating) GFX_EndUpdate( 0 ); @@ -698,6 +715,101 @@ dosurface: break; }//OPENGL #endif //C_OPENGL +#if (HAVE_D3D9_H) && defined(WIN32) + case SCREEN_DIRECT3D: { + // Calculate texture size + if((!d3d->square) && (!d3d->pow2)) { + d3d->dwTexWidth=width; + d3d->dwTexHeight=height; + } else if(d3d->square) { + int texsize=2 << int_log2(width > height ? width : height); + d3d->dwTexWidth=d3d->dwTexHeight=texsize; + } else { + d3d->dwTexWidth=2 << int_log2(width); + d3d->dwTexHeight=2 << int_log2(height); + } + + sdl.clip.x=0; sdl.clip.y=0; + if(sdl.desktop.fullscreen) { + if(sdl.desktop.full.fixed) { + sdl.clip.w=sdl.desktop.full.width; + sdl.clip.h=sdl.desktop.full.height; + scalex=(double)sdl.desktop.full.width/width; + scaley=(double)sdl.desktop.full.height/height; + } + } else { + if((sdl.desktop.window.width) && (sdl.desktop.window.height)) { + scalex=(double)sdl.desktop.window.width/(sdl.draw.width*sdl.draw.scalex); + scaley=(double)sdl.desktop.window.height/(sdl.draw.height*sdl.draw.scaley); + if(scalex < scaley) { + sdl.clip.w=sdl.desktop.window.width; + sdl.clip.h=(Bit16u)(sdl.draw.height*sdl.draw.scaley*scalex); + } else { + sdl.clip.w=(Bit16u)(sdl.draw.width*sdl.draw.scalex*scaley); + sdl.clip.h=(Bit16u)sdl.desktop.window.height; + } + scalex=(double)sdl.clip.w/width; + scaley=(double)sdl.clip.h/height; + } else { + sdl.clip.w=(Bit16u)(width*scalex); + sdl.clip.h=(Bit16u)(height*scaley); + } + } + + Section_prop *section=static_cast(control->GetSection("sdl")); + if(section) { + Prop_multival* prop = section->Get_multival("pixelshader"); + std::string f = prop->GetSection()->Get_string("force"); + d3d->LoadPixelShader(prop->GetSection()->Get_string("type"), scalex, scaley, (f == "forced")); + } else { + LOG_MSG("SDL:D3D:Could not get pixelshader info, shader disabled"); + } + + d3d->aspect=RENDER_GetAspect(); + if((sdl.desktop.fullscreen) && (!sdl.desktop.full.fixed)) { + // Don't do aspect ratio correction when fullfixed=false + d3d->aspect=2; + sdl.clip.w=(Uint16)scalex; + sdl.clip.h=(Uint16)scaley; + // Do fullscreen scaling if pixel shaders are enabled + // or the game uses some weird resolution + if((d3d->psActive) || (sdl.clip.w != sdl.clip.h)) { + sdl.clip.w*=width; + sdl.clip.h*=height; + } else { // just use native resolution + sdl.clip.w=width; + sdl.clip.h=height; + } + } else if(!sdl.desktop.fullscreen) d3d->aspect=-1; + + // Create a dummy sdl surface + // D3D will hang or crash when using fullscreen with ddraw surface, therefore we hack SDL to provide + // a GDI window with an additional 0x40 flag. If this fails or stock SDL is used, use WINDIB output + if(GCC_UNLIKELY(d3d->bpp16)) { + sdl.surface=SDL_SetVideoMode(sdl.clip.w,sdl.clip.h,16,sdl.desktop.fullscreen ? SDL_FULLSCREEN|0x40 : 0x40); + retFlags = GFX_CAN_16 | GFX_SCALING; + } else { + sdl.surface=SDL_SetVideoMode(sdl.clip.w,sdl.clip.h,0,sdl.desktop.fullscreen ? SDL_FULLSCREEN|0x40 : 0x40); + retFlags = GFX_CAN_32 | GFX_SCALING; + } + + if (sdl.surface == NULL) E_Exit("Could not set video mode %ix%i-%i: %s",sdl.clip.w,sdl.clip.h, + d3d->bpp16 ? 16:32,SDL_GetError()); + sdl.desktop.type=SCREEN_DIRECT3D; + + if(d3d->dynamic) retFlags |= GFX_HARDWARE; + + if(GCC_UNLIKELY(d3d->Resize3DEnvironment(sdl.clip.w,sdl.clip.h,width, + height,sdl.desktop.fullscreen) != S_OK)) { + retFlags = 0; + } +#if LOG_D3D + LOG_MSG("SDL:D3D:Display mode set to: %dx%d with %fx%f scale", + sdl.clip.w, sdl.clip.h,sdl.draw.scalex, sdl.draw.scaley); +#endif + break; + } +#endif default: goto dosurface; break; @@ -860,6 +972,11 @@ bool GFX_StartUpdate(Bit8u * & pixels,Bitu & pitch) { sdl.updating=true; return true; #endif +#if (HAVE_D3D9_H) && defined(WIN32) + case SCREEN_DIRECT3D: + sdl.updating=d3d->LockTexture(pixels, pitch); + return sdl.updating; +#endif default: break; } @@ -871,6 +988,11 @@ void GFX_EndUpdate( const Bit16u *changedLines ) { #if (HAVE_DDRAW_H) && defined(WIN32) int ret; #endif + +#if (HAVE_D3D9_H) && defined(WIN32) + if (d3d && d3d->getForceUpdate()); // continue + else +#endif if (!sdl.updating) return; sdl.updating=false; @@ -965,6 +1087,13 @@ void GFX_EndUpdate( const Bit16u *changedLines ) { } break; #endif +#if (HAVE_D3D9_H) && defined(WIN32) + case SCREEN_DIRECT3D: + if(GCC_UNLIKELY(!d3d->UnlockTexture(changedLines))) { + E_Exit("Failed to draw screen!"); + } + break; +#endif default: break; } @@ -1004,6 +1133,13 @@ Bitu GFX_GetRGB(Bit8u red,Bit8u green,Bit8u blue) { // return ((red << 0) | (green << 8) | (blue << 16)) | (255 << 24); //USE BGRA return ((blue << 0) | (green << 8) | (red << 16)) | (255 << 24); + case SCREEN_DIRECT3D: +#if (HAVE_D3D9_H) && defined(WIN32) + if(GCC_UNLIKELY(d3d->bpp16)) + return SDL_MapRGB(sdl.surface->format,red,green,blue); + else +#endif + return ((blue << 0) | (green << 8) | (red << 16)) | (255 << 24); } return 0; } @@ -1023,6 +1159,9 @@ static void GUI_ShutDown(Section * /*sec*/) { if (sdl.draw.callback) (sdl.draw.callback)( GFX_CallBackStop ); if (sdl.mouse.locked) GFX_CaptureMouse(); if (sdl.desktop.fullscreen) GFX_SwitchFullScreen(); +#if (HAVE_D3D9_H) && defined(WIN32) + if ((sdl.desktop.type==SCREEN_DIRECT3D) && (d3d)) delete d3d; +#endif } @@ -1100,6 +1239,20 @@ static void OutputString(Bitu x,Bitu y,const char * text,Bit32u color,Bit32u col #include "dosbox_splash.h" +#if (HAVE_D3D9_H) && defined(WIN32) +#include "SDL_syswm.h" + +static void D3D_reconfigure(Section * sec) { + if (d3d) { + Section_prop *section=static_cast(sec); + Prop_multival* prop = section->Get_multival("pixelshader"); + if(SUCCEEDED(d3d->LoadPixelShader(prop->GetSection()->Get_string("type"), 0, 0))) { + GFX_ResetScreen(); + } + } +} +#endif + //extern void UI_Run(bool); void Restart(bool pressed); @@ -1218,6 +1371,14 @@ static void GUI_StartUp(Section * sec) { sdl.desktop.want_type=SCREEN_OPENGL; sdl.opengl.bilinear=false; #endif +#if (HAVE_D3D9_H) && defined(WIN32) + } else if (output == "direct3d") { + sdl.desktop.want_type=SCREEN_DIRECT3D; +#if LOG_D3D + LOG_MSG("SDL:Direct3D activated"); +#endif +#endif + } else { LOG_MSG("SDL:Unsupported output device %s, switching back to surface",output.c_str()); sdl.desktop.want_type=SCREEN_SURFACE;//SHOULDN'T BE POSSIBLE anymore @@ -1263,6 +1424,26 @@ static void GUI_StartUp(Section * sec) { if (sdl.desktop.bpp==24) { LOG_MSG("SDL:You are running in 24 bpp mode, this will slow down things!"); } +#if (HAVE_D3D9_H) && defined(WIN32) + if(sdl.desktop.want_type==SCREEN_DIRECT3D) { + SDL_SysWMinfo wmi; + SDL_VERSION(&wmi.version); + + if(!SDL_GetWMInfo(&wmi)) { + LOG_MSG("SDL:Error retrieving window information"); + E_Exit("Failed to get window info"); + } + + if(d3d) delete d3d; + d3d = new CDirect3D(640,400); + + if(!d3d) E_Exit("Failed to create d3d object"); + + if(d3d->InitializeDX(wmi.window,sdl.desktop.doublebuf) != S_OK) + E_Exit("Unable to initialize DirectX"); + } +#endif + GFX_Stop(); SDL_WM_SetCaption("DOSBox",VERSION); @@ -1580,6 +1761,10 @@ void GFX_ShowMsg(char const* format,...) { void Config_Add_SDL() { Section_prop * sdl_sec=control->AddSection_prop("sdl",&GUI_StartUp); sdl_sec->AddInitFunction(&MAPPER_StartUp); +#if (HAVE_D3D9_H) && defined(WIN32) + // Allows dynamic pixelshader change + sdl_sec->AddInitFunction(&D3D_reconfigure,true); +#endif Prop_bool* Pbool; Prop_string* Pstring; Prop_int* Pint; @@ -1608,6 +1793,9 @@ void Config_Add_SDL() { #if (HAVE_DDRAW_H) && defined(WIN32) "ddraw", #endif +#if (HAVE_D3D9_H) && defined(WIN32) + "direct3d", +#endif 0 }; Pstring = sdl_sec->Add_string("output",Property::Changeable::Always,"surface"); Pstring->Set_help("What video system to use for output."); @@ -1639,6 +1827,16 @@ void Config_Add_SDL() { Pstring = sdl_sec->Add_path("mapperfile",Property::Changeable::Always,MAPPERFILE); Pstring->Set_help("File used to load/save the key/event mappings from. Resetmapper only works with the defaul value."); +#if (HAVE_D3D9_H) && (C_D3DSHADERS) && defined(WIN32) + Pmulti = sdl_sec->Add_multi("pixelshader",Property::Changeable::Always," "); + Pmulti->SetValue("none"); + Pmulti->Set_help("Pixelshader program (effect file must be in Shaders subdirectory). If 'forced' is appended,\n" + "then the shader will be used even if the result might not be desired."); + + Pstring = Pmulti->GetSection()->Add_string("type",Property::Changeable::Always,"none"); + Pstring = Pmulti->GetSection()->Add_string("force",Property::Changeable::Always,""); +#endif + Pbool = sdl_sec->Add_bool("usescancodes",Property::Changeable::Always,true); Pbool->Set_help("Avoid usage of symkeys, might not work on all operating systems."); } diff --git a/src/platform/visualc/config.h b/src/platform/visualc/config.h --- a/src/platform/visualc/config.h +++ b/src/platform/visualc/config.h @@ -49,6 +49,12 @@ /* Define to 1 if you have the header file. */ #define HAVE_DDRAW_H 1 +/* Define to 1 if you have the header file. */ +#define HAVE_D3D9_H 1 + +/* Define to 1 to use Direct3D shaders, requires d3d9.h and libd3dx9 */ +#define C_D3DSHADERS 1 + /* Define to 1 if you want serial passthrough support (Win32 only). */ #define C_DIRECTSERIAL 1