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: extern u32 RGB_LOW_BITS_MASK; rlm@1: extern int systemSpeed; rlm@1: extern void winlog(const char *, ...); rlm@1: extern int Init_2xSaI(u32); rlm@1: rlm@1: class GDIDisplay : public IDisplay rlm@1: { rlm@1: private: rlm@1: u8 *filterData; rlm@1: u8 info[sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD)]; rlm@1: public: rlm@1: GDIDisplay(); rlm@1: virtual ~GDIDisplay(); 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 DISPLAY_TYPE getType() { return GDI; }; rlm@1: virtual void setOption(const char *, int) {} rlm@1: virtual int selectFullScreenMode(GUID * *); rlm@1: }; rlm@1: rlm@1: static int calculateShift(u32 mask) rlm@1: { rlm@1: int m = 0; rlm@1: rlm@1: while (mask) rlm@1: { rlm@1: m++; rlm@1: mask >>= 1; rlm@1: } rlm@1: rlm@1: return m-5; rlm@1: } rlm@1: rlm@1: GDIDisplay::GDIDisplay() rlm@1: { rlm@1: filterData = (u8 *)malloc(4*16*256*256); // sufficient for 4x filters @ 32bit color depth rlm@1: } rlm@1: rlm@1: GDIDisplay::~GDIDisplay() rlm@1: { rlm@1: cleanup(); rlm@1: } rlm@1: rlm@1: void GDIDisplay::cleanup() rlm@1: { rlm@1: if (filterData) rlm@1: { rlm@1: free(filterData); rlm@1: filterData = NULL; rlm@1: } rlm@1: } rlm@1: rlm@1: bool GDIDisplay::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: HDC dc = GetDC(NULL); rlm@1: HBITMAP hbm = CreateCompatibleBitmap(dc, 1, 1); rlm@1: BITMAPINFO *bi = (BITMAPINFO *)info; rlm@1: ZeroMemory(bi, sizeof(info)); rlm@1: bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); rlm@1: GetDIBits(dc, hbm, 0, 1, NULL, (LPBITMAPINFO)info, DIB_RGB_COLORS); rlm@1: GetDIBits(dc, hbm, 0, 1, NULL, (LPBITMAPINFO)info, DIB_RGB_COLORS); rlm@1: DeleteObject(hbm); rlm@1: ReleaseDC(NULL, dc); rlm@1: rlm@1: if (bi->bmiHeader.biCompression == BI_BITFIELDS) rlm@1: { rlm@1: systemColorDepth = bi->bmiHeader.biBitCount; rlm@1: if (systemColorDepth == 15) rlm@1: systemColorDepth = 16; rlm@1: systemRedShift = calculateShift(*((DWORD *)&bi->bmiColors[0])); rlm@1: systemGreenShift = calculateShift(*((DWORD *)&bi->bmiColors[1])); rlm@1: systemBlueShift = calculateShift(*((DWORD *)&bi->bmiColors[2])); rlm@1: if (systemColorDepth == 16) rlm@1: { rlm@1: if (systemGreenShift == 6) rlm@1: { rlm@1: Init_2xSaI(565); rlm@1: RGB_LOW_BITS_MASK = 0x821; rlm@1: } rlm@1: else rlm@1: { rlm@1: Init_2xSaI(555); rlm@1: RGB_LOW_BITS_MASK = 0x421; rlm@1: } rlm@1: } rlm@1: else if (systemColorDepth == 32) rlm@1: Init_2xSaI(32); rlm@1: } rlm@1: else rlm@1: { rlm@1: systemColorDepth = 32; rlm@1: systemRedShift = 19; rlm@1: systemGreenShift = 11; rlm@1: systemBlueShift = 3; rlm@1: rlm@1: Init_2xSaI(32); rlm@1: } rlm@1: theApp.fsColorDepth = systemColorDepth; rlm@1: if (systemColorDepth == 24) rlm@1: theApp.filterFunction = NULL; 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: 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: pWnd->DragAcceptFiles(TRUE); rlm@1: rlm@1: return TRUE; rlm@1: } rlm@1: rlm@1: void GDIDisplay::clear() rlm@1: {} rlm@1: rlm@1: void GDIDisplay::renderMenu() rlm@1: { rlm@1: checkFullScreen(); rlm@1: theApp.m_pMainWnd->DrawMenuBar(); rlm@1: } rlm@1: rlm@1: void GDIDisplay::checkFullScreen() rlm@1: {} rlm@1: rlm@1: void GDIDisplay::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*2; rlm@1: filterHeight = copyY*2; rlm@1: } rlm@1: */ rlm@1: BITMAPINFO *bi = (BITMAPINFO *)info; rlm@1: bi->bmiHeader.biWidth = filterWidth+1; rlm@1: bi->bmiHeader.biHeight = -filterHeight; rlm@1: rlm@1: int pitch = filterWidth * 2 + 4; rlm@1: if (systemColorDepth == 32) rlm@1: pitch = filterWidth * 4 + 4; rlm@1: // FIXME: is the 24bit color depth still being used nowadays? rlm@1: else if (systemColorDepth == 24) rlm@1: pitch = filterWidth * 3; rlm@1: rlm@1: // FIXME: is this working if systemColorDepth == 24? rlm@1: int filterPitch = theApp.rect.right*2; rlm@1: if (systemColorDepth == 32) rlm@1: filterPitch = theApp.rect.right*4; rlm@1: else if (systemColorDepth == 24) rlm@1: filterPitch = theApp.rect.right*3; 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: bi->bmiHeader.biWidth = theApp.rect.right; rlm@1: bi->bmiHeader.biHeight = -theApp.rect.bottom; rlm@1: 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: POINT p; rlm@1: p.x = theApp.dest.left; rlm@1: p.y = theApp.dest.top; rlm@1: CWnd *pWnd = theApp.m_pMainWnd; rlm@1: pWnd->ScreenToClient(&p); rlm@1: POINT p2; rlm@1: p2.x = theApp.dest.right; rlm@1: p2.y = theApp.dest.bottom; rlm@1: pWnd->ScreenToClient(&p2); rlm@1: rlm@1: CDC *dc = pWnd->GetDC(); rlm@1: rlm@1: StretchDIBits((HDC)*dc, rlm@1: p.x, rlm@1: p.y, rlm@1: p2.x - p.x, rlm@1: p2.y - p.y, rlm@1: 0, rlm@1: 0, rlm@1: theApp.rect.right, rlm@1: theApp.rect.bottom, rlm@1: filterFunction ? filterData : pix+pitch, rlm@1: bi, rlm@1: DIB_RGB_COLORS, rlm@1: SRCCOPY); rlm@1: rlm@1: if (textMethod == 2 || (textMethod == 1 && !filterFunction)) // HACK: so that textMethod isn't changed 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: 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(p.x+10+xd[i], p2.y - 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(p.x+10, p2.y - 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: pWnd->ReleaseDC(dc); rlm@1: } rlm@1: rlm@1: int GDIDisplay::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 *newGDIDisplay() rlm@1: { rlm@1: return new GDIDisplay(); rlm@1: } rlm@1: