rlm@1: #include "stdafx.h" rlm@1: #include rlm@1: rlm@1: #include "resource.h" rlm@1: #include "MainWnd.h" rlm@1: #include "Reg.h" rlm@1: #include "VBA.h" rlm@1: rlm@1: #include "../gba/GBAGlobals.h" rlm@1: #include "../gb/gbGlobals.h" rlm@1: #include "../common/Text.h" rlm@1: #include "../version.h" rlm@1: rlm@1: #ifdef MMX rlm@1: extern "C" bool cpu_mmx; rlm@1: rlm@1: extern bool detectMMX(); rlm@1: #endif rlm@1: rlm@1: extern int systemSpeed; rlm@1: extern int Init_2xSaI(u32); rlm@1: extern void winlog(const char *, ...); rlm@1: rlm@1: class OpenGLDisplay : public IDisplay rlm@1: { rlm@1: private: rlm@1: HDC hDC; rlm@1: HGLRC hglrc; rlm@1: GLuint texture; rlm@1: int width; rlm@1: int height; rlm@1: float size; rlm@1: u8 * filterData; rlm@1: bool failed; rlm@1: rlm@1: bool initializeTexture(int w, int h); rlm@1: void updateFiltering(int); rlm@1: public: rlm@1: OpenGLDisplay(); rlm@1: virtual ~OpenGLDisplay(); rlm@1: rlm@1: virtual bool initialize(); rlm@1: virtual void cleanup(); rlm@1: virtual void render(); rlm@1: virtual void checkFullScreen(); rlm@1: virtual void renderMenu(); rlm@1: virtual void clear(); rlm@1: virtual bool changeRenderSize(int w, int h); rlm@1: virtual void resize(int w, int h); rlm@1: virtual DISPLAY_TYPE getType() { return OPENGL; }; rlm@1: virtual void setOption(const char *, int); rlm@1: virtual int selectFullScreenMode(GUID * *); rlm@1: }; rlm@1: rlm@1: OpenGLDisplay::OpenGLDisplay() rlm@1: { rlm@1: hDC = NULL; rlm@1: hglrc = NULL; rlm@1: texture = 0; rlm@1: width = 0; rlm@1: height = 0; rlm@1: size = 0.0f; rlm@1: filterData = (u8 *)malloc(4*16*256*256); // sufficient for 4x filters @ 32bit color depth rlm@1: failed = false; rlm@1: } rlm@1: rlm@1: OpenGLDisplay::~OpenGLDisplay() rlm@1: { rlm@1: cleanup(); rlm@1: } rlm@1: rlm@1: void OpenGLDisplay::cleanup() rlm@1: { rlm@1: if (texture != 0) rlm@1: { rlm@1: glDeleteTextures(1, &texture); rlm@1: texture = 0; rlm@1: } rlm@1: if (hglrc != NULL) rlm@1: { rlm@1: wglDeleteContext(hglrc); rlm@1: wglMakeCurrent(NULL, NULL); rlm@1: hglrc = NULL; rlm@1: } rlm@1: if (hDC != NULL) rlm@1: { rlm@1: ReleaseDC(*theApp.m_pMainWnd, hDC); rlm@1: hDC = NULL; rlm@1: } rlm@1: if (filterData) rlm@1: { rlm@1: free(filterData); rlm@1: filterData = NULL; rlm@1: } rlm@1: width = 0; rlm@1: height = 0; rlm@1: size = 0.0f; rlm@1: } rlm@1: rlm@1: bool OpenGLDisplay::initialize() rlm@1: { rlm@1: CWnd *pWnd = theApp.m_pMainWnd; rlm@1: rlm@1: theApp.mode320Available = false; rlm@1: theApp.mode640Available = false; rlm@1: theApp.mode800Available = false; rlm@1: rlm@1: CDC *dc = pWnd->GetDC(); rlm@1: HDC hDC = dc->GetSafeHdc(); rlm@1: rlm@1: PIXELFORMATDESCRIPTOR pfd = { rlm@1: sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd rlm@1: 1, // version number rlm@1: PFD_DRAW_TO_WINDOW | // support window rlm@1: PFD_SUPPORT_OPENGL | // support OpenGL rlm@1: PFD_DOUBLEBUFFER, // double buffered rlm@1: PFD_TYPE_RGBA, // RGBA type rlm@1: 16, // 16-bit color depth rlm@1: 0, 0, 0, 0, 0, 0, // color bits ignored rlm@1: 0, // no alpha buffer rlm@1: 0, // shift bit ignored rlm@1: 0, // no accumulation buffer rlm@1: 0, 0, 0, 0, // accum bits ignored rlm@1: 32, // 32-bit z-buffer rlm@1: 0, // no stencil buffer rlm@1: 0, // no auxiliary buffer rlm@1: PFD_MAIN_PLANE, // main layer rlm@1: 0, // reserved rlm@1: 0, 0, 0 // layer masks ignored rlm@1: }; rlm@1: int iPixelFormat; rlm@1: rlm@1: if (!(iPixelFormat = ChoosePixelFormat(hDC, &pfd))) rlm@1: { rlm@1: winlog("Failed ChoosePixelFormat\n"); rlm@1: return false; rlm@1: } rlm@1: rlm@1: // obtain detailed information about rlm@1: // the device context's first pixel format rlm@1: if (!(DescribePixelFormat(hDC, iPixelFormat, rlm@1: sizeof(PIXELFORMATDESCRIPTOR), &pfd))) rlm@1: { rlm@1: winlog("Failed DescribePixelFormat\n"); rlm@1: return false; rlm@1: } rlm@1: rlm@1: if (!SetPixelFormat(hDC, iPixelFormat, &pfd)) rlm@1: { rlm@1: winlog("Failed SetPixelFormat\n"); rlm@1: return false; rlm@1: } rlm@1: rlm@1: if (!(hglrc = wglCreateContext(hDC))) rlm@1: { rlm@1: winlog("Failed wglCreateContext\n"); rlm@1: return false; rlm@1: } rlm@1: rlm@1: if (!wglMakeCurrent(hDC, hglrc)) rlm@1: { rlm@1: winlog("Failed wglMakeCurrent\n"); rlm@1: return false; rlm@1: } rlm@1: pWnd->ReleaseDC(dc); rlm@1: rlm@1: // setup 2D gl environment rlm@1: glPushAttrib(GL_ENABLE_BIT); rlm@1: glDisable(GL_DEPTH_TEST); rlm@1: glDisable(GL_CULL_FACE); rlm@1: glEnable(GL_TEXTURE_2D); rlm@1: rlm@1: glViewport(0, 0, theApp.surfaceSizeX, theApp.surfaceSizeY); rlm@1: rlm@1: glMatrixMode(GL_PROJECTION); rlm@1: glLoadIdentity(); rlm@1: rlm@1: glOrtho(0.0, (GLdouble)(theApp.surfaceSizeX), (GLdouble)(theApp.surfaceSizeY), rlm@1: 0.0, 0.0, 1.0); rlm@1: glMatrixMode(GL_MODELVIEW); rlm@1: glLoadIdentity(); rlm@1: rlm@1: systemRedShift = 3; rlm@1: systemGreenShift = 11; rlm@1: systemBlueShift = 19; rlm@1: systemColorDepth = 32; rlm@1: theApp.fsColorDepth = 32; rlm@1: rlm@1: Init_2xSaI(32); rlm@1: #ifdef MMX rlm@1: if (!theApp.disableMMX) rlm@1: cpu_mmx = theApp.detectMMX(); rlm@1: else rlm@1: cpu_mmx = 0; rlm@1: #endif rlm@1: rlm@1: if (theApp.ddrawDebug) rlm@1: { rlm@1: winlog("R shift: %d\n", systemRedShift); rlm@1: winlog("G shift: %d\n", systemGreenShift); rlm@1: winlog("B shift: %d\n", systemBlueShift); rlm@1: } rlm@1: rlm@1: switch (systemColorDepth) rlm@1: { rlm@1: case 16: rlm@1: { rlm@1: for (int i = 0; i < 0x10000; i++) rlm@1: { rlm@1: systemColorMap16[i] = ((i & 0x1f) << systemRedShift) | rlm@1: (((i & 0x3e0) >> 5) << systemGreenShift) | rlm@1: (((i & 0x7c00) >> 10) << systemBlueShift); rlm@1: } rlm@1: break; rlm@1: } rlm@1: case 24: rlm@1: case 32: rlm@1: { rlm@1: for (int i = 0; i < 0x10000; i++) rlm@1: { rlm@1: systemColorMap32[i] = ((i & 0x1f) << systemRedShift) | rlm@1: (((i & 0x3e0) >> 5) << systemGreenShift) | rlm@1: (((i & 0x7c00) >> 10) << systemBlueShift); rlm@1: } rlm@1: break; rlm@1: } rlm@1: } rlm@1: theApp.updateFilter(); rlm@1: theApp.updateIFB(); rlm@1: rlm@1: if (failed) rlm@1: return false; rlm@1: rlm@1: pWnd->DragAcceptFiles(TRUE); rlm@1: rlm@1: return TRUE; rlm@1: } rlm@1: rlm@1: void OpenGLDisplay::clear() rlm@1: {} rlm@1: rlm@1: void OpenGLDisplay::renderMenu() rlm@1: { rlm@1: checkFullScreen(); rlm@1: if (theApp.m_pMainWnd) rlm@1: theApp.m_pMainWnd->DrawMenuBar(); rlm@1: } rlm@1: rlm@1: void OpenGLDisplay::checkFullScreen() rlm@1: { rlm@1: // if(tripleBuffering) rlm@1: // pOpenGL->FlipToGDISurface(); rlm@1: } rlm@1: rlm@1: void OpenGLDisplay::render() rlm@1: { rlm@1: void (*filterFunction)(u8 *, u32, u8 *, u8 *, u32, int, int) = theApp.filterFunction; rlm@1: int filterWidth = theApp.filterWidth, filterHeight = theApp.filterHeight; rlm@1: /* rlm@1: if(textMethod == 1) rlm@1: { rlm@1: int copyX = 240, copyY = 160; rlm@1: if(systemCartridgeType == 1) rlm@1: if(gbBorderOn) copyX = 256, copyY = 224; rlm@1: else copyX = 160, copyY = 144; rlm@1: rlm@1: extern void Simple1x(u8*,u32,u8*,u8*,u32,int,int); rlm@1: filterFunction = Simple1x; rlm@1: filterWidth = copyX; rlm@1: filterHeight = copyY; rlm@1: } rlm@1: */ rlm@1: int pitch = filterWidth * 4 + 4; rlm@1: u8 *data = pix + (theApp.sizeX+1)*4; rlm@1: rlm@1: int filterPitch = theApp.rect.right*4; rlm@1: rlm@1: /* rlm@1: // HACK: see below rlm@1: if (textMethod == 1 && !filterFunction) rlm@1: { rlm@1: textMethod = 0; // must not be after systemMessage! rlm@1: systemMessage( rlm@1: 0, rlm@1: "The \"On Game\" text display mode does not work with this combination of renderers and filters.\nThe display mode is automatically being changed to \"In Game\" instead,\nbut this may cause message text to go into AVI recordings and screenshots.\nThis can be reconfigured by choosing \"Options->Video->Text Display Options...\""); rlm@1: } rlm@1: */ rlm@1: rlm@1: if (filterFunction) rlm@1: { rlm@1: data = filterData; rlm@1: filterFunction(pix + pitch, rlm@1: pitch, rlm@1: (u8 *)theApp.delta, rlm@1: (u8 *)filterData, rlm@1: filterPitch, rlm@1: filterWidth, rlm@1: filterHeight); rlm@1: } rlm@1: rlm@1: if (theApp.showSpeed && theApp.videoOption > VIDEO_4X) rlm@1: { rlm@1: char buffer[30]; rlm@1: if (theApp.showSpeed == 1) rlm@1: sprintf(buffer, "%3d%%", systemSpeed); rlm@1: else rlm@1: sprintf(buffer, "%3d%%(%d, %d fps)", systemSpeed, rlm@1: systemFrameSkip, rlm@1: theApp.showRenderedFrames); rlm@1: rlm@1: if (filterFunction) rlm@1: { rlm@1: if (theApp.showSpeedTransparent) rlm@1: drawTextTransp((u8 *)filterData, rlm@1: filterPitch, rlm@1: theApp.rect.left+10, rlm@1: theApp.rect.bottom-10, rlm@1: buffer); rlm@1: else rlm@1: drawText((u8 *)filterData, rlm@1: filterPitch, rlm@1: theApp.rect.left+10, rlm@1: theApp.rect.bottom-10, rlm@1: buffer); rlm@1: } rlm@1: else rlm@1: { rlm@1: if (theApp.showSpeedTransparent) rlm@1: drawTextTransp((u8 *)pix, rlm@1: pitch, rlm@1: theApp.rect.left+10, rlm@1: theApp.rect.bottom-10, rlm@1: buffer); rlm@1: else rlm@1: drawText((u8 *)pix, rlm@1: pitch, rlm@1: theApp.rect.left+10, rlm@1: theApp.rect.bottom-10, rlm@1: buffer); rlm@1: } rlm@1: } rlm@1: rlm@1: if (textMethod == 1 && filterFunction) rlm@1: { rlm@1: DrawTextMessages((u8 *)filterData, filterPitch, theApp.rect.left, theApp.rect.bottom); rlm@1: } rlm@1: rlm@1: // Texturemap complete texture to surface so we have free scaling rlm@1: // and antialiasing rlm@1: if (filterFunction) rlm@1: { rlm@1: glPixelStorei(GL_UNPACK_ROW_LENGTH, theApp.rect.right); rlm@1: } rlm@1: else rlm@1: { rlm@1: glPixelStorei(GL_UNPACK_ROW_LENGTH, theApp.sizeX+1); rlm@1: } rlm@1: rlm@1: glTexSubImage2D(GL_TEXTURE_2D, 0, rlm@1: 0, 0, theApp.rect.right, theApp.rect.bottom, rlm@1: GL_RGBA, GL_UNSIGNED_BYTE, data); rlm@1: rlm@1: if (theApp.glType == 0) rlm@1: { rlm@1: glBegin(GL_TRIANGLE_STRIP); rlm@1: glTexCoord2f(0.0, 0.0); glVertex3i(0, 0, 0); rlm@1: glTexCoord2f(theApp.rect.right/size, 0.0); glVertex3i(theApp.surfaceSizeX, 0, 0); rlm@1: glTexCoord2f(0.0, theApp.rect.bottom/size); glVertex3i(0, theApp.surfaceSizeY, 0); rlm@1: glTexCoord2f(theApp.rect.right/size, theApp.rect.bottom/size); glVertex3i(theApp.surfaceSizeX, theApp.surfaceSizeY, 0); rlm@1: glEnd(); rlm@1: } rlm@1: else rlm@1: { rlm@1: glBegin(GL_QUADS); rlm@1: glTexCoord2f(0.0, 0.0); glVertex3i(0, 0, 0); rlm@1: glTexCoord2f(theApp.rect.right/size, 0.0); glVertex3i(theApp.surfaceSizeX, 0, 0); rlm@1: glTexCoord2f(theApp.rect.right/size, theApp.rect.bottom/size); glVertex3i(theApp.surfaceSizeX, theApp.surfaceSizeY, 0); rlm@1: glTexCoord2f(0.0, theApp.rect.bottom/size); glVertex3i(0, theApp.surfaceSizeY, 0); rlm@1: glEnd(); rlm@1: } rlm@1: rlm@1: CDC *dc = theApp.m_pMainWnd->GetDC(); rlm@1: rlm@1: if (textMethod == 2 || (textMethod == 1 && !filterFunction)) // HACK: so that textMethod isn't changed rlm@1: { rlm@1: for (int slot = 0; slot < SCREEN_MESSAGE_SLOTS; slot++) rlm@1: { rlm@1: if (theApp.screenMessage[slot]) rlm@1: { rlm@1: if ((theApp.screenMessageDuration[slot] < 0 || rlm@1: (int)(GetTickCount() - theApp.screenMessageTime[slot]) < theApp.screenMessageDuration[slot]) && rlm@1: (!theApp.disableStatusMessage || slot == 1 || slot == 2)) rlm@1: { rlm@1: dc->SetBkMode(TRANSPARENT); rlm@1: rlm@1: if (outlinedText) rlm@1: { rlm@1: dc->SetTextColor(textColor != 7 ? RGB(0, 0, 0) : RGB(255, 255, 255)); rlm@1: // draw black outline rlm@1: const static int xd [8] = {-1, 0, 1, 1, 1, 0, -1, -1}; rlm@1: const static int yd [8] = {-1, -1, -1, 0, 1, 1, 1, 0}; rlm@1: for (int i = 0; i < 8; i++) rlm@1: { rlm@1: dc->TextOut(10+xd[i], theApp.surfaceSizeY - 20*(slot+1)+yd[i], theApp.screenMessageBuffer[slot]); rlm@1: } rlm@1: } rlm@1: rlm@1: COLORREF color; rlm@1: switch (textColor) rlm@1: { rlm@1: case 0: rlm@1: color = RGB(255, 255, 255); break; rlm@1: case 1: rlm@1: color = RGB(255, 0, 0); break; rlm@1: case 2: rlm@1: color = RGB(255, 255, 0); break; rlm@1: case 3: rlm@1: color = RGB(0, 255, 0); break; rlm@1: case 4: rlm@1: color = RGB(0, 255, 255); break; rlm@1: case 5: rlm@1: color = RGB(0, 0, 255); break; rlm@1: case 6: rlm@1: color = RGB(255, 0, 255); break; rlm@1: case 7: rlm@1: color = RGB(0, 0, 0); break; rlm@1: } rlm@1: dc->SetTextColor(color); rlm@1: rlm@1: // draw center text rlm@1: dc->TextOut(10, theApp.surfaceSizeY - 20*(slot+1), theApp.screenMessageBuffer[slot]); rlm@1: } rlm@1: else rlm@1: { rlm@1: theApp.screenMessage[slot] = false; rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: SwapBuffers(dc->GetSafeHdc()); rlm@1: rlm@1: theApp.m_pMainWnd->ReleaseDC(dc); rlm@1: } rlm@1: rlm@1: void OpenGLDisplay::resize(int w, int h) rlm@1: { rlm@1: glViewport(0, 0, w, h); rlm@1: glMatrixMode(GL_PROJECTION); rlm@1: glLoadIdentity(); rlm@1: rlm@1: glOrtho(0.0, (GLdouble)(w), (GLdouble)(h), 0.0, 0.0, 1.0); rlm@1: glMatrixMode(GL_MODELVIEW); rlm@1: glLoadIdentity(); rlm@1: } rlm@1: rlm@1: void OpenGLDisplay::updateFiltering(int value) rlm@1: { rlm@1: switch (value) rlm@1: { rlm@1: case 0: rlm@1: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); rlm@1: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); rlm@1: break; rlm@1: case 1: rlm@1: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); rlm@1: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: bool OpenGLDisplay::initializeTexture(int w, int h) rlm@1: { rlm@1: int mySize = 256; rlm@1: size = 256.0f; rlm@1: if (w > 511 || h > 511) rlm@1: { rlm@1: size = 1024.0f; rlm@1: mySize = 1024; rlm@1: } rlm@1: else if (w > 255 || h > 255) rlm@1: { rlm@1: size = 512.0f; rlm@1: mySize = 512; rlm@1: } rlm@1: glGenTextures(1, &texture); rlm@1: glBindTexture(GL_TEXTURE_2D, texture); rlm@1: rlm@1: int filter = regQueryDwordValue("glFilter", 0); rlm@1: if (filter < 0 || filter > 1) rlm@1: filter = 0; rlm@1: updateFiltering(filter); rlm@1: rlm@1: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mySize, mySize, 0, GL_RGBA, rlm@1: GL_UNSIGNED_BYTE, NULL); rlm@1: width = w; rlm@1: height = h; rlm@1: rlm@1: return true; rlm@1: } rlm@1: rlm@1: bool OpenGLDisplay::changeRenderSize(int w, int h) rlm@1: { rlm@1: if (width != w || height != h) rlm@1: { rlm@1: if (texture != 0) rlm@1: { rlm@1: glDeleteTextures(1, &texture); rlm@1: texture = 0; rlm@1: } rlm@1: if (!initializeTexture(w, h)) rlm@1: { rlm@1: failed = true; rlm@1: return false; rlm@1: } rlm@1: } rlm@1: return true; rlm@1: } rlm@1: rlm@1: void OpenGLDisplay::setOption(const char *option, int value) rlm@1: { rlm@1: if (!strcmp(option, "glFilter")) rlm@1: updateFiltering(value); rlm@1: } rlm@1: rlm@1: int OpenGLDisplay::selectFullScreenMode(GUID * *) rlm@1: { rlm@1: HWND wnd = GetDesktopWindow(); rlm@1: RECT r; rlm@1: GetWindowRect(wnd, &r); rlm@1: int w = (r.right - r.left) & 4095; rlm@1: int h = (r.bottom - r.top) & 4095; rlm@1: HDC dc = GetDC(wnd); rlm@1: int c = GetDeviceCaps(dc, BITSPIXEL); rlm@1: ReleaseDC(wnd, dc); rlm@1: rlm@1: return (c << 24) | (w << 12) | h; rlm@1: } rlm@1: rlm@1: IDisplay *newOpenGLDisplay() rlm@1: { rlm@1: return new OpenGLDisplay(); rlm@1: } rlm@1: