1 // DirectX9 Enhanced video output
2 #include "burner.h"
3 #include "vid_softfx.h"
4
5 //#ifdef _MSC_VER
6 //#pragma comment(lib, "d3d9")
7 //#pragma comment(lib, "d3dx9")
8
9
10 // #define ENABLE_PROFILING FBNEO_DEBUG
11 // #define LOAD_EFFECT_FROM_FILE
12
13 #include <initguid.h>
14 #define DIRECT3D_VERSION 0x0900 // Use this Direct3D version
15 #define D3D_OVERLOADS
16 #include <d3d9.h>
17 #include <d3dx9effect.h>
18
19 #include "directx9_core.h"
20
21 const float PI = 3.14159265358979323846f;
22
23 typedef struct _D3DLVERTEX2 {
24 union { FLOAT x; FLOAT dvX; };
25 union { FLOAT y; FLOAT dvY; };
26 union { FLOAT z; FLOAT dvZ; };
27 union { D3DCOLOR color; D3DCOLOR dcColor; };
28 union { D3DCOLOR specular; D3DCOLOR dcSpecular; };
29 union { FLOAT tu; FLOAT dvTU; };
30 union { FLOAT tv; FLOAT dvTV; };
31 union { FLOAT tu1; FLOAT dvTU1; };
32 union { FLOAT tv1; FLOAT dvTV1; };
33 #if(DIRECT3D_VERSION >= 0x0500)
34 #if (defined __cplusplus) && (defined D3D_OVERLOADS)
_D3DLVERTEX2_D3DLVERTEX235 _D3DLVERTEX2() { }
_D3DLVERTEX2_D3DLVERTEX236 _D3DLVERTEX2(FLOAT _x, FLOAT _y, FLOAT _z, D3DCOLOR _color, D3DCOLOR _specular, FLOAT _tu, FLOAT _tv, FLOAT _tu1, FLOAT _tv1)
37 {
38 x = _x; y = _y; z = _z;
39 color = _color; specular = _specular;
40 tu = _tu; tv = _tv;
41 tu1 = _tu1; tv1 = _tv1;
42 }
43 #endif
44 #endif
45 } D3DLVERTEX2, *LPD3DLVERTEX2;
46
47 #define D3DFVF_LVERTEX2 ( D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2 | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE2(1) | D3DFVF_TEXCOORDSIZE2(2) | D3DFVF_TEXCOORDSIZE2(3) )
48
49 #define RENDER_STRIPS (4)
50
51 #define DX9_SHADERPRECISION ((nVidBlitterOpt[nVidSelect] & (7 << 28)) >> 28)
52 #define DX9_FILTER ((nVidBlitterOpt[nVidSelect] & (3 << 24)) >> 24)
53 #define DX9_USE_PS20 ( nVidBlitterOpt[nVidSelect] & (1 << 9))
54 #define DX9_USE_FPTEXTURE ( nVidBlitterOpt[nVidSelect] & (1 << 8))
55
56 static IDirect3D9* pD3D = NULL; // Direct3D interface
57 static D3DPRESENT_PARAMETERS d3dpp;
58 static IDirect3DDevice9* pD3DDevice = NULL;
59 static IDirect3DVertexBuffer9* pVB[RENDER_STRIPS] = { NULL, };
60 static IDirect3DTexture9* pTexture = NULL;
61 static IDirect3DTexture9* pScanlineTexture[2] = { NULL, };
62 static int nTextureWidth = 0, nTextureHeight = 0;
63 static IDirect3DSurface9* pSurface = NULL;
64
65 static IDirect3DVertexBuffer9* pIntermediateVB = NULL;
66 static IDirect3DTexture9* pIntermediateTexture = NULL;
67 static int nIntermediateTextureWidth, nIntermediateTextureHeight;
68
69 static ID3DXEffect* pEffect = NULL;
70 static ID3DXTextureShader* pEffectShader = NULL;
71 static D3DXHANDLE hTechnique = NULL;
72 //static D3DXHANDLE hScanIntensity = NULL;
73 static IDirect3DTexture9* pEffectTexture = NULL;
74
75 static ID3DXFont* pFont = NULL; // OSD font
76 static D3DCOLOR osdColor = D3DCOLOR_ARGB(0xFF, 0xFF, 0xFF, 0xFF);
77
78 static double dPrevCubicB, dPrevCubicC;
79
80 static bool bUsePS14;
81
82 static int nGameWidth = 0, nGameHeight = 0; // Game screen size
83 static int nGameImageWidth, nGameImageHeight;
84
85 static int nRotateGame;
86 static int nImageWidth, nImageHeight/*, nImageZoom*/;
87
88 static RECT Dest;
89
90 static unsigned int nD3DAdapter;
91
92 // ----------------------------------------------------------------------------
93 #ifdef PRINT_DEBUG_INFO
TextureFormatString(D3DFORMAT nFormat)94 static TCHAR* TextureFormatString(D3DFORMAT nFormat)
95 {
96 switch (nFormat) {
97 case D3DFMT_X1R5G5B5:
98 return _T("16-bit xRGB 1555");
99 case D3DFMT_R5G6B5:
100 return _T("16-bit RGB 565");
101 case D3DFMT_X8R8G8B8:
102 return _T("32-bit xRGB 8888");
103 case D3DFMT_A8R8G8B8:
104 return _T("32-bit ARGB 8888");
105 case D3DFMT_A16B16G16R16F:
106 return _T("64-bit ARGB 16161616fp");
107 case D3DFMT_A32B32G32R32F:
108 return _T("128-bit ARGB 32323232fp");
109 default:
110 return _T("unknown format");
111 }
112
113 return _T("unknown format");
114 }
115 #endif
116 // ----------------------------------------------------------------------------
117
GetTextureSize(int nSize)118 static int GetTextureSize(int nSize)
119 {
120 int nTextureSize = 128;
121
122 while (nTextureSize < nSize) {
123 nTextureSize <<= 1;
124 }
125
126 return nTextureSize;
127 }
128
129 /*
130 static void PutPixel(unsigned char** ppSurface, unsigned int nColour)
131 {
132 switch (nVidScrnDepth) {
133 case 15:
134 *((unsigned short*)(*ppSurface)) = ((nColour >> 9) & 0x7C00) | ((nColour >> 6) & 0x03E0) | ((nColour >> 3) & 0x001F);
135 *ppSurface += 2;
136 break;
137 case 16:
138 *((unsigned short*)(*ppSurface)) = ((nColour >> 8) & 0xF800) | ((nColour >> 5) & 0x07E0) | ((nColour >> 3) & 0x001F);
139 *ppSurface += 2;
140 break;
141 case 24:
142 (*ppSurface)[0] = (nColour >> 16) & 0xFF;
143 (*ppSurface)[1] = (nColour >> 8) & 0xFF;
144 (*ppSurface)[2] = (nColour >> 0) & 0xFF;
145 *ppSurface += 3;
146 break;
147 case 32:
148 *((unsigned int*)(*ppSurface)) = nColour;
149 *ppSurface += 4;
150 break;
151 }
152 }
153 */
154
dx9GetAdapter(wchar_t * name)155 static UINT dx9GetAdapter(wchar_t* name)
156 {
157 for (int a = pD3D->GetAdapterCount() - 1; a >= 0; a--)
158 {
159 D3DADAPTER_IDENTIFIER9 identifier;
160
161 pD3D->GetAdapterIdentifier(a, 0, &identifier);
162
163 if (identifier.DeviceName[11] == name[11]) {
164 return a;
165 }
166 }
167
168 return 0;
169 }
170
171 // Select optimal full-screen resolution
dx9SelectFullscreenMode(VidSDisplayScoreInfo * pScoreInfo)172 int dx9SelectFullscreenMode(VidSDisplayScoreInfo* pScoreInfo)
173 {
174 //int nWidth, nHeight;
175
176 if (bVidArcaderes) {
177 if (!VidSGetArcaderes((int*)&(pScoreInfo->nBestWidth), (int*)&(pScoreInfo->nBestHeight))) {
178 return 1;
179 }
180 } else {
181 if (nScreenSize) {
182 D3DFORMAT nFormat = (nVidDepth == 16) ? D3DFMT_R5G6B5 : D3DFMT_X8R8G8B8;
183 D3DDISPLAYMODE dm;
184
185 memset(pScoreInfo, 0, sizeof(VidSDisplayScoreInfo));
186 pScoreInfo->nRequestedZoom = nScreenSize;
187 VidSInitScoreInfo(pScoreInfo);
188
189 // Enumerate the available screenmodes
190 for (int i = pD3D->GetAdapterModeCount(nD3DAdapter, nFormat) - 1; i >= 0; i--) {
191 if (FAILED(pD3D->EnumAdapterModes(nD3DAdapter, nFormat, i, &dm))) {
192 return 1;
193 }
194 pScoreInfo->nModeWidth = dm.Width;
195 pScoreInfo->nModeHeight = dm.Height;
196
197 VidSScoreDisplayMode(pScoreInfo);
198 }
199
200 if (pScoreInfo->nBestWidth == -1U) {
201 FBAPopupAddText(PUF_TEXT_DEFAULT, MAKEINTRESOURCE(IDS_ERR_UI_FULL_NOMODE));
202 FBAPopupDisplay(PUF_TYPE_ERROR);
203 return 1;
204 }
205 } else {
206 pScoreInfo->nBestWidth = nVidWidth;
207 pScoreInfo->nBestHeight = nVidHeight;
208 }
209 }
210
211 if (!bDrvOkay && (pScoreInfo->nBestWidth < 640 || pScoreInfo->nBestHeight < 480)) {
212 return 1;
213 }
214
215 return 0;
216 }
217
218 // ----------------------------------------------------------------------------
219
FillEffectTexture()220 static void FillEffectTexture()
221 {
222 FLOAT B = (FLOAT)dVidCubicB;
223 FLOAT C = (FLOAT)dVidCubicC;
224
225 if (pEffect == NULL) {
226 return;
227 }
228
229 /*
230 if (dVidCubicSharpness > 0.5) {
231 C = dVidCubicSharpness;
232 B = 0.0;
233 } else {
234 C = dVidCubicSharpness;
235 B = 1.0 - 2.0 * C;
236 }
237 */
238
239 if (DX9_SHADERPRECISION == 4 || bUsePS14) {
240 B = 0.0;
241 }
242
243 if (pEffectShader && pEffectTexture) {
244 pEffectShader->SetFloat("B", B);
245 pEffectShader->SetFloat("C", C);
246
247 _D3DXFillTextureTX(pEffectTexture, pEffectShader);
248 }
249
250 pEffect->SetFloat("B", B);
251 pEffect->SetFloat("C", C);
252 }
253
254 // ----------------------------------------------------------------------------
255
dx9ReleaseResources()256 static void dx9ReleaseResources()
257 {
258 RELEASE(pEffect);
259 RELEASE(pEffectShader);
260 RELEASE(pEffectTexture);
261
262 RELEASE(pScanlineTexture[0]);
263 RELEASE(pScanlineTexture[1]);
264 RELEASE(pIntermediateTexture);
265
266 RELEASE(pSurface);
267 RELEASE(pTexture);
268
269 for (int y = 0; y < RENDER_STRIPS; y++) {
270 RELEASE(pVB[y]);
271 }
272 RELEASE(pIntermediateVB);
273 }
274
dx9Exit()275 static int dx9Exit()
276 {
277 dx9ReleaseResources();
278
279 VidSFreeVidImage();
280
281 RELEASE(pFont);
282 RELEASE(pD3DDevice);
283 RELEASE(pD3D);
284
285 nRotateGame = 0;
286
287 return 0;
288 }
289
dx9SurfaceInit()290 static int dx9SurfaceInit()
291 {
292 D3DFORMAT nFormat = D3DFMT_UNKNOWN;
293
294 if (nRotateGame & 1) {
295 nVidImageWidth = nGameHeight;
296 nVidImageHeight = nGameWidth;
297 } else {
298 nVidImageWidth = nGameWidth;
299 nVidImageHeight = nGameHeight;
300 }
301
302 nGameImageWidth = nVidImageWidth;
303 nGameImageHeight = nVidImageHeight;
304
305 if (bDrvOkay && (BurnDrvGetFlags() & BDF_16BIT_ONLY)) {
306 nVidImageDepth = 15;
307 } else {
308 nVidImageDepth = nVidScrnDepth;
309 }
310
311 switch (nVidImageDepth) {
312 case 32:
313 nFormat = D3DFMT_X8R8G8B8;
314 break;
315 case 24:
316 nFormat = D3DFMT_R8G8B8;
317 break;
318 case 16:
319 nFormat = D3DFMT_R5G6B5;
320 break;
321 case 15:
322 nFormat = D3DFMT_X1R5G5B5;
323 break;
324 }
325
326 nVidImageBPP = (nVidImageDepth + 7) >> 3;
327 nBurnBpp = nVidImageBPP; // Set Burn library Bytes per pixel
328
329 // Use our callback to get colors:
330 SetBurnHighCol(nVidImageDepth);
331
332 // Make the normal memory buffer
333 if (VidSAllocVidImage()) {
334 dx9Exit();
335 return 1;
336 }
337
338 if (FAILED(pD3DDevice->CreateOffscreenPlainSurface(nVidImageWidth, nVidImageHeight, nFormat, D3DPOOL_DEFAULT, &pSurface, NULL))) {
339 #ifdef PRINT_DEBUG_INFO
340 dprintf(_T(" * Error: Couldn't create surface.\n"));
341 #endif
342 return 1;
343 }
344 #ifdef PRINT_DEBUG_INFO
345 dprintf(_T(" * Allocated a %i x %i (%s) surface.\n"), nVidImageWidth, nVidImageHeight, TextureFormatString(nFormat));
346 #endif
347
348 nTextureWidth = GetTextureSize(nGameImageWidth);
349 nTextureHeight = GetTextureSize(nGameImageHeight);
350
351 if (FAILED(pD3DDevice->CreateTexture(nTextureWidth, nTextureHeight, 1, D3DUSAGE_RENDERTARGET, nFormat, D3DPOOL_DEFAULT, &pTexture, NULL))) {
352 #ifdef PRINT_DEBUG_INFO
353 dprintf(_T(" * Error: Couldn't create texture.\n"));
354 #endif
355 return 1;
356 }
357 #ifdef PRINT_DEBUG_INFO
358 dprintf(_T(" * Allocated a %i x %i (%s) image texture.\n"), nTextureWidth, nTextureHeight, TextureFormatString(nFormat));
359 #endif
360
361 return 0;
362 }
363
dx9EffectSurfaceInit()364 static int dx9EffectSurfaceInit()
365 {
366 D3DFORMAT nFormat;
367
368 if (DX9_FILTER == 2 && (bUsePS14 || (DX9_SHADERPRECISION != 0 && DX9_SHADERPRECISION != 2))) {
369 switch (DX9_SHADERPRECISION) {
370 case 0:
371 nFormat = D3DFMT_A32B32G32R32F;
372 break;
373 case 1:
374 nFormat = D3DFMT_A16B16G16R16F;
375 break;
376 case 2:
377 nFormat = D3DFMT_A32B32G32R32F;
378 break;
379 case 3:
380 nFormat = D3DFMT_A16B16G16R16F;
381 break;
382 default:
383 nFormat = D3DFMT_A8R8G8B8;
384 }
385
386 if (bUsePS14) {
387 nFormat = D3DFMT_A8R8G8B8;
388 }
389
390 if (FAILED(pD3DDevice->CreateTexture(1024, 1, 1, D3DUSAGE_RENDERTARGET, nFormat, D3DPOOL_DEFAULT, &pEffectTexture, NULL))) {
391 #ifdef PRINT_DEBUG_INFO
392 dprintf(_T(" * Error: Couldn't create effects texture.\n"));
393 #endif
394 return 1;
395 }
396 #ifdef PRINT_DEBUG_INFO
397 dprintf(_T(" * Allocated a %i x %i (%s) LUT texture.\n"), 1024, 1, TextureFormatString(nFormat));
398 #endif
399 }
400
401 if ((DX9_FILTER == 1 && bVidScanlines) || (DX9_FILTER == 2 && (bUsePS14 || DX9_SHADERPRECISION >= 2 || bVidScanlines))) {
402 if (nVidFullscreen) {
403 nIntermediateTextureWidth = GetTextureSize(nRotateGame ? nVidScrnHeight : nVidScrnWidth);
404 } else {
405 nIntermediateTextureWidth = GetTextureSize(nRotateGame ? SystemWorkArea.bottom - SystemWorkArea.top : SystemWorkArea.right - SystemWorkArea.left);
406 }
407 nIntermediateTextureHeight = nTextureHeight;
408
409 nFormat = D3DFMT_A8R8G8B8;
410 if ((DX9_FILTER == 2) && !bUsePS14 && DX9_USE_FPTEXTURE) {
411 #if 0
412 if ((DX9_SHADERPRECISION == 0 || DX9_SHADERPRECISION == 2) && !bVidScanlines) {
413 nFormat = D3DFMT_A32B32G32R32F;
414 } else {
415 nFormat = D3DFMT_A16B16G16R16F;
416 }
417 #else
418 nFormat = D3DFMT_A16B16G16R16F;
419 #endif
420 }
421
422 if (FAILED(pD3DDevice->CreateTexture(nIntermediateTextureWidth, nIntermediateTextureHeight, 1, D3DUSAGE_RENDERTARGET, nFormat, D3DPOOL_DEFAULT, &pIntermediateTexture, NULL))) {
423 #ifdef PRINT_DEBUG_INFO
424 dprintf(_T(" * Error: Couldn't create intermediate texture.\n"));
425 #endif
426 return 1;
427 }
428 #ifdef PRINT_DEBUG_INFO
429 dprintf(_T(" * Allocated a %i x %i (%s) intermediate texture.\n"), nIntermediateTextureWidth, nIntermediateTextureHeight, TextureFormatString(nFormat));
430 #endif
431 }
432
433 {
434 // Clear textures and set border colour
435
436 IDirect3DSurface9* pSurf;
437
438 pTexture->GetSurfaceLevel(0, &pSurf);
439 pD3DDevice->ColorFill(pSurf, 0, D3DCOLOR_XRGB(0, 0, 0));
440 RELEASE(pSurf);
441
442 if (pIntermediateTexture) {
443 pIntermediateTexture->GetSurfaceLevel(0, &pSurf);
444 pD3DDevice->ColorFill(pSurf, 0, D3DCOLOR_XRGB(0, 0, 0));
445 RELEASE(pSurf);
446 }
447
448 pD3DDevice->SetSamplerState(0, D3DSAMP_BORDERCOLOR, D3DCOLOR_XRGB(0, 0, 0));
449 pD3DDevice->SetSamplerState(1, D3DSAMP_BORDERCOLOR, D3DCOLOR_XRGB(0, 0, 0));
450 }
451
452 // Allocate scanline textures
453 for (int i = 0, nSize = 2; i < 2; i++, nSize <<= 1) {
454 RECT rect = { 0, 0, nSize, nSize };
455 IDirect3DSurface9* pSurf = NULL;
456
457 unsigned int scan2x2[] = { 0xFFFFFF, 0xFFFFFF,
458 0x000000, 0x000000 };
459
460 unsigned int scan4x4[] = { 0x9F9F9F, 0x9F9F9F, 0x9F9F9F, 0x9F9F9F,
461 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
462 0x9F9F9F, 0x9F9F9F, 0x9F9F9F, 0x9F9F9F,
463 0x000000, 0x000000, 0x000000, 0x000000 };
464
465 unsigned int* scandata[] = { scan2x2, scan4x4 };
466
467 if (FAILED(pD3DDevice->CreateTexture(nSize, nSize, 1, D3DUSAGE_DYNAMIC, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &(pScanlineTexture[i]), NULL))) {
468 #ifdef PRINT_DEBUG_INFO
469 dprintf(_T(" * Error: Couldn't create texture.\n"));
470 #endif
471 return 1;
472 }
473 if (FAILED(pScanlineTexture[i]->GetSurfaceLevel(0, &pSurf))) {
474 #ifdef PRINT_DEBUG_INFO
475 dprintf(_T(" * Error: Couldn't get texture surface.\n"));
476 #endif
477 }
478
479 if (FAILED(_D3DXLoadSurfaceFromMemory(pSurf, NULL, &rect, scandata[i], D3DFMT_X8R8G8B8, nSize * sizeof(int), NULL, &rect, D3DX_FILTER_NONE, 0))) {
480 #ifdef PRINT_DEBUG_INFO
481 dprintf(_T(" * Error: D3DXLoadSurfaceFromMemory failed.\n"));
482 #endif
483 }
484
485 RELEASE(pSurf);
486 }
487
488 return 0;
489 }
490
dx9GeometryInit()491 int dx9GeometryInit()
492 {
493 for (int y = 0; y < RENDER_STRIPS; y++) {
494
495 D3DLVERTEX2 vScreen[4];
496
497 // The polygons for the emulator image on the screen
498 {
499 int nWidth = pIntermediateTexture ? nImageWidth : nGameImageWidth;
500 int nHeight = nGameImageHeight;
501 int nTexWidth = pIntermediateTexture ? nIntermediateTextureWidth : nTextureWidth;
502 int nTexHeight = nTextureHeight;
503
504 // Add 0.0000001 to ensure consistent rounding
505 double dTexCoordXl = 0.0000001;
506 double dTexCoordXr = (double)nWidth / (double)nTexWidth + 0.0000001;
507 double dTexCoordYt = (double)nHeight * (double)(y + 0) / (double)(nTexHeight * RENDER_STRIPS) + 0.0000001;
508 double dTexCoordYb = (double)nHeight * (double)(y + 1) / (double)(nTexHeight * RENDER_STRIPS) + 0.0000001;
509
510 double dLeft = 1.0 - 2.0;
511 double dRight = 1.0 - 0.0;
512 double dTop = 1.0 - (((double)((nRotateGame & 1) ? (RENDER_STRIPS - y - 0) : (y + 0))) * 2.0 / RENDER_STRIPS);
513 double dBottom = 1.0 - (((double)((nRotateGame & 1) ? (RENDER_STRIPS - y - 1) : (y + 1))) * 2.0 / RENDER_STRIPS);
514
515 // ugly fix for flipped game, modified by regret
516 if ((nRotateGame & 1) && (nRotateGame & 2)) {
517 dTop = 1.0 - (((double)(y + 0)) * 2.0 / RENDER_STRIPS);
518 dBottom = 1.0 - (((double)(y + 1)) * 2.0 / RENDER_STRIPS);
519 }
520 else if (nRotateGame & 2) {
521 dTop = 1.0 - (((double)(RENDER_STRIPS - y - 0)) * 2.0 / RENDER_STRIPS);
522 dBottom = 1.0 - (((double)(RENDER_STRIPS - y - 1)) * 2.0 / RENDER_STRIPS);
523 }
524
525 if (pIntermediateTexture && bVidScanlines) {
526 dTexCoordXl += 0.5 / (double)nIntermediateTextureWidth;
527 dTexCoordXr += 0.5 / (double)nIntermediateTextureWidth;
528 dTexCoordYt += 1.0 / (double)nIntermediateTextureHeight;
529 dTexCoordYb += 1.0 / (double)nIntermediateTextureHeight;
530 }
531
532 #if 0
533 if (nPreScaleEffect) {
534 if (nPreScale & 1) {
535 nWidth *= nPreScaleZoom;
536 nTexWidth = nPreScaleTextureWidth;
537 }
538 if (nPreScale & 2) {
539 nHeight *= nPreScaleZoom;
540 nTexHeight = nPreScaleTextureHeight;
541 }
542 }
543 #endif
544
545 // Set up the vertices for the game image, including the texture coordinates for the game image only
546 // ugly fix for flipped game, modified by regret
547 if (nRotateGame & 1) {
548 vScreen[(nRotateGame & 2) ? 3 : 0] = D3DLVERTEX2(dTop, dLeft, 0.0, 0xFFFFFFFF, 0, (nRotateGame & 2) ? dTexCoordXr : dTexCoordXl, dTexCoordYt, 0, 0);
549 vScreen[(nRotateGame & 2) ? 2 : 1] = D3DLVERTEX2(dTop, dRight, 0.0, 0xFFFFFFFF, 0, (nRotateGame & 2) ? dTexCoordXl : dTexCoordXr, dTexCoordYt, 0, 0);
550 vScreen[(nRotateGame & 2) ? 1 : 2] = D3DLVERTEX2(dBottom, dLeft, 0.0, 0xFFFFFFFF, 0, (nRotateGame & 2) ? dTexCoordXr : dTexCoordXl, dTexCoordYb, 0, 0);
551 vScreen[(nRotateGame & 2) ? 0 : 3] = D3DLVERTEX2(dBottom, dRight, 0.0, 0xFFFFFFFF, 0, (nRotateGame & 2) ? dTexCoordXl : dTexCoordXr, dTexCoordYb, 0, 0);
552 } else {
553 vScreen[(nRotateGame & 2) ? 3 : 0] = D3DLVERTEX2(dLeft, dTop, 0.0, 0xFFFFFFFF, 0, (nRotateGame & 2) ? dTexCoordXr : dTexCoordXl, dTexCoordYt, 0, 0);
554 vScreen[(nRotateGame & 2) ? 2 : 1] = D3DLVERTEX2(dRight, dTop, 0.0, 0xFFFFFFFF, 0, (nRotateGame & 2) ? dTexCoordXl : dTexCoordXr, dTexCoordYt, 0, 0);
555 vScreen[(nRotateGame & 2) ? 1 : 2] = D3DLVERTEX2(dLeft, dBottom, 0.0, 0xFFFFFFFF, 0, (nRotateGame & 2) ? dTexCoordXr : dTexCoordXl, dTexCoordYb, 0, 0);
556 vScreen[(nRotateGame & 2) ? 0 : 3] = D3DLVERTEX2(dRight, dBottom, 0.0, 0xFFFFFFFF, 0, (nRotateGame & 2) ? dTexCoordXl : dTexCoordXr, dTexCoordYb, 0, 0);
557 }
558
559 {
560 // Set up the 2nd pair of texture coordinates, used for scanlines or the high performance version of the cubic filter
561
562 double dScanOffset = nGameImageHeight / -2.0;
563
564 if (bVidScanlines) {
565 int s, z = nImageHeight / nGameImageHeight;
566
567 for (s = 2; s < z; s <<= 1) { }
568 dScanOffset += 0.5 / s;
569 } else {
570 dScanOffset += 0.5;
571 }
572
573 // Set the texture coordinates for the scanlines
574 if (nRotateGame & 1) {
575 vScreen[nRotateGame & 2 ? 3 : 0].tu1 = dScanOffset + 0.0; vScreen[nRotateGame & 2 ? 3 : 0].tv1 = dScanOffset + 0.0 + 0.0000001;
576 vScreen[nRotateGame & 2 ? 2 : 1].tu1 = dScanOffset + (double)nGameHeight; vScreen[nRotateGame & 2 ? 2 : 1].tv1 = dScanOffset + 0.0 + 0.0000001;
577 vScreen[nRotateGame & 2 ? 1 : 2].tu1 = dScanOffset + 0.0; vScreen[nRotateGame & 2 ? 1 : 2].tv1 = dScanOffset + (double)nGameWidth / RENDER_STRIPS + 0.0000001;
578 vScreen[nRotateGame & 2 ? 0 : 3].tu1 = dScanOffset + (double)nGameHeight; vScreen[nRotateGame & 2 ? 0 : 3].tv1 = dScanOffset + (double)nGameWidth / RENDER_STRIPS + 0.0000001;
579 } else {
580 vScreen[nRotateGame & 2 ? 3 : 0].tu1 = dScanOffset + 0.0; vScreen[nRotateGame & 2 ? 3 : 0].tv1 = dScanOffset + 0.0 + 0.0000001;
581 vScreen[nRotateGame & 2 ? 2 : 1].tu1 = dScanOffset + (double)nGameWidth; vScreen[nRotateGame & 2 ? 2 : 1].tv1 = dScanOffset + 0.0 + 0.0000001;
582 vScreen[nRotateGame & 2 ? 1 : 2].tu1 = dScanOffset + 0.0; vScreen[nRotateGame & 2 ? 1 : 2].tv1 = dScanOffset + (double)nGameHeight / RENDER_STRIPS + 0.0000001;
583 vScreen[nRotateGame & 2 ? 0 : 3].tu1 = dScanOffset + (double)nGameWidth; vScreen[nRotateGame & 2 ? 0 : 3].tv1 = dScanOffset + (double)nGameHeight / RENDER_STRIPS + 0.0000001;
584 }
585 }
586 }
587
588 {
589 D3DLVERTEX2* pVertexData;
590
591 if (FAILED(pVB[y]->Lock(0, 4 * sizeof(D3DLVERTEX2), (void**)&pVertexData, 0))) {
592 #ifdef PRINT_DEBUG_INFO
593 dprintf(_T(" * Error: Couldn't create vertex buffer.\n"));
594 #endif
595 return 1;
596 }
597 memcpy(pVertexData, &vScreen, 4 * sizeof(D3DLVERTEX2));
598 pVB[y]->Unlock();
599 }
600 }
601
602 if (bVidScanlines) {
603 pEffect->SetTexture("scanTexture", pScanlineTexture[(nImageHeight / nGameImageHeight >= 4) ? 1 : 0]);
604 }
605
606 if (pIntermediateTexture) {
607 D3DLVERTEX2* pVertexData;
608 D3DLVERTEX2 vTemp[4];
609
610 double dTexCoordXl = 0.0;
611 double dTexCoordXr = (double)nGameImageWidth / (double)nTextureWidth;
612 double dTexCoordYt = 0.0 + 0.0000001;
613 double dTexCoordYb = 1.0 + 0.0000001;
614
615 if (DX9_FILTER == 1) {
616 dTexCoordYt -= 0.5 / nTextureHeight;
617 dTexCoordYb -= 0.5 / nTextureHeight;
618 }
619
620 vTemp[0] = D3DLVERTEX2(-1.0, 1.0, 0.0, 0xFFFFFFFF, 0, dTexCoordXl, dTexCoordYt, 0.5 , 0.5);
621 vTemp[1] = D3DLVERTEX2( 1.0, 1.0, 0.0, 0xFFFFFFFF, 0, dTexCoordXr, dTexCoordYt, 0.5 + nGameImageWidth, 0.5);
622 vTemp[2] = D3DLVERTEX2(-1.0, -1.0, 0.0, 0xFFFFFFFF, 0, dTexCoordXl, dTexCoordYb, 0.5, 0.5 + nGameImageHeight);
623 vTemp[3] = D3DLVERTEX2( 1.0, -1.0, 0.0, 0xFFFFFFFF, 0, dTexCoordXr, dTexCoordYb, 0.5 + nGameImageWidth, 0.5 + nGameImageHeight);
624
625 if (FAILED(pIntermediateVB->Lock(0, 4 * sizeof(D3DLVERTEX2), (void**)&pVertexData, 0))) {
626 #ifdef PRINT_DEBUG_INFO
627 dprintf(_T(" * Error: Couldn't create vertex buffer.\n"));
628 #endif
629 return 1;
630 }
631
632 memcpy(pVertexData, &vTemp, 4 * sizeof(D3DLVERTEX2));
633 pIntermediateVB->Unlock();
634 }
635
636 return 0;
637 }
638
dx9EffectInit()639 int dx9EffectInit()
640 {
641 // Set up the bicubic filter
642
643 // char szB[MAX_PATH] = "(1.0)";
644 // char szC[MAX_PATH] = "(0.0)";
645 // D3DXMACRO d3dxm[] = {{ "USE_BC_MACRO", "1", }, { "B", szB, }, { "C", szC, }, { NULL, NULL, }};
646
647 char* pszTechniqueOpt[] = { "ScanBilinear", "Bilinear", "ScanPoint", "Point" };
648 char* pszTechnique = NULL;
649
650 ID3DXBuffer* pErrorBuffer = NULL;
651 FLOAT pFloatArray[2];
652
653 pEffect = NULL;
654 pEffectShader = NULL;
655
656 _D3DXCreateBuffer(0x10000, &pErrorBuffer);
657
658 #ifdef LOAD_EFFECT_FROM_FILE
659 if (FAILED(_D3DXCreateEffectFromFile(pD3DDevice, _T("bicubic.fx"), NULL /* d3dxm */, NULL, D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY, NULL, &pEffect, &pErrorBuffer))) {
660 #else
661 if (FAILED(_D3DXCreateEffectFromResource(pD3DDevice, NULL, MAKEINTRESOURCE(ID_DX9EFFECT), NULL /* d3dxm */, NULL, D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY, NULL, &pEffect, &pErrorBuffer))) {
662 #endif
663 #ifdef PRINT_DEBUG_INFO
664 dprintf(_T(" * Error: Couldn't compile effect.\n"));
665 dprintf(_T("\n%hs\n\n"), pErrorBuffer->GetBufferPointer());
666 #endif
667 goto HANDLE_ERROR;
668 }
669
670 // Check if we need to use PS1.4 (instead of 2.0)
671 bUsePS14 = !DX9_USE_PS20;
672 if (pEffect->GetTechniqueByName("SinglePassHQBicubic") == NULL) {
673 bUsePS14 = true;
674 }
675
676 if (dx9EffectSurfaceInit()) {
677 goto HANDLE_ERROR;
678 }
679
680 switch (DX9_FILTER) {
681 case 1: {
682 pszTechnique = bVidScanlines ? pszTechniqueOpt[0] : pszTechniqueOpt[1];
683 break;
684 }
685 case 2: {
686 if (bVidScanlines) {
687 char* pszFunction[8] = { "ScanHQBicubic", "ScanBicubic", "ScanHQBicubic", "ScanBicubic", "ScanHP20Bicubic", "ScanHP14Bicubic", "ScanHP14Bicubic", "ScanHP14Bicubic" };
688 pszTechnique = pszFunction[bUsePS14 ? 7 : DX9_SHADERPRECISION];
689 } else {
690 char* pszFunction[8] = { "SinglePassHQBicubic", "SinglePassBicubic", "MultiPassHQBicubic", "MultiPassBicubic", "MultiPassHP20Bicubic", "MultiPassHP14Bicubic", "MultiPassHP14Bicubic", "MultiPassHP14Bicubic" };
691 pszTechnique = pszFunction[bUsePS14 ? 7 : DX9_SHADERPRECISION];
692 }
693 break;
694 }
695 default: {
696 pszTechnique = bVidScanlines ? pszTechniqueOpt[2] : pszTechniqueOpt[3];
697 break;
698 }
699 }
700
701 pEffect->SetTexture("imageTexture", pTexture);
702 pEffect->SetTexture("intermediateTexture", pIntermediateTexture);
703 pEffect->SetTexture("scanTexture", pScanlineTexture[(nImageHeight / nGameImageHeight >= 4) ? 1 : 0]);
704
705 pFloatArray[0] = nTextureWidth; pFloatArray[1] = nTextureHeight;
706 pEffect->SetFloatArray("imageSize", pFloatArray, 2);
707 pFloatArray[0] = 1.0 / nTextureWidth; pFloatArray[1] = 1.0 / nTextureHeight;
708 pEffect->SetFloatArray("texelSize", pFloatArray, 2);
709
710 /*
711 {
712 FLOAT fScanIntensity[4] = { (float)((nVidScanIntensity >> 16) & 255) / 255.0,
713 (float)((nVidScanIntensity >> 8) & 255) / 255.0,
714 (float)((nVidScanIntensity >> 0) & 255) / 255.0,
715 (float)((nVidScanIntensity >> 24) & 255) / 255.0 };
716
717 pEffect->SetFloatArray("scanIntensity", fScanIntensity, 4);
718 }
719 */
720 hTechnique = pEffect->GetTechniqueByName(pszTechnique);
721 if (FAILED(pEffect->SetTechnique(hTechnique))) {
722 #ifdef PRINT_DEBUG_INFO
723 dprintf(_T(" * Error: Couldn't set technique.\n"));
724 #endif
725 goto HANDLE_ERROR;
726 }
727
728 pEffect->SetTexture("weightTex", pEffectTexture);
729
730 {
731 ID3DXBuffer* pEffectShaderBuffer = NULL;
732 _D3DXCreateBuffer(0x10000, &pEffectShaderBuffer);
733
734 #ifdef LOAD_EFFECT_FROM_FILE
735 if (FAILED(_D3DXCompileShaderFromFile(_T("bicubic.fx"), NULL, NULL, (DX9_SHADERPRECISION < 4 && !bUsePS14) ? "genWeightTex20" : "genWeightTex14", "tx_1_0", 0, &pEffectShaderBuffer, &pErrorBuffer, NULL))) {
736 #else
737 if (FAILED(_D3DXCompileShaderFromResource(NULL, MAKEINTRESOURCE(ID_DX9EFFECT), NULL, NULL, (DX9_SHADERPRECISION < 4 && !bUsePS14) ? "genWeightTex20" : "genWeightTex14", "tx_1_0", 0, &pEffectShaderBuffer, &pErrorBuffer, NULL))) {
738 #endif
739 #ifdef PRINT_DEBUG_INFO
740 dprintf(_T(" * Error: Couldn't compile shader.\n"));
741 dprintf(_T("\n%hs\n\n"), pErrorBuffer->GetBufferPointer());
742 #endif
743 goto HANDLE_ERROR;
744 }
745
746 if (FAILED(_D3DXCreateTextureShader((DWORD*)(pEffectShaderBuffer->GetBufferPointer()), &pEffectShader))) {
747 #ifdef PRINT_DEBUG_INFO
748 dprintf(_T(" * Error: Couldn't create texture shader.\n"));
749 #endif
750 RELEASE(pEffectShaderBuffer);
751
752 goto HANDLE_ERROR;
753 }
754
755 FillEffectTexture();
756
757 RELEASE(pEffectShaderBuffer);
758 }
759
760 RELEASE(pErrorBuffer);
761
762 return 0;
763
764 HANDLE_ERROR:
765
766 RELEASE(pErrorBuffer);
767
768 return 1;
769 }
770
771 // ==> osd for dx9 video output (ugly), added by regret
772 static int dx9CreateFont()
773 {
774 if (pFont) {
775 return 0;
776 }
777
778 HRESULT hr = _D3DXCreateFont(pD3DDevice, d3dpp.BackBufferHeight / 18,
779 0, FW_DEMIBOLD, 1, FALSE,
780 DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
781 DEFAULT_PITCH || FF_DONTCARE,
782 _T("Arial"), &pFont);
783
784 if (FAILED(hr)) {
785 return 1;
786 }
787 return 0;
788 }
789
790 static void dx9DrawText()
791 {
792 if (nVidSDisplayStatus == 0 || nOSDTimer == 0) {
793 return;
794 }
795
796 if (nFramesEmulated > nOSDTimer) {
797 VidSKillShortMsg();
798 VidSKillOSDMsg();
799 }
800
801 RECT osdRect;
802 if (nVidFullscreen) {
803 osdRect.left = Dest.left;
804 osdRect.top = Dest.top;
805 osdRect.right = Dest.right - 1;
806 osdRect.bottom = Dest.bottom - 1;
807 } else {
808 osdRect.left = 0;
809 osdRect.top = 0;
810 osdRect.right = Dest.right - Dest.left - 1;
811 osdRect.bottom = Dest.bottom - Dest.top - 1;
812 }
813
814 pFont->DrawText(NULL, OSDMsg, -1, &osdRect, DT_RIGHT | DT_TOP, osdColor);
815 }
816 // <== osd for dx9 video output (ugly)
817
818 static int dx9Init()
819 {
820 if (nVidFullscreen && !hScrnWnd) {
821 return 1;
822 }
823
824 #ifdef ENABLE_PROFILING
825 ProfileInit();
826 #endif
827
828 #ifdef PRINT_DEBUG_INFO
829 dprintf(_T("*** Initialising Direct3D 9 blitter.\n"));
830 #endif
831
832 hVidWnd = hScrnWnd; // Use Screen window for video
833
834 // Get pointer to Direct3D
835 if ((pD3D = _Direct3DCreate9(D3D_SDK_VERSION)) == NULL) {
836 #ifdef PRINT_DEBUG_INFO
837 dprintf(_T(" * Error: Couldn't initialise Direct3D.\n"));
838 #endif
839 dx9Exit();
840 return 1;
841 }
842
843 nRotateGame = 0;
844 if (bDrvOkay) {
845 if (BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL) {
846 if (nVidRotationAdjust & 1) {
847 nRotateGame |= (nVidRotationAdjust & 2);
848 } else {
849 nRotateGame |= 1;
850 }
851 }
852
853 if (BurnDrvGetFlags() & BDF_ORIENTATION_FLIPPED) {
854 nRotateGame ^= 2;
855 }
856 }
857
858 nD3DAdapter = D3DADAPTER_DEFAULT;
859 if (nRotateGame & 1 && VerScreen[0]) {
860 nD3DAdapter = dx9GetAdapter(VerScreen);
861 } else {
862 if (HorScreen[0]) {
863 nD3DAdapter = dx9GetAdapter(HorScreen);
864 }
865 }
866
867 memset(&d3dpp, 0, sizeof(d3dpp));
868 if (nVidFullscreen) {
869 VidSDisplayScoreInfo ScoreInfo;
870 if (dx9SelectFullscreenMode(&ScoreInfo)) {
871 dx9Exit();
872 #ifdef PRINT_DEBUG_INFO
873 dprintf(_T(" * Error: Couldn't determine display mode.\n"));
874 #endif
875 return 1;
876 }
877
878 d3dpp.BackBufferWidth = ScoreInfo.nBestWidth;
879 d3dpp.BackBufferHeight = ScoreInfo.nBestHeight;
880 d3dpp.BackBufferFormat = (nVidDepth == 16) ? D3DFMT_R5G6B5 : D3DFMT_X8R8G8B8;
881 d3dpp.SwapEffect = D3DSWAPEFFECT_FLIP;
882 d3dpp.BackBufferCount = bVidTripleBuffer ? 2 : 1;
883 d3dpp.hDeviceWindow = hVidWnd;
884 d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
885 d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
886 } else {
887 d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
888 d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
889 d3dpp.hDeviceWindow = hVidWnd;
890 d3dpp.Windowed = TRUE;
891 d3dpp.PresentationInterval = bVidVSync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
892 }
893
894 DWORD dwBehaviorFlags = bVidVSync ? (D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED) : (D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE);
895 #ifdef _DEBUG
896 dwBehaviorFlags |= D3DCREATE_DISABLE_DRIVER_MANAGEMENT;
897 #endif
898
899 if (FAILED(pD3D->CreateDevice(nD3DAdapter, D3DDEVTYPE_HAL, hVidWnd, dwBehaviorFlags, &d3dpp, &pD3DDevice))) {
900 // if (FAILED(pD3D->CreateDevice(pD3D->GetAdapterCount() - 1, D3DDEVTYPE_REF, hVidWnd, dwBehaviorFlags, &d3dpp, &pD3DDevice))) {
901
902 #ifdef PRINT_DEBUG_INFO
903 dprintf(_T(" * Error: Couldn't create Direct3D device.\n"));
904 #endif
905
906 if (nVidFullscreen) {
907 FBAPopupAddText(PUF_TEXT_DEFAULT, MAKEINTRESOURCE(IDS_ERR_UI_FULL_PROBLEM));
908 if (bVidArcaderes && (d3dpp.BackBufferWidth != 320 && d3dpp.BackBufferHeight != 240)) {
909 FBAPopupAddText(PUF_TEXT_DEFAULT, MAKEINTRESOURCE(IDS_ERR_UI_FULL_CUSTRES));
910 }
911 FBAPopupDisplay(PUF_TYPE_ERROR);
912 }
913
914 dx9Exit();
915 return 1;
916 }
917
918 {
919 D3DDISPLAYMODE dm;
920 pD3D->GetAdapterDisplayMode(nD3DAdapter, &dm);
921 nVidScrnWidth = dm.Width; nVidScrnHeight = dm.Height;
922 nVidScrnDepth = (dm.Format == D3DFMT_R5G6B5) ? 16 : 32;
923 }
924
925 nGameWidth = nVidImageWidth; nGameHeight = nVidImageHeight;
926
927 nRotateGame = 0;
928 if (bDrvOkay) {
929 // Get the game screen size
930 BurnDrvGetVisibleSize(&nGameWidth, &nGameHeight);
931
932 if (BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL) {
933 if (nVidRotationAdjust & 1) {
934 int n = nGameWidth;
935 nGameWidth = nGameHeight;
936 nGameHeight = n;
937 nRotateGame |= (nVidRotationAdjust & 2);
938 } else {
939 nRotateGame |= 1;
940 }
941 }
942
943 if (BurnDrvGetFlags() & BDF_ORIENTATION_FLIPPED) {
944 nRotateGame ^= 2;
945 }
946 }
947
948 // VidSSetupGamma(BlitFXPrim);
949
950 // Initialize the buffer surfaces
951 if (dx9SurfaceInit()) {
952 dx9Exit();
953 return 1;
954 }
955 if (dx9EffectInit()) {
956 dx9Exit();
957 return 1;
958 }
959
960 for (int y = 0; y < RENDER_STRIPS; y++) {
961 if (FAILED(pD3DDevice->CreateVertexBuffer(4 * sizeof(D3DLVERTEX2), D3DUSAGE_WRITEONLY, D3DFVF_LVERTEX2, D3DPOOL_DEFAULT, &pVB[y], NULL))) {
962 dx9Exit();
963 return 1;
964 }
965 }
966 if (FAILED(pD3DDevice->CreateVertexBuffer(4 * sizeof(D3DLVERTEX2), D3DUSAGE_WRITEONLY, D3DFVF_LVERTEX2, D3DPOOL_DEFAULT, &pIntermediateVB, NULL))) {
967 dx9Exit();
968 return 1;
969 }
970
971 nImageWidth = 0; nImageHeight = 0;
972
973 dPrevCubicB = dPrevCubicC = -999;
974
975 pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
976 pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
977 pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
978
979 // Clear the swapchain's buffers
980 if (nVidFullscreen) {
981 for (int i = 0; i < 3; i++) {
982 pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
983 pD3DDevice->Present(NULL, NULL, NULL, NULL);
984 }
985 } else {
986 RECT rect;
987
988 GetClientScreenRect(hVidWnd, &rect);
989 rect.top += nMenuHeight; rect.bottom += nMenuHeight;
990 pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
991 pD3DDevice->Present(&rect, &rect, NULL, NULL);
992 }
993
994 // Create osd font
995 dx9CreateFont();
996
997 #ifdef PRINT_DEBUG_INFO
998 {
999 dprintf(_T(" * Initialisation complete: %.2lfMB texture memory free (total).\n"), (double)pD3DDevice->GetAvailableTextureMem() / (1024 * 1024));
1000 dprintf(_T(" Displaying and rendering in %i-bit mode, emulation running in %i-bit mode.\n"), nVidScrnDepth, nVidImageDepth);
1001 if (nVidFullscreen) {
1002 dprintf(_T(" Running in fullscreen mode (%i x %i), "), nVidScrnWidth, nVidScrnHeight);
1003 dprintf(_T("using a %s buffer.\n"), bVidTripleBuffer ? _T("triple") : _T("double"));
1004 } else {
1005 dprintf(_T(" Running in windowed mode, using D3DSWAPEFFECT_COPY to present the image.\n"));
1006 }
1007 }
1008 #endif
1009
1010 return 0;
1011 }
1012
1013 static int dx9Reset()
1014 {
1015 #ifdef PRINT_DEBUG_INFO
1016 dprintf(_T("*** Resestting Direct3D device.\n"));
1017 #endif
1018
1019 if (pFont) {
1020 pFont->OnLostDevice();
1021 }
1022
1023 dx9ReleaseResources();
1024
1025 if (FAILED(pD3DDevice->Reset(&d3dpp))) {
1026 return 1;
1027 }
1028
1029 if (pFont) {
1030 pFont->OnResetDevice();
1031 }
1032
1033 dx9SurfaceInit();
1034 dx9EffectInit();
1035
1036 for (int y = 0; y < RENDER_STRIPS; y++) {
1037 pD3DDevice->CreateVertexBuffer(4 * sizeof(D3DLVERTEX2), D3DUSAGE_WRITEONLY, D3DFVF_LVERTEX2, D3DPOOL_DEFAULT, &pVB[y], NULL);
1038 }
1039 pD3DDevice->CreateVertexBuffer(4 * sizeof(D3DLVERTEX2), D3DUSAGE_WRITEONLY, D3DFVF_LVERTEX2, D3DPOOL_DEFAULT, &pIntermediateVB, NULL);
1040
1041 pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
1042 pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
1043 pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
1044
1045 nImageWidth = 0; nImageHeight = 0;
1046
1047 dPrevCubicB = dPrevCubicC = -999;
1048
1049 return 0;
1050 }
1051
1052 static int dx9Scale(RECT* pRect, int nWidth, int nHeight)
1053 {
1054 return VidSScaleImage(pRect, nWidth, nHeight, bVidScanRotate);
1055 }
1056
1057 // Copy BlitFXsMem to pddsBlitFX
1058 static int dx9MemToSurf()
1059 {
1060 GetClientRect(hVidWnd, &Dest);
1061
1062 if (nVidFullscreen == 0) {
1063 Dest.top += nMenuHeight;
1064 }
1065
1066 if (bVidArcaderes && nVidFullscreen) {
1067 Dest.left = (Dest.right + Dest.left) / 2;
1068 Dest.left -= nGameWidth / 2;
1069 Dest.right = Dest.left + nGameWidth;
1070
1071 Dest.top = (Dest.top + Dest.bottom) / 2;
1072 Dest.top -= nGameHeight / 2;
1073 Dest.bottom = Dest.top + nGameHeight;
1074 } else {
1075 dx9Scale(&Dest, nGameWidth, nGameHeight);
1076 }
1077
1078 {
1079 int nNewImageWidth = nRotateGame ? (Dest.bottom - Dest.top) : (Dest.right - Dest.left);
1080 int nNewImageHeight = nRotateGame ? (Dest.right - Dest.left) : (Dest.bottom - Dest.top);
1081
1082 if (nImageWidth != nNewImageWidth || nImageHeight != nNewImageHeight) {
1083 nImageWidth = nNewImageWidth;
1084 nImageHeight = nNewImageHeight;
1085 dx9GeometryInit();
1086 }
1087 }
1088
1089 {
1090 if (dPrevCubicB != dVidCubicB || dPrevCubicC != dVidCubicC) {
1091 dPrevCubicB = dVidCubicB;
1092 dPrevCubicC = dVidCubicC;
1093 FillEffectTexture();
1094 }
1095 }
1096
1097 {
1098 // Copy the game image to a surface in video memory
1099
1100 D3DLOCKED_RECT lr;
1101
1102 if (FAILED(pSurface->LockRect(&lr, NULL, 0))) {
1103 #ifdef PRINT_DEBUG_INFO
1104 dprintf(_T(" * Error: Couldn't lock surface.\n"));
1105 #endif
1106 return 1;
1107 }
1108
1109 unsigned char* ps = pVidImage + nVidImageLeft * nVidImageBPP;
1110 unsigned char* pd = (unsigned char*)lr.pBits;
1111 int p = lr.Pitch;
1112 int s = nVidImageWidth * nVidImageBPP;
1113
1114 for (int y = 0; y < nVidImageHeight; y++, pd += p, ps += nVidImagePitch) {
1115 memcpy(pd, ps, s);
1116 }
1117
1118 pSurface->UnlockRect();
1119 }
1120
1121 {
1122 // Copy the game image onto a texture for rendering
1123
1124 RECT rect = { 0, 0, nVidImageWidth, nVidImageHeight };
1125 IDirect3DSurface9* pDest;
1126
1127 if (FAILED(pTexture->GetSurfaceLevel(0, &pDest))) {
1128 #ifdef PRINT_DEBUG_INFO
1129 dprintf(_T(" * Error: Couldn't get texture surface.\n"));
1130 return 1;
1131 #endif
1132 }
1133
1134 if (FAILED(pD3DDevice->StretchRect(pSurface, &rect, pDest, &rect, D3DTEXF_NONE))) {
1135 #ifdef PRINT_DEBUG_INFO
1136 dprintf(_T(" * Error: Couldn't copy image.\n"));
1137 #endif
1138 }
1139
1140 pDest->Release();
1141 }
1142
1143 #ifdef ENABLE_PROFILING
1144 {
1145 // Force the D3D pipeline to be flushed
1146
1147 D3DLVERTEX2* pVertexData;
1148
1149 if (SUCCEEDED(pIntermediateVB->Lock(0, 4 * sizeof(D3DLVERTEX2), (void**)&pVertexData, 0))) {
1150 pIntermediateVB->Unlock();
1151 }
1152
1153 ProfileProfileStart(2);
1154 }
1155 #endif
1156
1157 pD3DDevice->SetRenderState(D3DRS_TEXTUREFACTOR, nVidScanIntensity);
1158
1159 UINT nTotalPasses, nPass = 0;
1160 pEffect->Begin(&nTotalPasses, D3DXFX_DONOTSAVESTATE);
1161
1162 if (nTotalPasses > 1) {
1163 IDirect3DSurface9* pPreviousTarget;
1164 IDirect3DSurface9* pNewTarget;
1165 D3DVIEWPORT9 vp;
1166
1167 pD3DDevice->GetRenderTarget(0, &pPreviousTarget);
1168 pIntermediateTexture->GetSurfaceLevel(0, &pNewTarget);
1169 pD3DDevice->SetRenderTarget(0, pNewTarget);
1170
1171 vp.X = 0;
1172 vp.Y = 0;
1173 vp.Width = nImageWidth;
1174 vp.Height = nTextureHeight;
1175 vp.MinZ = 0.0f;
1176 vp.MaxZ = 1.0f;
1177
1178 pD3DDevice->SetViewport(&vp);
1179
1180 pD3DDevice->BeginScene();
1181
1182 pD3DDevice->SetFVF(D3DFVF_LVERTEX2);
1183
1184 pEffect->BeginPass(nPass);
1185 pEffect->CommitChanges();
1186
1187 pD3DDevice->SetStreamSource(0, pIntermediateVB, 0, sizeof(D3DLVERTEX2));
1188 pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
1189 pEffect->EndPass();
1190
1191 pD3DDevice->EndScene();
1192
1193 pD3DDevice->SetRenderTarget(0, pPreviousTarget);
1194
1195 RELEASE(pPreviousTarget);
1196 RELEASE(pNewTarget);
1197
1198 nPass++;
1199 }
1200
1201 #if 0
1202 {
1203 // blit the intermediate texture to the screen
1204
1205 RECT srect = { 0, 0, Dest.right - Dest.left, 256 };
1206 RECT drect = { 0, nMenuHeight, Dest.right - Dest.left, nMenuHeight + 256 };
1207 IDirect3DSurface9* pDest;
1208 IDirect3DSurface9* pSrc;
1209
1210 pD3DDevice->GetRenderTarget(0, &pDest);
1211 pIntermediateTexture->GetSurfaceLevel(0, &pSrc);
1212
1213 pD3DDevice->StretchRect(pSrc, &srect, pDest, &drect, D3DTEXF_NONE);
1214
1215 pSrc->Release();
1216 pDest->Release();
1217
1218 pEffect->End();
1219
1220 return 0;
1221 }
1222 #endif
1223
1224 #ifdef ENABLE_PROFILING
1225 {
1226 // Force the D3D pipeline to be flushed
1227
1228 D3DLVERTEX2* pVertexData;
1229
1230 if (SUCCEEDED(pIntermediateVB->Lock(0, 4 * sizeof(D3DLVERTEX2), (void**)&pVertexData, 0))) {
1231 pIntermediateVB->Unlock();
1232 }
1233
1234 ProfileProfileEnd(2);
1235 }
1236 ProfileProfileStart(0);
1237 #endif
1238
1239 {
1240 D3DVIEWPORT9 vp;
1241
1242 // Set the size of the image on the PC screen
1243 if (nVidFullscreen) {
1244 vp.X = Dest.left;
1245 vp.Y = Dest.top;
1246 vp.Width = Dest.right - Dest.left;
1247 vp.Height = Dest.bottom - Dest.top;
1248 vp.MinZ = 0.0f;
1249 vp.MaxZ = 1.0f;
1250 } else {
1251 vp.X = 0;
1252 vp.Y = 0;
1253 vp.Width = Dest.right - Dest.left;
1254 vp.Height = Dest.bottom - Dest.top;
1255 vp.MinZ = 0.0f;
1256 vp.MaxZ = 1.0f;
1257 }
1258
1259 pD3DDevice->SetViewport(&vp);
1260
1261 pD3DDevice->BeginScene();
1262
1263 pD3DDevice->SetFVF(D3DFVF_LVERTEX2);
1264
1265 // pD3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
1266
1267 pEffect->BeginPass(nPass);
1268 pEffect->CommitChanges();
1269
1270 for (int y = 0; y < RENDER_STRIPS; y++) {
1271 pD3DDevice->SetStreamSource(0, pVB[y], 0, sizeof(D3DLVERTEX2));
1272 pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
1273 }
1274 pEffect->EndPass();
1275
1276 // draw osd text
1277 dx9DrawText();
1278
1279 pD3DDevice->EndScene();
1280 }
1281
1282 pEffect->End();
1283
1284 #ifdef ENABLE_PROFILING
1285 {
1286 // Force the D3D pipeline to be flushed
1287
1288 D3DLVERTEX2* pVertexData;
1289
1290 if (SUCCEEDED(pVB[RENDER_STRIPS - 1]->Lock(0, 4 * sizeof(D3DLVERTEX2), (void**)&pVertexData, 0))) {
1291 pVB[RENDER_STRIPS - 1]->Unlock();
1292 }
1293
1294 ProfileProfileEnd(0);
1295 }
1296 #endif
1297
1298 return 0;
1299 }
1300
1301 // Run one frame and render the screen
1302 static int dx9Frame(bool bRedraw) // bRedraw = 0
1303 {
1304 if (pVidImage == NULL) {
1305 return 1;
1306 }
1307
1308 HRESULT nCoopLevel = pD3DDevice->TestCooperativeLevel();
1309 if (nCoopLevel != D3D_OK) { // We've lost control of the screen
1310 if (nCoopLevel != D3DERR_DEVICENOTRESET) {
1311 return 1;
1312 }
1313
1314 if (dx9Reset()) {
1315 return 1;
1316 }
1317
1318 return 1; // Skip this frame, pBurnDraw pointer not valid (dx9Reset() -> dx9SurfaceInit -> VidSAllocVidImage())
1319 }
1320
1321 #ifdef ENABLE_PROFILING
1322 // ProfileProfileStart(0);
1323 #endif
1324
1325 VidFrameCallback(bRedraw); // Run emulation for 1 frame / render image
1326
1327 if (pVidImage == NULL) { // If a mode change was requested by game, pVidImage has been invalidated - time to leave.
1328 return 0;
1329 }
1330
1331 #ifdef ENABLE_PROFILING
1332 // ProfileProfileEnd(0);
1333 ProfileProfileStart(1);
1334 #endif
1335
1336 dx9MemToSurf(); // Copy the memory buffer to the directdraw buffer for later blitting
1337
1338 #ifdef ENABLE_PROFILING
1339 ProfileProfileEnd(1);
1340
1341 dprintf(_T(" blit %3.2lf (effect p1 %3.2lf - effect p2 %3.2lf)\n"), ProfileProfileReadAverage(1), ProfileProfileReadAverage(2), ProfileProfileReadAverage(0));
1342 #endif
1343
1344 return 0;
1345 }
1346
1347 // Paint the BlitFX surface onto the primary surface
1348 static int dx9Paint(int bValidate)
1349 {
1350 if (pD3DDevice->TestCooperativeLevel()) { // We've lost control of the screen
1351 return 1;
1352 }
1353
1354 RECT rect = { 0, 0, 0, 0 };
1355
1356 if (!nVidFullscreen) {
1357 GetClientScreenRect(hVidWnd, &rect);
1358 rect.top += nMenuHeight;
1359
1360 dx9Scale(&rect, nGameWidth, nGameHeight);
1361
1362 if ((rect.right - rect.left) != (Dest.right - Dest.left) || (rect.bottom - rect.top ) != (Dest.bottom - Dest.top)) {
1363 bValidate |= 2;
1364 }
1365 }
1366
1367 if (bValidate & 2) {
1368 dx9MemToSurf(); // Copy the memory buffer to the directdraw buffer for later blitting
1369 }
1370
1371 // Display OSD text message
1372 // VidSDisplayOSD(pddsBlitFX[nUseSys], &rect, 0);
1373
1374 if (nVidFullscreen) {
1375 pD3DDevice->Present(NULL, NULL, NULL, NULL);
1376 } else {
1377 RECT src = { 0, 0, Dest.right - Dest.left, Dest.bottom - Dest.top };
1378
1379 POINT c = { 0, 0 };
1380 ClientToScreen(hVidWnd, &c);
1381 RECT dst = { rect.left - c.x, rect.top - c.y, rect.right - c.x, rect.bottom - c.y };
1382
1383 /*
1384 if (bVidVSync) {
1385 D3DRASTER_STATUS rs;
1386 RECT window;
1387
1388 GetWindowRect(hVidWnd, &window);
1389
1390 while (1) {
1391 pD3DDevice->GetRasterStatus(0, &rs);
1392 if (rs.InVBlank || rs.ScanLine >= window.bottom) {
1393 break;
1394 }
1395 Sleep(1);
1396 }
1397 }
1398 */
1399
1400 pD3DDevice->Present(&src, &dst, NULL, NULL);
1401
1402 // Validate the rectangle we just drew
1403 if (bValidate & 1) {
1404 ValidateRect(hVidWnd, &dst);
1405 }
1406 }
1407
1408 return 0;
1409 }
1410
1411 // ----------------------------------------------------------------------------
1412
1413 static int dx9GetSettings(InterfaceInfo* pInfo)
1414 {
1415 TCHAR szString[MAX_PATH] = _T("");
1416
1417 if (nVidFullscreen) {
1418 if (bVidTripleBuffer) {
1419 IntInfoAddStringModule(pInfo, _T("Using a triple buffer"));
1420 } else {
1421 IntInfoAddStringModule(pInfo, _T("Using a double buffer"));
1422 }
1423 } else {
1424 IntInfoAddStringModule(pInfo, _T("Using D3DSWAPEFFECT_COPY to present the image"));
1425 }
1426 switch (DX9_FILTER) {
1427 case 1: {
1428 IntInfoAddStringModule(pInfo, _T("Applying linear filter"));
1429 break;
1430 }
1431 case 2: {
1432 _sntprintf(szString, MAX_PATH, _T("Applying cubic filter using VS1.1 & %s"), bUsePS14 ? _T("PS1.4") : _T("PS2.0"));
1433 IntInfoAddStringModule(pInfo, szString);
1434
1435 if (bUsePS14) {
1436 IntInfoAddStringModule(pInfo, _T("Using high-performance implementation"));
1437 break;
1438 }
1439
1440 if (bVidScanlines) {
1441 switch (DX9_SHADERPRECISION) {
1442 case 0:
1443 case 2:
1444 IntInfoAddStringModule(pInfo, _T("Using reference implementation"));
1445 break;
1446 case 1:
1447 case 3:
1448 IntInfoAddStringModule(pInfo, _T("Using partial precision implementation"));
1449 break;
1450 case 4:
1451 IntInfoAddStringModule(pInfo, _T("Using high-performance implementation"));
1452 break;
1453 }
1454 } else {
1455 switch (DX9_SHADERPRECISION) {
1456 case 0:
1457 IntInfoAddStringModule(pInfo, _T("Using single-pass reference implementation"));
1458 break;
1459 case 1:
1460 IntInfoAddStringModule(pInfo, _T("Using partial precision single-pass implementation"));
1461 break;
1462 case 2:
1463 IntInfoAddStringModule(pInfo, _T("Using full precision multi-pass implementation"));
1464 break;
1465 case 3:
1466 IntInfoAddStringModule(pInfo, _T("Using partial precision multi-pass implementation"));
1467 break;
1468 case 4:
1469 IntInfoAddStringModule(pInfo, _T("Using high-performance multi-pass implementation"));
1470 break;
1471 }
1472 }
1473 if (DX9_USE_FPTEXTURE) {
1474 _sntprintf(szString, MAX_PATH, _T("Using floating-point textures where applicable"));
1475 IntInfoAddStringModule(pInfo, szString);
1476 }
1477 break;
1478 }
1479 default: {
1480 IntInfoAddStringModule(pInfo, _T("Applying point filter"));
1481 }
1482 }
1483 if (bVidScanlines) {
1484 _sntprintf(szString, MAX_PATH, _T("Applying scanlines at %.1lf%% brightness"), (double)(nVidScanIntensity & 255) / 2.55);
1485 IntInfoAddStringModule(pInfo, szString);
1486 }
1487
1488 return 0;
1489 }
1490
1491 // The Video Output plugin:
1492 struct VidOut VidOutDX9 = { dx9Init, dx9Exit, dx9Frame, dx9Paint, dx9Scale, dx9GetSettings, _T("DirectX9 Experimental video output") };
1493 //#else
1494 //struct VidOut VidOutDX9 = { NULL, NULL, NULL, NULL, NULL, NULL, _T("DirectX9 Experimental video output") };
1495 //#endif
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507 // Direct3D9 video output
1508 // rewritten by regret (Motion Blur source from VBA-M)
1509
1510 struct d3dvertex {
1511 float x, y, z, rhw; //screen coords
1512 float u, v; //texture coords
1513 };
1514
1515 struct transp_vertex {
1516 float x, y, z, rhw;
1517 D3DCOLOR color;
1518 float u, v;
1519 };
1520
1521 #undef D3DFVF_LVERTEX2
1522 #define D3DFVF_LVERTEX2 (D3DFVF_XYZRHW | D3DFVF_TEX1)
1523
1524 IDirect3DTexture9* emuTexture[2];
1525 static unsigned char mbCurrentTexture = 0; // current texture for motion blur
1526 static bool mbTextureEmpty = true;
1527 static d3dvertex vertex[4];
1528 static transp_vertex transpVertex[4];
1529
1530 D3DFORMAT textureFormat;
1531
1532 static int nPreScale = 0;
1533 static int nPreScaleZoom = 0;
1534 static int nPreScaleEffect = 0;
1535
1536 // Select optimal full-screen resolution
1537 static int dx9AltSelectFullscreenMode(VidSDisplayScoreInfo* pScoreInfo)
1538 {
1539 if (bVidArcaderes) {
1540 if (!VidSGetArcaderes((int*)&(pScoreInfo->nBestWidth), (int*)&(pScoreInfo->nBestHeight))) {
1541 return 1;
1542 }
1543 } else {
1544 pScoreInfo->nBestWidth = nVidWidth;
1545 pScoreInfo->nBestHeight = nVidHeight;
1546 }
1547
1548 if (!bDrvOkay && (pScoreInfo->nBestWidth < 640 || pScoreInfo->nBestHeight < 480)) {
1549 return 1;
1550 }
1551
1552 return 0;
1553 }
1554
1555 static void dx9AltReleaseTexture()
1556 {
1557 RELEASE(pTexture)
1558 RELEASE(emuTexture[0])
1559 RELEASE(emuTexture[1])
1560 }
1561
1562 static int dx9AltExit()
1563 {
1564 VidSoftFXExit();
1565
1566 dx9AltReleaseTexture();
1567
1568 VidSFreeVidImage();
1569
1570 RELEASE(pFont)
1571 RELEASE(pD3DDevice)
1572 RELEASE(pD3D)
1573
1574 nRotateGame = 0;
1575
1576 VidSKillShortMsg();
1577 VidSKillOSDMsg();
1578
1579 return 0;
1580 }
1581
1582 static int dx9AltResize(int width, int height)
1583 {
1584 if (FAILED(pD3DDevice->CreateTexture(width, height, 1, 0, textureFormat, D3DPOOL_SYSTEMMEM, &pTexture, NULL))) {
1585 return 1;
1586 }
1587
1588 if (!emuTexture[0]) {
1589 if (FAILED(pD3DDevice->CreateTexture(width, height, 1, 0, textureFormat, D3DPOOL_DEFAULT, &emuTexture[0], NULL))) {
1590 return 1;
1591 }
1592 }
1593
1594 if (!emuTexture[1] && bVidMotionBlur) {
1595 if (FAILED(pD3DDevice->CreateTexture(width, height, 1, 0, textureFormat, D3DPOOL_DEFAULT, &emuTexture[1], NULL))) {
1596 return 1;
1597 }
1598 mbTextureEmpty = true;
1599 }
1600
1601 return 0;
1602 }
1603
1604 static int dx9AltTextureInit()
1605 {
1606 if (nRotateGame & 1) {
1607 nVidImageWidth = nGameHeight;
1608 nVidImageHeight = nGameWidth;
1609 } else {
1610 nVidImageWidth = nGameWidth;
1611 nVidImageHeight = nGameHeight;
1612 }
1613
1614 nGameImageWidth = nVidImageWidth;
1615 nGameImageHeight = nVidImageHeight;
1616
1617 nVidImageDepth = nVidScrnDepth;
1618
1619 // Determine if we should use a texture format different from the screen format
1620 if ((bDrvOkay && VidSoftFXCheckDepth(nPreScaleEffect, 32) != 32) || (bDrvOkay && bVidForce16bitDx9Alt)) {
1621 nVidImageDepth = 16;
1622 }
1623
1624 switch (nVidImageDepth) {
1625 case 32:
1626 textureFormat = D3DFMT_X8R8G8B8;
1627 break;
1628 case 24:
1629 textureFormat = D3DFMT_R8G8B8;
1630 break;
1631 case 16:
1632 textureFormat = D3DFMT_R5G6B5;
1633 break;
1634 case 15:
1635 textureFormat = D3DFMT_X1R5G5B5;
1636 break;
1637 }
1638
1639 nVidImageBPP = (nVidImageDepth + 7) >> 3;
1640 nBurnBpp = nVidImageBPP; // Set Burn library Bytes per pixel
1641
1642 // Use our callback to get colors:
1643 SetBurnHighCol(nVidImageDepth);
1644
1645 // Make the normal memory buffer
1646 if (VidSAllocVidImage()) {
1647 dx9AltExit();
1648 return 1;
1649 }
1650
1651 nTextureWidth = GetTextureSize(nGameImageWidth * nPreScaleZoom);
1652 nTextureHeight = GetTextureSize(nGameImageHeight * nPreScaleZoom);
1653
1654 if (dx9AltResize(nTextureWidth, nTextureHeight)) {
1655 return 1;
1656 }
1657
1658 return 0;
1659 }
1660
1661 // Vertex format:
1662 //
1663 // 0---------1
1664 // | /|
1665 // | / |
1666 // | / |
1667 // | / |
1668 // |/ |
1669 // 2---------3
1670 //
1671 // (x,y) screen coords, in pixels
1672 // (u,v) texture coords, betweeen 0.0 (top, left) to 1.0 (bottom, right)
1673 static int dx9AltSetVertex(unsigned int px, unsigned int py, unsigned int pw, unsigned int ph, unsigned int tw, unsigned int th, unsigned int x, unsigned int y, unsigned int w, unsigned int h)
1674 {
1675 // configure triangles
1676 // -0.5f is necessary in order to match texture alignment to display pixels
1677 float diff = -0.5f;
1678 if (nRotateGame & 1) {
1679 if (nRotateGame & 2) {
1680 vertex[2].x = vertex[3].x = (double)(y ) + diff;
1681 vertex[0].x = vertex[1].x = (double)(y + h) + diff;
1682 vertex[1].y = vertex[3].y = (double)(x + w) + diff;
1683 vertex[0].y = vertex[2].y = (double)(x ) + diff;
1684 } else {
1685 vertex[0].x = vertex[1].x = (double)(y ) + diff;
1686 vertex[2].x = vertex[3].x = (double)(y + h) + diff;
1687 vertex[1].y = vertex[3].y = (double)(x ) + diff;
1688 vertex[0].y = vertex[2].y = (double)(x + w) + diff;
1689 }
1690 } else {
1691 if (nRotateGame & 2) {
1692 vertex[1].x = vertex[3].x = (double)(y ) + diff;
1693 vertex[0].x = vertex[2].x = (double)(y + h) + diff;
1694 vertex[2].y = vertex[3].y = (double)(x ) + diff;
1695 vertex[0].y = vertex[1].y = (double)(x + w) + diff;
1696 } else {
1697 vertex[0].x = vertex[2].x = (double)(x ) + diff;
1698 vertex[1].x = vertex[3].x = (double)(x + w) + diff;
1699 vertex[0].y = vertex[1].y = (double)(y ) + diff;
1700 vertex[2].y = vertex[3].y = (double)(y + h) + diff;
1701 }
1702 }
1703
1704 double rw = (double)w / (double)pw * (double)tw;
1705 double rh = (double)h / (double)ph * (double)th;
1706 vertex[0].u = vertex[2].u = (double)(px ) / rw;
1707 vertex[1].u = vertex[3].u = (double)(px + w) / rw;
1708 vertex[0].v = vertex[1].v = (double)(py ) / rh;
1709 vertex[2].v = vertex[3].v = (double)(py + h) / rh;
1710
1711 // Z-buffer and RHW are unused for 2D blit, set to normal values
1712 vertex[0].z = vertex[1].z = vertex[2].z = vertex[3].z = 0.0f;
1713 vertex[0].rhw = vertex[1].rhw = vertex[2].rhw = vertex[3].rhw = 1.0f;
1714
1715 // configure semi-transparent triangles
1716 if (bVidMotionBlur) {
1717 D3DCOLOR semiTrans = D3DCOLOR_ARGB(0x7F, 0xFF, 0xFF, 0xFF);
1718 transpVertex[0].x = vertex[0].x;
1719 transpVertex[0].y = vertex[0].y;
1720 transpVertex[0].z = vertex[0].z;
1721 transpVertex[0].rhw = vertex[0].rhw;
1722 transpVertex[0].color = semiTrans;
1723 transpVertex[0].u = vertex[0].u;
1724 transpVertex[0].v = vertex[0].v;
1725 transpVertex[1].x = vertex[1].x;
1726 transpVertex[1].y = vertex[1].y;
1727 transpVertex[1].z = vertex[1].z;
1728 transpVertex[1].rhw = vertex[1].rhw;
1729 transpVertex[1].color = semiTrans;
1730 transpVertex[1].u = vertex[1].u;
1731 transpVertex[1].v = vertex[1].v;
1732 transpVertex[2].x = vertex[2].x;
1733 transpVertex[2].y = vertex[2].y;
1734 transpVertex[2].z = vertex[2].z;
1735 transpVertex[2].rhw = vertex[2].rhw;
1736 transpVertex[2].color = semiTrans;
1737 transpVertex[2].u = vertex[2].u;
1738 transpVertex[2].v = vertex[2].v;
1739 transpVertex[3].x = vertex[3].x;
1740 transpVertex[3].y = vertex[3].y;
1741 transpVertex[3].z = vertex[3].z;
1742 transpVertex[3].rhw = vertex[3].rhw;
1743 transpVertex[3].color = semiTrans;
1744 transpVertex[3].u = vertex[3].u;
1745 transpVertex[3].v = vertex[3].v;
1746 }
1747
1748 return 0;
1749 }
1750
1751 // ==> osd for dx9 video output (ugly), added by regret
1752 static int dx9AltCreateFont()
1753 {
1754 if (pFont) {
1755 return 0;
1756 }
1757
1758 HRESULT hr = _D3DXCreateFont(pD3DDevice, d3dpp.BackBufferHeight / 40, 0, FW_NORMAL, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH || FF_DONTCARE, _T("Arial"), &pFont);
1759
1760 if (FAILED(hr)) {
1761 return 1;
1762 }
1763
1764 return 0;
1765 }
1766
1767 static void dx9AltDrawText()
1768 {
1769 if (!nOSDTimer) {
1770 return;
1771 }
1772
1773 if (nFramesEmulated > nOSDTimer) {
1774 VidSKillShortMsg();
1775 VidSKillOSDMsg();
1776 }
1777
1778 RECT osdRect;
1779 if (nVidFullscreen) {
1780 osdRect.left = Dest.left;
1781 osdRect.top = Dest.top;
1782 osdRect.right = Dest.right - 1;
1783 osdRect.bottom = Dest.bottom - 1;
1784 } else {
1785 osdRect.left = 0;
1786 osdRect.top = 0;
1787 osdRect.right = Dest.right - Dest.left - 1;
1788 osdRect.bottom = Dest.bottom - Dest.top - 1;
1789 }
1790
1791 if (nOSDTimer) {
1792 pFont->DrawText(NULL, OSDMsg, -1, &osdRect, DT_RIGHT | DT_TOP, osdColor);
1793 }
1794 }
1795 // <== osd for dx9 video output (ugly)
1796
1797 static int dx9AltInit()
1798 {
1799 if (hScrnWnd == NULL) {
1800 return 1;
1801 }
1802
1803 hVidWnd = hScrnWnd;
1804
1805 // Get pointer to Direct3D
1806 if ((pD3D = _Direct3DCreate9(D3D_SDK_VERSION)) == NULL) {
1807 dx9AltExit();
1808 return 1;
1809 }
1810
1811 nRotateGame = 0;
1812 if (bDrvOkay) {
1813 if (BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL) {
1814 if (nVidRotationAdjust & 1) {
1815 nRotateGame |= (nVidRotationAdjust & 2);
1816 } else {
1817 nRotateGame |= 1;
1818 }
1819 }
1820
1821 if (BurnDrvGetFlags() & BDF_ORIENTATION_FLIPPED) {
1822 nRotateGame ^= 2;
1823 }
1824 }
1825
1826 nD3DAdapter = D3DADAPTER_DEFAULT;
1827 if (nRotateGame & 1 && VerScreen[0]) {
1828 nD3DAdapter = dx9GetAdapter(VerScreen);
1829 } else {
1830 if (HorScreen[0]) {
1831 nD3DAdapter = dx9GetAdapter(HorScreen);
1832 }
1833 }
1834
1835 // check selected atapter
1836 D3DDISPLAYMODE dm;
1837 pD3D->GetAdapterDisplayMode(nD3DAdapter, &dm);
1838
1839 memset(&d3dpp, 0, sizeof(d3dpp));
1840 if (nVidFullscreen) {
1841 VidSDisplayScoreInfo ScoreInfo;
1842 memset(&ScoreInfo, 0, sizeof(VidSDisplayScoreInfo));
1843
1844 if (dx9AltSelectFullscreenMode(&ScoreInfo)) {
1845 dx9AltExit();
1846 return 1;
1847 }
1848
1849 bool sizefit = true;
1850 if (ScoreInfo.nBestWidth > dm.Width || ScoreInfo.nBestHeight > dm.Height) {
1851 sizefit = false;
1852 }
1853
1854 d3dpp.BackBufferWidth = sizefit ? ScoreInfo.nBestWidth : dm.Width;
1855 d3dpp.BackBufferHeight = sizefit ? ScoreInfo.nBestHeight : dm.Height;
1856 d3dpp.BackBufferFormat = (nVidDepth == 16) ? D3DFMT_R5G6B5 : D3DFMT_X8R8G8B8;
1857 d3dpp.SwapEffect = D3DSWAPEFFECT_FLIP;
1858 d3dpp.BackBufferCount = bVidTripleBuffer ? 2 : 1;
1859 d3dpp.hDeviceWindow = hVidWnd;
1860 d3dpp.FullScreen_RefreshRateInHz = dm.RefreshRate;
1861 d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
1862 } else {
1863 d3dpp.BackBufferWidth = dm.Width;
1864 d3dpp.BackBufferHeight = dm.Height;
1865 d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
1866 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1867 d3dpp.BackBufferCount = 1;
1868 d3dpp.hDeviceWindow = hVidWnd;
1869 d3dpp.Windowed = TRUE;
1870 d3dpp.PresentationInterval = bVidVSync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
1871 }
1872
1873 DWORD dwBehaviorFlags = D3DCREATE_FPU_PRESERVE;
1874 if (bVidHardwareVertex) {
1875 dwBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
1876 } else {
1877 dwBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
1878 }
1879
1880 if (FAILED(pD3D->CreateDevice(nD3DAdapter, D3DDEVTYPE_HAL, hVidWnd, dwBehaviorFlags, &d3dpp, &pD3DDevice))) {
1881 if (nVidFullscreen) {
1882 FBAPopupAddText(PUF_TEXT_DEFAULT, MAKEINTRESOURCE(IDS_ERR_UI_FULL_PROBLEM), d3dpp.BackBufferWidth, d3dpp.BackBufferHeight, d3dpp.BackBufferFormat, d3dpp.FullScreen_RefreshRateInHz);
1883 if (bVidArcaderes && (d3dpp.BackBufferWidth != 320 && d3dpp.BackBufferHeight != 240)) {
1884 FBAPopupAddText(PUF_TEXT_DEFAULT, MAKEINTRESOURCE(IDS_ERR_UI_FULL_CUSTRES));
1885 }
1886 FBAPopupDisplay(PUF_TYPE_ERROR);
1887 }
1888
1889 dx9AltExit();
1890 return 1;
1891 }
1892
1893 {
1894 nVidScrnWidth = dm.Width; nVidScrnHeight = dm.Height;
1895 nVidScrnDepth = (dm.Format == D3DFMT_R5G6B5) ? 16 : 32;
1896 }
1897
1898 nGameWidth = nVidImageWidth;
1899 nGameHeight = nVidImageHeight;
1900 nRotateGame = 0;
1901
1902 if (bDrvOkay) {
1903 // Get the game screen size
1904 BurnDrvGetVisibleSize(&nGameWidth, &nGameHeight);
1905
1906 if (BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL) {
1907 if (nVidRotationAdjust & 1) {
1908 int n = nGameWidth;
1909 nGameWidth = nGameHeight;
1910 nGameHeight = n;
1911 nRotateGame |= (nVidRotationAdjust & 2);
1912 } else {
1913 nRotateGame |= 1;
1914 }
1915 }
1916
1917 if (BurnDrvGetFlags() & BDF_ORIENTATION_FLIPPED) {
1918 nRotateGame ^= 2;
1919 }
1920 }
1921
1922 // enable vertex alpha blending
1923 if (bVidMotionBlur) {
1924 pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
1925 } else {
1926 mbCurrentTexture = 0;
1927 pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
1928 }
1929 pD3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
1930 pD3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
1931 pD3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
1932 // apply vertex alpha values to texture
1933 pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
1934
1935 // for filter
1936 nPreScale = 3;
1937 nPreScaleZoom = 2;
1938 nPreScaleEffect = 0;
1939 if (bDrvOkay) {
1940 nPreScaleEffect = nVidBlitterOpt[nVidSelect] & 0xFF;
1941 nPreScaleZoom = VidSoftFXGetZoom(nPreScaleEffect);
1942 }
1943
1944 // Initialize the buffer surfaces
1945 if (dx9AltTextureInit()) {
1946 dx9AltExit();
1947 return 1;
1948 }
1949
1950 if (nPreScaleEffect) {
1951 if (VidSoftFXInit(nPreScaleEffect, 0)) {
1952 dx9AltExit();
1953 return 1;
1954 }
1955 }
1956
1957 pD3DDevice->SetSamplerState(0, D3DSAMP_MINFILTER, bVidDX9Bilinear ? D3DTEXF_LINEAR : D3DTEXF_POINT);
1958 pD3DDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, bVidDX9Bilinear ? D3DTEXF_LINEAR : D3DTEXF_POINT);
1959
1960 nImageWidth = 0; nImageHeight = 0;
1961
1962 // Clear the swapchain's buffers
1963 if (nVidFullscreen) {
1964 for (int i = 0; i < 3; i++) {
1965 pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
1966 pD3DDevice->Present(NULL, NULL, NULL, NULL);
1967 }
1968 } else {
1969 RECT rect;
1970 GetClientScreenRect(hVidWnd, &rect);
1971
1972 pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
1973 pD3DDevice->Present(&rect, &rect, NULL, NULL);
1974 }
1975
1976 // Create osd font
1977 dx9AltCreateFont();
1978
1979 return 0;
1980 }
1981
1982 static int dx9AltReset()
1983 {
1984 if (pFont) {
1985 pFont->OnLostDevice();
1986 }
1987
1988 dx9AltReleaseTexture();
1989
1990 if (FAILED(pD3DDevice->Reset(&d3dpp))) {
1991 return 1;
1992 }
1993
1994 if (pFont) {
1995 pFont->OnResetDevice();
1996 }
1997
1998 if (bVidMotionBlur) {
1999 pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
2000 } else {
2001 mbCurrentTexture = 0;
2002 pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
2003 }
2004 pD3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
2005 pD3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
2006 pD3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
2007 // apply vertex alpha values to texture
2008 pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
2009
2010 dx9AltTextureInit();
2011
2012 nImageWidth = 0; nImageHeight = 0;
2013
2014 return 0;
2015 }
2016
2017 static int dx9AltScale(RECT* rect, int width, int height)
2018 {
2019 if (nVidBlitterOpt[nVidSelect] & 0x0100) {
2020 return VidSoftFXScale(rect, width, height);
2021 }
2022 return VidSScaleImage(rect, width, height, bVidScanRotate);
2023 }
2024
2025 static void VidSCpyImg32(unsigned char* dst, unsigned int dstPitch, unsigned char *src, unsigned int srcPitch, unsigned short width, unsigned short height)
2026 {
2027 // fast, iterative C version
2028 // copies an width*height array of visible pixels from src to dst
2029 // srcPitch and dstPitch are the number of garbage bytes after a scanline
2030 register unsigned short lineSize = width << 2;
2031
2032 while (height--) {
2033 memcpy(dst, src, lineSize);
2034 src += srcPitch;
2035 dst += dstPitch;
2036 }
2037 }
2038
2039 static void VidSCpyImg16(unsigned char* dst, unsigned int dstPitch, unsigned char *src, unsigned int srcPitch, unsigned short width, unsigned short height)
2040 {
2041 register unsigned short lineSize = width << 1;
2042
2043 while (height--) {
2044 memcpy(dst, src, lineSize);
2045 src += srcPitch;
2046 dst += dstPitch;
2047 }
2048 }
2049
2050 // Copy BlitFXsMem to pddsBlitFX
2051 static int dx9AltRender()
2052 {
2053 GetClientRect(hVidWnd, &Dest);
2054
2055 if (bVidArcaderes && nVidFullscreen) {
2056 Dest.left = (Dest.right + Dest.left) / 2;
2057 Dest.left -= nGameWidth / 2;
2058 Dest.right = Dest.left + nGameWidth;
2059
2060 Dest.top = (Dest.top + Dest.bottom) / 2;
2061 Dest.top -= nGameHeight / 2;
2062 Dest.bottom = Dest.top + nGameHeight;
2063 } else {
2064 dx9AltScale(&Dest, nGameWidth, nGameHeight);
2065 }
2066
2067 {
2068 int nNewImageWidth = nRotateGame ? (Dest.bottom - Dest.top) : (Dest.right - Dest.left);
2069 int nNewImageHeight = nRotateGame ? (Dest.right - Dest.left) : (Dest.bottom - Dest.top);
2070
2071 if (nImageWidth != nNewImageWidth || nImageHeight != nNewImageHeight) {
2072 nImageWidth = nNewImageWidth;
2073 nImageHeight = nNewImageHeight;
2074
2075 int nWidth = nGameImageWidth;
2076 int nHeight = nGameImageHeight;
2077
2078 if (nPreScaleEffect) {
2079 if (nPreScale & 1) {
2080 nWidth *= nPreScaleZoom;
2081 }
2082 if (nPreScale & 2) {
2083 nHeight *= nPreScaleZoom;
2084 }
2085 }
2086
2087 if (nVidFullscreen) {
2088 dx9AltSetVertex(0, 0, nWidth, nHeight, nTextureWidth, nTextureHeight, nRotateGame ? Dest.top : Dest.left, nRotateGame ? Dest.left : Dest.top, nImageWidth, nImageHeight);
2089 } else {
2090 dx9AltSetVertex(0, 0, nWidth, nHeight, nTextureWidth, nTextureHeight, 0, 0, nImageWidth, nImageHeight);
2091 }
2092
2093 D3DVIEWPORT9 vp;
2094
2095 // Set the size of the image on the PC screen
2096 if (nVidFullscreen) {
2097 vp.X = Dest.left;
2098 vp.Y = Dest.top;
2099 vp.Width = Dest.right - Dest.left;
2100 vp.Height = Dest.bottom - Dest.top;
2101 vp.MinZ = 0.0f;
2102 vp.MaxZ = 1.0f;
2103 } else {
2104 vp.X = 0;
2105 vp.Y = 0;
2106 vp.Width = Dest.right - Dest.left;
2107 vp.Height = Dest.bottom - Dest.top;
2108 vp.MinZ = 0.0f;
2109 vp.MaxZ = 1.0f;
2110 }
2111
2112 pD3DDevice->SetViewport(&vp);
2113 }
2114 }
2115
2116 pD3DDevice->BeginScene();
2117
2118 {
2119 // Copy the game image onto a texture for rendering
2120 D3DLOCKED_RECT d3dlr;
2121 pTexture->LockRect(0, &d3dlr, 0, 0);
2122
2123 int pitch = d3dlr.Pitch;
2124 unsigned char* pd = (unsigned char*)d3dlr.pBits;
2125
2126 if (nPreScaleEffect) {
2127 VidFilterApplyEffect(pd, pitch);
2128 } else {
2129 unsigned char* ps = pVidImage + nVidImageLeft * nVidImageBPP;
2130 int s = nVidImageWidth * nVidImageBPP;
2131
2132 switch (nVidImageDepth) {
2133 case 32:
2134 VidSCpyImg32(pd, pitch, ps, s, nVidImageWidth, nVidImageHeight);
2135 break;
2136 case 16:
2137 VidSCpyImg16(pd, pitch, ps, s, nVidImageWidth, nVidImageHeight);
2138 break;
2139 }
2140 }
2141
2142 pTexture->UnlockRect(0);
2143 }
2144
2145 pD3DDevice->UpdateTexture(pTexture, emuTexture[mbCurrentTexture]);
2146
2147 if (bVidMotionBlur) {
2148 // Motion Blur enabled
2149 if (!mbTextureEmpty) {
2150 // draw previous frame to the screen
2151 pD3DDevice->SetTexture( 0, emuTexture[mbCurrentTexture ^ 1]);
2152 pD3DDevice->SetFVF(D3DFVF_LVERTEX2);
2153 pD3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, vertex, sizeof(d3dvertex));
2154 // draw the current frame with transparency to the screen
2155 pD3DDevice->SetTexture(0, emuTexture[mbCurrentTexture]);
2156 pD3DDevice->SetFVF(D3DFVF_LVERTEX2 | D3DFVF_DIFFUSE);
2157 pD3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, transpVertex, sizeof(transp_vertex));
2158 } else {
2159 mbTextureEmpty = false;
2160 // draw the current frame to the screen
2161 pD3DDevice->SetTexture(0, emuTexture[ mbCurrentTexture]);
2162 pD3DDevice->SetFVF(D3DFVF_LVERTEX2);
2163 pD3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, vertex, sizeof(d3dvertex));
2164 }
2165 mbCurrentTexture ^= 1; // switch current texture
2166 } else {
2167 // draw the current frame to the screen
2168 pD3DDevice->SetTexture( 0, emuTexture[mbCurrentTexture] );
2169 pD3DDevice->SetFVF(D3DFVF_LVERTEX2);
2170 pD3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, vertex, sizeof(d3dvertex));
2171 }
2172
2173 // draw osd text
2174 dx9AltDrawText();
2175
2176 pD3DDevice->EndScene();
2177
2178 return 0;
2179 }
2180
2181 // Run one frame and render the screen
2182 static int dx9AltFrame(bool bRedraw) // bRedraw = 0
2183 {
2184 if (pVidImage == NULL) {
2185 return 1;
2186 }
2187
2188 HRESULT nCoopLevel = pD3DDevice->TestCooperativeLevel();
2189 if (nCoopLevel != D3D_OK) { // We've lost control of the screen
2190 if (nCoopLevel != D3DERR_DEVICENOTRESET) {
2191 return 1;
2192 }
2193
2194 if (dx9AltReset()) {
2195 return 1;
2196 }
2197
2198 return 1; // Skip this frame, pBurnDraw pointer not valid (dx9AltReset() -> dx9AltTextureInit() -> VidSAllocVidImage())
2199 }
2200
2201 VidFrameCallback(bRedraw); // Run emulation for 1 frame / render image
2202
2203 if (pVidImage == NULL) { // If a mode change was requested by game, pVidImage has been invalidated - time to leave.
2204 return 0;
2205 }
2206
2207 dx9AltRender();
2208
2209 return 0;
2210 }
2211
2212 // Paint the BlitFX surface onto the primary surface
2213 static int dx9AltPaint(int bValidate)
2214 {
2215 if (pD3DDevice->TestCooperativeLevel()) { // We've lost control of the screen
2216 return 1;
2217 }
2218
2219 RECT rect = { 0, 0, 0, 0 };
2220
2221 if (!nVidFullscreen) {
2222 GetClientScreenRect(hVidWnd, &rect);
2223 rect.top += nMenuHeight;
2224
2225 dx9AltScale(&rect, nGameWidth, nGameHeight);
2226
2227 if ((rect.right - rect.left) != (Dest.right - Dest.left) || (rect.bottom - rect.top ) != (Dest.bottom - Dest.top)) {
2228 bValidate |= 2;
2229 }
2230 }
2231
2232 if (bValidate & 2) {
2233 dx9AltRender();
2234 }
2235
2236 if (nVidFullscreen) {
2237 pD3DDevice->Present(NULL, NULL, NULL, NULL);
2238 } else {
2239 RECT src = { 0, 0, Dest.right - Dest.left, Dest.bottom - Dest.top };
2240 POINT c = { 0, 0 };
2241 ClientToScreen(hVidWnd, &c);
2242 RECT dst = { rect.left - c.x, rect.top - c.y, rect.right - c.x, rect.bottom - c.y };
2243
2244 pD3DDevice->Present(&src, &dst, NULL, NULL);
2245
2246 // Validate the rectangle we just drew
2247 if (bValidate & 1) {
2248 ValidateRect(hVidWnd, &dst);
2249 }
2250 }
2251
2252 return 0;
2253 }
2254
2255 static int dx9AltGetSettings(InterfaceInfo* pInfo)
2256 {
2257 if (nVidFullscreen) {
2258 if (bVidTripleBuffer) {
2259 IntInfoAddStringModule(pInfo, _T("Using a triple buffer"));
2260 } else {
2261 IntInfoAddStringModule(pInfo, _T("Using a double buffer"));
2262 }
2263 }
2264
2265 if (bDrvOkay) {
2266 TCHAR szString[MAX_PATH] = _T("");
2267
2268 _sntprintf(szString, MAX_PATH, _T("Prescaling using %s (%ix zoom)"), VidSoftFXGetEffect(nPreScaleEffect), nPreScaleZoom);
2269 IntInfoAddStringModule(pInfo, szString);
2270 }
2271
2272 if (bVidDX9Bilinear) {
2273 IntInfoAddStringModule(pInfo, _T("Applying linear filter"));
2274 } else {
2275 IntInfoAddStringModule(pInfo, _T("Applying point filter"));
2276 }
2277
2278 if (bVidMotionBlur) {
2279 IntInfoAddStringModule(pInfo, _T("Applying motion blur effect"));
2280 }
2281
2282 return 0;
2283 }
2284
2285 // The Video Output plugin:
2286 struct VidOut VidOutDX9Alt = { dx9AltInit, dx9AltExit, dx9AltFrame, dx9AltPaint, dx9AltScale, dx9AltGetSettings, _T("DirectX9 Alternate video output") };
2287
2288
2289
2290
2291
2292
2293