1 /*****************************************************************************\
2      Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3                 This file is licensed under the Snes9x License.
4    For further information, consult the LICENSE file in the root directory.
5 \*****************************************************************************/
6 
7 #pragma comment( lib, "d3d9" )
8 
9 #include "cdirect3d.h"
10 #include "win32_display.h"
11 #include "../snes9x.h"
12 #include "../gfx.h"
13 #include "../display.h"
14 #include "wsnes9x.h"
15 #include "dxerr.h"
16 #include <commctrl.h>
17 
18 #include "../filter/hq2x.h"
19 #include "../filter/2xsai.h"
20 
21 #ifndef max
22 #define max(a, b) (((a) > (b)) ? (a) : (b))
23 #endif
24 #ifndef min
25 #define min(a, b) (((a) < (b)) ? (a) : (b))
26 #endif
27 
28 const D3DVERTEXELEMENT9 CDirect3D::vertexElems[4] = {
29 		{0, 0,  D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
30 		{0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
31 		{0, 20, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
32 		D3DDECL_END()
33 	};
34 
35 /* CDirect3D::CDirect3D()
36 sets default values for the variables
37 */
CDirect3D()38 CDirect3D::CDirect3D()
39 {
40 	init_done = false;
41 	pD3D = NULL;
42 	pDevice = NULL;
43 	drawSurface = NULL;
44 	vertexBuffer = NULL;
45 	afterRenderWidth = 0;
46 	afterRenderHeight = 0;
47 	quadTextureSize = 0;
48 	fullscreen = false;
49 	filterScale = 1;
50 	for(int i = 0; i < MAX_SHADER_TEXTURES; i++) {
51 		rubyLUT[i] = NULL;
52 	}
53 	shader_type = D3D_SHADER_NONE;
54 	shaderTimer = 1.0f;
55 	shaderTimeStart = 0;
56 	shaderTimeElapsed = 0;
57 	frameCount = 0;
58 	cgContext = NULL;
59 	cgAvailable = false;
60 	cgShader = NULL;
61 	vertexDeclaration = NULL;
62 }
63 
64 /* CDirect3D::~CDirect3D()
65 releases allocated objects
66 */
~CDirect3D()67 CDirect3D::~CDirect3D()
68 {
69 	DeInitialize();
70 }
71 
72 
73 /*  CDirect3D::Initialize
74 Initializes Direct3D (always in window mode)
75 IN:
76 hWnd	-	the HWND of the window in which we render/the focus window for fullscreen
77 -----
78 returns true if successful, false otherwise
79 */
Initialize(HWND hWnd)80 bool CDirect3D::Initialize(HWND hWnd)
81 {
82 	if(init_done)
83 		return true;
84 
85 	pD3D = Direct3DCreate9(D3D_SDK_VERSION);
86 	if(pD3D == NULL) {
87 		DXTRACE_ERR_MSGBOX(TEXT("Error creating initial D3D9 object"), 0);
88 		return false;
89 	}
90 
91 	memset(&dPresentParams, 0, sizeof(dPresentParams));
92 	dPresentParams.hDeviceWindow = hWnd;
93     dPresentParams.Windowed = true;
94 	dPresentParams.BackBufferCount = GUI.DoubleBuffered?2:1;
95     dPresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
96 	dPresentParams.BackBufferFormat = D3DFMT_UNKNOWN;
97 
98 	HRESULT hr = pD3D->CreateDevice(D3DADAPTER_DEFAULT,
99                       D3DDEVTYPE_HAL,
100                       hWnd,
101                       D3DCREATE_MIXED_VERTEXPROCESSING,
102 					  &dPresentParams,
103                       &pDevice);
104 	if(FAILED(hr)) {
105 		DXTRACE_ERR_MSGBOX(TEXT("Error creating D3D9 device"), hr);
106 		return false;
107 	}
108 
109 	hr = pDevice->CreateVertexBuffer(sizeof(vertexStream),D3DUSAGE_WRITEONLY,0,D3DPOOL_MANAGED,&vertexBuffer,NULL);
110 	if(FAILED(hr)) {
111 		DXTRACE_ERR_MSGBOX(TEXT("Error creating vertex buffer"), hr);
112 		return false;
113 	}
114 
115 	hr = pDevice->CreateVertexDeclaration(vertexElems,&vertexDeclaration);
116 	if(FAILED(hr)) {
117 		DXTRACE_ERR_MSGBOX(TEXT("Error creating vertex declaration"), hr);
118 		return false;
119 	}
120 
121 	cgAvailable = loadCgFunctions();
122 
123 	if(cgAvailable) {
124 		cgContext = cgCreateContext();
125 		hr = cgD3D9SetDevice(pDevice);
126 		if(FAILED(hr)) {
127 			DXTRACE_ERR_MSGBOX(TEXT("Error setting cg device"), hr);
128 		}
129 		cgShader = new CD3DCG(cgContext,pDevice);
130 	}
131 
132 	pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
133 	pDevice->SetRenderState( D3DRS_ZENABLE, FALSE);
134 	pDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER);
135 	pDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER);
136 
137 	Clear();
138 
139 	init_done = true;
140 
141 	ApplyDisplayChanges();
142 
143 	return true;
144 
145 }
146 
DeInitialize()147 void CDirect3D::DeInitialize()
148 {
149 	DestroyDrawSurface();
150 	SetShader(NULL);
151 
152 	if(cgShader) {
153 		delete cgShader;
154 		cgShader = NULL;
155 	}
156 	if(cgContext) {
157 		cgDestroyContext(cgContext);
158 		cgContext = NULL;
159 	}
160 	if(cgAvailable)
161 		cgD3D9SetDevice(NULL);
162 
163 	if(vertexBuffer) {
164 		vertexBuffer->Release();
165 		vertexBuffer = NULL;
166 	}
167 
168 	if(vertexDeclaration) {
169 		vertexDeclaration->Release();
170 		vertexDeclaration = NULL;
171 	}
172 
173 	if( pDevice ) {
174 		pDevice->Release();
175 		pDevice = NULL;
176 	}
177 
178 	if( pD3D ) {
179 		pD3D->Release();
180 		pD3D = NULL;
181 	}
182 
183 	init_done = false;
184 	afterRenderWidth = 0;
185 	afterRenderHeight = 0;
186 	quadTextureSize = 0;
187 	fullscreen = false;
188 	filterScale = 0;
189 	if(cgAvailable)
190 		unloadCgLibrary();
191 	cgAvailable = false;
192 }
193 
SetShader(const TCHAR * file)194 bool CDirect3D::SetShader(const TCHAR *file)
195 {
196 	SetShaderCG(NULL);
197 	shader_type = D3D_SHADER_NONE;
198 	if(file!=NULL &&
199 		(lstrlen(file)>3 && _tcsncicmp(&file[lstrlen(file)-3],TEXT(".cg"),3)==0) ||
200 		(lstrlen(file)>4 && _tcsncicmp(&file[lstrlen(file)-4],TEXT(".cgp"),4)==0)){
201 		return SetShaderCG(file);
202 	}
203 
204 	return true;
205 }
206 
checkForCgError(const char * situation)207 void CDirect3D::checkForCgError(const char *situation)
208 {
209 	char buffer[4096];
210 	CGerror error = cgGetError();
211 	const char *string = cgGetErrorString(error);
212 
213 	if (error != CG_NO_ERROR) {
214 		sprintf(buffer,
215 			  "Situation: %s\n"
216 			  "Error: %s\n\n"
217 			  "Cg compiler output...\n", situation, string);
218 		MessageBoxA(0, buffer,
219 				  "Cg error", MB_OK|MB_ICONEXCLAMATION);
220 		if (error == CG_COMPILER_ERROR) {
221 			MessageBoxA(0, cgGetLastListing(cgContext),
222 					  "Cg compilation error", MB_OK|MB_ICONEXCLAMATION);
223 		}
224 	}
225 }
226 
SetShaderCG(const TCHAR * file)227 bool CDirect3D::SetShaderCG(const TCHAR *file)
228 {
229 	if(!cgAvailable) {
230 		if(file)
231 			MessageBox(NULL, TEXT("The CG runtime is unavailable, CG shaders will not run.\nConsult the snes9x readme for information on how to obtain the runtime."), TEXT("CG Error"),
232 				MB_OK|MB_ICONEXCLAMATION);
233         return false;
234     }
235 
236 	if(!cgShader->LoadShader(file))
237 		return false;
238 
239 	shader_type = D3D_SHADER_CG;
240 
241 	return true;
242 }
243 
244 /*  CDirect3D::Render
245 does the actual rendering, changes the draw surface if necessary and recalculates
246 the vertex information if filter output size changes
247 IN:
248 Src		-	the input surface
249 */
Render(SSurface Src)250 void CDirect3D::Render(SSurface Src)
251 {
252 	SSurface Dst;
253 	RECT dstRect;
254 	unsigned int newFilterScale;
255 	D3DLOCKED_RECT lr;
256 	D3DLOCKED_RECT lrConv;
257 	HRESULT hr;
258 
259 	if(!init_done) return;
260 
261 	//create a new draw surface if the filter scale changes
262 	//at least factor 2 so we can display unscaled hi-res images
263 	newFilterScale = max(2,max(GetFilterScale(GUI.ScaleHiRes),GetFilterScale(GUI.Scale)));
264 	if(newFilterScale!=filterScale) {
265 		ChangeDrawSurfaceSize(newFilterScale);
266 	}
267 
268 	if(FAILED(hr = pDevice->TestCooperativeLevel())) {
269 		switch(hr) {
270 			case D3DERR_DEVICELOST:		//do no rendering until device is restored
271 				return;
272 			case D3DERR_DEVICENOTRESET: //we can reset now
273                 if(!IsIconic(dPresentParams.hDeviceWindow))
274 				    ResetDevice();
275 				return;
276 			default:
277 				DXTRACE_ERR_MSGBOX(TEXT("Internal driver error"), hr);
278 				return;
279 		}
280 	}
281 
282 	//BlankTexture(drawSurface);
283 	if(FAILED(hr = drawSurface->LockRect(0, &lr, NULL, 0))) {
284 		DXTRACE_ERR_MSGBOX(TEXT("Unable to lock texture"), hr);
285 		return;
286 	} else {
287 		Dst.Surface = (unsigned char *)lr.pBits;
288 		Dst.Height = quadTextureSize;
289 		Dst.Width = quadTextureSize;
290 		Dst.Pitch = lr.Pitch;
291 
292 		RenderMethod (Src, Dst, &dstRect);
293 		if(!Settings.AutoDisplayMessages) {
294 			WinSetCustomDisplaySurface((void *)Dst.Surface, Dst.Pitch/2, dstRect.right-dstRect.left, dstRect.bottom-dstRect.top, GetFilterScale(CurrentScale));
295 			S9xDisplayMessages ((uint16*)Dst.Surface, Dst.Pitch/2, dstRect.right-dstRect.left, dstRect.bottom-dstRect.top, GetFilterScale(CurrentScale));
296 		}
297 
298 		drawSurface->UnlockRect(0);
299 	}
300 
301 	if (!GUI.Stretch || GUI.AspectRatio) {
302 		Clear();
303 	}
304 
305 	//if the output size of the render method changes we need to update the viewport
306 	if(afterRenderHeight != dstRect.bottom || afterRenderWidth != dstRect.right) {
307 		afterRenderHeight = dstRect.bottom;
308 		afterRenderWidth = dstRect.right;
309 		SetViewport();
310 	}
311 
312 	pDevice->SetTexture(0, drawSurface);
313 	pDevice->SetVertexDeclaration(vertexDeclaration);
314 	pDevice->SetStreamSource(0,vertexBuffer,0,sizeof(VERTEX));
315 
316 	if(shader_type == D3D_SHADER_CG) {
317 		RECT displayRect;
318 		//Get maximum rect respecting AR setting
319 		displayRect=CalculateDisplayRect(dPresentParams.BackBufferWidth,dPresentParams.BackBufferHeight,
320 										dPresentParams.BackBufferWidth,dPresentParams.BackBufferHeight);
321 		cgShader->Render(drawSurface,
322 			XMFLOAT2((float)quadTextureSize, (float)quadTextureSize),
323 			XMFLOAT2((float)afterRenderWidth, (float)afterRenderHeight),
324 			XMFLOAT2((float)(displayRect.right - displayRect.left),
325 								(float)(displayRect.bottom - displayRect.top)),
326 			XMFLOAT2((float)dPresentParams.BackBufferWidth, (float)dPresentParams.BackBufferHeight));
327 	}
328 
329 	SetFiltering();
330 
331 	pDevice->SetVertexDeclaration(vertexDeclaration);
332 
333 	pDevice->BeginScene();
334 	pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2);
335 	pDevice->EndScene();
336 
337 	pDevice->Present(NULL, NULL, NULL, NULL);
338 
339 	if (GUI.ReduceInputLag)
340 	{
341 		IDirect3DSurface9 *surface;
342 		RECT r = { 0, 0, 2, 2 };
343 
344 		if (pDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &surface) == D3D_OK)
345 		{
346 			if (surface->LockRect(&lr, &r, D3DLOCK_READONLY) == D3D_OK)
347 			{
348 				surface->UnlockRect();
349 			}
350 			surface->Release();
351 		}
352 	}
353 
354     return;
355 }
356 
357 /*  CDirect3D::CreateDrawSurface
358 calculates the necessary texture size (multiples of 2)
359 and creates a new texture
360 */
CreateDrawSurface()361 void CDirect3D::CreateDrawSurface()
362 {
363 	unsigned int neededSize;
364 	HRESULT hr;
365 
366 	//we need at least 512 pixels (SNES_WIDTH * 2) so we can start with that value
367 	quadTextureSize = 512;
368 	neededSize = SNES_WIDTH * filterScale;
369 	while(quadTextureSize < neededSize)
370 		quadTextureSize *=2;
371 
372 	if(!drawSurface) {
373 		hr = pDevice->CreateTexture(
374 			quadTextureSize, quadTextureSize,
375 			1, // 1 level, no mipmaps
376 			0, // dynamic textures can be locked
377 			D3DFMT_R5G6B5,
378 			D3DPOOL_MANAGED,
379 			&drawSurface,
380 			NULL );
381 
382 		if(FAILED(hr)) {
383 			DXTRACE_ERR_MSGBOX(TEXT("Error while creating texture"), hr);
384 			return;
385 		}
386 	}
387 }
388 
389 /*  CDirect3D::DestroyDrawSurface
390 releases the old textures (if allocated)
391 */
DestroyDrawSurface()392 void CDirect3D::DestroyDrawSurface()
393 {
394 	if(drawSurface) {
395 		drawSurface->Release();
396 		drawSurface = NULL;
397 	}
398 }
399 
400 /*  CDirect3D::BlankTexture
401 clears a texture (fills it with zeroes)
402 IN:
403 texture		-	the texture to be blanked
404 -----
405 returns true if successful, false otherwise
406 */
BlankTexture(LPDIRECT3DTEXTURE9 texture)407 bool CDirect3D::BlankTexture(LPDIRECT3DTEXTURE9 texture)
408 {
409 	D3DLOCKED_RECT lr;
410 	HRESULT hr;
411 
412 	if(FAILED(hr = texture->LockRect(0, &lr, NULL, 0))) {
413 		DXTRACE_ERR_MSGBOX(TEXT("Unable to lock texture"), hr);
414 		return false;
415 	} else {
416 		memset(lr.pBits, 0, lr.Pitch * quadTextureSize);
417 		texture->UnlockRect(0);
418 		return true;
419 	}
420 }
421 
422 /*  CDirect3D::ChangeDrawSurfaceSize
423 changes the draw surface size: deletes the old textures, creates a new texture
424 and calculate new vertices
425 IN:
426 scale	-	the scale that has to fit into the textures
427 -----
428 returns true if successful, false otherwise
429 */
ChangeDrawSurfaceSize(unsigned int scale)430 bool CDirect3D::ChangeDrawSurfaceSize(unsigned int scale)
431 {
432 	filterScale = scale;
433 
434 	if(pDevice) {
435 		DestroyDrawSurface();
436 		CreateDrawSurface();
437 		SetupVertices();
438 		return true;
439 	}
440 	return false;
441 }
442 
443 /*  CDirect3D::SetupVertices
444 calculates the vertex coordinates
445 (respecting the stretch and aspect ratio settings)
446 */
SetupVertices()447 void CDirect3D::SetupVertices()
448 {
449 	void *pLockedVertexBuffer;
450 
451 	float tX = (float)afterRenderWidth / (float)quadTextureSize;
452 	float tY = (float)afterRenderHeight / (float)quadTextureSize;
453 
454 	vertexStream[0] = VERTEX(0.0f,0.0f,0.0f,0.0f,tY,0.0f,0.0f);
455 	vertexStream[1] = VERTEX(0.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f);
456 	vertexStream[2] = VERTEX(1.0f,0.0f,0.0f,tX,tY,0.0f,0.0f);
457 	vertexStream[3] = VERTEX(1.0f,1.0f,0.0f,tX,0.0f,0.0f,0.0f);
458 	for(int i=0;i<4;i++) {
459 		vertexStream[i].x -= 0.5f / (float)dPresentParams.BackBufferWidth;
460 		vertexStream[i].y += 0.5f / (float)dPresentParams.BackBufferHeight;
461 	}
462 
463 
464 	HRESULT hr = vertexBuffer->Lock(0,0,&pLockedVertexBuffer,NULL);
465 	memcpy(pLockedVertexBuffer,vertexStream,sizeof(vertexStream));
466 	vertexBuffer->Unlock();
467 }
468 
SetViewport()469 void CDirect3D::SetViewport()
470 {
471 	XMMATRIX matIdentity;
472 	XMMATRIX matProjection;
473 
474 	matProjection = XMMatrixOrthographicOffCenterLH(0.0f,1.0f,0.0f,1.0f,0.0f,1.0f);
475 	matIdentity = XMMatrixIdentity();
476 	pDevice->SetTransform(D3DTS_WORLD,(D3DMATRIX*)&matIdentity);
477 	pDevice->SetTransform(D3DTS_VIEW, (D3DMATRIX*)&matIdentity);
478 	pDevice->SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)&matProjection);
479 
480 	RECT drawRect = CalculateDisplayRect(afterRenderWidth,afterRenderHeight,dPresentParams.BackBufferWidth,dPresentParams.BackBufferHeight);
481 	D3DVIEWPORT9 viewport;
482 	viewport.X = drawRect.left;
483 	viewport.Y = drawRect.top;
484 	viewport.Height = drawRect.bottom - drawRect.top;
485 	viewport.Width = drawRect.right - drawRect.left;
486 	viewport.MinZ = 0.0f;
487 	viewport.MaxZ = 1.0f;
488 	HRESULT hr = pDevice->SetViewport(&viewport);
489 
490 	SetupVertices();
491 }
492 
493 /*  CDirect3D::ChangeRenderSize
494 determines if we need to reset the device (if the size changed)
495 called with (0,0) whenever we want new settings to take effect
496 IN:
497 newWidth,newHeight	-	the new window size
498 -----
499 returns true if successful, false otherwise
500 */
ChangeRenderSize(unsigned int newWidth,unsigned int newHeight)501 bool CDirect3D::ChangeRenderSize(unsigned int newWidth, unsigned int newHeight)
502 {
503 	if(!init_done)
504 		return false;
505 
506 	//if we already have the desired size no change is necessary
507 	//during fullscreen no changes are allowed
508 	if(dPresentParams.BackBufferWidth == newWidth && dPresentParams.BackBufferHeight == newHeight)
509 		return true;
510 
511 	if(!ResetDevice())
512 		return false;
513 
514 	return true;
515 }
516 
517 /*  CDirect3D::ResetDevice
518 resets the device
519 called if surface was lost or the settings/display size require a device reset
520 -----
521 returns true if successful, false otherwise
522 */
ResetDevice()523 bool CDirect3D::ResetDevice()
524 {
525 	if(!init_done) return false;
526 
527 	HRESULT hr;
528 
529 	//release prior to reset
530 	DestroyDrawSurface();
531 
532 	if(cgAvailable) {
533 		cgShader->OnLostDevice();
534 		cgD3D9SetDevice(NULL);
535 	}
536 
537 	//zero or unknown values result in the current window size/display settings
538 	dPresentParams.BackBufferWidth = 0;
539 	dPresentParams.BackBufferHeight = 0;
540 	dPresentParams.BackBufferCount = GUI.DoubleBuffered?2:1;
541 	dPresentParams.BackBufferFormat = D3DFMT_UNKNOWN;
542 	dPresentParams.FullScreen_RefreshRateInHz = 0;
543 	dPresentParams.Windowed = true;
544 	dPresentParams.PresentationInterval = GUI.Vsync?D3DPRESENT_INTERVAL_ONE:D3DPRESENT_INTERVAL_IMMEDIATE;
545 	dPresentParams.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
546 
547 	if(fullscreen) {
548 		dPresentParams.BackBufferWidth = GUI.FullscreenMode.width;
549 		dPresentParams.BackBufferHeight = GUI.FullscreenMode.height;
550 		dPresentParams.BackBufferCount = GUI.DoubleBuffered?2:1;
551 		dPresentParams.Windowed = false;
552 		if(GUI.FullscreenMode.depth == 32)
553 			dPresentParams.BackBufferFormat = D3DFMT_X8R8G8B8;
554 		else
555 			dPresentParams.BackBufferFormat = D3DFMT_R5G6B5;
556 		dPresentParams.FullScreen_RefreshRateInHz = GUI.FullscreenMode.rate;
557 	}
558 
559 	if(FAILED(hr = pDevice->Reset(&dPresentParams))) {
560 		DXTRACE_ERR(TEXT("Unable to reset device"), hr);
561 		return false;
562 	}
563 
564 	if(cgAvailable) {
565 		cgD3D9SetDevice(pDevice);
566 		cgShader->OnResetDevice();
567 	}
568 
569 	pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
570 
571 	pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
572 
573 	//recreate the surface
574 	CreateDrawSurface();
575 
576 	SetViewport();
577 
578 	return true;
579 }
580 
581 /*  CDirect3D::SetSnes9xColorFormat
582 sets the color format to 16bit (since the texture is always 16bit)
583 no depth conversion is necessary (done by D3D)
584 */
SetSnes9xColorFormat()585 void CDirect3D::SetSnes9xColorFormat()
586 {
587 	GUI.ScreenDepth = 16;
588 	GUI.BlueShift = 0;
589 	GUI.GreenShift = 6;
590 	GUI.RedShift = 11;
591 	S9xBlit2xSaIFilterInit();
592 	S9xBlitHQ2xFilterInit();
593 	GUI.NeedDepthConvert = FALSE;
594 	GUI.DepthConverted = TRUE;
595 	return;
596 }
597 
598 /*  CDirect3D::SetFullscreen
599 enables/disables fullscreen mode
600 IN:
601 fullscreen	-	determines if fullscreen is enabled/disabled
602 -----
603 returns true if successful, false otherwise
604 */
SetFullscreen(bool fullscreen)605 bool CDirect3D::SetFullscreen(bool fullscreen)
606 {
607 	if(!init_done)
608 		return false;
609 
610 	if(this->fullscreen==fullscreen)
611 		return true;
612 
613 	this->fullscreen = fullscreen;
614 	if(!ResetDevice())
615 		return false;
616 
617 	//present here to get a fullscreen blank even if no rendering is done
618 	pDevice->Present(NULL,NULL,NULL,NULL);
619 
620 	return true;
621 }
622 
623 /*  CDirect3D::EnumModes
624 enumerates possible display modes (only 16 and 32 bit) and fills the vector
625 IN:
626 modeVector	-	pointer to the mode vector
627 */
EnumModes(std::vector<dMode> * modeVector)628 void CDirect3D::EnumModes(std::vector<dMode> *modeVector)
629 {
630 	D3DDISPLAYMODE d3dMode;
631 	int modeCount,index;
632 	dMode mode;
633 
634 	if(!init_done)
635 		return;
636 
637 	//enumerate 32bit modes
638 	modeCount = pD3D->GetAdapterModeCount(D3DADAPTER_DEFAULT,D3DFMT_X8R8G8B8);
639 	for(int i=0;i<modeCount;i++) {
640 		if(pD3D->EnumAdapterModes(D3DADAPTER_DEFAULT,D3DFMT_X8R8G8B8,i,&d3dMode)==D3D_OK) {
641 			mode.width = d3dMode.Width;
642 			mode.height = d3dMode.Height;
643 			mode.rate = d3dMode.RefreshRate;
644 			mode.depth = 32;
645 
646 			modeVector->push_back(mode);
647 		}
648 
649 	}
650 
651 	//enumerate 16bit modes
652 	modeCount = pD3D->GetAdapterModeCount(D3DADAPTER_DEFAULT,D3DFMT_R5G6B5);
653 	for(int i=0;i<modeCount;i++) {
654 		if(pD3D->EnumAdapterModes(D3DADAPTER_DEFAULT,D3DFMT_R5G6B5,i,&d3dMode)==D3D_OK) {
655 			mode.width = d3dMode.Width;
656 			mode.height = d3dMode.Height;
657 			mode.rate = d3dMode.RefreshRate;
658 			mode.depth = 16;
659 
660 			modeVector->push_back(mode);
661 		}
662 
663 	}
664 }
665 
666 /*  CDirect3D::ApplyDisplayChanges
667 calls changerendersize to apply new display settings
668 -----
669 returns true if successful, false otherwise
670 */
ApplyDisplayChanges(void)671 bool CDirect3D::ApplyDisplayChanges(void)
672 {
673 	if(GUI.shaderEnabled && GUI.D3DshaderFileName)
674 		SetShader(GUI.D3DshaderFileName);
675 	else
676 		SetShader(NULL);
677 
678 	return ChangeRenderSize(0,0);
679 }
680 
SetFiltering()681 void CDirect3D::SetFiltering()
682 {
683 	if(Settings.BilinearFilter) {
684 		pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
685 		pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
686 	} else {
687 		pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
688 		pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
689 	}
690 }
691 
692 // reset viewport to whole window, clear, set back to current viewport
Clear()693 void CDirect3D::Clear()
694 {
695 	if (!init_done)
696 		return;
697 
698 	D3DVIEWPORT9 vp_current, vp_all;
699 	pDevice->GetViewport(&vp_current);
700 
701 	vp_all.X = 0;
702 	vp_all.Y = 0;
703 	vp_all.Width = dPresentParams.BackBufferWidth;
704 	vp_all.Height = dPresentParams.BackBufferHeight;
705 	vp_all.MinZ = 0.0;
706 	vp_all.MaxZ = 1.0;
707 
708 	pDevice->SetViewport(&vp_all);
709 	pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
710 	pDevice->SetViewport(&vp_current);
711 }
712