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