home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 July / CMCD0704.ISO / Software / Freeware / Utilitare / VisualBoyAdvance-1.7.2 / src / win32 / DirectDraw.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-05-13  |  22.9 KB  |  870 lines

  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);
  71.   virtual DISPLAY_TYPE getType() { return DIRECT_DRAW; };
  72.   virtual void setOption(const char *, int) {}
  73.   virtual bool isSkinSupported() { return true; }
  74.   virtual int selectFullScreenMode(GUID **);  
  75. };
  76.  
  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.  
  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.  
  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.  
  123. DirectDrawDisplay::~DirectDrawDisplay()
  124. {
  125.   cleanup();
  126. }
  127.  
  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.  
  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.  
  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.  
  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.  
  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.  
  634. void DirectDrawDisplay::renderMenu()
  635. {
  636.   checkFullScreen();
  637.   theApp.m_pMainWnd->DrawMenuBar();
  638. }
  639.  
  640. void DirectDrawDisplay::checkFullScreen()
  641. {
  642.   if(theApp.tripleBuffering)
  643.     pDirectDraw->FlipToGDISurface();
  644. }
  645.  
  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.  
  860. int DirectDrawDisplay::selectFullScreenMode(GUID **pGUID)
  861. {
  862.   return winVideoModeSelect(theApp.m_pMainWnd, pGUID);
  863. }
  864.  
  865. IDisplay *newDirectDrawDisplay()
  866. {
  867.   return new DirectDrawDisplay();
  868. }
  869.  
  870.