home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 July / CMCD0704.ISO / Software / Freeware / Utilitare / VisualBoyAdvance-1.7.2 / src / win32 / Direct3D.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-05-13  |  19.4 KB  |  762 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. #include "vba.h"
  21.  
  22. #define DIRECT3D_VERSION 0x0800
  23. #include <d3d8.h>
  24. #include <d3dx8.h>
  25.  
  26. #include "MainWnd.h"
  27.  
  28. #include "../System.h"
  29. #include "../GBA.h"
  30. #include "../Globals.h"
  31. #include "../Text.h"
  32. #include "../gb/gbGlobals.h"
  33.  
  34. #include "Reg.h"
  35. #include "resource.h"
  36.  
  37. #ifdef _DEBUG
  38. #define new DEBUG_NEW
  39. #undef THIS_FILE
  40. static char THIS_FILE[] = __FILE__;
  41. #endif
  42.  
  43. #ifdef MMX
  44. extern "C" bool cpu_mmx;
  45.  
  46. extern bool detectMMX();
  47. #endif
  48.  
  49. extern int Init_2xSaI(u32);
  50. extern void winlog(const char *,...);
  51. extern int systemSpeed;
  52.  
  53. typedef struct _D3DTLVERTEX {
  54.   float sx; /* Screen coordinates */
  55.   float sy;
  56.   float sz;
  57.   float rhw; /* Reciprocal of homogeneous w */
  58.   D3DCOLOR color; /* Vertex color */
  59.   float tu; /* Texture coordinates */
  60.   float tv;
  61.   _D3DTLVERTEX() { }
  62.   _D3DTLVERTEX(const D3DVECTOR& v, float _rhw,
  63.                D3DCOLOR _color, 
  64.                float _tu, float _tv)
  65.   { sx = v.x; sy = v.y; sz = v.z; rhw = _rhw;
  66.   color = _color; 
  67.   tu = _tu; tv = _tv;
  68.   }
  69. } D3DTLVERTEX, *LPD3DTLVERTEX;
  70.  
  71. #define D3DFVF_TLVERTEX D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1
  72.  
  73. class Direct3DDisplay : public IDisplay {
  74. private:
  75.   HINSTANCE             d3dDLL;
  76.   LPDIRECT3D8           pD3D;
  77.   LPDIRECT3DDEVICE8     pDevice;
  78.   LPDIRECT3DTEXTURE8    pTexture;
  79.   D3DSURFACE_DESC       dsdBackBuffer;
  80.   D3DPRESENT_PARAMETERS dpp;
  81.   D3DFORMAT             screenFormat;
  82.   int                   width;
  83.   int                   height;
  84.   bool                  filterDisabled;
  85.   ID3DXFont             *pFont;
  86.   bool                  failed;
  87.   
  88.   void restoreDeviceObjects();
  89.   void invalidateDeviceObjects();
  90.   bool initializeOffscreen(int w, int h);
  91.   void updateFiltering(int);
  92. public:
  93.   Direct3DDisplay();
  94.   virtual ~Direct3DDisplay();
  95.  
  96.   virtual bool initialize();
  97.   virtual void cleanup();
  98.   virtual void render();
  99.   virtual void checkFullScreen();
  100.   virtual void renderMenu();
  101.   virtual void clear();
  102.   virtual bool changeRenderSize(int w, int h);
  103.   virtual void resize(int w, int h);
  104.   virtual DISPLAY_TYPE getType() { return DIRECT_3D; };
  105.   virtual void setOption(const char *, int);
  106.   virtual int selectFullScreenMode(GUID **);  
  107. };
  108.  
  109. Direct3DDisplay::Direct3DDisplay()
  110. {
  111.   d3dDLL = NULL;
  112.   pD3D = NULL;  
  113.   pDevice = NULL;
  114.   pTexture = NULL;
  115.   pFont = NULL;
  116.   screenFormat = D3DFMT_R5G6B5;
  117.   width = 0;
  118.   height = 0;
  119.   filterDisabled = false;
  120.   failed = false;
  121. }
  122.  
  123. Direct3DDisplay::~Direct3DDisplay()
  124. {
  125.   cleanup();
  126. }
  127.  
  128. void Direct3DDisplay::cleanup()
  129. {
  130.   if(pD3D != NULL) {
  131.     if(pFont) {
  132.       pFont->Release();
  133.       pFont = NULL;
  134.     }
  135.     
  136.     if(pTexture) {
  137.       pTexture->Release();
  138.       pTexture = NULL;
  139.     }
  140.     
  141.     if(pDevice) {
  142.       pDevice->Release();
  143.       pDevice = NULL;
  144.     }
  145.     
  146.     pD3D->Release();
  147.     pD3D = NULL;
  148.  
  149.     if(d3dDLL != NULL) {
  150.       FreeLibrary(d3dDLL);
  151.       d3dDLL = NULL;
  152.     }
  153.   }
  154. }
  155.  
  156. bool Direct3DDisplay::initialize()
  157. {
  158.   theApp.sizeX = 240;
  159.   theApp.sizeY = 160;
  160.  
  161.   switch(theApp.videoOption) {
  162.   case VIDEO_1X:
  163.     theApp.surfaceSizeX = theApp.sizeX;
  164.     theApp.surfaceSizeY = theApp.sizeY;
  165.     break;
  166.   case VIDEO_2X:
  167.     theApp.surfaceSizeX = theApp.sizeX * 2;
  168.     theApp.surfaceSizeY = theApp.sizeY * 2;
  169.     break;
  170.   case VIDEO_3X:
  171.     theApp.surfaceSizeX = theApp.sizeX * 3;
  172.     theApp.surfaceSizeY = theApp.sizeY * 3;
  173.     break;
  174.   case VIDEO_4X:
  175.     theApp.surfaceSizeX = theApp.sizeX * 4;
  176.     theApp.surfaceSizeY = theApp.sizeY * 4;
  177.     break;
  178.   case VIDEO_320x240:
  179.   case VIDEO_640x480:
  180.   case VIDEO_800x600:
  181.   case VIDEO_OTHER:
  182.     {
  183.       RECT r;
  184.       ::GetWindowRect(GetDesktopWindow(), &r);
  185.       theApp.fsWidth = r.right - r.left;
  186.       theApp.fsHeight = r.bottom - r.top;
  187.  
  188.       /* Need to fix this code later. For now, Fullscreen takes the whole
  189.          screen.
  190.          int scaleX = (fsWidth / sizeX);
  191.          int scaleY = (fsHeight / sizeY);
  192.          int min = scaleX < scaleY ? scaleX : scaleY;
  193.          surfaceSizeX = sizeX * min;
  194.          surfaceSizeY = sizeY * min;
  195.          if(fullScreenStretch) {
  196.       */
  197.       theApp.surfaceSizeX = theApp.fsWidth;
  198.       theApp.surfaceSizeY = theApp.fsHeight;
  199.       //      }
  200.     }
  201.     break;
  202.   }
  203.   
  204.   theApp.rect.left = 0;
  205.   theApp.rect.top = 0;
  206.   theApp.rect.right = theApp.sizeX;
  207.   theApp.rect.bottom = theApp.sizeY;
  208.  
  209.   theApp.dest.left = 0;
  210.   theApp.dest.top = 0;
  211.   theApp.dest.right = theApp.surfaceSizeX;
  212.   theApp.dest.bottom = theApp.surfaceSizeY;
  213.  
  214.   DWORD style = WS_POPUP | WS_VISIBLE;
  215.   DWORD styleEx = 0;
  216.   
  217.   if(theApp.videoOption <= VIDEO_4X)
  218.     style |= WS_OVERLAPPEDWINDOW;
  219.   else
  220.     styleEx = 0;
  221.  
  222.   if(theApp.videoOption <= VIDEO_4X)
  223.     AdjustWindowRectEx(&theApp.dest, style, TRUE, styleEx);
  224.   else
  225.     AdjustWindowRectEx(&theApp.dest, style, FALSE, styleEx);    
  226.  
  227.   int winSizeX = theApp.dest.right-theApp.dest.left;
  228.   int winSizeY = theApp.dest.bottom-theApp.dest.top;
  229.  
  230.   if(theApp.videoOption > VIDEO_4X) {
  231.     winSizeX = theApp.fsWidth;
  232.     winSizeY = theApp.fsHeight;
  233.   }
  234.   
  235.   int x = 0;
  236.   int y = 0;
  237.  
  238.   if(theApp.videoOption <= VIDEO_4X) {
  239.     x = theApp.windowPositionX;
  240.     y = theApp.windowPositionY;
  241.   }
  242.   
  243.   // Create a window
  244.   MainWnd *pWnd = new MainWnd;
  245.   theApp.m_pMainWnd = pWnd;
  246.  
  247.   pWnd->CreateEx(styleEx,
  248.                  theApp.wndClass,
  249.                  "VisualBoyAdvance",
  250.                  style,
  251.                  x,y,winSizeX,winSizeY,
  252.                  NULL,
  253.                  0);
  254.   
  255.   if (!(HWND)*pWnd) {
  256.     winlog("Error creating Window %08x\n", GetLastError());
  257.     return FALSE;
  258.   }
  259.   
  260.   theApp.updateMenuBar();
  261.   
  262.   theApp.adjustDestRect();
  263.   
  264.   d3dDLL = LoadLibrary("D3D8.DLL");
  265.   LPDIRECT3D8 (WINAPI *D3DCreate)(UINT);
  266.   if(d3dDLL != NULL) {    
  267.     D3DCreate = (LPDIRECT3D8 (WINAPI *)(UINT))
  268.       GetProcAddress(d3dDLL, "Direct3DCreate8");
  269.  
  270.     if(D3DCreate == NULL) {
  271.       theApp.directXMessage("Direct3DCreate8");
  272.       return FALSE;
  273.     }
  274.   } else {
  275.     theApp.directXMessage("D3D8.DLL");
  276.     return FALSE;
  277.   }
  278.  
  279.   pD3D = D3DCreate(120);
  280.     
  281.   if(pD3D == NULL) {
  282.     winlog("Error creating Direct3D object\n");
  283.     return FALSE;
  284.   }
  285.   
  286.   theApp.mode320Available = FALSE;
  287.   theApp.mode640Available = FALSE;
  288.   theApp.mode800Available = FALSE;
  289.  
  290.   D3DDISPLAYMODE mode;
  291.   pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &mode);
  292.   
  293.   switch(mode.Format) {
  294.   case D3DFMT_R8G8B8:
  295.     systemColorDepth = 24;
  296.     systemRedShift = 19;
  297.     systemGreenShift = 11;
  298.     systemBlueShift = 3;
  299.     break;
  300.   case D3DFMT_X8R8G8B8:
  301.     systemColorDepth = 32;
  302.     systemRedShift = 19;
  303.     systemGreenShift = 11;
  304.     systemBlueShift = 3;
  305.     Init_2xSaI(32);
  306.     break;
  307.   case D3DFMT_R5G6B5:
  308.     systemColorDepth = 16;
  309.     systemRedShift = 11;
  310.     systemGreenShift = 6;
  311.     systemBlueShift = 0;    
  312.     Init_2xSaI(565);
  313.     break;
  314.   case D3DFMT_X1R5G5B5:
  315.     systemColorDepth = 16;
  316.     systemRedShift = 10;
  317.     systemGreenShift = 5;
  318.     systemBlueShift = 0;
  319.     Init_2xSaI(555);
  320.     break;
  321.   default:
  322.     systemMessage(0,"Unsupport D3D format %d", mode.Format);
  323.     return false;
  324.   }
  325.   theApp.fsColorDepth = systemColorDepth;
  326.  
  327. #ifdef MMX
  328.   if(!theApp.disableMMX)
  329.     cpu_mmx = theApp.detectMMX();
  330.   else
  331.     cpu_mmx = 0;
  332. #endif
  333.   
  334.   screenFormat = mode.Format;
  335.  
  336.   // check for available fullscreen modes
  337.   ZeroMemory(&dpp, sizeof(dpp));
  338.   dpp.Windowed = TRUE;
  339.   dpp.BackBufferFormat = mode.Format;
  340.   dpp.BackBufferCount = 1;
  341.   dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
  342.   dpp.BackBufferWidth = theApp.surfaceSizeX;
  343.   dpp.BackBufferHeight = theApp.surfaceSizeY;
  344.   
  345.   HRESULT hret = pD3D->CreateDevice(D3DADAPTER_DEFAULT,
  346.                                     D3DDEVTYPE_HAL,
  347.                                     pWnd->GetSafeHwnd(),
  348.                                     D3DCREATE_SOFTWARE_VERTEXPROCESSING,
  349.                                     &dpp,
  350.                                     &pDevice);
  351.   if(!SUCCEEDED(hret)) {
  352.     winlog("Error creating Direct3DDevice %08x\n", hret);
  353.     return false;
  354.   }
  355.   
  356.   restoreDeviceObjects();
  357.  
  358.   switch(systemColorDepth) {
  359.   case 16:
  360.     {
  361.       for(int i = 0; i < 0x10000; i++) {
  362.         systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
  363.           (((i & 0x3e0) >> 5) << systemGreenShift) |
  364.           (((i & 0x7c00) >> 10) << systemBlueShift);
  365.       }
  366.     }
  367.     break;
  368.   case 24:
  369.   case 32:
  370.     {
  371.       for(int i = 0; i < 0x10000; i++) {
  372.         systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
  373.           (((i & 0x3e0) >> 5) << systemGreenShift) |
  374.           (((i & 0x7c00) >> 10) << systemBlueShift);
  375.       }      
  376.     }
  377.     break;
  378.   }
  379.   
  380.   theApp.updateFilter();
  381.   theApp.updateIFB();
  382.  
  383.   if(failed)
  384.     return false;
  385.   
  386.   pWnd->DragAcceptFiles(TRUE);
  387.   
  388.   return TRUE;  
  389. }
  390.  
  391. bool Direct3DDisplay::initializeOffscreen(int w, int h)
  392. {
  393.   int size = 256;
  394.   if(w > 256 || h > 256)
  395.     size = 512;
  396.  
  397.   UINT ww = size;
  398.   UINT hh = size;
  399.   D3DFORMAT format = screenFormat;
  400.   
  401.   if(SUCCEEDED(D3DXCheckTextureRequirements(pDevice,
  402.                                             &ww,
  403.                                             &hh,
  404.                                             NULL,
  405.                                             0,
  406.                                             &format,
  407.                                             D3DPOOL_MANAGED))) {
  408.     if((int)ww < w || (int)hh < h) {
  409.       if(theApp.filterFunction) {
  410.         filterDisabled = true;
  411.         theApp.filterFunction = NULL;
  412.         systemMessage(0, "3D card cannot support needed texture size for filter function. Disabling it");
  413.       }
  414.     } else
  415.       filterDisabled = false; 
  416.     if(SUCCEEDED(D3DXCreateTexture(pDevice,
  417.                                    ww,
  418.                                    hh,
  419.                                    0,
  420.                                    0,
  421.                                    format,
  422.                                    D3DPOOL_MANAGED,
  423.                                    &pTexture))) {
  424.       width = w;
  425.       height = h;
  426.       return true;
  427.     }
  428.   }
  429.   return false;
  430. }
  431.  
  432. void Direct3DDisplay::updateFiltering(int filter)
  433. {
  434.   switch(filter) {
  435.   default:
  436.   case 0:
  437.     // point filtering
  438.     pDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_POINT );
  439.     pDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_POINT );
  440.     pDevice->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_POINT );
  441.     break;
  442.   case 1:
  443.     // bilinear
  444.     pDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  445.     pDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  446.     pDevice->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_POINT );
  447.     break;
  448.   }
  449. }
  450.  
  451. void Direct3DDisplay::restoreDeviceObjects()
  452. {
  453.   // Store render target surface desc
  454.   LPDIRECT3DSURFACE8 pBackBuffer;
  455.   HRESULT hr;
  456.   if(SUCCEEDED(hr = pDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer ))) {
  457.     pBackBuffer->GetDesc( &dsdBackBuffer );
  458.     pBackBuffer->Release();
  459.   } else
  460.     systemMessage(0, "Failed GetBackBuffer %08x", hr);
  461.   
  462.   // Set up the texture 
  463.   pDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
  464.   pDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  465.   pDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  466.  
  467.   int filter = regQueryDwordValue("d3dFilter", 0);
  468.   if(filter < 0 || filter > 3)
  469.     filter = 0;
  470.   updateFiltering(filter);
  471.  
  472.   // Set miscellaneous render states
  473.   pDevice->SetRenderState( D3DRS_DITHERENABLE,   TRUE );
  474.   pDevice->SetRenderState( D3DRS_ZENABLE,        FALSE );
  475.  
  476.   // Set the projection matrix
  477.   D3DXMATRIX matProj;
  478.   FLOAT fAspect = ((FLOAT)dsdBackBuffer.Width) / dsdBackBuffer.Height;
  479.   D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, fAspect, 1.0f, 100.0f );
  480.   pDevice->SetTransform( D3DTS_PROJECTION, &matProj );
  481.  
  482.   // turn off lighting
  483.   pDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
  484.  
  485.   if(pFont) {
  486.     pFont->Release();
  487.     pFont = NULL;
  488.   }
  489.   // Create a D3D font using D3DX
  490.   HFONT hFont = CreateFont( 14, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
  491.                             ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  492.                             ANTIALIASED_QUALITY, FF_DONTCARE, "Arial" );      
  493.   D3DXCreateFont( pDevice, hFont, &pFont );
  494. }
  495.  
  496. void Direct3DDisplay::clear()
  497. {
  498. }
  499.  
  500. void Direct3DDisplay::renderMenu()
  501. {
  502.   checkFullScreen();
  503.   if(theApp.m_pMainWnd)
  504.     theApp.m_pMainWnd->DrawMenuBar();
  505. }
  506.  
  507. void Direct3DDisplay::checkFullScreen()
  508. {
  509.   //  if(tripleBuffering)
  510.   //    pDirect3D->FlipToGDISurface();
  511. }
  512.  
  513. static void BlitRect(LPDIRECT3DDEVICE8 lpDevice,
  514.                      LPDIRECT3DTEXTURE8 lpSrc,
  515.                      float left, float top,
  516.                      float right, float bottom,
  517.                      D3DCOLOR col,float z)
  518. {
  519.   // calculate rhw
  520.  
  521.   float rhw=1.0f/(z*990.0f+10.0f);
  522.  
  523.   // set up rectangle
  524.  
  525.   D3DTLVERTEX verts[4];
  526.   verts[0]=D3DTLVERTEX(D3DXVECTOR3(left-0.5f,  top-0.5f,    z),rhw,col,0.0f,0.0f); 
  527.   verts[1]=D3DTLVERTEX(D3DXVECTOR3(right-0.5f, top-0.5f,    z),rhw,col,1.0f,0.0f);
  528.   verts[2]=D3DTLVERTEX(D3DXVECTOR3(right-0.5f, bottom-0.5f, z),rhw,col,1.0f,1.0f); 
  529.   verts[3]=D3DTLVERTEX(D3DXVECTOR3(left-0.5f,  bottom-0.5f, z),rhw,col,0.0f,1.0f);
  530.  
  531.   // set the texture
  532.  
  533.   lpDevice->SetTexture(0,lpSrc);
  534.  
  535.   // configure shader for vertex type
  536.  
  537.   lpDevice->SetVertexShader(D3DFVF_TLVERTEX);
  538.  
  539.   // draw the rectangle
  540.  
  541.   lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN,2,verts,sizeof(D3DTLVERTEX));
  542. }
  543.  
  544. void Direct3DDisplay::render()
  545. {
  546.   if(!pDevice)
  547.     return;
  548.   
  549.   // Test the cooperative level to see if it's okay to render
  550.   if( FAILED( pDevice->TestCooperativeLevel() ) )
  551.     {
  552.       return;
  553.     }
  554.   pDevice->Clear( 0L, NULL, D3DCLEAR_TARGET, 0x000000ff, 1.0f, 0L );
  555.  
  556.   if(SUCCEEDED(pDevice->BeginScene())) {
  557.     D3DLOCKED_RECT locked;
  558.     if(pTexture && SUCCEEDED(pTexture->LockRect(0, &locked, NULL, 0))) {
  559.       if(theApp.filterFunction) {
  560.         if(systemColorDepth == 16)
  561.           theApp.filterFunction(pix+theApp.filterWidth*2+4,
  562.                                 theApp.filterWidth*2+4,
  563.                                 (u8*)theApp.delta,
  564.                                 (u8*)locked.pBits,
  565.                                 locked.Pitch,
  566.                                 theApp.filterWidth,
  567.                                 theApp.filterHeight);
  568.         else
  569.           theApp.filterFunction(pix+theApp.filterWidth*4+4,
  570.                                 theApp.filterWidth*4+4,
  571.                                 (u8*)theApp.delta,
  572.                                 (u8*)locked.pBits,
  573.                                 locked.Pitch,
  574.                                 theApp.filterWidth,
  575.                                 theApp.filterHeight);
  576.       } else {
  577.         int copyX = 240;
  578.         int copyY = 160;
  579.         
  580.         if(theApp.cartridgeType == 1) {
  581.           if(gbBorderOn) {
  582.             copyX = 256;
  583.             copyY = 224;
  584.           } else {
  585.             copyX = 160;
  586.             copyY = 144;
  587.           }
  588.         }
  589.         // MMX doesn't seem to be faster to copy the data
  590.         __asm {
  591.           mov eax, copyX;
  592.           mov ebx, copyY;
  593.           
  594.           mov esi, pix;
  595.           mov edi, locked.pBits;
  596.           mov edx, locked.Pitch;
  597.           cmp systemColorDepth, 16;
  598.           jnz gbaOtherColor;
  599.           sub edx, eax;
  600.           sub edx, eax;
  601.           lea esi,[esi+2*eax+4];
  602.           shr eax, 1;
  603.         gbaLoop16bit:
  604.           mov ecx, eax;
  605.           repz movsd;
  606.           inc esi;
  607.           inc esi;
  608.           inc esi;
  609.           inc esi;
  610.           add edi, edx;
  611.           dec ebx;
  612.           jnz gbaLoop16bit;
  613.           jmp gbaLoopEnd;
  614.         gbaOtherColor:
  615.           cmp systemColorDepth, 32;
  616.           jnz gbaOtherColor2;
  617.           
  618.           sub edx, eax;
  619.           sub edx, eax;
  620.           sub edx, eax;
  621.           sub edx, eax;
  622.           lea esi, [esi+4*eax+4];
  623.         gbaLoop32bit:
  624.           mov ecx, eax;
  625.           repz movsd;
  626.           add esi, 4;
  627.           add edi, edx;
  628.           dec ebx;
  629.           jnz gbaLoop32bit;
  630.           jmp gbaLoopEnd;
  631.         gbaOtherColor2:
  632.           lea eax, [eax+2*eax];
  633.           sub edx, eax;
  634.         gbaLoop24bit:
  635.           mov ecx, eax;
  636.           shr ecx, 2;
  637.           repz movsd;
  638.           add edi, edx;
  639.           dec ebx;
  640.           jnz gbaLoop24bit;
  641.         gbaLoopEnd:
  642.         }
  643.       }
  644.  
  645.       if(theApp.videoOption > VIDEO_4X && theApp.showSpeed) {
  646.         char buffer[30];
  647.         if(theApp.showSpeed == 1)
  648.           sprintf(buffer, "%3d%%", systemSpeed);
  649.         else
  650.           sprintf(buffer, "%3d%%(%d, %d fps)", systemSpeed,
  651.                   systemFrameSkip,
  652.                   theApp.showRenderedFrames);
  653.         if(theApp.showSpeedTransparent)
  654.           drawTextTransp((u8*)locked.pBits,
  655.                          locked.Pitch,
  656.                          theApp.rect.left+10,
  657.                          theApp.rect.bottom-10,
  658.                          buffer);
  659.         else
  660.           drawText((u8*)locked.pBits,
  661.                    locked.Pitch,
  662.                    theApp.rect.left+10,
  663.                    theApp.rect.bottom-10,
  664.                    buffer);
  665.       }
  666.       
  667.       pTexture->UnlockRect(0);
  668.  
  669.       float scaleX = (float)theApp.surfaceSizeX / theApp.sizeX;
  670.       float scaleY = (float)theApp.surfaceSizeY / theApp.sizeY;
  671.       BlitRect(pDevice, pTexture, 0, 0, scaleX*256, scaleY*256, 0xffffff, 0.1f);
  672.     }
  673.     
  674.     if(theApp.screenMessage) {
  675.       if(((GetTickCount() - theApp.screenMessageTime) < 3000) &&
  676.          !theApp.disableStatusMessage && pFont) {
  677.         D3DCOLOR color = D3DCOLOR_ARGB(255, 255, 0, 0);
  678.         pFont->Begin();
  679.         RECT r;
  680.         r.left = 10;
  681.         r.top = dpp.BackBufferHeight - 20;
  682.         r.right = dpp.BackBufferWidth - 10;
  683.         r.bottom = r.top + 20;
  684.  
  685.         pFont->DrawText(theApp.screenMessageBuffer, -1, &r, 0, color);
  686.         pFont->End();
  687.       } else {
  688.         theApp.screenMessage = false;
  689.       }
  690.     }
  691.     
  692.     pDevice->EndScene();
  693.  
  694.     pDevice->Present( NULL, NULL, NULL, NULL );    
  695.   }
  696. }
  697.  
  698. void Direct3DDisplay::invalidateDeviceObjects()
  699. {
  700.   if(pFont)
  701.     pFont->Release();
  702.   pFont = NULL;
  703. }
  704.  
  705. void Direct3DDisplay::resize(int w, int h)
  706. {
  707.   if(pDevice) {
  708.     dpp.BackBufferWidth = w;
  709.     dpp.BackBufferHeight = h;
  710.     HRESULT hr;
  711.     invalidateDeviceObjects();
  712.     if(SUCCEEDED(hr = pDevice->Reset(&dpp))) {
  713.       restoreDeviceObjects();
  714.     } else
  715.       systemMessage(0, "Failed device reset %08x", hr);
  716.   }
  717. }
  718.  
  719. bool Direct3DDisplay::changeRenderSize(int w, int h)
  720. {
  721.   if(w != width || h != height) {
  722.     if(pTexture) {
  723.       pTexture->Release();
  724.       pTexture = NULL;
  725.     }
  726.     if(!initializeOffscreen(w, h)) {
  727.       failed = true;
  728.       return false;
  729.     }
  730.   }
  731.   if(filterDisabled && theApp.filterFunction)
  732.     theApp.filterFunction = NULL;
  733.  
  734.   return true;
  735. }
  736.  
  737. void Direct3DDisplay::setOption(const char *option, int value)
  738. {
  739.   if(!strcmp(option, "d3dFilter"))
  740.     updateFiltering(value);
  741. }
  742.  
  743. int Direct3DDisplay::selectFullScreenMode(GUID **)
  744. {
  745.   HWND wnd = GetDesktopWindow();
  746.   RECT r;
  747.   GetWindowRect(wnd, &r);
  748.   int w = (r.right - r.left) & 4095;
  749.   int h = (r.bottom - r.top) & 4095;
  750.   HDC dc = GetDC(wnd);
  751.   int c = GetDeviceCaps(dc, BITSPIXEL);
  752.   ReleaseDC(wnd, dc);
  753.  
  754.   return (c << 24) | (w << 12) | h;
  755. }
  756.  
  757. IDisplay *newDirect3DDisplay()
  758. {
  759.   return new Direct3DDisplay();
  760. }
  761.  
  762.