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