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 FBA_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 if (bDrvOkay) {
1326 if (bRedraw) { // Redraw current frame
1327 if (BurnDrvRedraw()) {
1328 BurnDrvFrame(); // No redraw function provided, advance one frame
1329 }
1330 } else {
1331 BurnDrvFrame(); // Run one frame and draw the screen
1332 }
1333
1334 if ((BurnDrvGetFlags() & BDF_16BIT_ONLY) && pVidTransCallback)
1335 pVidTransCallback();
1336 }
1337
1338 #ifdef ENABLE_PROFILING
1339 // ProfileProfileEnd(0);
1340 ProfileProfileStart(1);
1341 #endif
1342
1343 dx9MemToSurf(); // Copy the memory buffer to the directdraw buffer for later blitting
1344
1345 #ifdef ENABLE_PROFILING
1346 ProfileProfileEnd(1);
1347
1348 dprintf(_T(" blit %3.2lf (effect p1 %3.2lf - effect p2 %3.2lf)\n"), ProfileProfileReadAverage(1), ProfileProfileReadAverage(2), ProfileProfileReadAverage(0));
1349 #endif
1350
1351 return 0;
1352 }
1353
1354 // Paint the BlitFX surface onto the primary surface
1355 static int dx9Paint(int bValidate)
1356 {
1357 if (pD3DDevice->TestCooperativeLevel()) { // We've lost control of the screen
1358 return 1;
1359 }
1360
1361 RECT rect = { 0, 0, 0, 0 };
1362
1363 if (!nVidFullscreen) {
1364 GetClientScreenRect(hVidWnd, &rect);
1365 rect.top += nMenuHeight;
1366
1367 dx9Scale(&rect, nGameWidth, nGameHeight);
1368
1369 if ((rect.right - rect.left) != (Dest.right - Dest.left) || (rect.bottom - rect.top ) != (Dest.bottom - Dest.top)) {
1370 bValidate |= 2;
1371 }
1372 }
1373
1374 if (bValidate & 2) {
1375 dx9MemToSurf(); // Copy the memory buffer to the directdraw buffer for later blitting
1376 }
1377
1378 // Display OSD text message
1379 // VidSDisplayOSD(pddsBlitFX[nUseSys], &rect, 0);
1380
1381 if (nVidFullscreen) {
1382 pD3DDevice->Present(NULL, NULL, NULL, NULL);
1383 } else {
1384 RECT src = { 0, 0, Dest.right - Dest.left, Dest.bottom - Dest.top };
1385
1386 POINT c = { 0, 0 };
1387 ClientToScreen(hVidWnd, &c);
1388 RECT dst = { rect.left - c.x, rect.top - c.y, rect.right - c.x, rect.bottom - c.y };
1389
1390 /*
1391 if (bVidVSync) {
1392 D3DRASTER_STATUS rs;
1393 RECT window;
1394
1395 GetWindowRect(hVidWnd, &window);
1396
1397 while (1) {
1398 pD3DDevice->GetRasterStatus(0, &rs);
1399 if (rs.InVBlank || rs.ScanLine >= window.bottom) {
1400 break;
1401 }
1402 Sleep(1);
1403 }
1404 }
1405 */
1406
1407 pD3DDevice->Present(&src, &dst, NULL, NULL);
1408
1409 // Validate the rectangle we just drew
1410 if (bValidate & 1) {
1411 ValidateRect(hVidWnd, &dst);
1412 }
1413 }
1414
1415 return 0;
1416 }
1417
1418 // ----------------------------------------------------------------------------
1419
1420 static int dx9GetSettings(InterfaceInfo* pInfo)
1421 {
1422 TCHAR szString[MAX_PATH] = _T("");
1423
1424 if (nVidFullscreen) {
1425 if (bVidTripleBuffer) {
1426 IntInfoAddStringModule(pInfo, _T("Using a triple buffer"));
1427 } else {
1428 IntInfoAddStringModule(pInfo, _T("Using a double buffer"));
1429 }
1430 } else {
1431 IntInfoAddStringModule(pInfo, _T("Using D3DSWAPEFFECT_COPY to present the image"));
1432 }
1433 switch (DX9_FILTER) {
1434 case 1: {
1435 IntInfoAddStringModule(pInfo, _T("Applying linear filter"));
1436 break;
1437 }
1438 case 2: {
1439 _sntprintf(szString, MAX_PATH, _T("Applying cubic filter using VS1.1 & %s"), bUsePS14 ? _T("PS1.4") : _T("PS2.0"));
1440 IntInfoAddStringModule(pInfo, szString);
1441
1442 if (bUsePS14) {
1443 IntInfoAddStringModule(pInfo, _T("Using high-performance implementation"));
1444 break;
1445 }
1446
1447 if (bVidScanlines) {
1448 switch (DX9_SHADERPRECISION) {
1449 case 0:
1450 case 2:
1451 IntInfoAddStringModule(pInfo, _T("Using reference implementation"));
1452 break;
1453 case 1:
1454 case 3:
1455 IntInfoAddStringModule(pInfo, _T("Using partial precision implementation"));
1456 break;
1457 case 4:
1458 IntInfoAddStringModule(pInfo, _T("Using high-performance implementation"));
1459 break;
1460 }
1461 } else {
1462 switch (DX9_SHADERPRECISION) {
1463 case 0:
1464 IntInfoAddStringModule(pInfo, _T("Using single-pass reference implementation"));
1465 break;
1466 case 1:
1467 IntInfoAddStringModule(pInfo, _T("Using partial precision single-pass implementation"));
1468 break;
1469 case 2:
1470 IntInfoAddStringModule(pInfo, _T("Using full precision multi-pass implementation"));
1471 break;
1472 case 3:
1473 IntInfoAddStringModule(pInfo, _T("Using partial precision multi-pass implementation"));
1474 break;
1475 case 4:
1476 IntInfoAddStringModule(pInfo, _T("Using high-performance multi-pass implementation"));
1477 break;
1478 }
1479 }
1480 if (DX9_USE_FPTEXTURE) {
1481 _sntprintf(szString, MAX_PATH, _T("Using floating-point textures where applicable"));
1482 IntInfoAddStringModule(pInfo, szString);
1483 }
1484 break;
1485 }
1486 default: {
1487 IntInfoAddStringModule(pInfo, _T("Applying point filter"));
1488 }
1489 }
1490 if (bVidScanlines) {
1491 _sntprintf(szString, MAX_PATH, _T("Applying scanlines at %.1lf%% brightness"), (double)(nVidScanIntensity & 255) / 2.55);
1492 IntInfoAddStringModule(pInfo, szString);
1493 }
1494
1495 return 0;
1496 }
1497
1498 // The Video Output plugin:
1499 struct VidOut VidOutDX9 = { dx9Init, dx9Exit, dx9Frame, dx9Paint, dx9Scale, dx9GetSettings, _T("DirectX9 Experimental video output") };
1500 //#else
1501 //struct VidOut VidOutDX9 = { NULL, NULL, NULL, NULL, NULL, NULL, _T("DirectX9 Experimental video output") };
1502 //#endif
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514 // Direct3D9 video output
1515 // rewritten by regret (Motion Blur source from VBA-M)
1516
1517 struct d3dvertex {
1518 float x, y, z, rhw; //screen coords
1519 float u, v; //texture coords
1520 };
1521
1522 struct transp_vertex {
1523 float x, y, z, rhw;
1524 D3DCOLOR color;
1525 float u, v;
1526 };
1527
1528 #undef D3DFVF_LVERTEX2
1529 #define D3DFVF_LVERTEX2 (D3DFVF_XYZRHW | D3DFVF_TEX1)
1530
1531 IDirect3DTexture9* emuTexture[2];
1532 static unsigned char mbCurrentTexture = 0; // current texture for motion blur
1533 static bool mbTextureEmpty = true;
1534 static d3dvertex vertex[4];
1535 static transp_vertex transpVertex[4];
1536
1537 D3DFORMAT textureFormat;
1538
1539 static int nPreScale = 0;
1540 static int nPreScaleZoom = 0;
1541 static int nPreScaleEffect = 0;
1542
1543 // Select optimal full-screen resolution
1544 static int dx9AltSelectFullscreenMode(VidSDisplayScoreInfo* pScoreInfo)
1545 {
1546 if (bVidArcaderes) {
1547 if (!VidSGetArcaderes((int*)&(pScoreInfo->nBestWidth), (int*)&(pScoreInfo->nBestHeight))) {
1548 return 1;
1549 }
1550 } else {
1551 pScoreInfo->nBestWidth = nVidWidth;
1552 pScoreInfo->nBestHeight = nVidHeight;
1553 }
1554
1555 if (!bDrvOkay && (pScoreInfo->nBestWidth < 640 || pScoreInfo->nBestHeight < 480)) {
1556 return 1;
1557 }
1558
1559 return 0;
1560 }
1561
1562 static void dx9AltReleaseTexture()
1563 {
1564 RELEASE(pTexture)
1565 RELEASE(emuTexture[0])
1566 RELEASE(emuTexture[1])
1567 }
1568
1569 static int dx9AltExit()
1570 {
1571 VidSoftFXExit();
1572
1573 dx9AltReleaseTexture();
1574
1575 VidSFreeVidImage();
1576
1577 RELEASE(pFont)
1578 RELEASE(pD3DDevice)
1579 RELEASE(pD3D)
1580
1581 nRotateGame = 0;
1582
1583 VidSKillShortMsg();
1584 VidSKillOSDMsg();
1585
1586 return 0;
1587 }
1588
1589 static int dx9AltResize(int width, int height)
1590 {
1591 if (FAILED(pD3DDevice->CreateTexture(width, height, 1, 0, textureFormat, D3DPOOL_SYSTEMMEM, &pTexture, NULL))) {
1592 return 1;
1593 }
1594
1595 if (!emuTexture[0]) {
1596 if (FAILED(pD3DDevice->CreateTexture(width, height, 1, 0, textureFormat, D3DPOOL_DEFAULT, &emuTexture[0], NULL))) {
1597 return 1;
1598 }
1599 }
1600
1601 if (!emuTexture[1] && bVidMotionBlur) {
1602 if (FAILED(pD3DDevice->CreateTexture(width, height, 1, 0, textureFormat, D3DPOOL_DEFAULT, &emuTexture[1], NULL))) {
1603 return 1;
1604 }
1605 mbTextureEmpty = true;
1606 }
1607
1608 return 0;
1609 }
1610
1611 static int dx9AltTextureInit()
1612 {
1613 if (nRotateGame & 1) {
1614 nVidImageWidth = nGameHeight;
1615 nVidImageHeight = nGameWidth;
1616 } else {
1617 nVidImageWidth = nGameWidth;
1618 nVidImageHeight = nGameHeight;
1619 }
1620
1621 nGameImageWidth = nVidImageWidth;
1622 nGameImageHeight = nVidImageHeight;
1623
1624 nVidImageDepth = nVidScrnDepth;
1625
1626 // Determine if we should use a texture format different from the screen format
1627 if ((bDrvOkay && VidSoftFXCheckDepth(nPreScaleEffect, 32) != 32) || (bDrvOkay && bVidForce16bitDx9Alt)) {
1628 nVidImageDepth = 16;
1629 }
1630
1631 switch (nVidImageDepth) {
1632 case 32:
1633 textureFormat = D3DFMT_X8R8G8B8;
1634 break;
1635 case 24:
1636 textureFormat = D3DFMT_R8G8B8;
1637 break;
1638 case 16:
1639 textureFormat = D3DFMT_R5G6B5;
1640 break;
1641 case 15:
1642 textureFormat = D3DFMT_X1R5G5B5;
1643 break;
1644 }
1645
1646 nVidImageBPP = (nVidImageDepth + 7) >> 3;
1647 nBurnBpp = nVidImageBPP; // Set Burn library Bytes per pixel
1648
1649 // Use our callback to get colors:
1650 SetBurnHighCol(nVidImageDepth);
1651
1652 // Make the normal memory buffer
1653 if (VidSAllocVidImage()) {
1654 dx9AltExit();
1655 return 1;
1656 }
1657
1658 nTextureWidth = GetTextureSize(nGameImageWidth * nPreScaleZoom);
1659 nTextureHeight = GetTextureSize(nGameImageHeight * nPreScaleZoom);
1660
1661 if (dx9AltResize(nTextureWidth, nTextureHeight)) {
1662 return 1;
1663 }
1664
1665 return 0;
1666 }
1667
1668 // Vertex format:
1669 //
1670 // 0---------1
1671 // | /|
1672 // | / |
1673 // | / |
1674 // | / |
1675 // |/ |
1676 // 2---------3
1677 //
1678 // (x,y) screen coords, in pixels
1679 // (u,v) texture coords, betweeen 0.0 (top, left) to 1.0 (bottom, right)
1680 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)
1681 {
1682 // configure triangles
1683 // -0.5f is necessary in order to match texture alignment to display pixels
1684 float diff = -0.5f;
1685 if (nRotateGame & 1) {
1686 if (nRotateGame & 2) {
1687 vertex[2].x = vertex[3].x = (double)(y ) + diff;
1688 vertex[0].x = vertex[1].x = (double)(y + h) + diff;
1689 vertex[1].y = vertex[3].y = (double)(x + w) + diff;
1690 vertex[0].y = vertex[2].y = (double)(x ) + diff;
1691 } else {
1692 vertex[0].x = vertex[1].x = (double)(y ) + diff;
1693 vertex[2].x = vertex[3].x = (double)(y + h) + diff;
1694 vertex[1].y = vertex[3].y = (double)(x ) + diff;
1695 vertex[0].y = vertex[2].y = (double)(x + w) + diff;
1696 }
1697 } else {
1698 if (nRotateGame & 2) {
1699 vertex[1].x = vertex[3].x = (double)(y ) + diff;
1700 vertex[0].x = vertex[2].x = (double)(y + h) + diff;
1701 vertex[2].y = vertex[3].y = (double)(x ) + diff;
1702 vertex[0].y = vertex[1].y = (double)(x + w) + diff;
1703 } else {
1704 vertex[0].x = vertex[2].x = (double)(x ) + diff;
1705 vertex[1].x = vertex[3].x = (double)(x + w) + diff;
1706 vertex[0].y = vertex[1].y = (double)(y ) + diff;
1707 vertex[2].y = vertex[3].y = (double)(y + h) + diff;
1708 }
1709 }
1710
1711 double rw = (double)w / (double)pw * (double)tw;
1712 double rh = (double)h / (double)ph * (double)th;
1713 vertex[0].u = vertex[2].u = (double)(px ) / rw;
1714 vertex[1].u = vertex[3].u = (double)(px + w) / rw;
1715 vertex[0].v = vertex[1].v = (double)(py ) / rh;
1716 vertex[2].v = vertex[3].v = (double)(py + h) / rh;
1717
1718 // Z-buffer and RHW are unused for 2D blit, set to normal values
1719 vertex[0].z = vertex[1].z = vertex[2].z = vertex[3].z = 0.0f;
1720 vertex[0].rhw = vertex[1].rhw = vertex[2].rhw = vertex[3].rhw = 1.0f;
1721
1722 // configure semi-transparent triangles
1723 if (bVidMotionBlur) {
1724 D3DCOLOR semiTrans = D3DCOLOR_ARGB(0x7F, 0xFF, 0xFF, 0xFF);
1725 transpVertex[0].x = vertex[0].x;
1726 transpVertex[0].y = vertex[0].y;
1727 transpVertex[0].z = vertex[0].z;
1728 transpVertex[0].rhw = vertex[0].rhw;
1729 transpVertex[0].color = semiTrans;
1730 transpVertex[0].u = vertex[0].u;
1731 transpVertex[0].v = vertex[0].v;
1732 transpVertex[1].x = vertex[1].x;
1733 transpVertex[1].y = vertex[1].y;
1734 transpVertex[1].z = vertex[1].z;
1735 transpVertex[1].rhw = vertex[1].rhw;
1736 transpVertex[1].color = semiTrans;
1737 transpVertex[1].u = vertex[1].u;
1738 transpVertex[1].v = vertex[1].v;
1739 transpVertex[2].x = vertex[2].x;
1740 transpVertex[2].y = vertex[2].y;
1741 transpVertex[2].z = vertex[2].z;
1742 transpVertex[2].rhw = vertex[2].rhw;
1743 transpVertex[2].color = semiTrans;
1744 transpVertex[2].u = vertex[2].u;
1745 transpVertex[2].v = vertex[2].v;
1746 transpVertex[3].x = vertex[3].x;
1747 transpVertex[3].y = vertex[3].y;
1748 transpVertex[3].z = vertex[3].z;
1749 transpVertex[3].rhw = vertex[3].rhw;
1750 transpVertex[3].color = semiTrans;
1751 transpVertex[3].u = vertex[3].u;
1752 transpVertex[3].v = vertex[3].v;
1753 }
1754
1755 return 0;
1756 }
1757
1758 // ==> osd for dx9 video output (ugly), added by regret
1759 static int dx9AltCreateFont()
1760 {
1761 if (pFont) {
1762 return 0;
1763 }
1764
1765 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);
1766
1767 if (FAILED(hr)) {
1768 return 1;
1769 }
1770
1771 return 0;
1772 }
1773
1774 static void dx9AltDrawText()
1775 {
1776 if (!nOSDTimer) {
1777 return;
1778 }
1779
1780 if (nFramesEmulated > nOSDTimer) {
1781 VidSKillShortMsg();
1782 VidSKillOSDMsg();
1783 }
1784
1785 RECT osdRect;
1786 if (nVidFullscreen) {
1787 osdRect.left = Dest.left;
1788 osdRect.top = Dest.top;
1789 osdRect.right = Dest.right - 1;
1790 osdRect.bottom = Dest.bottom - 1;
1791 } else {
1792 osdRect.left = 0;
1793 osdRect.top = 0;
1794 osdRect.right = Dest.right - Dest.left - 1;
1795 osdRect.bottom = Dest.bottom - Dest.top - 1;
1796 }
1797
1798 if (nOSDTimer) {
1799 pFont->DrawText(NULL, OSDMsg, -1, &osdRect, DT_RIGHT | DT_TOP, osdColor);
1800 }
1801 }
1802 // <== osd for dx9 video output (ugly)
1803
1804 static int dx9AltInit()
1805 {
1806 if (hScrnWnd == NULL) {
1807 return 1;
1808 }
1809
1810 hVidWnd = hScrnWnd;
1811
1812 // Get pointer to Direct3D
1813 if ((pD3D = _Direct3DCreate9(D3D_SDK_VERSION)) == NULL) {
1814 dx9AltExit();
1815 return 1;
1816 }
1817
1818 nRotateGame = 0;
1819 if (bDrvOkay) {
1820 if (BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL) {
1821 if (nVidRotationAdjust & 1) {
1822 nRotateGame |= (nVidRotationAdjust & 2);
1823 } else {
1824 nRotateGame |= 1;
1825 }
1826 }
1827
1828 if (BurnDrvGetFlags() & BDF_ORIENTATION_FLIPPED) {
1829 nRotateGame ^= 2;
1830 }
1831 }
1832
1833 nD3DAdapter = D3DADAPTER_DEFAULT;
1834 if (nRotateGame & 1 && VerScreen[0]) {
1835 nD3DAdapter = dx9GetAdapter(VerScreen);
1836 } else {
1837 if (HorScreen[0]) {
1838 nD3DAdapter = dx9GetAdapter(HorScreen);
1839 }
1840 }
1841
1842 // check selected atapter
1843 D3DDISPLAYMODE dm;
1844 pD3D->GetAdapterDisplayMode(nD3DAdapter, &dm);
1845
1846 memset(&d3dpp, 0, sizeof(d3dpp));
1847 if (nVidFullscreen) {
1848 VidSDisplayScoreInfo ScoreInfo;
1849 memset(&ScoreInfo, 0, sizeof(VidSDisplayScoreInfo));
1850
1851 if (dx9AltSelectFullscreenMode(&ScoreInfo)) {
1852 dx9AltExit();
1853 return 1;
1854 }
1855
1856 bool sizefit = true;
1857 if (ScoreInfo.nBestWidth > dm.Width || ScoreInfo.nBestHeight > dm.Height) {
1858 sizefit = false;
1859 }
1860
1861 d3dpp.BackBufferWidth = sizefit ? ScoreInfo.nBestWidth : dm.Width;
1862 d3dpp.BackBufferHeight = sizefit ? ScoreInfo.nBestHeight : dm.Height;
1863 d3dpp.BackBufferFormat = (nVidDepth == 16) ? D3DFMT_R5G6B5 : D3DFMT_X8R8G8B8;
1864 d3dpp.SwapEffect = D3DSWAPEFFECT_FLIP;
1865 d3dpp.BackBufferCount = bVidTripleBuffer ? 2 : 1;
1866 d3dpp.hDeviceWindow = hVidWnd;
1867 d3dpp.FullScreen_RefreshRateInHz = dm.RefreshRate;
1868 d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
1869 } else {
1870 d3dpp.BackBufferWidth = dm.Width;
1871 d3dpp.BackBufferHeight = dm.Height;
1872 d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
1873 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1874 d3dpp.BackBufferCount = 1;
1875 d3dpp.hDeviceWindow = hVidWnd;
1876 d3dpp.Windowed = TRUE;
1877 d3dpp.PresentationInterval = bVidVSync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
1878 }
1879
1880 DWORD dwBehaviorFlags = D3DCREATE_FPU_PRESERVE;
1881 if (bVidHardwareVertex) {
1882 dwBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
1883 } else {
1884 dwBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
1885 }
1886
1887 if (FAILED(pD3D->CreateDevice(nD3DAdapter, D3DDEVTYPE_HAL, hVidWnd, dwBehaviorFlags, &d3dpp, &pD3DDevice))) {
1888 if (nVidFullscreen) {
1889 FBAPopupAddText(PUF_TEXT_DEFAULT, MAKEINTRESOURCE(IDS_ERR_UI_FULL_PROBLEM), d3dpp.BackBufferWidth, d3dpp.BackBufferHeight, d3dpp.BackBufferFormat, d3dpp.FullScreen_RefreshRateInHz);
1890 if (bVidArcaderes && (d3dpp.BackBufferWidth != 320 && d3dpp.BackBufferHeight != 240)) {
1891 FBAPopupAddText(PUF_TEXT_DEFAULT, MAKEINTRESOURCE(IDS_ERR_UI_FULL_CUSTRES));
1892 }
1893 FBAPopupDisplay(PUF_TYPE_ERROR);
1894 }
1895
1896 dx9AltExit();
1897 return 1;
1898 }
1899
1900 {
1901 nVidScrnWidth = dm.Width; nVidScrnHeight = dm.Height;
1902 nVidScrnDepth = (dm.Format == D3DFMT_R5G6B5) ? 16 : 32;
1903 }
1904
1905 nGameWidth = nVidImageWidth;
1906 nGameHeight = nVidImageHeight;
1907 nRotateGame = 0;
1908
1909 if (bDrvOkay) {
1910 // Get the game screen size
1911 BurnDrvGetVisibleSize(&nGameWidth, &nGameHeight);
1912
1913 if (BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL) {
1914 if (nVidRotationAdjust & 1) {
1915 int n = nGameWidth;
1916 nGameWidth = nGameHeight;
1917 nGameHeight = n;
1918 nRotateGame |= (nVidRotationAdjust & 2);
1919 } else {
1920 nRotateGame |= 1;
1921 }
1922 }
1923
1924 if (BurnDrvGetFlags() & BDF_ORIENTATION_FLIPPED) {
1925 nRotateGame ^= 2;
1926 }
1927 }
1928
1929 // enable vertex alpha blending
1930 if (bVidMotionBlur) {
1931 pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
1932 } else {
1933 mbCurrentTexture = 0;
1934 pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
1935 }
1936 pD3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
1937 pD3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
1938 pD3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
1939 // apply vertex alpha values to texture
1940 pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
1941
1942 // for filter
1943 nPreScale = 3;
1944 nPreScaleZoom = 2;
1945 nPreScaleEffect = 0;
1946 if (bDrvOkay) {
1947 nPreScaleEffect = nVidBlitterOpt[nVidSelect] & 0xFF;
1948 nPreScaleZoom = VidSoftFXGetZoom(nPreScaleEffect);
1949 }
1950
1951 // Initialize the buffer surfaces
1952 if (dx9AltTextureInit()) {
1953 dx9AltExit();
1954 return 1;
1955 }
1956
1957 if (nPreScaleEffect) {
1958 if (VidSoftFXInit(nPreScaleEffect, 0)) {
1959 dx9AltExit();
1960 return 1;
1961 }
1962 }
1963
1964 pD3DDevice->SetSamplerState(0, D3DSAMP_MINFILTER, bVidDX9Bilinear ? D3DTEXF_LINEAR : D3DTEXF_POINT);
1965 pD3DDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, bVidDX9Bilinear ? D3DTEXF_LINEAR : D3DTEXF_POINT);
1966
1967 nImageWidth = 0; nImageHeight = 0;
1968
1969 // Clear the swapchain's buffers
1970 if (nVidFullscreen) {
1971 for (int i = 0; i < 3; i++) {
1972 pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
1973 pD3DDevice->Present(NULL, NULL, NULL, NULL);
1974 }
1975 } else {
1976 RECT rect;
1977 GetClientScreenRect(hVidWnd, &rect);
1978
1979 pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
1980 pD3DDevice->Present(&rect, &rect, NULL, NULL);
1981 }
1982
1983 // Create osd font
1984 dx9AltCreateFont();
1985
1986 return 0;
1987 }
1988
1989 static int dx9AltReset()
1990 {
1991 if (pFont) {
1992 pFont->OnLostDevice();
1993 }
1994
1995 dx9AltReleaseTexture();
1996
1997 if (FAILED(pD3DDevice->Reset(&d3dpp))) {
1998 return 1;
1999 }
2000
2001 if (pFont) {
2002 pFont->OnResetDevice();
2003 }
2004
2005 if (bVidMotionBlur) {
2006 pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
2007 } else {
2008 mbCurrentTexture = 0;
2009 pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
2010 }
2011 pD3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
2012 pD3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
2013 pD3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
2014 // apply vertex alpha values to texture
2015 pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
2016
2017 dx9AltTextureInit();
2018
2019 nImageWidth = 0; nImageHeight = 0;
2020
2021 return 0;
2022 }
2023
2024 static int dx9AltScale(RECT* rect, int width, int height)
2025 {
2026 if (nVidBlitterOpt[nVidSelect] & 0x0100) {
2027 return VidSoftFXScale(rect, width, height);
2028 }
2029 return VidSScaleImage(rect, width, height, bVidScanRotate);
2030 }
2031
2032 static void VidSCpyImg32(unsigned char* dst, unsigned int dstPitch, unsigned char *src, unsigned int srcPitch, unsigned short width, unsigned short height)
2033 {
2034 // fast, iterative C version
2035 // copies an width*height array of visible pixels from src to dst
2036 // srcPitch and dstPitch are the number of garbage bytes after a scanline
2037 register unsigned short lineSize = width << 2;
2038
2039 while (height--) {
2040 memcpy(dst, src, lineSize);
2041 src += srcPitch;
2042 dst += dstPitch;
2043 }
2044 }
2045
2046 static void VidSCpyImg16(unsigned char* dst, unsigned int dstPitch, unsigned char *src, unsigned int srcPitch, unsigned short width, unsigned short height)
2047 {
2048 register unsigned short lineSize = width << 1;
2049
2050 while (height--) {
2051 memcpy(dst, src, lineSize);
2052 src += srcPitch;
2053 dst += dstPitch;
2054 }
2055 }
2056
2057 // Copy BlitFXsMem to pddsBlitFX
2058 static int dx9AltRender()
2059 {
2060 GetClientRect(hVidWnd, &Dest);
2061
2062 if (bVidArcaderes && nVidFullscreen) {
2063 Dest.left = (Dest.right + Dest.left) / 2;
2064 Dest.left -= nGameWidth / 2;
2065 Dest.right = Dest.left + nGameWidth;
2066
2067 Dest.top = (Dest.top + Dest.bottom) / 2;
2068 Dest.top -= nGameHeight / 2;
2069 Dest.bottom = Dest.top + nGameHeight;
2070 } else {
2071 dx9AltScale(&Dest, nGameWidth, nGameHeight);
2072 }
2073
2074 {
2075 int nNewImageWidth = nRotateGame ? (Dest.bottom - Dest.top) : (Dest.right - Dest.left);
2076 int nNewImageHeight = nRotateGame ? (Dest.right - Dest.left) : (Dest.bottom - Dest.top);
2077
2078 if (nImageWidth != nNewImageWidth || nImageHeight != nNewImageHeight) {
2079 nImageWidth = nNewImageWidth;
2080 nImageHeight = nNewImageHeight;
2081
2082 int nWidth = nGameImageWidth;
2083 int nHeight = nGameImageHeight;
2084
2085 if (nPreScaleEffect) {
2086 if (nPreScale & 1) {
2087 nWidth *= nPreScaleZoom;
2088 }
2089 if (nPreScale & 2) {
2090 nHeight *= nPreScaleZoom;
2091 }
2092 }
2093
2094 if (nVidFullscreen) {
2095 dx9AltSetVertex(0, 0, nWidth, nHeight, nTextureWidth, nTextureHeight, nRotateGame ? Dest.top : Dest.left, nRotateGame ? Dest.left : Dest.top, nImageWidth, nImageHeight);
2096 } else {
2097 dx9AltSetVertex(0, 0, nWidth, nHeight, nTextureWidth, nTextureHeight, 0, 0, nImageWidth, nImageHeight);
2098 }
2099
2100 D3DVIEWPORT9 vp;
2101
2102 // Set the size of the image on the PC screen
2103 if (nVidFullscreen) {
2104 vp.X = Dest.left;
2105 vp.Y = Dest.top;
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 } else {
2111 vp.X = 0;
2112 vp.Y = 0;
2113 vp.Width = Dest.right - Dest.left;
2114 vp.Height = Dest.bottom - Dest.top;
2115 vp.MinZ = 0.0f;
2116 vp.MaxZ = 1.0f;
2117 }
2118
2119 pD3DDevice->SetViewport(&vp);
2120 }
2121 }
2122
2123 pD3DDevice->BeginScene();
2124
2125 {
2126 // Copy the game image onto a texture for rendering
2127 D3DLOCKED_RECT d3dlr;
2128 pTexture->LockRect(0, &d3dlr, 0, 0);
2129
2130 int pitch = d3dlr.Pitch;
2131 unsigned char* pd = (unsigned char*)d3dlr.pBits;
2132
2133 if (nPreScaleEffect) {
2134 VidFilterApplyEffect(pd, pitch);
2135 } else {
2136 unsigned char* ps = pVidImage + nVidImageLeft * nVidImageBPP;
2137 int s = nVidImageWidth * nVidImageBPP;
2138
2139 switch (nVidImageDepth) {
2140 case 32:
2141 VidSCpyImg32(pd, pitch, ps, s, nVidImageWidth, nVidImageHeight);
2142 break;
2143 case 16:
2144 VidSCpyImg16(pd, pitch, ps, s, nVidImageWidth, nVidImageHeight);
2145 break;
2146 }
2147 }
2148
2149 pTexture->UnlockRect(0);
2150 }
2151
2152 pD3DDevice->UpdateTexture(pTexture, emuTexture[mbCurrentTexture]);
2153
2154 if (bVidMotionBlur) {
2155 // Motion Blur enabled
2156 if (!mbTextureEmpty) {
2157 // draw previous frame to the screen
2158 pD3DDevice->SetTexture( 0, emuTexture[mbCurrentTexture ^ 1]);
2159 pD3DDevice->SetFVF(D3DFVF_LVERTEX2);
2160 pD3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, vertex, sizeof(d3dvertex));
2161 // draw the current frame with transparency to the screen
2162 pD3DDevice->SetTexture(0, emuTexture[mbCurrentTexture]);
2163 pD3DDevice->SetFVF(D3DFVF_LVERTEX2 | D3DFVF_DIFFUSE);
2164 pD3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, transpVertex, sizeof(transp_vertex));
2165 } else {
2166 mbTextureEmpty = false;
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 mbCurrentTexture ^= 1; // switch current texture
2173 } else {
2174 // draw the current frame to the screen
2175 pD3DDevice->SetTexture( 0, emuTexture[mbCurrentTexture] );
2176 pD3DDevice->SetFVF(D3DFVF_LVERTEX2);
2177 pD3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, vertex, sizeof(d3dvertex));
2178 }
2179
2180 // draw osd text
2181 dx9AltDrawText();
2182
2183 pD3DDevice->EndScene();
2184
2185 return 0;
2186 }
2187
2188 // Run one frame and render the screen
2189 static int dx9AltFrame(bool bRedraw) // bRedraw = 0
2190 {
2191 if (pVidImage == NULL) {
2192 return 1;
2193 }
2194
2195 HRESULT nCoopLevel = pD3DDevice->TestCooperativeLevel();
2196 if (nCoopLevel != D3D_OK) { // We've lost control of the screen
2197 if (nCoopLevel != D3DERR_DEVICENOTRESET) {
2198 return 1;
2199 }
2200
2201 if (dx9AltReset()) {
2202 return 1;
2203 }
2204
2205 return 1; // Skip this frame, pBurnDraw pointer not valid (dx9AltReset() -> dx9AltTextureInit() -> VidSAllocVidImage())
2206
2207 }
2208
2209 if (bDrvOkay) {
2210 if (bRedraw) { // Redraw current frame
2211 if (BurnDrvRedraw()) {
2212 BurnDrvFrame(); // No redraw function provided, advance one frame
2213 }
2214 } else {
2215 BurnDrvFrame(); // Run one frame and draw the screen
2216 }
2217
2218 if ((BurnDrvGetFlags() & BDF_16BIT_ONLY) && pVidTransCallback)
2219 pVidTransCallback();
2220 }
2221
2222 dx9AltRender();
2223
2224 return 0;
2225 }
2226
2227 // Paint the BlitFX surface onto the primary surface
2228 static int dx9AltPaint(int bValidate)
2229 {
2230 if (pD3DDevice->TestCooperativeLevel()) { // We've lost control of the screen
2231 return 1;
2232 }
2233
2234 RECT rect = { 0, 0, 0, 0 };
2235
2236 if (!nVidFullscreen) {
2237 GetClientScreenRect(hVidWnd, &rect);
2238 rect.top += nMenuHeight;
2239
2240 dx9AltScale(&rect, nGameWidth, nGameHeight);
2241
2242 if ((rect.right - rect.left) != (Dest.right - Dest.left) || (rect.bottom - rect.top ) != (Dest.bottom - Dest.top)) {
2243 bValidate |= 2;
2244 }
2245 }
2246
2247 if (bValidate & 2) {
2248 dx9AltRender();
2249 }
2250
2251 if (nVidFullscreen) {
2252 pD3DDevice->Present(NULL, NULL, NULL, NULL);
2253 } else {
2254 RECT src = { 0, 0, Dest.right - Dest.left, Dest.bottom - Dest.top };
2255 POINT c = { 0, 0 };
2256 ClientToScreen(hVidWnd, &c);
2257 RECT dst = { rect.left - c.x, rect.top - c.y, rect.right - c.x, rect.bottom - c.y };
2258
2259 pD3DDevice->Present(&src, &dst, NULL, NULL);
2260
2261 // Validate the rectangle we just drew
2262 if (bValidate & 1) {
2263 ValidateRect(hVidWnd, &dst);
2264 }
2265 }
2266
2267 return 0;
2268 }
2269
2270 static int dx9AltGetSettings(InterfaceInfo* pInfo)
2271 {
2272 if (nVidFullscreen) {
2273 if (bVidTripleBuffer) {
2274 IntInfoAddStringModule(pInfo, _T("Using a triple buffer"));
2275 } else {
2276 IntInfoAddStringModule(pInfo, _T("Using a double buffer"));
2277 }
2278 }
2279
2280 if (bDrvOkay) {
2281 TCHAR szString[MAX_PATH] = _T("");
2282
2283 _sntprintf(szString, MAX_PATH, _T("Prescaling using %s (%ix zoom)"), VidSoftFXGetEffect(nPreScaleEffect), nPreScaleZoom);
2284 IntInfoAddStringModule(pInfo, szString);
2285 }
2286
2287 if (bVidDX9Bilinear) {
2288 IntInfoAddStringModule(pInfo, _T("Applying linear filter"));
2289 } else {
2290 IntInfoAddStringModule(pInfo, _T("Applying point filter"));
2291 }
2292
2293 if (bVidMotionBlur) {
2294 IntInfoAddStringModule(pInfo, _T("Applying motion blur effect"));
2295 }
2296
2297 return 0;
2298 }
2299
2300 // The Video Output plugin:
2301 struct VidOut VidOutDX9Alt = { dx9AltInit, dx9AltExit, dx9AltFrame, dx9AltPaint, dx9AltScale, dx9AltGetSettings, _T("DirectX9 Alternate video output") };
2302
2303
2304
2305
2306
2307
2308