2010-09-25 15:46:12 +00:00
/***********************************************************************************
Snes9x - Portable Super Nintendo Entertainment System ( TM ) emulator .
( c ) Copyright 1996 - 2002 Gary Henderson ( gary . henderson @ ntlworld . com ) ,
Jerremy Koot ( jkoot @ snes9x . com )
( c ) Copyright 2002 - 2004 Matthew Kendora
( c ) Copyright 2002 - 2005 Peter Bortas ( peter @ bortas . org )
( c ) Copyright 2004 - 2005 Joel Yliluoma ( http : //iki.fi/bisqwit/)
( c ) Copyright 2001 - 2006 John Weidman ( jweidman @ slip . net )
( c ) Copyright 2002 - 2006 funkyass ( funkyass @ spam . shaw . ca ) ,
Kris Bleakley ( codeviolation @ hotmail . com )
( c ) Copyright 2002 - 2010 Brad Jorsch ( anomie @ users . sourceforge . net ) ,
Nach ( n - a - c - h @ users . sourceforge . net ) ,
2011-04-11 19:51:20 +00:00
( c ) Copyright 2002 - 2011 zones ( kasumitokoduck @ yahoo . com )
2010-09-25 15:46:12 +00:00
( c ) Copyright 2006 - 2007 nitsuja
2011-04-11 19:51:20 +00:00
( c ) Copyright 2009 - 2011 BearOso ,
2010-09-25 15:46:12 +00:00
OV2
BS - X C emulator code
( c ) Copyright 2005 - 2006 Dreamer Nom ,
zones
C4 x86 assembler and some C emulation code
( c ) Copyright 2000 - 2003 _Demo_ ( _demo_ @ zsnes . com ) ,
Nach ,
zsKnight ( zsknight @ zsnes . com )
C4 C + + code
( c ) Copyright 2003 - 2006 Brad Jorsch ,
Nach
DSP - 1 emulator code
( c ) Copyright 1998 - 2006 _Demo_ ,
Andreas Naive ( andreasnaive @ gmail . com ) ,
Gary Henderson ,
Ivar ( ivar @ snes9x . com ) ,
John Weidman ,
Kris Bleakley ,
Matthew Kendora ,
Nach ,
neviksti ( neviksti @ hotmail . com )
DSP - 2 emulator code
( c ) Copyright 2003 John Weidman ,
Kris Bleakley ,
Lord Nightmare ( lord_nightmare @ users . sourceforge . net ) ,
Matthew Kendora ,
neviksti
DSP - 3 emulator code
( c ) Copyright 2003 - 2006 John Weidman ,
Kris Bleakley ,
Lancer ,
z80 gaiden
DSP - 4 emulator code
( c ) Copyright 2004 - 2006 Dreamer Nom ,
John Weidman ,
Kris Bleakley ,
Nach ,
z80 gaiden
OBC1 emulator code
( c ) Copyright 2001 - 2004 zsKnight ,
pagefault ( pagefault @ zsnes . com ) ,
Kris Bleakley
Ported from x86 assembler to C by sanmaiwashi
SPC7110 and RTC C + + emulator code used in 1.39 - 1.51
( c ) Copyright 2002 Matthew Kendora with research by
zsKnight ,
John Weidman ,
Dark Force
SPC7110 and RTC C + + emulator code used in 1.52 +
( c ) Copyright 2009 byuu ,
neviksti
S - DD1 C emulator code
( c ) Copyright 2003 Brad Jorsch with research by
Andreas Naive ,
John Weidman
S - RTC C emulator code
( c ) Copyright 2001 - 2006 byuu ,
John Weidman
ST010 C + + emulator code
( c ) Copyright 2003 Feather ,
John Weidman ,
Kris Bleakley ,
Matthew Kendora
Super FX x86 assembler emulator code
( c ) Copyright 1998 - 2003 _Demo_ ,
pagefault ,
zsKnight
Super FX C emulator code
( c ) Copyright 1997 - 1999 Ivar ,
Gary Henderson ,
John Weidman
Sound emulator code used in 1.5 - 1.51
( c ) Copyright 1998 - 2003 Brad Martin
( c ) Copyright 1998 - 2006 Charles Bilyue '
Sound emulator code used in 1.52 +
( c ) Copyright 2004 - 2007 Shay Green ( gblargg @ gmail . com )
SH assembler code partly based on x86 assembler code
( c ) Copyright 2002 - 2004 Marcus Comstedt ( marcus @ mc . pp . se )
2 xSaI filter
( c ) Copyright 1999 - 2001 Derek Liauw Kie Fa
HQ2x , HQ3x , HQ4x filters
( c ) Copyright 2003 Maxim Stepin ( maxim @ hiend3d . com )
NTSC filter
( c ) Copyright 2006 - 2007 Shay Green
GTK + GUI code
2011-04-11 19:51:20 +00:00
( c ) Copyright 2004 - 2011 BearOso
2010-09-25 15:46:12 +00:00
Win32 GUI code
( c ) Copyright 2003 - 2006 blip ,
funkyass ,
Matthew Kendora ,
Nach ,
nitsuja
2011-04-11 19:51:20 +00:00
( c ) Copyright 2009 - 2011 OV2
2010-09-25 15:46:12 +00:00
Mac OS GUI code
( c ) Copyright 1998 - 2001 John Stiles
2011-04-11 19:51:20 +00:00
( c ) Copyright 2001 - 2011 zones
2010-09-25 15:46:12 +00:00
Specific ports contains the works of other authors . See headers in
individual files .
Snes9x homepage : http : //www.snes9x.com/
Permission to use , copy , modify and / or distribute Snes9x in both binary
and source form , for non - commercial purposes , is hereby granted without
fee , providing that this license information and copyright notice appear
with all copies and any derived work .
This software is provided ' as - is ' , without any express or implied
warranty . In no event shall the authors be held liable for any damages
arising from the use of this software or it ' s derivatives .
Snes9x is freeware for PERSONAL USE only . Commercial users should
seek permission of the copyright holders first . Commercial use includes ,
but is not limited to , charging money for Snes9x or software derived from
Snes9x , including Snes9x or derivatives in commercial game bundles , and / or
using Snes9x as a promotion for your commercial product .
The copyright holders request that bug fixes and improvements to the code
should be forwarded to them so everyone can benefit from the modifications
in future versions .
Super NES and Super Nintendo Entertainment System are trademarks of
Nintendo Co . , Limited and its subsidiary companies .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# pragma comment( lib, "d3d9" )
# pragma comment( lib, "d3dx9" )
2011-02-13 00:18:55 +00:00
# pragma comment( lib, "DxErr" )
2010-09-25 15:46:12 +00:00
# include "cdirect3d.h"
# include "win32_display.h"
2010-09-25 17:35:19 +00:00
# include "../snes9x.h"
2010-09-25 15:46:12 +00:00
# include "../gfx.h"
2010-09-25 17:35:19 +00:00
# include "../display.h"
2010-09-25 15:46:12 +00:00
# include "wsnes9x.h"
2010-09-25 17:35:19 +00:00
# include <Dxerr.h>
2010-09-25 15:46:12 +00:00
# include <commctrl.h>
# include "../filter/hq2x.h"
# include "../filter/2xsai.h"
# ifndef max
# define max(a, b) (((a) > (b)) ? (a) : (b))
# endif
# ifndef min
# define min(a, b) (((a) < (b)) ? (a) : (b))
# endif
/* CDirect3D::CDirect3D()
sets default values for the variables
*/
CDirect3D : : CDirect3D ( )
{
init_done = false ;
pD3D = NULL ;
pDevice = NULL ;
drawSurface = NULL ;
vertexBuffer = NULL ;
afterRenderWidth = 0 ;
afterRenderHeight = 0 ;
quadTextureSize = 0 ;
fullscreen = false ;
2010-09-25 17:35:19 +00:00
filterScale = 1 ;
for ( int i = 0 ; i < MAX_SHADER_TEXTURES ; i + + ) {
rubyLUT [ i ] = NULL ;
}
effect = NULL ;
2011-02-24 00:26:42 +00:00
shader_type = D3D_SHADER_NONE ;
2010-09-25 17:35:19 +00:00
shaderTimer = 1.0f ;
shaderTimeStart = 0 ;
shaderTimeElapsed = 0 ;
2011-05-11 19:39:06 +00:00
frameCount = 0 ;
2011-02-24 00:26:42 +00:00
cgContext = NULL ;
cgVertexProgram = cgFragmentProgram = NULL ;
2011-03-20 22:21:12 +00:00
cgAvailable = false ;
2010-09-25 15:46:12 +00:00
}
/* CDirect3D::~CDirect3D()
releases allocated objects
*/
CDirect3D : : ~ CDirect3D ( )
{
DeInitialize ( ) ;
}
/* CDirect3D::Initialize
Initializes Direct3D ( always in window mode )
IN :
hWnd - the HWND of the window in which we render / the focus window for fullscreen
- - - - -
returns true if successful , false otherwise
*/
bool CDirect3D : : Initialize ( HWND hWnd )
{
if ( init_done )
return true ;
pD3D = Direct3DCreate9 ( D3D_SDK_VERSION ) ;
if ( pD3D = = NULL ) {
DXTRACE_ERR_MSGBOX ( TEXT ( " Error creating initial D3D9 object " ) , 0 ) ;
return false ;
}
ZeroMemory ( & dPresentParams , sizeof ( dPresentParams ) ) ;
dPresentParams . hDeviceWindow = hWnd ;
2010-09-25 17:35:19 +00:00
dPresentParams . Windowed = true ;
2010-09-25 15:46:12 +00:00
dPresentParams . BackBufferCount = GUI . DoubleBuffered ? 2 : 1 ;
dPresentParams . SwapEffect = D3DSWAPEFFECT_DISCARD ;
dPresentParams . BackBufferFormat = D3DFMT_UNKNOWN ;
HRESULT hr = pD3D - > CreateDevice ( D3DADAPTER_DEFAULT ,
D3DDEVTYPE_HAL ,
hWnd ,
D3DCREATE_MIXED_VERTEXPROCESSING ,
& dPresentParams ,
& pDevice ) ;
if ( FAILED ( hr ) ) {
DXTRACE_ERR_MSGBOX ( TEXT ( " Error creating D3D9 device " ) , hr ) ;
return false ;
}
hr = pDevice - > CreateVertexBuffer ( sizeof ( triangleStripVertices ) , D3DUSAGE_WRITEONLY , FVF_COORDS_TEX , D3DPOOL_MANAGED , & vertexBuffer , NULL ) ;
if ( FAILED ( hr ) ) {
DXTRACE_ERR_MSGBOX ( TEXT ( " Error creating vertex buffer " ) , hr ) ;
return false ;
}
2011-03-20 22:21:12 +00:00
cgAvailable = loadCgFunctions ( ) ;
if ( cgAvailable ) {
cgContext = cgCreateContext ( ) ;
hr = cgD3D9SetDevice ( pDevice ) ;
if ( FAILED ( hr ) ) {
DXTRACE_ERR_MSGBOX ( TEXT ( " Error setting cg device " ) , hr ) ;
}
2011-02-24 00:26:42 +00:00
}
2011-03-05 23:48:54 +00:00
pDevice - > SetRenderState ( D3DRS_LIGHTING , FALSE ) ;
2010-09-25 15:46:12 +00:00
pDevice - > Clear ( 0 , NULL , D3DCLEAR_TARGET , D3DCOLOR_XRGB ( 0 , 0 , 0 ) , 1.0f , 0 ) ;
init_done = true ;
2010-09-25 17:35:19 +00:00
ApplyDisplayChanges ( ) ;
2010-09-25 15:46:12 +00:00
return true ;
}
void CDirect3D : : DeInitialize ( )
{
DestroyDrawSurface ( ) ;
2010-09-25 17:35:19 +00:00
SetShader ( NULL ) ;
2010-09-25 15:46:12 +00:00
2011-04-10 14:06:24 +00:00
if ( cgContext ) {
cgDestroyContext ( cgContext ) ;
cgContext = NULL ;
}
if ( cgAvailable )
cgD3D9SetDevice ( NULL ) ;
2010-09-25 15:46:12 +00:00
if ( vertexBuffer ) {
vertexBuffer - > Release ( ) ;
vertexBuffer = NULL ;
}
if ( pDevice ) {
pDevice - > Release ( ) ;
pDevice = NULL ;
}
if ( pD3D ) {
pD3D - > Release ( ) ;
pD3D = NULL ;
}
init_done = false ;
afterRenderWidth = 0 ;
afterRenderHeight = 0 ;
quadTextureSize = 0 ;
fullscreen = false ;
2010-09-25 17:35:19 +00:00
filterScale = 0 ;
2011-04-10 14:06:24 +00:00
if ( cgAvailable )
unloadCgLibrary ( ) ;
2011-03-20 22:21:12 +00:00
cgAvailable = false ;
2010-09-25 17:35:19 +00:00
}
bool CDirect3D : : SetShader ( const TCHAR * file )
2011-02-24 00:26:42 +00:00
{
SetShaderCG ( NULL ) ;
SetShaderHLSL ( NULL ) ;
shader_type = D3D_SHADER_NONE ;
if ( file ! = NULL & & lstrlen ( file ) > 3 & & _tcsncicmp ( & file [ lstrlen ( file ) - 3 ] , TEXT ( " .cg " ) , 3 ) = = 0 ) {
return SetShaderCG ( file ) ;
} else {
return SetShaderHLSL ( file ) ;
}
}
2011-03-04 01:11:36 +00:00
void CDirect3D : : checkForCgError ( const char * situation )
{
char buffer [ 4096 ] ;
CGerror error = cgGetError ( ) ;
const char * string = cgGetErrorString ( error ) ;
if ( error ! = CG_NO_ERROR ) {
sprintf ( buffer ,
" Situation: %s \n "
" Error: %s \n \n "
" Cg compiler output... \n " , situation , string ) ;
MessageBoxA ( 0 , buffer ,
" Cg error " , MB_OK | MB_ICONEXCLAMATION ) ;
if ( error = = CG_COMPILER_ERROR ) {
MessageBoxA ( 0 , cgGetLastListing ( cgContext ) ,
" Cg compilation error " , MB_OK | MB_ICONEXCLAMATION ) ;
}
}
}
2011-02-24 00:26:42 +00:00
bool CDirect3D : : SetShaderCG ( const TCHAR * file )
{
TCHAR errorMsg [ MAX_PATH + 50 ] ;
HRESULT hr ;
if ( cgFragmentProgram ) {
cgDestroyProgram ( cgFragmentProgram ) ;
cgFragmentProgram = NULL ;
}
if ( cgVertexProgram ) {
cgDestroyProgram ( cgVertexProgram ) ;
cgVertexProgram = NULL ;
}
if ( file = = NULL | | * file = = TEXT ( ' \0 ' ) )
return true ;
2011-03-20 22:21:12 +00:00
if ( ! cgAvailable ) {
MessageBox ( NULL , TEXT ( " The CG runtime is unavailable, CG shaders will not run. \n Consult the snes9x readme for information on how to obtain the runtime. " ) , TEXT ( " CG Error " ) ,
MB_OK | MB_ICONEXCLAMATION ) ;
return false ;
}
2011-02-24 00:26:42 +00:00
CGprofile vertexProfile = cgD3D9GetLatestVertexProfile ( ) ;
CGprofile pixelProfile = cgD3D9GetLatestPixelProfile ( ) ;
const char * * vertexOptions = cgD3D9GetOptimalOptions ( vertexProfile ) ;
const char * * pixelOptions = cgD3D9GetOptimalOptions ( pixelProfile ) ;
char * fileContents = ReadShaderFileContents ( file ) ;
if ( ! fileContents )
return false ;
cgVertexProgram = cgCreateProgram ( cgContext , CG_SOURCE , fileContents ,
vertexProfile , " main_vertex " , vertexOptions ) ;
2011-03-04 01:11:36 +00:00
checkForCgError ( " Compiling vertex program " ) ;
2011-02-24 00:26:42 +00:00
cgFragmentProgram = cgCreateProgram ( cgContext , CG_SOURCE , fileContents ,
pixelProfile , " main_fragment " , pixelOptions ) ;
2011-03-04 01:11:36 +00:00
checkForCgError ( " Compiling fragment program " ) ;
2011-02-24 00:26:42 +00:00
delete [ ] fileContents ;
2011-03-04 01:11:36 +00:00
if ( ! cgVertexProgram | | ! cgFragmentProgram ) {
2011-02-24 00:26:42 +00:00
return false ;
}
if ( cgVertexProgram ) {
2011-03-05 23:48:54 +00:00
hr = cgD3D9LoadProgram ( cgVertexProgram , true , 0 ) ;
2011-02-24 00:26:42 +00:00
hr = cgD3D9BindProgram ( cgVertexProgram ) ;
}
if ( cgFragmentProgram ) {
hr = cgD3D9LoadProgram ( cgFragmentProgram , false , 0 ) ;
hr = cgD3D9BindProgram ( cgFragmentProgram ) ;
}
shader_type = D3D_SHADER_CG ;
return true ;
}
bool CDirect3D : : SetShaderHLSL ( const TCHAR * file )
2010-09-25 17:35:19 +00:00
{
//MUDLORD: the guts
//Compiles a shader from files on disc
//Sets LUT textures to texture files in PNG format.
TCHAR folder [ MAX_PATH ] ;
TCHAR rubyLUTfileName [ MAX_PATH ] ;
TCHAR * slash ;
2010-11-13 19:41:38 +00:00
char * shaderText = NULL ;
TCHAR errorMsg [ MAX_PATH + 50 ] ;
IXMLDOMDocument * pXMLDoc = NULL ;
IXMLDOMElement * pXDE = NULL ;
IXMLDOMNode * pXDN = NULL ;
BSTR queryString , nodeContent ;
2010-09-25 17:35:19 +00:00
HRESULT hr ;
shaderTimer = 1.0f ;
shaderTimeStart = 0 ;
shaderTimeElapsed = 0 ;
if ( effect ) {
effect - > Release ( ) ;
effect = NULL ;
}
for ( int i = 0 ; i < MAX_SHADER_TEXTURES ; i + + ) {
if ( rubyLUT [ i ] ! = NULL ) {
rubyLUT [ i ] - > Release ( ) ;
rubyLUT [ i ] = NULL ;
}
}
if ( file = = NULL | | * file = = TEXT ( ' \0 ' ) )
return true ;
2010-11-13 19:41:38 +00:00
hr = CoCreateInstance ( CLSID_DOMDocument , NULL , CLSCTX_INPROC_SERVER , IID_PPV_ARGS ( & pXMLDoc ) ) ;
if ( FAILED ( hr ) ) {
MessageBox ( NULL , TEXT ( " Error creating XML Parser " ) , TEXT ( " Shader Loading Error " ) ,
MB_OK | MB_ICONEXCLAMATION ) ;
return false ;
}
VARIANT fileName ;
VARIANT_BOOL ret ;
fileName . vt = VT_BSTR ;
# ifdef UNICODE
fileName . bstrVal = SysAllocString ( file ) ;
# else
wchar_t tempfilename [ MAX_PATH ] ;
MultiByteToWideChar ( CP_UTF8 , 0 , file , - 1 , tempfilename , MAX_PATH ) ;
fileName . bstrVal = SysAllocString ( tempfilename ) ;
# endif
hr = pXMLDoc - > load ( fileName , & ret ) ;
SysFreeString ( fileName . bstrVal ) ;
if ( FAILED ( hr ) | | hr = = S_FALSE ) {
_stprintf ( errorMsg , TEXT ( " Error loading HLSL shader file: \n %s " ) , file ) ;
MessageBox ( NULL , errorMsg , TEXT ( " Shader Loading Error " ) , MB_OK | MB_ICONEXCLAMATION ) ;
pXMLDoc - > Release ( ) ;
return false ;
}
VARIANT attributeValue ;
BSTR attributeName ;
hr = pXMLDoc - > get_documentElement ( & pXDE ) ;
if ( FAILED ( hr ) | | hr = = S_FALSE ) {
_stprintf ( errorMsg , TEXT ( " Error loading root element from file: \n %s " ) , file ) ;
MessageBox ( NULL , errorMsg , TEXT ( " Shader Loading Error " ) , MB_OK | MB_ICONEXCLAMATION ) ;
pXMLDoc - > Release ( ) ;
return false ;
}
attributeName = SysAllocString ( L " language " ) ;
pXDE - > getAttribute ( attributeName , & attributeValue ) ;
SysFreeString ( attributeName ) ;
pXDE - > Release ( ) ;
if ( attributeValue . vt ! = VT_BSTR | | lstrcmpiW ( attributeValue . bstrVal , L " hlsl " ) ) {
_stprintf ( errorMsg , TEXT ( " Shader language is <%s>, expected <HLSL> in file: \n %s " ) , attributeValue . bstrVal , file ) ;
MessageBox ( NULL , errorMsg , TEXT ( " Shader Loading Error " ) , MB_OK | MB_ICONEXCLAMATION ) ;
if ( attributeValue . vt = = VT_BSTR ) SysFreeString ( attributeValue . bstrVal ) ;
pXMLDoc - > Release ( ) ;
return false ;
}
if ( attributeValue . vt = = VT_BSTR ) SysFreeString ( attributeValue . bstrVal ) ;
queryString = SysAllocString ( L " /shader/source " ) ;
hr = pXMLDoc - > selectSingleNode ( queryString , & pXDN ) ;
SysFreeString ( queryString ) ;
if ( hr = = S_OK ) {
hr = pXDN - > get_text ( & nodeContent ) ;
if ( hr = = S_OK ) {
int requiredChars = WideCharToMultiByte ( CP_ACP , 0 , nodeContent , - 1 , shaderText , 0 , NULL , NULL ) ;
shaderText = new char [ requiredChars ] ;
WideCharToMultiByte ( CP_UTF8 , 0 , nodeContent , - 1 , shaderText , requiredChars , NULL , NULL ) ;
}
SysFreeString ( nodeContent ) ;
pXDN - > Release ( ) ;
pXDN = NULL ;
}
pXMLDoc - > Release ( ) ;
if ( ! shaderText ) {
_stprintf ( errorMsg , TEXT ( " No HLSL shader program in file: \n %s " ) , file ) ;
MessageBox ( NULL , errorMsg , TEXT ( " Shader Loading Error " ) ,
MB_OK | MB_ICONEXCLAMATION ) ;
return false ;
}
LPD3DXBUFFER pBufferErrors = NULL ;
hr = D3DXCreateEffect ( pDevice , shaderText , strlen ( shaderText ) , NULL , NULL ,
D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY , NULL , & effect ,
& pBufferErrors ) ;
delete [ ] shaderText ;
if ( FAILED ( hr ) ) {
_stprintf ( errorMsg , TEXT ( " Error parsing HLSL shader file: \n %s " ) , file ) ;
MessageBox ( NULL , errorMsg , TEXT ( " Shader Loading Error " ) , MB_OK | MB_ICONEXCLAMATION ) ;
if ( pBufferErrors ) {
LPVOID pCompilErrors = pBufferErrors - > GetBufferPointer ( ) ;
MessageBox ( NULL , ( const TCHAR * ) pCompilErrors , TEXT ( " FX Compile Error " ) ,
MB_OK | MB_ICONEXCLAMATION ) ;
}
return false ;
}
2010-09-25 17:35:19 +00:00
lstrcpy ( folder , file ) ;
slash = _tcsrchr ( folder , TEXT ( ' \\ ' ) ) ;
if ( slash )
* ( slash + 1 ) = TEXT ( ' \0 ' ) ;
else
* folder = TEXT ( ' \0 ' ) ;
SetCurrentDirectory ( S9xGetDirectoryT ( DEFAULT_DIR ) ) ;
for ( int i = 0 ; i < MAX_SHADER_TEXTURES ; i + + ) {
_stprintf ( rubyLUTfileName , TEXT ( " %srubyLUT%d.png " ) , folder , i ) ;
hr = D3DXCreateTextureFromFile ( pDevice , rubyLUTfileName , & rubyLUT [ i ] ) ;
if FAILED ( hr ) {
rubyLUT [ i ] = NULL ;
}
}
D3DXHANDLE hTech ;
effect - > FindNextValidTechnique ( NULL , & hTech ) ;
effect - > SetTechnique ( hTech ) ;
2011-02-24 00:26:42 +00:00
shader_type = D3D_SHADER_HLSL ;
2010-09-25 17:35:19 +00:00
return true ;
}
2011-05-13 07:46:43 +00:00
void CDirect3D : : SetShaderVars ( bool setMatrix )
2010-09-25 17:35:19 +00:00
{
2011-02-24 00:26:42 +00:00
if ( shader_type = = D3D_SHADER_HLSL ) {
D3DXVECTOR4 rubyTextureSize ;
D3DXVECTOR4 rubyInputSize ;
D3DXVECTOR4 rubyOutputSize ;
D3DXHANDLE rubyTimer ;
int shaderTime = GetTickCount ( ) ;
shaderTimeElapsed + = shaderTime - shaderTimeStart ;
shaderTimeStart = shaderTime ;
if ( shaderTimeElapsed > 100 ) {
shaderTimeElapsed = 0 ;
shaderTimer + = 0.01f ;
2010-09-25 17:35:19 +00:00
}
2011-02-24 00:26:42 +00:00
rubyTextureSize . x = rubyTextureSize . y = ( float ) quadTextureSize ;
rubyTextureSize . z = rubyTextureSize . w = 1.0 / quadTextureSize ;
rubyInputSize . x = ( float ) afterRenderWidth ;
rubyInputSize . y = ( float ) afterRenderHeight ;
rubyInputSize . z = 1.0 / rubyInputSize . y ;
rubyInputSize . w = 1.0 / rubyInputSize . z ;
rubyOutputSize . x = GUI . Stretch ? ( float ) dPresentParams . BackBufferWidth : ( float ) afterRenderWidth ;
rubyOutputSize . y = GUI . Stretch ? ( float ) dPresentParams . BackBufferHeight : ( float ) afterRenderHeight ;
rubyOutputSize . z = 1.0 / rubyOutputSize . y ;
rubyOutputSize . w = 1.0 / rubyOutputSize . x ;
rubyTimer = effect - > GetParameterByName ( 0 , " rubyTimer " ) ;
effect - > SetFloat ( rubyTimer , shaderTimer ) ;
effect - > SetVector ( " rubyTextureSize " , & rubyTextureSize ) ;
effect - > SetVector ( " rubyInputSize " , & rubyInputSize ) ;
effect - > SetVector ( " rubyOutputSize " , & rubyOutputSize ) ;
effect - > SetTexture ( " rubyTexture " , drawSurface ) ;
for ( int i = 0 ; i < MAX_SHADER_TEXTURES ; i + + ) {
char rubyLUTName [ 256 ] ;
sprintf ( rubyLUTName , " rubyLUT%d " , i ) ;
if ( rubyLUT [ i ] ! = NULL ) {
effect - > SetTexture ( rubyLUTName , rubyLUT [ i ] ) ;
}
}
} else if ( shader_type = = D3D_SHADER_CG ) {
2011-03-05 23:48:54 +00:00
2011-02-24 00:26:42 +00:00
D3DXVECTOR2 videoSize ;
D3DXVECTOR2 textureSize ;
D3DXVECTOR2 outputSize ;
2011-05-11 19:39:06 +00:00
float frameCnt ;
2011-02-24 00:26:42 +00:00
videoSize . x = ( float ) afterRenderWidth ;
videoSize . y = ( float ) afterRenderHeight ;
textureSize . x = textureSize . y = ( float ) quadTextureSize ;
outputSize . x = GUI . Stretch ? ( float ) dPresentParams . BackBufferWidth : ( float ) afterRenderWidth ;
outputSize . y = GUI . Stretch ? ( float ) dPresentParams . BackBufferHeight : ( float ) afterRenderHeight ;
2011-05-11 19:39:06 +00:00
frameCnt = ( float ) + + frameCount ;
2011-02-24 00:26:42 +00:00
2011-03-04 01:11:36 +00:00
# define setProgramUniform(program,varname,floats)\
{ \
CGparameter cgp = cgGetNamedParameter ( program , varname ) ; \
if ( cgp ) \
cgD3D9SetUniform ( cgp , floats ) ; \
} \
setProgramUniform ( cgFragmentProgram , " IN.video_size " , & videoSize ) ;
setProgramUniform ( cgFragmentProgram , " IN.texture_size " , & textureSize ) ;
setProgramUniform ( cgFragmentProgram , " IN.output_size " , & outputSize ) ;
2011-05-11 19:39:06 +00:00
setProgramUniform ( cgFragmentProgram , " IN.frame_count " , & frameCnt ) ;
2011-03-04 01:11:36 +00:00
setProgramUniform ( cgVertexProgram , " IN.video_size " , & videoSize ) ;
setProgramUniform ( cgVertexProgram , " IN.texture_size " , & textureSize ) ;
setProgramUniform ( cgVertexProgram , " IN.output_size " , & outputSize ) ;
2011-05-11 19:39:06 +00:00
setProgramUniform ( cgVertexProgram , " IN.frame_count " , & frameCnt ) ;
2011-05-13 07:46:43 +00:00
if ( setMatrix ) {
D3DXMATRIX matWorld ;
D3DXMATRIX matView ;
D3DXMATRIX matProj ;
D3DXMATRIX mvp ;
pDevice - > GetTransform ( D3DTS_WORLD , & matWorld ) ;
pDevice - > GetTransform ( D3DTS_VIEW , & matView ) ;
pDevice - > GetTransform ( D3DTS_PROJECTION , & matProj ) ;
mvp = matWorld * matView * matProj ;
D3DXMatrixTranspose ( & mvp , & mvp ) ;
CGparameter cgpModelViewProj = cgGetNamedParameter ( cgVertexProgram , " modelViewProj " ) ;
if ( cgpModelViewProj )
cgD3D9SetUniformMatrix ( cgpModelViewProj , & mvp ) ;
}
2010-09-25 17:35:19 +00:00
}
2010-09-25 15:46:12 +00:00
}
/* CDirect3D::Render
does the actual rendering , changes the draw surface if necessary and recalculates
the vertex information if filter output size changes
IN :
Src - the input surface
*/
void CDirect3D : : Render ( SSurface Src )
{
SSurface Dst ;
RECT dstRect ;
2010-09-25 17:35:19 +00:00
unsigned int newFilterScale ;
2010-09-25 15:46:12 +00:00
D3DLOCKED_RECT lr ;
D3DLOCKED_RECT lrConv ;
HRESULT hr ;
if ( ! init_done ) return ;
//create a new draw surface if the filter scale changes
//at least factor 2 so we can display unscaled hi-res images
2010-09-25 17:35:19 +00:00
newFilterScale = max ( 2 , max ( GetFilterScale ( GUI . ScaleHiRes ) , GetFilterScale ( GUI . Scale ) ) ) ;
if ( newFilterScale ! = filterScale ) {
ChangeDrawSurfaceSize ( newFilterScale ) ;
2010-09-25 15:46:12 +00:00
}
if ( FAILED ( hr = pDevice - > TestCooperativeLevel ( ) ) ) {
switch ( hr ) {
case D3DERR_DEVICELOST : //do no rendering until device is restored
return ;
case D3DERR_DEVICENOTRESET : //we can reset now
ResetDevice ( ) ;
return ;
default :
2010-09-25 15:52:32 +00:00
DXTRACE_ERR_MSGBOX ( TEXT ( " Internal driver error " ) , hr ) ;
2010-09-25 15:46:12 +00:00
return ;
}
}
//BlankTexture(drawSurface);
if ( FAILED ( hr = drawSurface - > LockRect ( 0 , & lr , NULL , 0 ) ) ) {
DXTRACE_ERR_MSGBOX ( TEXT ( " Unable to lock texture " ) , hr ) ;
return ;
} else {
Dst . Surface = ( unsigned char * ) lr . pBits ;
Dst . Height = quadTextureSize ;
Dst . Width = quadTextureSize ;
Dst . Pitch = lr . Pitch ;
RenderMethod ( Src , Dst , & dstRect ) ;
if ( ! Settings . AutoDisplayMessages ) {
2010-09-25 15:52:32 +00:00
WinSetCustomDisplaySurface ( ( void * ) Dst . Surface , Dst . Pitch / 2 , dstRect . right - dstRect . left , dstRect . bottom - dstRect . top , GetFilterScale ( CurrentScale ) ) ;
S9xDisplayMessages ( ( uint16 * ) Dst . Surface , Dst . Pitch / 2 , dstRect . right - dstRect . left , dstRect . bottom - dstRect . top , GetFilterScale ( CurrentScale ) ) ;
2010-09-25 15:46:12 +00:00
}
drawSurface - > UnlockRect ( 0 ) ;
}
2011-04-29 23:26:42 +00:00
if ( ! GUI . Stretch | | GUI . AspectRatio )
pDevice - > Clear ( 0 , NULL , D3DCLEAR_TARGET , D3DCOLOR_XRGB ( 0 , 0 , 0 ) , 1.0f , 0 ) ;
2011-03-05 23:48:54 +00:00
//if the output size of the render method changes we need to update the viewport
2010-09-25 15:46:12 +00:00
if ( afterRenderHeight ! = dstRect . bottom | | afterRenderWidth ! = dstRect . right ) {
afterRenderHeight = dstRect . bottom ;
afterRenderWidth = dstRect . right ;
2011-03-05 23:48:54 +00:00
SetViewport ( ) ;
2010-09-25 15:46:12 +00:00
}
pDevice - > BeginScene ( ) ;
pDevice - > SetTexture ( 0 , drawSurface ) ;
pDevice - > SetFVF ( FVF_COORDS_TEX ) ;
pDevice - > SetStreamSource ( 0 , vertexBuffer , 0 , sizeof ( VERTEX ) ) ;
2010-09-25 17:35:19 +00:00
2011-03-05 23:48:54 +00:00
SetShaderVars ( ) ;
2011-02-24 00:26:42 +00:00
if ( shader_type = = D3D_SHADER_CG ) {
cgD3D9BindProgram ( cgFragmentProgram ) ;
cgD3D9BindProgram ( cgVertexProgram ) ;
}
if ( shader_type = = D3D_SHADER_HLSL ) {
2010-09-25 17:35:19 +00:00
UINT passes ;
hr = effect - > Begin ( & passes , 0 ) ;
for ( UINT pass = 0 ; pass < passes ; pass + + ) {
effect - > BeginPass ( pass ) ;
pDevice - > DrawPrimitive ( D3DPT_TRIANGLESTRIP , 0 , 2 ) ;
effect - > EndPass ( ) ;
}
effect - > End ( ) ;
} else {
pDevice - > DrawPrimitive ( D3DPT_TRIANGLESTRIP , 0 , 2 ) ;
}
2010-09-25 15:46:12 +00:00
pDevice - > EndScene ( ) ;
pDevice - > Present ( NULL , NULL , NULL , NULL ) ;
return ;
}
/* CDirect3D::CreateDrawSurface
calculates the necessary texture size ( multiples of 2 )
and creates a new texture
*/
void CDirect3D : : CreateDrawSurface ( )
{
2010-09-25 17:35:19 +00:00
unsigned int neededSize ;
2010-09-25 15:46:12 +00:00
HRESULT hr ;
//we need at least 512 pixels (SNES_WIDTH * 2) so we can start with that value
quadTextureSize = 512 ;
2010-09-25 17:35:19 +00:00
neededSize = SNES_WIDTH * filterScale ;
2010-09-25 15:46:12 +00:00
while ( quadTextureSize < neededSize )
quadTextureSize * = 2 ;
if ( ! drawSurface ) {
hr = pDevice - > CreateTexture (
quadTextureSize , quadTextureSize ,
1 , // 1 level, no mipmaps
0 , // dynamic textures can be locked
D3DFMT_R5G6B5 ,
D3DPOOL_MANAGED ,
& drawSurface ,
NULL ) ;
if ( FAILED ( hr ) ) {
DXTRACE_ERR_MSGBOX ( TEXT ( " Error while creating texture " ) , hr ) ;
return ;
}
}
}
/* CDirect3D::DestroyDrawSurface
releases the old textures ( if allocated )
*/
void CDirect3D : : DestroyDrawSurface ( )
{
if ( drawSurface ) {
drawSurface - > Release ( ) ;
drawSurface = NULL ;
}
}
/* CDirect3D::BlankTexture
clears a texture ( fills it with zeroes )
IN :
texture - the texture to be blanked
- - - - -
returns true if successful , false otherwise
*/
bool CDirect3D : : BlankTexture ( LPDIRECT3DTEXTURE9 texture )
{
D3DLOCKED_RECT lr ;
HRESULT hr ;
if ( FAILED ( hr = texture - > LockRect ( 0 , & lr , NULL , 0 ) ) ) {
DXTRACE_ERR_MSGBOX ( TEXT ( " Unable to lock texture " ) , hr ) ;
return false ;
} else {
memset ( lr . pBits , 0 , lr . Pitch * quadTextureSize ) ;
texture - > UnlockRect ( 0 ) ;
return true ;
}
}
/* CDirect3D::ChangeDrawSurfaceSize
changes the draw surface size : deletes the old textures , creates a new texture
and calculate new vertices
IN :
2010-09-25 17:35:19 +00:00
scale - the scale that has to fit into the textures
2010-09-25 15:46:12 +00:00
- - - - -
returns true if successful , false otherwise
*/
2010-09-25 17:35:19 +00:00
bool CDirect3D : : ChangeDrawSurfaceSize ( unsigned int scale )
2010-09-25 15:46:12 +00:00
{
2010-09-25 17:35:19 +00:00
filterScale = scale ;
2010-09-25 15:46:12 +00:00
if ( pDevice ) {
DestroyDrawSurface ( ) ;
CreateDrawSurface ( ) ;
SetupVertices ( ) ;
return true ;
}
return false ;
}
/* CDirect3D::SetupVertices
calculates the vertex coordinates
( respecting the stretch and aspect ratio settings )
*/
void CDirect3D : : SetupVertices ( )
{
void * pLockedVertexBuffer ;
float tX = ( float ) afterRenderWidth / ( float ) quadTextureSize ;
float tY = ( float ) afterRenderHeight / ( float ) quadTextureSize ;
2011-03-05 23:48:54 +00:00
triangleStripVertices [ 0 ] = VERTEX ( 0.0f , 0.0f , 0.0f , 0.0f , tY ) ;
triangleStripVertices [ 1 ] = VERTEX ( 0.0f , 1.0f , 0.0f , 0.0f , 0.0f ) ;
triangleStripVertices [ 2 ] = VERTEX ( 1.0f , 0.0f , 0.0f , tX , tY ) ;
triangleStripVertices [ 3 ] = VERTEX ( 1.0f , 1.0f , 0.0f , tX , 0.0f ) ;
2010-09-25 15:46:12 +00:00
HRESULT hr = vertexBuffer - > Lock ( 0 , 0 , & pLockedVertexBuffer , NULL ) ;
memcpy ( pLockedVertexBuffer , triangleStripVertices , sizeof ( triangleStripVertices ) ) ;
vertexBuffer - > Unlock ( ) ;
}
2011-03-05 23:48:54 +00:00
void CDirect3D : : SetViewport ( )
{
D3DXMATRIX matIdentity ;
D3DXMATRIX matProjection ;
D3DXMatrixOrthoOffCenterLH ( & matProjection , 0.0f , 1.0f , 0.0f , 1.0f , 0.0f , 1.0f ) ;
D3DXMatrixIdentity ( & matIdentity ) ;
pDevice - > SetTransform ( D3DTS_WORLD , & matIdentity ) ;
pDevice - > SetTransform ( D3DTS_VIEW , & matIdentity ) ;
pDevice - > SetTransform ( D3DTS_PROJECTION , & matProjection ) ;
2011-05-13 07:46:43 +00:00
SetShaderVars ( true ) ;
2011-03-05 23:48:54 +00:00
RECT drawRect = CalculateDisplayRect ( afterRenderWidth , afterRenderHeight , dPresentParams . BackBufferWidth , dPresentParams . BackBufferHeight ) ;
D3DVIEWPORT9 viewport ;
viewport . X = drawRect . left ;
viewport . Y = drawRect . top ;
viewport . Height = drawRect . bottom - drawRect . top ;
viewport . Width = drawRect . right - drawRect . left ;
viewport . MinZ = 0.0f ;
viewport . MaxZ = 1.0f ;
HRESULT hr = pDevice - > SetViewport ( & viewport ) ;
SetupVertices ( ) ;
}
2010-09-25 15:46:12 +00:00
/* CDirect3D::ChangeRenderSize
determines if we need to reset the device ( if the size changed )
called with ( 0 , 0 ) whenever we want new settings to take effect
IN :
newWidth , newHeight - the new window size
- - - - -
returns true if successful , false otherwise
*/
bool CDirect3D : : ChangeRenderSize ( unsigned int newWidth , unsigned int newHeight )
{
if ( ! init_done )
return false ;
//if we already have the desired size no change is necessary
//during fullscreen no changes are allowed
2010-09-25 17:35:19 +00:00
if ( dPresentParams . BackBufferWidth = = newWidth & & dPresentParams . BackBufferHeight = = newHeight )
2010-09-25 15:46:12 +00:00
return true ;
if ( ! ResetDevice ( ) )
return false ;
2011-03-05 23:48:54 +00:00
2010-09-25 15:46:12 +00:00
return true ;
}
/* CDirect3D::ResetDevice
resets the device
called if surface was lost or the settings / display size require a device reset
- - - - -
returns true if successful , false otherwise
*/
bool CDirect3D : : ResetDevice ( )
{
2010-09-25 17:35:19 +00:00
if ( ! init_done ) return false ;
2010-09-25 15:46:12 +00:00
HRESULT hr ;
//release prior to reset
DestroyDrawSurface ( ) ;
2011-04-10 14:06:24 +00:00
if ( cgAvailable ) {
cgD3D9SetDevice ( NULL ) ;
}
2010-09-25 17:35:19 +00:00
if ( effect )
effect - > OnLostDevice ( ) ;
2010-09-25 15:46:12 +00:00
//zero or unknown values result in the current window size/display settings
dPresentParams . BackBufferWidth = 0 ;
dPresentParams . BackBufferHeight = 0 ;
dPresentParams . BackBufferCount = GUI . DoubleBuffered ? 2 : 1 ;
dPresentParams . BackBufferFormat = D3DFMT_UNKNOWN ;
dPresentParams . FullScreen_RefreshRateInHz = 0 ;
dPresentParams . Windowed = true ;
dPresentParams . PresentationInterval = GUI . Vsync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE ;
if ( fullscreen ) {
dPresentParams . BackBufferWidth = GUI . FullscreenMode . width ;
dPresentParams . BackBufferHeight = GUI . FullscreenMode . height ;
dPresentParams . BackBufferCount = GUI . DoubleBuffered ? 2 : 1 ;
dPresentParams . Windowed = false ;
if ( GUI . FullscreenMode . depth = = 32 )
dPresentParams . BackBufferFormat = D3DFMT_X8R8G8B8 ;
else
dPresentParams . BackBufferFormat = D3DFMT_R5G6B5 ;
dPresentParams . FullScreen_RefreshRateInHz = GUI . FullscreenMode . rate ;
}
if ( FAILED ( hr = pDevice - > Reset ( & dPresentParams ) ) ) {
DXTRACE_ERR ( TEXT ( " Unable to reset device " ) , hr ) ;
return false ;
}
2010-09-25 17:35:19 +00:00
if ( effect )
effect - > OnResetDevice ( ) ;
2011-04-10 14:06:24 +00:00
if ( cgAvailable ) {
cgD3D9SetDevice ( pDevice ) ;
}
2010-09-25 15:46:12 +00:00
if ( GUI . BilinearFilter ) {
pDevice - > SetSamplerState ( 0 , D3DSAMP_MAGFILTER , D3DTEXF_LINEAR ) ;
pDevice - > SetSamplerState ( 0 , D3DSAMP_MINFILTER , D3DTEXF_LINEAR ) ;
} else {
pDevice - > SetSamplerState ( 0 , D3DSAMP_MAGFILTER , D3DTEXF_POINT ) ;
pDevice - > SetSamplerState ( 0 , D3DSAMP_MINFILTER , D3DTEXF_POINT ) ;
}
2011-03-05 23:48:54 +00:00
pDevice - > SetRenderState ( D3DRS_LIGHTING , FALSE ) ;
2010-09-25 15:46:12 +00:00
pDevice - > Clear ( 0 , NULL , D3DCLEAR_TARGET , D3DCOLOR_XRGB ( 0 , 0 , 0 ) , 1.0f , 0 ) ;
//recreate the surface
CreateDrawSurface ( ) ;
2011-04-29 23:26:42 +00:00
SetViewport ( ) ;
2010-09-25 15:46:12 +00:00
return true ;
}
/* CDirect3D::SetSnes9xColorFormat
sets the color format to 16 bit ( since the texture is always 16 bit )
no depth conversion is necessary ( done by D3D )
*/
void CDirect3D : : SetSnes9xColorFormat ( )
{
GUI . ScreenDepth = 16 ;
GUI . BlueShift = 0 ;
GUI . GreenShift = 6 ;
GUI . RedShift = 11 ;
S9xSetRenderPixelFormat ( RGB565 ) ;
S9xBlit2xSaIFilterInit ( ) ;
S9xBlitHQ2xFilterInit ( ) ;
GUI . NeedDepthConvert = FALSE ;
GUI . DepthConverted = TRUE ;
return ;
}
/* CDirect3D::SetFullscreen
enables / disables fullscreen mode
IN :
fullscreen - determines if fullscreen is enabled / disabled
- - - - -
returns true if successful , false otherwise
*/
bool CDirect3D : : SetFullscreen ( bool fullscreen )
{
if ( ! init_done )
return false ;
if ( this - > fullscreen = = fullscreen )
return true ;
this - > fullscreen = fullscreen ;
if ( ! ResetDevice ( ) )
return false ;
//present here to get a fullscreen blank even if no rendering is done
pDevice - > Present ( NULL , NULL , NULL , NULL ) ;
2011-04-29 23:26:42 +00:00
2010-09-25 15:46:12 +00:00
return true ;
}
/* CDirect3D::EnumModes
enumerates possible display modes ( only 16 and 32 bit ) and fills the vector
IN :
modeVector - pointer to the mode vector
*/
void CDirect3D : : EnumModes ( std : : vector < dMode > * modeVector )
{
D3DDISPLAYMODE d3dMode ;
int modeCount , index ;
dMode mode ;
if ( ! init_done )
return ;
//enumerate 32bit modes
modeCount = pD3D - > GetAdapterModeCount ( D3DADAPTER_DEFAULT , D3DFMT_X8R8G8B8 ) ;
for ( int i = 0 ; i < modeCount ; i + + ) {
if ( pD3D - > EnumAdapterModes ( D3DADAPTER_DEFAULT , D3DFMT_X8R8G8B8 , i , & d3dMode ) = = D3D_OK ) {
mode . width = d3dMode . Width ;
mode . height = d3dMode . Height ;
mode . rate = d3dMode . RefreshRate ;
mode . depth = 32 ;
modeVector - > push_back ( mode ) ;
}
}
//enumerate 16bit modes
modeCount = pD3D - > GetAdapterModeCount ( D3DADAPTER_DEFAULT , D3DFMT_R5G6B5 ) ;
for ( int i = 0 ; i < modeCount ; i + + ) {
if ( pD3D - > EnumAdapterModes ( D3DADAPTER_DEFAULT , D3DFMT_R5G6B5 , i , & d3dMode ) = = D3D_OK ) {
mode . width = d3dMode . Width ;
mode . height = d3dMode . Height ;
mode . rate = d3dMode . RefreshRate ;
mode . depth = 16 ;
modeVector - > push_back ( mode ) ;
}
}
}
/* CDirect3D::ApplyDisplayChanges
calls changerendersize to apply new display settings
- - - - -
returns true if successful , false otherwise
*/
bool CDirect3D : : ApplyDisplayChanges ( void )
{
2011-02-24 00:26:42 +00:00
if ( GUI . shaderEnabled & & GUI . D3DshaderFileName )
SetShader ( GUI . D3DshaderFileName ) ;
2010-09-25 17:35:19 +00:00
else
SetShader ( NULL ) ;
2010-09-25 15:46:12 +00:00
return ChangeRenderSize ( 0 , 0 ) ;
}