1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
2 // Copyright (C) 1999-2003 Forgotten
3 // Copyright (C) 2004 Forgotten and the VBA development team
4
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2, or(at your option)
8 // any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 #include "stdafx.h"
20
21 #define DIRECTDRAW_VERSION 0x0700
22 #include <ddraw.h>
23
24 #include "../System.h"
25 #include "../gb/gbGlobals.h"
26 #include "../GBA.h"
27 #include "../Globals.h"
28 #include "../Text.h"
29
30 #include "VBA.h"
31 #include "MainWnd.h"
32 #include "Reg.h"
33 #include "resource.h"
34
35 #ifdef _DEBUG
36 #define new DEBUG_NEW
37 #undef THIS_FILE
38 static char THIS_FILE[] = __FILE__;
39 #endif
40
41 extern int Init_2xSaI(u32);
42 extern int RGB_LOW_BITS_MASK;
43 extern void winlog(const char *,...);
44 extern int systemSpeed;
45 extern int winVideoModeSelect(CWnd *, GUID **);
46
47 class DirectDrawDisplay : public IDisplay {
48 private:
49 HINSTANCE ddrawDLL;
50 LPDIRECTDRAW7 pDirectDraw;
51 LPDIRECTDRAWSURFACE7 ddsPrimary;
52 LPDIRECTDRAWSURFACE7 ddsOffscreen;
53 LPDIRECTDRAWSURFACE7 ddsFlip;
54 LPDIRECTDRAWCLIPPER ddsClipper;
55 int width;
56 int height;
57 bool failed;
58
59 bool initializeOffscreen(int w, int h);
60 public:
61 DirectDrawDisplay();
62 virtual ~DirectDrawDisplay();
63
64 virtual bool initialize();
65 virtual void cleanup();
66 virtual void render();
67 virtual void checkFullScreen();
68 virtual void renderMenu();
69 virtual void clear();
70 virtual bool changeRenderSize(int w, int h);
getType()71 virtual DISPLAY_TYPE getType() { return DIRECT_DRAW; };
setOption(const char *,int)72 virtual void setOption(const char *, int) {}
isSkinSupported()73 virtual bool isSkinSupported() { return true; }
74 virtual int selectFullScreenMode(GUID **);
75 };
76
checkModesAvailable(LPDDSURFACEDESC2 surf,LPVOID lpContext)77 static HRESULT WINAPI checkModesAvailable(LPDDSURFACEDESC2 surf, LPVOID lpContext)
78 {
79 if(surf->dwWidth == 320 &&
80 surf->dwHeight == 240 &&
81 surf->ddpfPixelFormat.dwRGBBitCount == 16) {
82 theApp.mode320Available = TRUE;
83 }
84 if(surf->dwWidth == 640 &&
85 surf->dwHeight == 480 &&
86 surf->ddpfPixelFormat.dwRGBBitCount == 16) {
87 theApp.mode640Available = TRUE;
88 }
89 if(surf->dwWidth == 800 &&
90 surf->dwHeight == 600 &&
91 surf->ddpfPixelFormat.dwRGBBitCount == 16) {
92 theApp.mode800Available = TRUE;
93 }
94 return DDENUMRET_OK;
95 }
96
ffs(UINT mask)97 static int ffs(UINT mask)
98 {
99 int m = 0;
100 if (mask) {
101 while (!(mask & (1 << m)))
102 m++;
103
104 return (m);
105 }
106
107 return (0);
108 }
109
DirectDrawDisplay()110 DirectDrawDisplay::DirectDrawDisplay()
111 {
112 pDirectDraw = NULL;
113 ddsPrimary = NULL;
114 ddsOffscreen = NULL;
115 ddsFlip = NULL;
116 ddsClipper = NULL;
117 ddrawDLL = NULL;
118 width = 0;
119 height = 0;
120 failed = false;
121 }
122
~DirectDrawDisplay()123 DirectDrawDisplay::~DirectDrawDisplay()
124 {
125 cleanup();
126 }
127
cleanup()128 void DirectDrawDisplay::cleanup()
129 {
130 if(pDirectDraw != NULL) {
131 if(ddsClipper != NULL) {
132 ddsClipper->Release();
133 ddsClipper = NULL;
134 }
135
136 if(ddsFlip != NULL) {
137 ddsFlip->Release();
138 ddsFlip = NULL;
139 }
140
141 if(ddsOffscreen != NULL) {
142 ddsOffscreen->Release();
143 ddsOffscreen = NULL;
144 }
145
146 if(ddsPrimary != NULL) {
147 ddsPrimary->Release();
148 ddsPrimary = NULL;
149 }
150
151 pDirectDraw->Release();
152 pDirectDraw = NULL;
153 }
154
155 if(ddrawDLL != NULL) {
156 AfxFreeLibrary(ddrawDLL);
157 ddrawDLL = NULL;
158 }
159 width = 0;
160 height = 0;
161 }
162
initialize()163 bool DirectDrawDisplay::initialize()
164 {
165 theApp.sizeX = 240;
166 theApp.sizeY = 160;
167
168 switch(theApp.videoOption) {
169 case VIDEO_1X:
170 theApp.surfaceSizeX = theApp.sizeX;
171 theApp.surfaceSizeY = theApp.sizeY;
172 break;
173 case VIDEO_2X:
174 theApp.surfaceSizeX = theApp.sizeX * 2;
175 theApp.surfaceSizeY = theApp.sizeY * 2;
176 break;
177 case VIDEO_3X:
178 theApp.surfaceSizeX = theApp.sizeX * 3;
179 theApp.surfaceSizeY = theApp.sizeY * 3;
180 break;
181 case VIDEO_4X:
182 theApp.surfaceSizeX = theApp.sizeX * 4;
183 theApp.surfaceSizeY = theApp.sizeY * 4;
184 break;
185 case VIDEO_320x240:
186 case VIDEO_640x480:
187 case VIDEO_800x600:
188 case VIDEO_OTHER:
189 {
190 int scaleX = (theApp.fsWidth / theApp.sizeX);
191 int scaleY = (theApp.fsHeight / theApp.sizeY);
192 int min = scaleX < scaleY ? scaleX : scaleY;
193 if(theApp.fsMaxScale)
194 min = min > theApp.fsMaxScale ? theApp.fsMaxScale : min;
195 theApp.surfaceSizeX = theApp.sizeX * min;
196 theApp.surfaceSizeY = theApp.sizeY * min;
197 if(theApp.fullScreenStretch) {
198 theApp.surfaceSizeX = theApp.fsWidth;
199 theApp.surfaceSizeY = theApp.fsHeight;
200 }
201 }
202 break;
203 }
204
205 theApp.rect.left = 0;
206 theApp.rect.top = 0;
207 theApp.rect.right = theApp.sizeX;
208 theApp.rect.bottom = theApp.sizeY;
209
210 theApp.dest.left = 0;
211 theApp.dest.top = 0;
212 theApp.dest.right = theApp.surfaceSizeX;
213 theApp.dest.bottom = theApp.surfaceSizeY;
214
215 DWORD style = WS_POPUP | WS_VISIBLE;
216 DWORD styleEx = 0;
217
218 if(theApp.videoOption <= VIDEO_4X)
219 style |= WS_OVERLAPPEDWINDOW;
220 else
221 styleEx = WS_EX_TOPMOST;
222
223 if(theApp.videoOption <= VIDEO_4X)
224 AdjustWindowRectEx(&theApp.dest, style, TRUE, styleEx);
225 else
226 AdjustWindowRectEx(&theApp.dest, style, FALSE, styleEx);
227
228 int winSizeX = theApp.dest.right-theApp.dest.left;
229 int winSizeY = theApp.dest.bottom-theApp.dest.top;
230
231 int x = 0;
232 int y = 0;
233
234 if(theApp.videoOption <= VIDEO_4X) {
235 x = theApp.windowPositionX;
236 y = theApp.windowPositionY;
237 }
238
239 // Create a window
240 MainWnd *pWnd = new MainWnd;
241 theApp.m_pMainWnd = pWnd;
242
243 pWnd->CreateEx(styleEx,
244 theApp.wndClass,
245 "VisualBoyAdvance",
246 style,
247 x,y,winSizeX,winSizeY,
248 NULL,
249 0);
250
251 if (!(HWND)*pWnd) {
252 winlog("Error creating Window %08x\n", GetLastError());
253 return FALSE;
254 }
255
256
257 theApp.updateMenuBar();
258
259 theApp.adjustDestRect();
260
261 GUID *guid = NULL;
262 if(theApp.ddrawEmulationOnly)
263 guid = (GUID *)DDCREATE_EMULATIONONLY;
264
265 if(theApp.pVideoDriverGUID)
266 guid = theApp.pVideoDriverGUID;
267
268 ddrawDLL = AfxLoadLibrary("DDRAW.DLL");
269 HRESULT (WINAPI *DDrawCreateEx)(GUID *,LPVOID *,REFIID,IUnknown *);
270 if(ddrawDLL != NULL) {
271 DDrawCreateEx = (HRESULT (WINAPI *)(GUID *,LPVOID *,REFIID,IUnknown *))
272 GetProcAddress(ddrawDLL, "DirectDrawCreateEx");
273
274 if(DDrawCreateEx == NULL) {
275 theApp.directXMessage("DirectDrawCreateEx");
276 return FALSE;
277 }
278 } else {
279 theApp.directXMessage("DDRAW.DLL");
280 return FALSE;
281 }
282
283 theApp.ddrawUsingEmulationOnly = theApp.ddrawEmulationOnly;
284
285 HRESULT hret = DDrawCreateEx(guid,
286 (void **)&pDirectDraw,
287 IID_IDirectDraw7,
288 NULL);
289
290 if(hret != DD_OK) {
291 winlog("Error creating DirectDraw object %08x\n", hret);
292 if(theApp.ddrawEmulationOnly) {
293 // disable emulation only setting in case of failure
294 regSetDwordValue("ddrawEmulationOnly", 0);
295 }
296 // errorMessage(myLoadString(IDS_ERROR_DISP_DRAWCREATE), hret);
297 return FALSE;
298 }
299
300 if(theApp.ddrawDebug) {
301 DDCAPS driver;
302 DDCAPS hel;
303 ZeroMemory(&driver, sizeof(driver));
304 ZeroMemory(&hel, sizeof(hel));
305 driver.dwSize = sizeof(driver);
306 hel.dwSize = sizeof(hel);
307 pDirectDraw->GetCaps(&driver, &hel);
308 int i;
309 DWORD *p = (DWORD *)&driver;
310 for(i = 0; i < (int)driver.dwSize; i+=4)
311 winlog("Driver CAPS %2d: %08x\n", i>>2, *p++);
312 p = (DWORD *)&hel;
313 for(i = 0; i < (int)hel.dwSize; i+=4)
314 winlog("HEL CAPS %2d: %08x\n", i>>2, *p++);
315 }
316
317 theApp.mode320Available = false;
318 theApp.mode640Available = false;
319 theApp.mode800Available = false;
320 // check for available fullscreen modes
321 pDirectDraw->EnumDisplayModes(DDEDM_STANDARDVGAMODES, NULL, NULL,
322 checkModesAvailable);
323
324 DWORD flags = DDSCL_NORMAL;
325
326 if(theApp.videoOption >= VIDEO_320x240)
327 flags = DDSCL_ALLOWMODEX |
328 DDSCL_ALLOWREBOOT |
329 DDSCL_EXCLUSIVE |
330 DDSCL_FULLSCREEN;
331
332 hret = pDirectDraw->SetCooperativeLevel(pWnd->m_hWnd,
333 flags);
334
335 if(hret != DD_OK) {
336 winlog("Error SetCooperativeLevel %08x\n", hret);
337 // errorMessage(myLoadString(IDS_ERROR_DISP_DRAWLEVEL), hret);
338 return FALSE;
339 }
340
341 if(theApp.videoOption > VIDEO_4X) {
342 hret = pDirectDraw->SetDisplayMode(theApp.fsWidth,
343 theApp.fsHeight,
344 theApp.fsColorDepth,
345 0,
346 0);
347 if(hret != DD_OK) {
348 winlog("Error SetDisplayMode %08x\n", hret);
349 // errorMessage(myLoadString(IDS_ERROR_DISP_DRAWSET), hret);
350 return FALSE;
351 }
352 }
353
354 DDSURFACEDESC2 ddsd;
355 ZeroMemory(&ddsd,sizeof(ddsd));
356 ddsd.dwSize = sizeof(ddsd);
357 ddsd.dwFlags = DDSD_CAPS;
358 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
359 if(theApp.videoOption > VIDEO_4X) {
360 if(theApp.tripleBuffering) {
361 // setup triple buffering
362 ddsd.dwFlags |= DDSD_BACKBUFFERCOUNT;
363 ddsd.ddsCaps.dwCaps |= DDSCAPS_COMPLEX | DDSCAPS_FLIP;
364 ddsd.dwBackBufferCount = 2;
365 }
366 }
367
368 hret = pDirectDraw->CreateSurface(&ddsd, &ddsPrimary, NULL);
369 if(hret != DD_OK) {
370 winlog("Error primary CreateSurface %08x\n", hret);
371 // errorMessage(myLoadString(IDS_ERROR_DISP_DRAWSURFACE), hret);
372 return FALSE;
373 }
374
375 if(theApp.ddrawDebug) {
376 DDSCAPS2 caps;
377 ZeroMemory(&caps, sizeof(caps));
378 ddsPrimary->GetCaps(&caps);
379
380 winlog("Primary CAPS 1: %08x\n", caps.dwCaps);
381 winlog("Primary CAPS 2: %08x\n", caps.dwCaps2);
382 winlog("Primary CAPS 3: %08x\n", caps.dwCaps3);
383 winlog("Primary CAPS 4: %08x\n", caps.dwCaps4);
384 }
385
386 if(theApp.videoOption > VIDEO_4X && theApp.tripleBuffering) {
387 DDSCAPS2 caps;
388 ZeroMemory(&caps, sizeof(caps));
389 // this gets the third surface. The front one is the primary,
390 // the second is the backbuffer and the third is the flip
391 // surface
392 caps.dwCaps = DDSCAPS_BACKBUFFER;
393
394 hret = ddsPrimary->GetAttachedSurface(&caps, &ddsFlip);
395 if(hret != DD_OK) {
396 winlog("Failed to get attached surface %08x", hret);
397 return FALSE;
398 }
399
400 ddsFlip->AddRef();
401 clear();
402 }
403
404 // create clipper in all modes to avoid paint problems
405 // if(videoOption <= VIDEO_4X) {
406 hret = pDirectDraw->CreateClipper(0, &ddsClipper, NULL);
407 if(hret == DD_OK) {
408 ddsClipper->SetHWnd(0, pWnd->m_hWnd);
409 if(theApp.videoOption > VIDEO_4X) {
410 if(theApp.tripleBuffering)
411 ddsFlip->SetClipper(ddsClipper);
412 else
413 ddsPrimary->SetClipper(ddsClipper);
414 } else
415 ddsPrimary->SetClipper(ddsClipper);
416 }
417 // }
418
419 DDPIXELFORMAT px;
420
421 px.dwSize = sizeof(px);
422
423 hret = ddsPrimary->GetPixelFormat(&px);
424
425 switch(px.dwRGBBitCount) {
426 case 15:
427 case 16:
428 systemColorDepth = 16;
429 break;
430 case 24:
431 systemColorDepth = 24;
432 theApp.filterFunction = NULL;
433 break;
434 case 32:
435 systemColorDepth = 32;
436 break;
437 default:
438 systemMessage(IDS_ERROR_DISP_COLOR, "Unsupported display setting for color depth: %d bits. \nWindows desktop must be in either 16-bit, 24-bit or 32-bit mode for this program to work in window mode.",px.dwRGBBitCount);
439 return FALSE;
440 }
441 theApp.updateFilter();
442 theApp.updateIFB();
443
444 if(failed)
445 return false;
446
447 pWnd->DragAcceptFiles(TRUE);
448
449 return true;
450 }
451
changeRenderSize(int w,int h)452 bool DirectDrawDisplay::changeRenderSize(int w, int h)
453 {
454 if(w != width || h != height) {
455 if(ddsOffscreen) {
456 ddsOffscreen->Release();
457 ddsOffscreen = NULL;
458 }
459 if(!initializeOffscreen(w, h)) {
460 failed = true;
461 return false;
462 }
463 }
464 return true;
465 }
466
initializeOffscreen(int w,int h)467 bool DirectDrawDisplay::initializeOffscreen(int w, int h)
468 {
469 DDSURFACEDESC2 ddsd;
470
471 ZeroMemory(&ddsd, sizeof(ddsd));
472 ddsd.dwSize = sizeof(ddsd);
473 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
474 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
475 if(theApp.ddrawUseVideoMemory)
476 ddsd.ddsCaps.dwCaps |= (DDSCAPS_LOCALVIDMEM|DDSCAPS_VIDEOMEMORY);
477 ddsd.dwWidth = w;
478 ddsd.dwHeight = h;
479
480 HRESULT hret = pDirectDraw->CreateSurface(&ddsd, &ddsOffscreen, NULL);
481
482 if(hret != DD_OK) {
483 winlog("Error offscreen CreateSurface %08x\n", hret);
484 if(theApp.ddrawUseVideoMemory) {
485 regSetDwordValue("ddrawUseVideoMemory", 0);
486 }
487 // errorMessage(myLoadString(IDS_ERROR_DISP_DRAWSURFACE2), hret);
488 return false;
489 }
490
491 if(theApp.ddrawDebug) {
492 DDSCAPS2 caps;
493 ZeroMemory(&caps, sizeof(caps));
494 ddsOffscreen->GetCaps(&caps);
495
496 winlog("Offscreen CAPS 1: %08x\n", caps.dwCaps);
497 winlog("Offscreen CAPS 2: %08x\n", caps.dwCaps2);
498 winlog("Offscreen CAPS 3: %08x\n", caps.dwCaps3);
499 winlog("Offscreen CAPS 4: %08x\n", caps.dwCaps4);
500 }
501
502 DDPIXELFORMAT px;
503
504 px.dwSize = sizeof(px);
505
506 hret = ddsOffscreen->GetPixelFormat(&px);
507
508 if(theApp.ddrawDebug) {
509 DWORD *pdword = (DWORD *)&px;
510 for(int ii = 0; ii < 8; ii++) {
511 winlog("Pixel format %d %08x\n", ii, pdword[ii]);
512 }
513 }
514
515 switch(px.dwRGBBitCount) {
516 case 15:
517 case 16:
518 systemColorDepth = 16;
519 break;
520 case 24:
521 systemColorDepth = 24;
522 theApp.filterFunction = NULL;
523 break;
524 case 32:
525 systemColorDepth = 32;
526 break;
527 default:
528 systemMessage(IDS_ERROR_DISP_COLOR, "Unsupported display setting for color depth: %d bits. \nWindows desktop must be in either 16-bit, 24-bit or 32-bit mode for this program to work in window mode.",px.dwRGBBitCount);
529 return FALSE;
530 }
531 if(theApp.ddrawDebug) {
532 winlog("R Mask: %08x\n", px.dwRBitMask);
533 winlog("G Mask: %08x\n", px.dwGBitMask);
534 winlog("B Mask: %08x\n", px.dwBBitMask);
535 }
536
537 systemRedShift = ffs(px.dwRBitMask);
538 systemGreenShift = ffs(px.dwGBitMask);
539 systemBlueShift = ffs(px.dwBBitMask);
540
541 #ifdef MMX
542 if(!theApp.disableMMX)
543 cpu_mmx = theApp.detectMMX();
544 else
545 cpu_mmx = 0;
546 #endif
547
548 if((px.dwFlags&DDPF_RGB) != 0 &&
549 px.dwRBitMask == 0xF800 &&
550 px.dwGBitMask == 0x07E0 &&
551 px.dwBBitMask == 0x001F) {
552 systemGreenShift++;
553 Init_2xSaI(565);
554 RGB_LOW_BITS_MASK=0x821;
555 } else if((px.dwFlags&DDPF_RGB) != 0 &&
556 px.dwRBitMask == 0x7C00 &&
557 px.dwGBitMask == 0x03E0 &&
558 px.dwBBitMask == 0x001F) {
559 Init_2xSaI(555);
560 RGB_LOW_BITS_MASK=0x421;
561 } else if((px.dwFlags&DDPF_RGB) != 0 &&
562 px.dwRBitMask == 0x001F &&
563 px.dwGBitMask == 0x07E0 &&
564 px.dwBBitMask == 0xF800) {
565 systemGreenShift++;
566 Init_2xSaI(565);
567 RGB_LOW_BITS_MASK=0x821;
568 } else if((px.dwFlags&DDPF_RGB) != 0 &&
569 px.dwRBitMask == 0x001F &&
570 px.dwGBitMask == 0x03E0 &&
571 px.dwBBitMask == 0x7C00) {
572 Init_2xSaI(555);
573 RGB_LOW_BITS_MASK=0x421;
574 } else {
575 // 32-bit or 24-bit
576 if(systemColorDepth == 32 || systemColorDepth == 24) {
577 systemRedShift += 3;
578 systemGreenShift += 3;
579 systemBlueShift += 3;
580 if(systemColorDepth == 32)
581 Init_2xSaI(32);
582 }
583 }
584
585 if(theApp.ddrawDebug) {
586 winlog("R shift: %d\n", systemRedShift);
587 winlog("G shift: %d\n", systemGreenShift);
588 winlog("B shift: %d\n", systemBlueShift);
589 }
590
591 switch(systemColorDepth) {
592 case 16:
593 {
594 for(int i = 0; i < 0x10000; i++) {
595 systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
596 (((i & 0x3e0) >> 5) << systemGreenShift) |
597 (((i & 0x7c00) >> 10) << systemBlueShift);
598 }
599 }
600 break;
601 case 24:
602 case 32:
603 {
604 for(int i = 0; i < 0x10000; i++) {
605 systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
606 (((i & 0x3e0) >> 5) << systemGreenShift) |
607 (((i & 0x7c00) >> 10) << systemBlueShift);
608 }
609 }
610 break;
611 }
612 width = w;
613 height = h;
614 return true;
615 }
616
clear()617 void DirectDrawDisplay::clear()
618 {
619 if(theApp.videoOption <= VIDEO_4X || !theApp.tripleBuffering || ddsFlip == NULL)
620 return;
621
622 DDBLTFX fx;
623 ZeroMemory(&fx, sizeof(fx));
624 fx.dwSize = sizeof(fx);
625 fx.dwFillColor = 0;
626 ddsFlip->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
627 ddsPrimary->Flip(NULL, 0);
628 ddsFlip->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
629 ddsPrimary->Flip(NULL, 0);
630 ddsFlip->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
631 ddsPrimary->Flip(NULL, 0);
632 }
633
renderMenu()634 void DirectDrawDisplay::renderMenu()
635 {
636 checkFullScreen();
637 theApp.m_pMainWnd->DrawMenuBar();
638 }
639
checkFullScreen()640 void DirectDrawDisplay::checkFullScreen()
641 {
642 if(theApp.tripleBuffering)
643 pDirectDraw->FlipToGDISurface();
644 }
645
render()646 void DirectDrawDisplay::render()
647 {
648 HRESULT hret;
649
650 if(pDirectDraw == NULL ||
651 ddsOffscreen == NULL ||
652 ddsPrimary == NULL)
653 return;
654
655 if(theApp.vsync && !speedup) {
656 hret = pDirectDraw->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, 0);
657 }
658
659 DDSURFACEDESC2 ddsDesc;
660
661 ZeroMemory(&ddsDesc, sizeof(ddsDesc));
662
663 ddsDesc.dwSize = sizeof(ddsDesc);
664
665 hret = ddsOffscreen->Lock(NULL,
666 &ddsDesc,
667 DDLOCK_WRITEONLY|
668 #ifndef FINAL_VERSION
669 DDLOCK_NOSYSLOCK|
670 #endif
671 DDLOCK_SURFACEMEMORYPTR,
672 NULL);
673
674 if(hret == DDERR_SURFACELOST) {
675 hret = ddsPrimary->Restore();
676 if(hret == DD_OK) {
677 hret = ddsOffscreen->Restore();
678
679 if(hret == DD_OK) {
680 hret = ddsOffscreen->Lock(NULL,
681 &ddsDesc,
682 DDLOCK_WRITEONLY|
683 #ifndef FINAL_VERSION
684 DDLOCK_NOSYSLOCK|
685 #endif
686 DDLOCK_SURFACEMEMORYPTR,
687 NULL);
688
689 }
690 }
691 }
692
693 if(hret == DD_OK) {
694 if(theApp.filterFunction) {
695 if(systemColorDepth == 16)
696 (*theApp.filterFunction)(pix+theApp.filterWidth*2+4,
697 theApp.filterWidth*2+4,
698 (u8*)theApp.delta,
699 (u8*)ddsDesc.lpSurface,
700 ddsDesc.lPitch,
701 theApp.filterWidth,
702 theApp.filterHeight);
703 else
704 (*theApp.filterFunction)(pix+theApp.filterWidth*4+4,
705 theApp.filterWidth*4+4,
706 (u8*)theApp.delta,
707 (u8*)ddsDesc.lpSurface,
708 ddsDesc.lPitch,
709 theApp.filterWidth,
710 theApp.filterHeight);
711
712 } else {
713 int copyX = 240;
714 int copyY = 160;
715
716 if(theApp.cartridgeType == 1) {
717 if(gbBorderOn) {
718 copyX = 256;
719 copyY = 224;
720 } else {
721 copyX = 160;
722 copyY = 144;
723 }
724 }
725 // MMX doesn't seem to be faster to copy the data
726 __asm {
727 mov eax, copyX;
728 mov ebx, copyY;
729
730 mov esi, pix;
731 mov edi, ddsDesc.lpSurface;
732 mov edx, ddsDesc.lPitch;
733 cmp systemColorDepth, 16;
734 jnz gbaOtherColor;
735 sub edx, eax;
736 sub edx, eax;
737 lea esi,[esi+2*eax+4];
738 shr eax, 1;
739 gbaLoop16bit:
740 mov ecx, eax;
741 repz movsd;
742 inc esi;
743 inc esi;
744 inc esi;
745 inc esi;
746 add edi, edx;
747 dec ebx;
748 jnz gbaLoop16bit;
749 jmp gbaLoopEnd;
750 gbaOtherColor:
751 cmp systemColorDepth, 32;
752 jnz gbaOtherColor2;
753
754 sub edx, eax;
755 sub edx, eax;
756 sub edx, eax;
757 sub edx, eax;
758 lea esi, [esi+4*eax+4];
759 gbaLoop32bit:
760 mov ecx, eax;
761 repz movsd;
762 add esi, 4;
763 add edi, edx;
764 dec ebx;
765 jnz gbaLoop32bit;
766 jmp gbaLoopEnd;
767 gbaOtherColor2:
768 lea eax, [eax+2*eax];
769 sub edx, eax;
770 gbaLoop24bit:
771 mov ecx, eax;
772 shr ecx, 2;
773 repz movsd;
774 add edi, edx;
775 dec ebx;
776 jnz gbaLoop24bit;
777 gbaLoopEnd:
778 }
779 }
780 if(theApp.showSpeed && (theApp.videoOption > VIDEO_4X || theApp.skin != NULL)) {
781 char buffer[30];
782 if(theApp.showSpeed == 1)
783 sprintf(buffer, "%3d%%", systemSpeed);
784 else
785 sprintf(buffer, "%3d%%(%d, %d fps)", systemSpeed,
786 systemFrameSkip,
787 theApp.showRenderedFrames);
788 if(theApp.showSpeedTransparent)
789 drawTextTransp((u8*)ddsDesc.lpSurface,
790 ddsDesc.lPitch,
791 theApp.rect.left+10,
792 theApp.rect.bottom-10,
793 buffer);
794 else
795 drawText((u8*)ddsDesc.lpSurface,
796 ddsDesc.lPitch,
797 theApp.rect.left+10,
798 theApp.rect.bottom-10,
799 buffer);
800 }
801 } else if(theApp.ddrawDebug)
802 winlog("Error during lock: %08x\n", hret);
803
804 hret = ddsOffscreen->Unlock(NULL);
805
806 if(hret == DD_OK) {
807 ddsOffscreen->PageLock(0);
808 if(theApp.tripleBuffering && theApp.videoOption > VIDEO_4X) {
809 hret = ddsFlip->Blt(&theApp.dest, ddsOffscreen, NULL, DDBLT_WAIT, NULL);
810 if(hret == DD_OK) {
811 if(theApp.menuToggle || !theApp.active) {
812 pDirectDraw->FlipToGDISurface();
813 ddsPrimary->SetClipper(ddsClipper);
814 hret = ddsPrimary->Blt(&theApp.dest, ddsFlip, NULL, DDBLT_ASYNC, NULL);
815 // if using emulation only, then we have to redraw the menu
816 // everytime. It seems like a bug in DirectDraw to me as we not
817 // overwritting the menu area at all.
818 if(theApp.ddrawUsingEmulationOnly)
819 theApp.m_pMainWnd->DrawMenuBar();
820 } else
821 hret = ddsPrimary->Flip(NULL, 0);
822 }
823 } else {
824 hret = ddsPrimary->Blt(&theApp.dest, ddsOffscreen, NULL,DDBLT_ASYNC,NULL);
825
826 if(hret == DDERR_SURFACELOST) {
827 hret = ddsPrimary->Restore();
828
829 if(hret == DD_OK) {
830 hret = ddsPrimary->Blt(&theApp.dest, ddsOffscreen, NULL, DDBLT_ASYNC, NULL);
831 }
832 }
833 }
834 ddsOffscreen->PageUnlock(0);
835 } else if(theApp.ddrawDebug)
836 winlog("Error during unlock: %08x\n", hret);
837
838 if(theApp.screenMessage) {
839 if(((GetTickCount() - theApp.screenMessageTime) < 3000) &&
840 !theApp.disableStatusMessage) {
841 ddsPrimary->SetClipper(ddsClipper);
842 HDC hdc;
843 ddsPrimary->GetDC(&hdc);
844 SetTextColor(hdc, RGB(255,0,0));
845 SetBkMode(hdc,TRANSPARENT);
846 TextOut(hdc, theApp.dest.left+10, theApp.dest.bottom - 20, theApp.screenMessageBuffer,
847 strlen(theApp.screenMessageBuffer));
848 ddsPrimary->ReleaseDC(hdc);
849 } else {
850 theApp.screenMessage = false;
851 }
852 }
853
854 if(hret != DD_OK) {
855 if(theApp.ddrawDebug)
856 winlog("Error on update screen: %08x\n", hret);
857 }
858 }
859
selectFullScreenMode(GUID ** pGUID)860 int DirectDrawDisplay::selectFullScreenMode(GUID **pGUID)
861 {
862 return winVideoModeSelect(theApp.m_pMainWnd, pGUID);
863 }
864
newDirectDrawDisplay()865 IDisplay *newDirectDrawDisplay()
866 {
867 return new DirectDrawDisplay();
868 }
869
870