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