home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 July / CMCD0704.ISO / Software / Freeware / Utilitare / VisualBoyAdvance-1.7.2 / src / win32 / OpenGL.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-05-13  |  14.0 KB  |  566 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 "MainWnd.h"
  21. #include <gl/GL.h>
  22.  
  23. #include "../System.h"
  24. #include "../GBA.h"
  25. #include "../Globals.h"
  26. #include "../Text.h"
  27.  
  28. #include "Reg.h"
  29. #include "resource.h"
  30.  
  31. #ifdef _DEBUG
  32. #define new DEBUG_NEW
  33. #undef THIS_FILE
  34. static char THIS_FILE[] = __FILE__;
  35. #endif
  36.  
  37. #ifdef MMX
  38. extern "C" bool cpu_mmx;
  39.  
  40. extern bool detectMMX();
  41. #endif
  42.  
  43. extern int Init_2xSaI(u32);
  44. extern void winlog(const char *,...);
  45. extern int systemSpeed;
  46.  
  47. class OpenGLDisplay : public IDisplay {
  48. private:
  49.   HDC hDC;
  50.   HGLRC hglrc;
  51.   GLuint texture;
  52.   int width;
  53.   int height;
  54.   float size;
  55.   u8 *filterData;
  56.   bool failed;
  57.   
  58.   bool initializeTexture(int w, int h);
  59.   void updateFiltering(int);
  60. public:
  61.   OpenGLDisplay();
  62.   virtual ~OpenGLDisplay();
  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 void resize(int w, int h);
  72.   virtual DISPLAY_TYPE getType() { return OPENGL; };
  73.   virtual void setOption(const char *, int);
  74.   virtual int selectFullScreenMode(GUID **);  
  75. };
  76.  
  77. OpenGLDisplay::OpenGLDisplay()
  78. {
  79.   hDC = NULL;
  80.   hglrc = NULL;
  81.   texture = 0;
  82.   width = 0;
  83.   height = 0;
  84.   size = 0.0f;
  85.   filterData = (u8 *)malloc(4*4*256*240);
  86.   failed = false;
  87. }
  88.  
  89. OpenGLDisplay::~OpenGLDisplay()
  90. {
  91.   cleanup();
  92. }
  93.  
  94. void OpenGLDisplay::cleanup()
  95. {
  96.   if(texture != 0) {
  97.     glDeleteTextures(1, &texture);
  98.     texture = 0;
  99.   }
  100.   if(hglrc != NULL) {
  101.     wglDeleteContext(hglrc);
  102.     wglMakeCurrent(NULL, NULL);
  103.     hglrc = NULL;
  104.   }
  105.   if(hDC != NULL) {
  106.     ReleaseDC(*theApp.m_pMainWnd, hDC);
  107.     hDC = NULL;
  108.   }
  109.   if(filterData) {
  110.     free(filterData);
  111.     filterData = NULL;
  112.   }
  113.   width = 0;
  114.   height = 0;
  115.   size = 0.0f;
  116. }
  117.  
  118. bool OpenGLDisplay::initialize()
  119. {
  120.   theApp.sizeX = 240;
  121.   theApp.sizeY = 160;
  122.  
  123.   switch(theApp.videoOption) {
  124.   case VIDEO_1X:
  125.     theApp.surfaceSizeX = theApp.sizeX;
  126.     theApp.surfaceSizeY = theApp.sizeY;
  127.     break;
  128.   case VIDEO_2X:
  129.     theApp.surfaceSizeX = theApp.sizeX * 2;
  130.     theApp.surfaceSizeY = theApp.sizeY * 2;
  131.     break;
  132.   case VIDEO_3X:
  133.     theApp.surfaceSizeX = theApp.sizeX * 3;
  134.     theApp.surfaceSizeY = theApp.sizeY * 3;
  135.     break;
  136.   case VIDEO_4X:
  137.     theApp.surfaceSizeX = theApp.sizeX * 4;
  138.     theApp.surfaceSizeY = theApp.sizeY * 4;
  139.     break;
  140.   case VIDEO_320x240:
  141.   case VIDEO_640x480:
  142.   case VIDEO_800x600:
  143.   case VIDEO_OTHER:
  144.     {
  145.       RECT r;
  146.       ::GetWindowRect(GetDesktopWindow(), &r);
  147.       theApp.fsWidth = r.right - r.left;
  148.       theApp.fsHeight = r.bottom - r.top;
  149.  
  150.       /* Need to fix this code later. For now, Fullscreen takes the whole
  151.          screen.
  152.          int scaleX = (fsWidth / sizeX);
  153.          int scaleY = (fsHeight / sizeY);
  154.          int min = scaleX < scaleY ? scaleX : scaleY;
  155.          surfaceSizeX = sizeX * min;
  156.          surfaceSizeY = sizeY * min;
  157.          if(fullScreenStretch) {
  158.       */
  159.       theApp.surfaceSizeX = theApp.fsWidth;
  160.       theApp.surfaceSizeY = theApp.fsHeight;
  161.       //      }
  162.     }
  163.     break;
  164.   }
  165.   
  166.   theApp.rect.left = 0;
  167.   theApp.rect.top = 0;
  168.   theApp.rect.right = theApp.sizeX;
  169.   theApp.rect.bottom = theApp.sizeY;
  170.  
  171.   theApp.dest.left = 0;
  172.   theApp.dest.top = 0;
  173.   theApp.dest.right = theApp.surfaceSizeX;
  174.   theApp.dest.bottom = theApp.surfaceSizeY;
  175.  
  176.   DWORD style = WS_POPUP | WS_VISIBLE;
  177.   DWORD styleEx = 0;
  178.   
  179.   if(theApp.videoOption <= VIDEO_4X)
  180.     style |= WS_OVERLAPPEDWINDOW;
  181.   else
  182.     styleEx = 0;
  183.  
  184.   if(theApp.videoOption <= VIDEO_4X)
  185.     AdjustWindowRectEx(&theApp.dest, style, TRUE, styleEx);
  186.   else
  187.     AdjustWindowRectEx(&theApp.dest, style, FALSE, styleEx);    
  188.  
  189.   int winSizeX = theApp.dest.right-theApp.dest.left;
  190.   int winSizeY = theApp.dest.bottom-theApp.dest.top;
  191.  
  192.   if(theApp.videoOption > VIDEO_4X) {
  193.     winSizeX = theApp.fsWidth;
  194.     winSizeY = theApp.fsHeight;
  195.   }
  196.   
  197.   int x = 0;
  198.   int y = 0;
  199.  
  200.   if(theApp.videoOption <= VIDEO_4X) {
  201.     x = theApp.windowPositionX;
  202.     y = theApp.windowPositionY;
  203.   }
  204.   
  205.   // Create a window
  206.   MainWnd *pWnd = new MainWnd;
  207.   theApp.m_pMainWnd = pWnd;
  208.  
  209.   pWnd->CreateEx(styleEx,
  210.                  theApp.wndClass,
  211.                  "VisualBoyAdvance",
  212.                  style,
  213.                  x,y,winSizeX,winSizeY,
  214.                  NULL,
  215.                  0);
  216.   
  217.   if (!(HWND)*pWnd) {
  218.     winlog("Error creating Window %08x\n", GetLastError());
  219.     return FALSE;
  220.   }
  221.   
  222.   theApp.updateMenuBar();
  223.   
  224.   theApp.adjustDestRect();
  225.   
  226.   theApp.mode320Available = FALSE;
  227.   theApp.mode640Available = FALSE;
  228.   theApp.mode800Available = FALSE;
  229.  
  230.   CDC *dc = pWnd->GetDC();
  231.   HDC hDC = dc->GetSafeHdc();
  232.  
  233.   PIXELFORMATDESCRIPTOR pfd = { 
  234.     sizeof(PIXELFORMATDESCRIPTOR),  //  size of this pfd 
  235.     1,                     // version number 
  236.     PFD_DRAW_TO_WINDOW |   // support window 
  237.     PFD_SUPPORT_OPENGL |   // support OpenGL 
  238.     PFD_DOUBLEBUFFER,      // double buffered 
  239.     PFD_TYPE_RGBA,         // RGBA type 
  240.     16,                    // 16-bit color depth 
  241.     0, 0, 0, 0, 0, 0,      // color bits ignored 
  242.     0,                     // no alpha buffer 
  243.     0,                     // shift bit ignored 
  244.     0,                     // no accumulation buffer 
  245.     0, 0, 0, 0,            // accum bits ignored 
  246.     32,                    // 32-bit z-buffer     
  247.     0,                     // no stencil buffer 
  248.     0,                     // no auxiliary buffer 
  249.     PFD_MAIN_PLANE,        // main layer 
  250.     0,                     // reserved 
  251.     0, 0, 0                // layer masks ignored 
  252.   }; 
  253.   int  iPixelFormat; 
  254.   
  255.   if(!(iPixelFormat = ChoosePixelFormat(hDC, &pfd))) {
  256.     winlog("Failed ChoosePixelFormat\n");
  257.     return false;
  258.   }
  259.  
  260.   // obtain detailed information about 
  261.   // the device context's first pixel format
  262.   if(!(DescribePixelFormat(hDC, iPixelFormat,  
  263.                            sizeof(PIXELFORMATDESCRIPTOR), &pfd))) {
  264.     winlog("Failed DescribePixelFormat\n");
  265.     return false;
  266.   }
  267.  
  268.   if(!SetPixelFormat(hDC, iPixelFormat, &pfd)) {
  269.     winlog("Failed SetPixelFormat\n");
  270.     return false;
  271.   }
  272.  
  273.   if(!(hglrc = wglCreateContext(hDC))) {
  274.     winlog("Failed wglCreateContext\n");
  275.     return false;
  276.   }
  277.  
  278.   if(!wglMakeCurrent(hDC, hglrc)) {
  279.     winlog("Failed wglMakeCurrent\n");
  280.     return false;
  281.   }
  282.   pWnd->ReleaseDC(dc);
  283.   
  284.   // setup 2D gl environment
  285.   glPushAttrib(GL_ENABLE_BIT);
  286.   glDisable(GL_DEPTH_TEST);
  287.   glDisable(GL_CULL_FACE);
  288.   glEnable(GL_TEXTURE_2D);
  289.  
  290.   glViewport(0, 0, theApp.surfaceSizeX, theApp.surfaceSizeY);
  291.  
  292.   glMatrixMode(GL_PROJECTION);
  293.   glLoadIdentity();
  294.  
  295.   glOrtho(0.0, (GLdouble)(theApp.surfaceSizeX), (GLdouble)(theApp.surfaceSizeY),
  296.           0.0, 0.0,1.0);
  297.   glMatrixMode(GL_MODELVIEW);
  298.   glLoadIdentity();
  299.  
  300.   systemRedShift = 3;
  301.   systemGreenShift = 11;
  302.   systemBlueShift = 19;
  303.   systemColorDepth = 32;
  304.   theApp.fsColorDepth = 32;
  305.   
  306.   Init_2xSaI(32);
  307. #ifdef MMX
  308.   if(!theApp.disableMMX)
  309.     cpu_mmx = theApp.detectMMX();
  310.   else
  311.     cpu_mmx = 0;
  312. #endif
  313.   
  314.   if(theApp.ddrawDebug) {
  315.     winlog("R shift: %d\n", systemRedShift);
  316.     winlog("G shift: %d\n", systemGreenShift);
  317.     winlog("B shift: %d\n", systemBlueShift);
  318.   }
  319.          
  320.   switch(systemColorDepth) {
  321.   case 16:
  322.     {
  323.       for(int i = 0; i < 0x10000; i++) {
  324.         systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
  325.           (((i & 0x3e0) >> 5) << systemGreenShift) |
  326.           (((i & 0x7c00) >> 10) << systemBlueShift);
  327.       }
  328.     }
  329.     break;
  330.   case 24:
  331.   case 32:
  332.     {
  333.       for(int i = 0; i < 0x10000; i++) {
  334.         systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
  335.           (((i & 0x3e0) >> 5) << systemGreenShift) |
  336.           (((i & 0x7c00) >> 10) << systemBlueShift);
  337.       }      
  338.     }
  339.     break;
  340.   }
  341.   theApp.updateFilter();
  342.   theApp.updateIFB();
  343.  
  344.   if(failed)
  345.     return false;
  346.   
  347.   pWnd->DragAcceptFiles(TRUE);
  348.   
  349.   return TRUE;  
  350. }
  351.  
  352. void OpenGLDisplay::clear()
  353. {
  354. }
  355.  
  356. void OpenGLDisplay::renderMenu()
  357. {
  358.   checkFullScreen();
  359.   if(theApp.m_pMainWnd)
  360.     theApp.m_pMainWnd->DrawMenuBar();
  361. }
  362.  
  363. void OpenGLDisplay::checkFullScreen()
  364. {
  365.   //  if(tripleBuffering)
  366.   //    pOpenGL->FlipToGDISurface();
  367. }
  368.  
  369. void OpenGLDisplay::render()
  370. {
  371.   int pitch = theApp.filterWidth * 4 + 4;
  372.   u8 *data = pix + (theApp.sizeX+1)*4;
  373.   
  374.   if(theApp.filterFunction) {
  375.     data = filterData;
  376.     theApp.filterFunction(pix+pitch,
  377.                           pitch,
  378.                           (u8*)theApp.delta,
  379.                           (u8*)filterData,
  380.                           theApp.filterWidth*4*2,
  381.                           theApp.filterWidth,
  382.                           theApp.filterHeight);
  383.   }
  384.  
  385.   if(theApp.videoOption > VIDEO_4X && theApp.showSpeed) {
  386.     char buffer[30];
  387.     if(theApp.showSpeed == 1)
  388.       sprintf(buffer, "%3d%%", systemSpeed);
  389.     else
  390.       sprintf(buffer, "%3d%%(%d, %d fps)", systemSpeed,
  391.               systemFrameSkip,
  392.               theApp.showRenderedFrames);
  393.  
  394.     if(theApp.filterFunction) {
  395.       int p = theApp.filterWidth * 4;
  396.       if(systemColorDepth == 24)
  397.         p = theApp.filterWidth * 6;
  398.       else if(systemColorDepth == 32)
  399.         p = theApp.filterWidth * 8;
  400.       if(theApp.showSpeedTransparent)
  401.         drawTextTransp((u8*)filterData,
  402.                        p,
  403.                        10,
  404.                        theApp.filterHeight*2-10,
  405.                        buffer);
  406.       else
  407.         drawText((u8*)filterData,
  408.                  p,
  409.                  10,
  410.                  theApp.filterHeight*2-10,
  411.                  buffer);      
  412.     } else {
  413.       if(theApp.showSpeedTransparent)
  414.         drawTextTransp((u8*)pix,
  415.                        pitch,
  416.                        10,
  417.                        theApp.filterHeight-10,
  418.                        buffer);
  419.       else
  420.         drawText((u8*)pix,
  421.                  pitch,
  422.                  10,
  423.                  theApp.filterHeight-10,
  424.                  buffer);
  425.     }
  426.   }
  427.   
  428.   // Texturemap complete texture to surface so we have free scaling 
  429.   // and antialiasing
  430.   int mult = 1;
  431.   if(theApp.filterFunction) {
  432.     glPixelStorei(GL_UNPACK_ROW_LENGTH, 2*theApp.sizeX);
  433.     mult = 2;
  434.   } else {
  435.     glPixelStorei(GL_UNPACK_ROW_LENGTH, theApp.sizeX+1);
  436.   }
  437.  
  438.   glTexSubImage2D( GL_TEXTURE_2D,0,
  439.                    0,0, mult*theApp.sizeX,mult*theApp.sizeY,
  440.                    GL_RGBA,GL_UNSIGNED_BYTE,data);
  441.  
  442.   if(theApp.glType == 0) {
  443.     glBegin(GL_TRIANGLE_STRIP);
  444.     glTexCoord2f(0.0, 0.0); glVertex3i(0, 0, 0);
  445.     glTexCoord2f(mult*theApp.sizeX/size, 0.0); glVertex3i(theApp.surfaceSizeX, 0, 0);
  446.     glTexCoord2f(0.0, mult*theApp.sizeY/size); glVertex3i(0, theApp.surfaceSizeY, 0);
  447.     glTexCoord2f(mult*theApp.sizeX/size, mult*theApp.sizeY/size); glVertex3i(theApp.surfaceSizeX, theApp.surfaceSizeY, 0);
  448.     glEnd();
  449.   } else {
  450.     glBegin(GL_QUADS);
  451.     glTexCoord2f(0.0, 0.0); glVertex3i(0, 0, 0);
  452.     glTexCoord2f(mult*theApp.sizeX/size, 0.0); glVertex3i(theApp.surfaceSizeX, 0, 0);
  453.     glTexCoord2f(mult*theApp.sizeX/size, mult*theApp.sizeY/size); glVertex3i(theApp.surfaceSizeX, theApp.surfaceSizeY, 0);
  454.     glTexCoord2f(0.0, mult*theApp.sizeY/size); glVertex3i(0, theApp.surfaceSizeY, 0);
  455.     glEnd();
  456.   }
  457.  
  458.   CDC *dc = theApp.m_pMainWnd->GetDC();
  459.  
  460.   if(theApp.screenMessage) {
  461.     if(((GetTickCount() - theApp.screenMessageTime) < 3000) &&
  462.        !theApp.disableStatusMessage) {
  463.       dc->SetTextColor(RGB(255,0,0));
  464.       dc->SetBkMode(TRANSPARENT);
  465.       dc->TextOut(10, theApp.surfaceSizeY - 20, theApp.screenMessageBuffer);
  466.     } else {
  467.       theApp.screenMessage = false;
  468.     }
  469.   }  
  470.   
  471.   SwapBuffers(dc->GetSafeHdc());
  472.   
  473.   theApp.m_pMainWnd->ReleaseDC(dc);
  474. }
  475.  
  476. void OpenGLDisplay::resize(int w, int h)
  477. {
  478.   glViewport(0, 0, w, h);
  479.   glMatrixMode(GL_PROJECTION);
  480.   glLoadIdentity();
  481.  
  482.   glOrtho(0.0, (GLdouble)(w), (GLdouble)(h),
  483.           0.0, 0.0,1.0);
  484.   glMatrixMode(GL_MODELVIEW);
  485.   glLoadIdentity();
  486. }
  487.  
  488. void OpenGLDisplay::updateFiltering(int value)
  489. {
  490.   switch(value) {
  491.   case 0:
  492.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  493.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  494.     break;
  495.   case 1:
  496.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  497.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  498.     break;
  499.   }
  500. }
  501.  
  502. bool OpenGLDisplay::initializeTexture(int w, int h)
  503. {
  504.   int mySize = 256;
  505.   size = 256.0f;
  506.   if(w > 255 || h > 255) {
  507.     size = 512.0f;
  508.     mySize = 512;
  509.   }
  510.   glGenTextures(1, &texture);
  511.   glBindTexture(GL_TEXTURE_2D, texture);
  512.  
  513.   int filter = regQueryDwordValue("glFilter", 0);
  514.   if(filter < 0 || filter > 1)
  515.     filter = 0;
  516.   updateFiltering(filter);
  517.   
  518.   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mySize, mySize, 0, GL_RGBA,
  519.                GL_UNSIGNED_BYTE, NULL );
  520.   width = w;
  521.   height = h;
  522.  
  523.   return true;
  524. }
  525.  
  526. bool OpenGLDisplay::changeRenderSize(int w, int h)
  527. {
  528.   if(width != w || height != h) {
  529.     if(texture != 0) {
  530.       glDeleteTextures(1, &texture);
  531.       texture = 0;
  532.     }
  533.     if(!initializeTexture(w, h)) {
  534.       failed = true;
  535.       return false;
  536.     }
  537.   }
  538.   return true;
  539. }
  540.  
  541. void OpenGLDisplay::setOption(const char *option, int value)
  542. {
  543.   if(!strcmp(option, "glFilter"))
  544.     updateFiltering(value);
  545. }
  546.  
  547. int OpenGLDisplay::selectFullScreenMode(GUID **)
  548. {
  549.   HWND wnd = GetDesktopWindow();
  550.   RECT r;
  551.   GetWindowRect(wnd, &r);
  552.   int w = (r.right - r.left) & 4095;
  553.   int h = (r.bottom - r.top) & 4095;
  554.   HDC dc = GetDC(wnd);
  555.   int c = GetDeviceCaps(dc, BITSPIXEL);
  556.   ReleaseDC(wnd, dc);
  557.  
  558.   return (c << 24) | (w << 12) | h;
  559. }
  560.  
  561. IDisplay *newOpenGLDisplay()
  562. {
  563.   return new OpenGLDisplay();
  564. }
  565.  
  566.