#pragma once #include "gxruntime.hpp" #include #include #include #include #include "GraphicsRuntime.hpp" #include "std.hpp" struct gxRuntime::GfxMode { DDSURFACEDESC2 desc; }; struct gxRuntime::GfxDriver { GUID* guid; std::string name; std::vector modes; D3DDEVICEDESC7 d3d_desc; }; static const int static_ws = WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; static const int scaled_ws = WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_SIZEBOX | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; static string app_title; static string app_close; static gxRuntime* runtime; static bool busy, suspended; static volatile bool run_flag; static DDSURFACEDESC2 desktop_desc; typedef int(_stdcall* LibFunc)(const void* in, int in_sz, void* out, int out_sz); struct gxDll { HINSTANCE hinst; map funcs; }; static map libs; static LRESULT CALLBACK windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); //current gfx mode // //0=NONE //1=SCALED WINDOW //2=FIXED SIZE WINDOW //3=EXCLUSIVE // static int gfx_mode; static bool gfx_lost; static bool auto_suspend; //for modes 1 and 2 static int mod_cnt; static MMRESULT timerID; static IDirectDrawClipper* clipper; static IDirectDrawSurface7* primSurf; //static Debugger *debugger; static set timers; enum { WM_STOP = WM_USER + 1, WM_RUN, WM_END }; //////////////////// // STATIC STARTUP // //////////////////// gxRuntime* gxRuntime::openRuntime(HINSTANCE hinst, const string& cmd_line, void* d) { if (runtime) return 0; //create debugger //debugger = d; //create WNDCLASS WNDCLASS wndclass; memset(&wndclass, 0, sizeof(wndclass)); wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wndclass.lpfnWndProc = ::windowProc; wndclass.hInstance = hinst; wndclass.lpszClassName = TEXT("Blitz Runtime Class"); wndclass.hCursor = (HCURSOR)LoadCursor(0, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); RegisterClass(&wndclass); gfx_mode = 0; clipper = 0; primSurf = 0; busy = suspended = false; run_flag = true; const char* app_t = " "; int ws = WS_CAPTION, ws_ex = 0; HWND hwnd = CreateWindowEx(ws_ex, "Blitz Runtime Class", app_t, ws, 0, 0, 0, 0, 0, 0, 0, 0); UpdateWindow(hwnd); runtime = new gxRuntime(hinst, cmd_line, hwnd); return runtime; } void gxRuntime::closeRuntime(gxRuntime* r) { if (!runtime || runtime != r) return; map::const_iterator it; for (it = libs.begin(); it != libs.end(); ++it) { FreeLibrary(it->second->hinst); } libs.clear(); delete runtime; runtime = 0; } ////////////////////////// // RUNTIME CONSTRUCTION // ////////////////////////// typedef int(_stdcall* SetAppCompatDataFunc)(int x, int y); gxRuntime::gxRuntime(HINSTANCE hi, const string& cl, HWND hw) : hinst(hi), cmd_line(cl), hwnd(hw), curr_driver(0), enum_all(false), pointer_visible(true), audio(0), input(0), graphics(0), fileSystem(0), use_di(false) { CoInitialize(0); enumGfx(); TIMECAPS tc; timeGetDevCaps(&tc, sizeof(tc)); timeBeginPeriod(tc.wPeriodMin); HMODULE ddraw = LoadLibraryA("ddraw.dll"); if (ddraw) { SetAppCompatDataFunc SetAppCompatData = (SetAppCompatDataFunc)GetProcAddress(ddraw, "SetAppCompatData"); if (SetAppCompatData) SetAppCompatData(12, 0); FreeLibrary(ddraw); } } gxRuntime::~gxRuntime() { while (timers.size()) freeTimer(*timers.begin()); if (audio) closeAudio(audio); if (graphics) closeGraphics(graphics); if (input) closeInput(input); TIMECAPS tc; timeGetDevCaps(&tc, sizeof(tc)); timeEndPeriod(tc.wPeriodMin); denumGfx(); DestroyWindow(hwnd); UnregisterClass("Blitz Runtime Class", hinst); CoUninitialize(); } void gxRuntime::pauseAudio() { if (audio) audio->pause(); } void gxRuntime::resumeAudio() { if (audio) audio->resume(); } void gxRuntime::backupGraphics() { if (auto_suspend) { graphics->backup(); } } void gxRuntime::restoreGraphics() { if (auto_suspend) { if (!graphics->restore()) gfx_lost = true; } } void gxRuntime::resetInput() { if (input) input->reset(); } void gxRuntime::acquireInput() { if (!input) return; if (gfx_mode == 3) { if (use_di) { use_di = input->acquire(); } else { } } input->reset(); } void gxRuntime::unacquireInput() { if (!input) return; if (gfx_mode == 3 && use_di) input->unacquire(); input->reset(); } ///////////// // SUSPEND // ///////////// void gxRuntime::suspend() { busy = true; pauseAudio(); backupGraphics(); unacquireInput(); suspended = true; busy = false; if (gfx_mode == 3) ShowCursor(1); //if (debugger) debugger->debugStop(); } //////////// // RESUME // //////////// void gxRuntime::resume() { if (gfx_mode == 3) ShowCursor(0); busy = true; acquireInput(); restoreGraphics(); resumeAudio(); suspended = false; busy = false; //if (debugger) debugger->debugRun(); } /////////////////// // FORCE SUSPEND // /////////////////// void gxRuntime::forceSuspend() { if (gfx_mode == 3) { SetForegroundWindow(GetDesktopWindow()); ShowWindow(GetDesktopWindow(), SW_SHOW); } else { suspend(); } } ////////////////// // FORCE RESUME // ////////////////// void gxRuntime::forceResume() { if (gfx_mode == 3) { SetForegroundWindow(hwnd); ShowWindow(hwnd, SW_SHOWMAXIMIZED); } else { resume(); } } /////////// // PAINT // /////////// void gxRuntime::paint() { switch (gfx_mode) { case 0: { } break; case 1: case 2: //scaled windowed mode. { RECT src, dest; src.left = src.top = 0; GetClientRect(hwnd, &dest); src.right = gfx_mode == 1 ? graphics->getWidth() : dest.right; src.bottom = gfx_mode == 1 ? graphics->getHeight() : dest.bottom; POINT p; p.x = p.y = 0; ClientToScreen(hwnd, &p); dest.left += p.x; dest.right += p.x; dest.top += p.y; dest.bottom += p.y; gxCanvas* f = graphics->getFrontCanvas(); primSurf->Blt(&dest, f->getSurface(), &src, 0, 0); } break; case 3: { //exclusive mode } break; } } ////////// // FLIP // ////////// void gxRuntime::flip(bool vwait) { gxCanvas* b = graphics->getBackCanvas(); gxCanvas* f = graphics->getFrontCanvas(); int n; switch (gfx_mode) { case 1: case 2: if (vwait) graphics->vwait(); f->setModify(b->getModify()); if (f->getModify() != mod_cnt) { mod_cnt = f->getModify(); paint(); } break; case 3: if (vwait) { BOOL vb; while (graphics->dirDraw->GetVerticalBlankStatus(&vb) >= 0 && vb) { } n = f->getSurface()->Flip(0, DDFLIP_WAIT); } else { n = f->getSurface()->Flip(0, DDFLIP_NOVSYNC | DDFLIP_WAIT); } if (n >= 0) return; string t = "Flip Failed! Return code:" + itoa(n & 0x7fff); debugLog(t.c_str()); break; } } //////////////// // MOVE MOUSE // //////////////// void gxRuntime::moveMouse(int x, int y) { POINT p; RECT rect; switch (gfx_mode) { case 1: GetClientRect(hwnd, &rect); x = x * (rect.right - rect.left) / graphics->getWidth(); y = y * (rect.bottom - rect.top) / graphics->getHeight(); case 2: p.x = x; p.y = y; ClientToScreen(hwnd, &p); x = p.x; y = p.y; break; case 3: if (use_di) return; break; default: return; } SetCursorPos(x, y); } ///////////////// // WINDOW PROC // ///////////////// LRESULT gxRuntime::windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { if (busy) { return DefWindowProc(hwnd, msg, wparam, lparam); } PAINTSTRUCT ps; //handle 'special' messages! switch (msg) { case WM_PAINT: if (gfx_mode && !auto_suspend) { if (!graphics->restore()) gfx_lost = true; } BeginPaint(hwnd, &ps); paint(); EndPaint(hwnd, &ps); return DefWindowProc(hwnd, msg, wparam, lparam); case WM_ERASEBKGND: return gfx_mode ? 1 : DefWindowProc(hwnd, msg, wparam, lparam); case WM_CLOSE: if (app_close.size()) { int n = MessageBox(hwnd, app_close.c_str(), app_title.c_str(), MB_OKCANCEL | MB_ICONWARNING | MB_SETFOREGROUND | MB_TOPMOST); if (n != IDOK) return 0; } asyncEnd(); return 0; case WM_SETCURSOR: if (!suspended) { if (gfx_mode == 3) { SetCursor(0); return 1; } else if (!pointer_visible) { POINT p; GetCursorPos(&p); ScreenToClient(hwnd, &p); RECT r; GetClientRect(hwnd, &r); if (p.x >= 0 && p.y >= 0 && p.x < r.right && p.y < r.bottom) { SetCursor(0); return 1; } } } break; case WM_ACTIVATEAPP: if (auto_suspend) { if (wparam) { if (suspended) resume(); } else { if (!suspended) suspend(); } } break; } if (!input || suspended) return DefWindowProc(hwnd, msg, wparam, lparam); if (gfx_mode == 3 && use_di) { use_di = input->acquire(); return DefWindowProc(hwnd, msg, wparam, lparam); } static const int MK_ALLBUTTONS = MK_LBUTTON | MK_RBUTTON | MK_MBUTTON; //handle input messages switch (msg) { case WM_LBUTTONDOWN: input->wm_mousedown(1); SetCapture(hwnd); break; case WM_LBUTTONUP: input->wm_mouseup(1); if (!(wparam & MK_ALLBUTTONS)) ReleaseCapture(); break; case WM_RBUTTONDOWN: input->wm_mousedown(2); SetCapture(hwnd); break; case WM_RBUTTONUP: input->wm_mouseup(2); if (!(wparam & MK_ALLBUTTONS)) ReleaseCapture(); break; case WM_MBUTTONDOWN: input->wm_mousedown(3); SetCapture(hwnd); break; case WM_MBUTTONUP: input->wm_mouseup(3); if (!(wparam & MK_ALLBUTTONS)) ReleaseCapture(); break; case WM_MOUSEMOVE: if (!graphics) break; if (gfx_mode == 3 && !use_di) { POINT p; GetCursorPos(&p); input->wm_mousemove(p.x, p.y); } else { int x = (short)(lparam & 0xffff), y = lparam >> 16; if (gfx_mode == 1) { RECT rect; GetClientRect(hwnd, &rect); x = x * graphics->getWidth() / (rect.right - rect.left); y = y * graphics->getHeight() / (rect.bottom - rect.top); } if (x < 0) x = 0; else if (x >= graphics->getWidth()) x = graphics->getWidth() - 1; if (y < 0) y = 0; else if (y >= graphics->getHeight()) y = graphics->getHeight() - 1; input->wm_mousemove(x, y); } break; case WM_MOUSEWHEEL: input->wm_mousewheel((short)HIWORD(wparam)); break; case WM_KEYDOWN: case WM_SYSKEYDOWN: if (lparam & 0x40000000) break; if (int n = ((lparam >> 17) & 0x80) | ((lparam >> 16) & 0x7f)) input->wm_keydown(n); break; case WM_KEYUP: case WM_SYSKEYUP: if (int n = ((lparam >> 17) & 0x80) | ((lparam >> 16) & 0x7f)) input->wm_keyup(n); break; default: return DefWindowProc(hwnd, msg, wparam, lparam); } return 0; } static LRESULT CALLBACK windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { if (runtime) return runtime->windowProc(hwnd, msg, wparam, lparam); return DefWindowProc(hwnd, msg, wparam, lparam); } ////////////////////////////// //STOP FROM EXTERNAL SOURCE // ////////////////////////////// void gxRuntime::asyncStop() { PostMessage(hwnd, WM_STOP, 0, 0); } ////////////////////////////// //RUN FROM EXTERNAL SOURCE // ////////////////////////////// void gxRuntime::asyncRun() { PostMessage(hwnd, WM_RUN, 0, 0); } ////////////////////////////// // END FROM EXTERNAL SOURCE // ////////////////////////////// void gxRuntime::asyncEnd() { PostMessage(hwnd, WM_END, 0, 0); } ////////// // IDLE // ////////// bool gxRuntime::idle() { for (;;) { MSG msg; if (suspended && run_flag) { GetMessage(&msg, 0, 0, 0); } else { if (!PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) return run_flag; } switch (msg.message) { case WM_STOP: if (!suspended) forceSuspend(); break; case WM_RUN: if (suspended) forceResume(); break; case WM_END: //debugger = 0; run_flag = false; break; default: DispatchMessage(&msg); } } return run_flag; } /////////// // DELAY // /////////// bool gxRuntime::delay(int ms) { int t = timeGetTime() + ms; for (;;) { if (!idle()) return false; int d = t - timeGetTime(); //how long left to wait if (d <= 0) return true; if (d > 100) d = 100; Sleep(d); } } /////////////// // DEBUGSTMT // /////////////// void gxRuntime::debugStmt(int pos, const char* file) { //if (debugger) debugger->debugStmt(pos, file); } /////////////// // DEBUGSTOP // /////////////// void gxRuntime::debugStop() { //if (!suspended) forceSuspend(); } //////////////// // DEBUGENTER // //////////////// void gxRuntime::debugEnter(void* frame, void* env, const char* func) { //if (debugger) debugger->debugEnter(frame, env, func); } //////////////// // DEBUGLEAVE // //////////////// void gxRuntime::debugLeave() { //if (debugger) debugger->debugLeave(); } //////////////// // DEBUGERROR // //////////////// void gxRuntime::debugError(const char* t) { /*if (!debugger) return; void*d = debugger; asyncEnd(); if (!suspended) { forceSuspend(); } d->debugMsg(t, true);*/ } /////////////// // DEBUGINFO // /////////////// void gxRuntime::debugInfo(const char* t) { /*if (!debugger) return; Debugger *d = debugger; asyncEnd(); if (!suspended) { forceSuspend(); } d->debugMsg(t, false);*/ } ////////////// // DEBUGLOG // ////////////// void gxRuntime::debugLog(const char* t) { //if (debugger) debugger->debugLog(t); } ///////////////////////// // RETURN COMMAND LINE // ///////////////////////// string gxRuntime::commandLine() { return cmd_line; } ///////////// // EXECUTE // ///////////// bool gxRuntime::execute(const string& cmd_line) { if (!cmd_line.size()) return false; //convert cmd_line to cmd and params string cmd = cmd_line, params; while (cmd.size() && cmd[0] == ' ') cmd = cmd.substr(1); if (cmd.find('\"') == 0) { int n = cmd.find('\"', 1); if (n != string::npos) { params = cmd.substr(n + 1); cmd = cmd.substr(1, n - 1); } } else { int n = cmd.find(' '); if (n != string::npos) { params = cmd.substr(n + 1); cmd = cmd.substr(0, n); } } while (params.size() && params[0] == ' ') params = params.substr(1); while (params.size() && params[params.size() - 1] == ' ') params = params.substr(0, params.size() - 1); SetForegroundWindow(GetDesktopWindow()); return (int)ShellExecute(GetDesktopWindow(), 0, cmd.c_str(), params.size() ? params.c_str() : 0, 0, SW_SHOW) > 32; } /////////////// // APP TITLE // /////////////// void gxRuntime::setTitle(const string& t, const string& e) { app_title = t; app_close = e; SetWindowText(hwnd, app_title.c_str()); } ////////////////// // GETMILLISECS // ////////////////// int gxRuntime::getMilliSecs() { return timeGetTime(); } ///////////////////// // POINTER VISIBLE // ///////////////////// void gxRuntime::setPointerVisible(bool vis) { if (pointer_visible == vis) return; pointer_visible = vis; if (gfx_mode == 3) return; //force a WM_SETCURSOR POINT pt; GetCursorPos(&pt); SetCursorPos(pt.x, pt.y); } ///////////////// // AUDIO SETUP // ///////////////// gxAudio* gxRuntime::openAudio(int flags) { if (audio) return 0; int f_flags = FSOUND_INIT_GLOBALFOCUS | FSOUND_INIT_USEDEFAULTMIDISYNTH; FSOUND_SetHWND(hwnd); if (!FSOUND_Init(44100, 1024, f_flags)) { return 0; } audio = new gxAudio(this); return audio; } void gxRuntime::closeAudio(gxAudio* a) { if (!audio || audio != a) return; delete audio; audio = 0; } ///////////////// // INPUT SETUP // ///////////////// gxInput* gxRuntime::openInput(int flags) { if (input) return 0; LPDIRECTINPUT8 di; if (DirectInput8Create(hinst, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&di, NULL) >= 0) { //if (DirectInput8Create(hinst, DIRECTINPUT_VERSION, (void**)&di, NULL) >= 0) { input = new gxInput(this, di); acquireInput(); } else { debugInfo("Create DirectInput failed"); } return input; } void gxRuntime::closeInput(gxInput* i) { if (!input || input != i) return; unacquireInput(); delete input; input = 0; } ///////////////////////////////////////////////////// // TIMER CALLBACK FOR AUTOREFRESH OF WINDOWED MODE // ///////////////////////////////////////////////////// static void CALLBACK timerCallback(UINT id, UINT msg, DWORD user, DWORD dw1, DWORD dw2) { if (gfx_mode) { gxCanvas* f = runtime->graphics->getFrontCanvas(); if (f->getModify() != mod_cnt) { mod_cnt = f->getModify(); InvalidateRect(runtime->hwnd, 0, false); } } } //////////////////// // GRAPHICS SETUP // //////////////////// void gxRuntime::backupWindowState() { GetWindowRect(hwnd, &t_rect); t_style = GetWindowLong(hwnd, GWL_STYLE); } void gxRuntime::restoreWindowState() { SetWindowLong(hwnd, GWL_STYLE, t_style); SetWindowPos(hwnd, 0, t_rect.left, t_rect.top, t_rect.right - t_rect.left, t_rect.bottom - t_rect.top, SWP_NOZORDER | SWP_FRAMECHANGED); } bool gxRuntime::setDisplayMode(int w, int h, int d, bool d3d, IDirectDraw7* dirDraw) { if (d) return dirDraw->SetDisplayMode(w, h, d, 0, 0) >= 0; int best_d = 0; if (d3d) { int bd = curr_driver->d3d_desc.dwDeviceRenderBitDepth; if (bd & DDBD_32) best_d = 32; else if (bd & DDBD_24) best_d = 24; else if (bd & DDBD_16) best_d = 16; } else { int best_n = 0; for (d = 16; d <= 32; d += 8) { if (dirDraw->SetDisplayMode(w, h, d, 0, 0) < 0) continue; DDCAPS caps = {sizeof(caps)}; dirDraw->GetCaps(&caps, 0); int n = 0; if (caps.dwCaps & DDCAPS_BLT) ++n; if (caps.dwCaps & DDCAPS_BLTCOLORFILL) ++n; if (caps.dwCKeyCaps & DDCKEYCAPS_SRCBLT) ++n; if (caps.dwCaps2 & DDCAPS2_WIDESURFACES) ++n; if (n == 4) return true; if (n > best_n) { best_d = d; best_n = n; } dirDraw->RestoreDisplayMode(); } } return best_d ? dirDraw->SetDisplayMode(w, h, best_d, 0, 0) >= 0 : false; } gxGraphics* gxRuntime::openWindowedGraphics(int w, int h, int d, bool d3d) { IDirectDraw7* dd; if (DirectDrawCreateEx(curr_driver->guid, (void**)&dd, IID_IDirectDraw7, 0) < 0) return 0; //set coop level if (dd->SetCooperativeLevel(hwnd, DDSCL_NORMAL) >= 0) { //create primary surface IDirectDrawSurface7* ps; DDSURFACEDESC2 desc = {sizeof(desc)}; desc.dwFlags = DDSD_CAPS; desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; if (dd->CreateSurface(&desc, &ps, 0) >= 0) { //create clipper IDirectDrawClipper* cp; if (dd->CreateClipper(0, &cp, 0) >= 0) { //attach clipper if (ps->SetClipper(cp) >= 0) { //set clipper HWND if (cp->SetHWnd(0, hwnd) >= 0) { //create front buffer IDirectDrawSurface7* fs; DDSURFACEDESC2 desc = {sizeof(desc)}; desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; desc.dwWidth = w; desc.dwHeight = h; desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; if (d3d) desc.ddsCaps.dwCaps |= DDSCAPS_3DDEVICE; if (dd->CreateSurface(&desc, &fs, 0) >= 0) { if (timerID = timeSetEvent(100, 10, timerCallback, 0, TIME_PERIODIC)) { //Success! clipper = cp; primSurf = ps; mod_cnt = 0; fs->AddRef(); return new gxGraphics(this, dd, fs, fs, d3d); } fs->Release(); } } } cp->Release(); } ps->Release(); } } dd->Release(); return 0; } gxGraphics* gxRuntime::openExclusiveGraphics(int w, int h, int d, bool d3d) { IDirectDraw7* dd; if (DirectDrawCreateEx(curr_driver->guid, (void**)&dd, IID_IDirectDraw7, 0) < 0) return 0; //Set coop level if (dd->SetCooperativeLevel(hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT) >= 0) { //Set display mode if (setDisplayMode(w, h, d, d3d, dd)) { //create primary surface IDirectDrawSurface7* ps; DDSURFACEDESC2 desc = {sizeof(desc)}; desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP; desc.dwBackBufferCount = 1; if (d3d) desc.ddsCaps.dwCaps |= DDSCAPS_3DDEVICE; if (dd->CreateSurface(&desc, &ps, 0) >= 0) { //find back surface IDirectDrawSurface7* bs; DDSCAPS2 caps = {sizeof caps}; caps.dwCaps = DDSCAPS_BACKBUFFER; if (ps->GetAttachedSurface(&caps, &bs) >= 0) { return new gxGraphics(this, dd, ps, bs, d3d); } ps->Release(); } dd->RestoreDisplayMode(); } } dd->Release(); return 0; } gxGraphics* gxRuntime::openGraphics(int w, int h, int d, int driver, int flags) { if (graphics) return 0; busy = true; bool d3d = flags & gxGraphics::GRAPHICS_3D ? true : false; bool windowed = flags & gxGraphics::GRAPHICS_WINDOWED ? true : false; if (windowed) driver = 0; curr_driver = drivers[driver]; if (windowed) { if (graphics = openWindowedGraphics(w, h, d, d3d)) { gfx_mode = (flags & gxGraphics::GRAPHICS_SCALED) ? 1 : 2; auto_suspend = (flags & gxGraphics::GRAPHICS_AUTOSUSPEND) ? true : false; int ws, ww, hh; if (gfx_mode == 1) { ws = scaled_ws; RECT c_r; GetClientRect(hwnd, &c_r); ww = c_r.right - c_r.left; hh = c_r.bottom - c_r.top; } else { ws = static_ws; ww = w; hh = h; } SetWindowLong(hwnd, GWL_STYLE, ws); SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); RECT w_r, c_r; GetWindowRect(hwnd, &w_r); GetClientRect(hwnd, &c_r); int tw = (w_r.right - w_r.left) - (c_r.right - c_r.left); int th = (w_r.bottom - w_r.top) - (c_r.bottom - c_r.top); int cx = (GetSystemMetrics(SM_CXSCREEN) - ww) / 2; int cy = (GetSystemMetrics(SM_CYSCREEN) - hh) / 2; POINT zz = {0, 0}; ClientToScreen(hwnd, &zz); int bw = zz.x - w_r.left, bh = zz.y - w_r.top; int wx = cx - bw, wy = cy - bh; if (wy < 0) wy = 0; //not above top! MoveWindow(hwnd, wx, wy, ww + tw, hh + th, true); } } else { backupWindowState(); SetWindowLong(hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP); SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); ShowCursor(0); if (graphics = openExclusiveGraphics(w, h, d, d3d)) { gfx_mode = 3; auto_suspend = true; SetCursorPos(0, 0); acquireInput(); } else { ShowCursor(1); restoreWindowState(); } } if (!graphics) curr_driver = 0; gfx_lost = false; busy = false; return graphics; } void gxRuntime::closeGraphics(gxGraphics* g) { if (!graphics || graphics != g) return; auto_suspend = false; busy = true; unacquireInput(); if (timerID) { timeKillEvent(timerID); timerID = 0; } if (clipper) { clipper->Release(); clipper = 0; } if (primSurf) { primSurf->Release(); primSurf = 0; } delete graphics; graphics = 0; if (gfx_mode == 3) { ShowCursor(1); restoreWindowState(); } gfx_mode = 0; gfx_lost = false; busy = false; } bool gxRuntime::graphicsLost() { return gfx_lost; } gxFileSystem* gxRuntime::openFileSystem(int flags) { if (fileSystem) return 0; fileSystem = new gxFileSystem(); return fileSystem; } void gxRuntime::closeFileSystem(gxFileSystem* f) { if (!fileSystem || fileSystem != f) return; delete fileSystem; fileSystem = 0; } //////////////////// // GFX ENUM STUFF // //////////////////// static HRESULT WINAPI enumMode(DDSURFACEDESC2* desc, void* context) { int dp = desc->ddpfPixelFormat.dwRGBBitCount; if (dp == 16 || dp == 24 || dp == 32) { gxRuntime::GfxMode* m = new gxRuntime::GfxMode; m->desc = *desc; gxRuntime::GfxDriver* d = (gxRuntime::GfxDriver*)context; d->modes.push_back(m); } return DDENUMRET_OK; } static int maxDevType; static HRESULT CALLBACK enumDevice(char* desc, char* name, D3DDEVICEDESC7* devDesc, void* context) { int t = 0; GUID guid = devDesc->deviceGUID; if (guid == IID_IDirect3DRGBDevice) t = 1; else if (guid == IID_IDirect3DHALDevice) t = 2; else if (guid == IID_IDirect3DTnLHalDevice) t = 3; if (t > 1 && t > maxDevType) { maxDevType = t; gxRuntime::GfxDriver* d = (gxRuntime::GfxDriver*)context; d->d3d_desc = *devDesc; } return D3DENUMRET_OK; } static BOOL WINAPI enumDriver(GUID FAR* guid, LPSTR desc, LPSTR name, LPVOID context, HMONITOR hm) { IDirectDraw7* dd; if (DirectDrawCreateEx(guid, (void**)&dd, IID_IDirectDraw7, 0) < 0) return 0; if (!guid && !desktop_desc.ddpfPixelFormat.dwRGBBitCount) { desktop_desc.dwSize = sizeof(desktop_desc); dd->GetDisplayMode(&desktop_desc); } gxRuntime::GfxDriver* d = new gxRuntime::GfxDriver; d->guid = guid ? new GUID(*guid) : 0; d->name = desc; //string( name )+" "+string( desc ); memset(&d->d3d_desc, 0, sizeof(d->d3d_desc)); IDirect3D7* dir3d; if (dd->QueryInterface(IID_IDirect3D7, (void**)&dir3d) >= 0) { maxDevType = 0; dir3d->EnumDevices(enumDevice, d); dir3d->Release(); } vector* drivers = (vector*)context; drivers->push_back(d); dd->EnumDisplayModes(0, 0, d, enumMode); dd->Release(); return 1; } void gxRuntime::enumGfx() { denumGfx(); if (enum_all) { DirectDrawEnumerateEx(enumDriver, &drivers, DDENUM_ATTACHEDSECONDARYDEVICES | DDENUM_NONDISPLAYDEVICES); } else { DirectDrawEnumerateEx(enumDriver, &drivers, 0); } } void gxRuntime::denumGfx() { for (size_t k = 0; k < drivers.size(); ++k) { gxRuntime::GfxDriver* d = drivers[k]; for (size_t j = 0; j < d->modes.size(); ++j) delete d->modes[j]; delete d->guid; delete d; } drivers.clear(); } int gxRuntime::enumerateGraphicsDrivers() { if (!enum_all) { enum_all = true; enumGfx(); } return drivers.size(); } void gxRuntime::graphicsDriverInfo(int driver, string* name, int* c) { GfxDriver* g = drivers[driver]; int caps = 0; if (g->d3d_desc.dwDeviceRenderBitDepth) caps |= GFXMODECAPS_3D; *name = g->name; *c = caps; } int gxRuntime::countGraphicsModes(int driver) { return drivers[driver]->modes.size(); } void gxRuntime::graphicsModeInfo(int driver, int mode, int* w, int* h, int* d, int* c) { GfxDriver* g = drivers[driver]; GfxMode* m = g->modes[mode]; int caps = 0; int bd = 0; switch (m->desc.ddpfPixelFormat.dwRGBBitCount) { case 16: bd = DDBD_16; break; case 24: bd = DDBD_24; break; case 32: bd = DDBD_32; break; } if (g->d3d_desc.dwDeviceRenderBitDepth & bd) caps |= GFXMODECAPS_3D; *w = m->desc.dwWidth; *h = m->desc.dwHeight; *d = m->desc.ddpfPixelFormat.dwRGBBitCount; *c = caps; } void gxRuntime::windowedModeInfo(int* c) { int caps = 0; int bd = 0; switch (desktop_desc.ddpfPixelFormat.dwRGBBitCount) { case 16: bd = DDBD_16; break; case 24: bd = DDBD_24; break; case 32: bd = DDBD_32; break; } if (drivers[0]->d3d_desc.dwDeviceRenderBitDepth & bd) caps |= GFXMODECAPS_3D; *c = caps; } gxTimer* gxRuntime::createTimer(int hertz) { gxTimer* t = new gxTimer(this, hertz); timers.insert(t); return t; } void gxRuntime::freeTimer(gxTimer* t) { if (!timers.count(t)) return; timers.erase(t); delete t; } static string toDir(string t) { if (t.size() && t[t.size() - 1] != '\\') t += '\\'; return t; } string gxRuntime::systemProperty(const std::string& p) { char buff[MAX_PATH + 1]; string t = tolower(p); if (t == "cpu") { return "Intel"; } else if (t == "os") { return "Windows"; } else if (t == "appdir") { if (GetModuleFileName(0, buff, MAX_PATH)) { string t = buff; int n = t.find_last_of('\\'); if (n != string::npos) t = t.substr(0, n); return toDir(t); } } else if (t == "apphwnd") { return itoa((int)hwnd); } else if (t == "apphinstance") { return itoa((int)hinst); } else if (t == "windowsdir") { if (GetWindowsDirectory(buff, MAX_PATH)) return toDir(buff); } else if (t == "systemdir") { if (GetSystemDirectory(buff, MAX_PATH)) return toDir(buff); } else if (t == "tempdir") { if (GetTempPath(MAX_PATH, buff)) return toDir(buff); } else if (t == "direct3d7") { if (graphics) return itoa((int)graphics->dir3d); } else if (t == "direct3ddevice7") { if (graphics) return itoa((int)graphics->dir3dDev); } else if (t == "directdraw7") { if (graphics) return itoa((int)graphics->dirDraw); } else if (t == "directinput7") { if (input) return itoa((int)input->dirInput); } return ""; } void gxRuntime::enableDirectInput(bool enable) { if (use_di = enable) { acquireInput(); } else { unacquireInput(); } } int gxRuntime::callDll(const std::string& dll, const std::string& func, const void* in, int in_sz, void* out, int out_sz) { map::const_iterator lib_it = libs.find(dll); if (lib_it == libs.end()) { HINSTANCE h = LoadLibrary(dll.c_str()); if (!h) return 0; gxDll* t = new gxDll; t->hinst = h; lib_it = libs.insert(make_pair(dll, t)).first; } gxDll* t = lib_it->second; map::const_iterator fun_it = t->funcs.find(func); if (fun_it == t->funcs.end()) { LibFunc f = (LibFunc)GetProcAddress(t->hinst, func.c_str()); if (!f) return 0; fun_it = t->funcs.insert(make_pair(func, f)).first; } static void* save_esp; _asm { mov[save_esp], esp } ; int n = fun_it->second(in, in_sz, out, out_sz); _asm { mov esp, [save_esp] } ; return n; }