From 61eeb96535d1575ca0cf698d833c0ddfc7ae0f50 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sun, 30 Dec 2007 16:18:40 +0000 Subject: [PATCH] Win32 compatibility (for most things) Bind GLContext to a Window at creation time --- Build | 20 ++++-- source/display.cpp | 22 +++++++ source/display.h | 4 ++ source/glcontext.cpp | 83 +++++++++++++++++++----- source/glcontext.h | 15 +++-- source/types.h | 8 +++ source/window.cpp | 150 ++++++++++++++++++++++++++++++++++++++++++- source/window.h | 9 +++ 8 files changed, 285 insertions(+), 26 deletions(-) diff --git a/Build b/Build index efb857b..19c48cb 100644 --- a/Build +++ b/Build @@ -7,11 +7,23 @@ package "mspgbase" require "mspcore"; require "sigc++-2.0"; - require "xlib"; - - build_info + // The OpenGL stuff is hackish, but only way to do it right now + if "arch!=win32" + { + require "xlib"; + require "opengl"; + build_info + { + library "Xxf86vm"; + }; + }; + if "arch=win32" { - library "Xxf86vm"; + build_info + { + library "opengl32"; + library "gdi32"; + }; }; library "mspgbase" diff --git a/source/display.cpp b/source/display.cpp index ba5a640..3baf7c1 100644 --- a/source/display.cpp +++ b/source/display.cpp @@ -6,8 +6,10 @@ Distributed under the LGPL */ #include +#ifndef WIN32 #include #include +#endif #include #include #include @@ -21,6 +23,7 @@ namespace { bool error_flag=false; std::string error_msg; +#ifndef WIN32 int x_error_handler(Display *display, XErrorEvent *event) { char err[128]; @@ -42,6 +45,7 @@ int x_error_handler(Display *display, XErrorEvent *event) return 0; } +#endif } @@ -50,6 +54,7 @@ namespace Graphics { Display::Display(const string &disp_name) { +#ifndef WIN32 if(disp_name.empty()) display=XOpenDisplay(0); else @@ -80,12 +85,17 @@ Display::Display(const string &disp_name) XF86VidModeGetModeLine(display, screen, &dotclock, &modeline); orig_mode=VideoMode(modeline.hdisplay, modeline.vdisplay); orig_mode.rate=dotclock/(modeline.htotal*modeline.vtotal); +#else + (void)disp_name; +#endif } Display::~Display() { +#ifndef WIN32 XCloseDisplay(display); display=0; +#endif } void Display::add_window(Window *wnd) @@ -100,6 +110,7 @@ void Display::remove_window(Window *wnd) void Display::set_mode(const VideoMode &mode) { +#ifndef WIN32 int screen=DefaultScreen(display); int nmodes; @@ -119,6 +130,9 @@ void Display::set_mode(const VideoMode &mode) } throw InvalidParameterValue("Requested mode not supported"); +#else + (void)mode; +#endif } void Display::tick() @@ -127,6 +141,13 @@ void Display::tick() while(1) { +#ifdef WIN32 + MSG msg; + if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) + DispatchMessage(&msg); + else + break; +#else int pending=XPending(display); if(pending==0) break; @@ -142,6 +163,7 @@ void Display::tick() if(j!=windows.end()) j->second->event(event); } +#endif } } diff --git a/source/display.h b/source/display.h index 7397a78..70efd20 100644 --- a/source/display.h +++ b/source/display.h @@ -31,7 +31,9 @@ struct VideoMode class Display { private: +#ifndef WIN32 ::Display *display; +#endif std::list modes; VideoMode orig_mode; std::map windows; @@ -40,7 +42,9 @@ public: Display(const std::string &disp_name=std::string()); ~Display(); +#ifndef WIN32 ::Display *get_display() const { return display; } +#endif void add_window(Window *); void remove_window(Window *); diff --git a/source/glcontext.cpp b/source/glcontext.cpp index 9377e88..a749c6c 100644 --- a/source/glcontext.cpp +++ b/source/glcontext.cpp @@ -6,11 +6,19 @@ Distributed under the LGPL */ #include +#ifdef WIN32 +#include +#endif +#include +#include #include #include "display.h" #include "glcontext.h" #include "window.h" +#include +using namespace std; + namespace Msp { namespace Graphics { @@ -22,9 +30,38 @@ GLOptions::GLOptions(): { } -GLContext::GLContext(Display &d, const GLOptions &opts): - display(d) +GLContext::GLContext(Window &wnd, const GLOptions &opts): + display(wnd.get_display()), + window(wnd) { +#ifdef WIN32 + HDC dc=GetDC(window.get_handle()); + + PIXELFORMATDESCRIPTOR pfd; + memset(&pfd, 0, sizeof(pfd)); + + pfd.nSize=sizeof(pfd); + pfd.nVersion=1; + pfd.dwFlags=PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; + if(opts.doublebuffer) + pfd.dwFlags|=PFD_DOUBLEBUFFER; + pfd.iPixelType=PFD_TYPE_RGBA; + if(opts.alpha) + pfd.cAlphaBits=1; + pfd.cDepthBits=1; + if(opts.stencil) + pfd.cStencilBits=1; + + int pf_index=ChoosePixelFormat(dc, &pfd); + if(!pf_index) + throw Exception("Couldn't find a suitable pixel format"); + SetPixelFormat(dc, pf_index, &pfd); + + context=wglCreateContext(dc); + wglMakeCurrent(dc, context); + + ReleaseDC(window.get_handle(), dc); +#else std::vector attribs; attribs.push_back(GLX_RGBA); @@ -55,44 +92,56 @@ GLContext::GLContext(Display &d, const GLOptions &opts): attribs.push_back(0); ::Display *dpy=display.get_display(); + XVisualInfo *vi=glXChooseVisual(dpy, DefaultScreen(dpy), &attribs.front()); if(!vi) - throw Exception("Couldn't find a GLX visual"); + throw Exception("Couldn't find a suitable GLX visual"); context=glXCreateContext(dpy, vi, 0, true); XSetWindowAttributes attr; attr.colormap=XCreateColormap(dpy, DefaultRootWindow(dpy), vi->visual, AllocNone); - window=XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, 1024, 768, 0, vi->depth, InputOutput, vi->visual, CWColormap, &attr); + subwnd=XCreateWindow(dpy, window.get_handle(), 0, 0, window.get_width(), window.get_height(), 0, vi->depth, InputOutput, vi->visual, CWColormap, &attr); + XMapWindow(display.get_display(), subwnd); XFree(vi); - glXMakeCurrent(dpy, window, context); -} + glXMakeCurrent(dpy, subwnd, context); -GLContext::~GLContext() -{ - glXDestroyContext(display.get_display(), context); - XDestroyWindow(display.get_display(), window); + window.signal_resize.connect(sigc::mem_fun(this, &GLContext::window_resized)); +#endif } -void GLContext::attach(Window &wnd) +GLContext::~GLContext() { - XReparentWindow(display.get_display(), window, wnd.get_handle(), 0, 0); - XMapWindow(display.get_display(), window); +#ifdef WIN32 + wglMakeCurrent(0, 0); + wglDeleteContext(context); +#else + ::Display *dpy=display.get_display(); - wnd.signal_resize.connect(sigc::mem_fun(this, &GLContext::window_resized)); - window_resized(wnd.get_width(), wnd.get_height()); + glXMakeCurrent(dpy, 0, 0); + glXDestroyContext(dpy, context); + XDestroyWindow(dpy, subwnd); +#endif } void GLContext::swap_buffers() { - glXSwapBuffers(display.get_display(), window); +#ifdef WIN32 + HDC dc=GetDC(window.get_handle()); + SwapBuffers(dc); + ReleaseDC(window.get_handle(), dc); +#else + glXSwapBuffers(display.get_display(), subwnd); +#endif } void GLContext::window_resized(unsigned w, unsigned h) { - XMoveResizeWindow(display.get_display(), window, 0, 0, w, h); +#ifndef WIN32 + XMoveResizeWindow(display.get_display(), subwnd, 0, 0, w, h); +#endif glViewport(0, 0, w, h); } diff --git a/source/glcontext.h b/source/glcontext.h index f9e5f46..36130e1 100644 --- a/source/glcontext.h +++ b/source/glcontext.h @@ -8,7 +8,9 @@ Distributed under the LGPL #ifndef MSP_GBASE_GLCONTEXT_H_ #define MSP_GBASE_GLCONTEXT_H_ +#ifndef WIN32 #include +#endif #include "types.h" namespace Msp { @@ -29,18 +31,23 @@ struct GLOptions class GLContext { private: +#ifdef WIN32 + typedef HGLRC Context; +#else typedef GLXContext Context; +#endif Display &display; + Window &window; Context context; - GLXWindow glx_wnd; - WindowHandle window; +#ifndef WIN32 + WindowHandle subwnd; +#endif public: - GLContext(Display &dpy, const GLOptions &opts); + GLContext(Window &wnd, const GLOptions &opts); ~GLContext(); - void attach(Window &wnd); void swap_buffers(); private: void window_resized(unsigned, unsigned); diff --git a/source/types.h b/source/types.h index 1badc5d..e3524f3 100644 --- a/source/types.h +++ b/source/types.h @@ -8,12 +8,20 @@ Distributed under the LGPL #ifndef MSP_GBASE_TYPES_H_ #define MSP_GBASE_TYPES_H_ +#ifdef WIN32 +#include +#else #include +#endif namespace Msp { namespace Graphics { +#ifdef WIN32 +typedef HWND WindowHandle; +#else typedef ::Window WindowHandle; +#endif } // namespace Graphics } // namespace Msp diff --git a/source/window.cpp b/source/window.cpp index f916d1c..7f6f6d8 100644 --- a/source/window.cpp +++ b/source/window.cpp @@ -6,14 +6,21 @@ Distributed under the LGPL */ #include +#ifndef WIN32 #include #include +#else +#include +#endif +#include #include #include "display.h" #include "window.h" using namespace std; +#include + namespace Msp { namespace Graphics { @@ -45,7 +52,11 @@ Window::Window(Display &dpy, const WindowOptions &opts): Window::~Window() { if(window) +#ifdef WIN32 + CloseWindow(window); +#else XDestroyWindow(display.get_display(), window); +#endif display.remove_window(this); @@ -55,6 +66,9 @@ Window::~Window() void Window::set_title(const string &title) { +#ifdef WIN32 + SetWindowText(window, title.c_str()); +#else vector buf(title.begin(), title.end()); XTextProperty prop; prop.value=&buf[0]; @@ -63,6 +77,7 @@ void Window::set_title(const string &title) prop.nitems=title.size(); XSetWMName(display.get_display(), window, &prop); display.check_error(); +#endif } void Window::reconfigure(const WindowOptions &opts) @@ -71,6 +86,12 @@ void Window::reconfigure(const WindowOptions &opts) options=opts; +#ifdef WIN32 + // XXX Preserve position + MoveWindow(window, 0, 0, options.width, options.height, false); + + (void)fullscreen_changed; +#else ::Display *dpy=display.get_display(); XMoveResizeWindow(dpy, window, 0, 0, options.width, options.height); @@ -88,22 +109,78 @@ void Window::reconfigure(const WindowOptions &opts) display.set_mode(VideoMode(options.width, options.height)); else if(fullscreen_changed) display.restore_mode(); +#endif } void Window::show() { +#ifdef WIN32 + ShowWindow(window, SW_SHOWNORMAL); +#else XMapRaised(display.get_display(), window); display.check_error(); +#endif } void Window::hide() { +#ifdef WIN32 + ShowWindow(window, SW_HIDE); +#else XUnmapWindow(display.get_display(), window); display.check_error(); +#endif } void Window::init() { +#ifdef WIN32 + static bool wndclass_created=false; + + if(!wndclass_created) + { + WNDCLASSEX wndcl; + + wndcl.cbSize=sizeof(WNDCLASSEX); + wndcl.style=0; + wndcl.lpfnWndProc=&wndproc_; + wndcl.cbClsExtra=0; + wndcl.cbWndExtra=sizeof(Window *); + wndcl.hInstance=reinterpret_cast(Application::get_data()); + wndcl.hIcon=0; + wndcl.hCursor=0; + wndcl.hbrBackground=0; + wndcl.lpszMenuName=0; + wndcl.lpszClassName="mspgbase"; + wndcl.hIconSm=0; + + if(!RegisterClassEx(&wndcl)) + throw Exception("Couldn't register window class"); + + wndclass_created=true; + } + + RECT rect; + rect.left=0; + rect.top=0; + rect.right=options.width; + rect.bottom=options.height; + AdjustWindowRectEx(&rect, WS_OVERLAPPEDWINDOW, false, WS_EX_OVERLAPPEDWINDOW); + + window=CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, + "mspgbase", + "Window", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, + rect.right-rect.left, rect.bottom-rect.top, + 0, + 0, + reinterpret_cast(Application::get_data()), + this); + if(!window) + throw Exception("CreateWindowEx failed"); + +#else ::Display *dpy=display.get_display(); wm_delete_window=XInternAtom(dpy, "WM_DELETE_WINDOW", true); @@ -112,7 +189,15 @@ void Window::init() attr.override_redirect=options.fullscreen; attr.event_mask=ButtonPressMask|ButtonReleaseMask|PointerMotionMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask|EnterWindowMask; - window=XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, options.width, options.height, 0, CopyFromParent, InputOutput, CopyFromParent, CWOverrideRedirect|CWEventMask, &attr); + window=XCreateWindow(dpy, + DefaultRootWindow(dpy), + 0, 0, + options.width, options.height, + 0, + CopyFromParent, + InputOutput, + CopyFromParent, + CWOverrideRedirect|CWEventMask, &attr); XSetWMProtocols(dpy, window, &wm_delete_window, 1); @@ -121,11 +206,13 @@ void Window::init() display.set_mode(VideoMode(options.width, options.height)); XWarpPointer(dpy, None, window, 0, 0, 0, 0, options.width/2, options.height/2); } +#endif display.add_window(this); display.check_error(); } +#ifndef WIN32 void Window::event(const XEvent &ev) { switch(ev.type) @@ -169,6 +256,67 @@ void Window::event(const XEvent &ev) default:; } } +#endif + +#ifdef WIN32 +int Window::wndproc(UINT msg, WPARAM wp, LPARAM lp) +{ + switch(msg) + { + case WM_KEYDOWN: + signal_key_press.emit(wp, 0, wp); + break; + case WM_KEYUP: + signal_key_release.emit(wp, 0); + break; + case WM_LBUTTONDOWN: + signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0); + break; + case WM_LBUTTONUP: + signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0); + break; + case WM_MBUTTONDOWN: + signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0); + break; + case WM_MBUTTONUP: + signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0); + break; + case WM_RBUTTONDOWN: + signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0); + break; + case WM_RBUTTONUP: + signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0); + break; + case WM_MOUSEMOVE: + signal_pointer_motion.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp)); + break; + case WM_CLOSE: + signal_close.emit(); + break; + default: + return 0; + } + + return 1; +} + +LRESULT CALLBACK Window::wndproc_(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if(msg==WM_CREATE) + { + CREATESTRUCT *cs=reinterpret_cast(lparam); + SetWindowLong(hwnd, 0, reinterpret_cast(cs->lpCreateParams)); + } + else + { + Window *wnd=reinterpret_cast(GetWindowLong(hwnd, 0)); + if(wnd && wnd->wndproc(msg, wparam, lparam)) + return 0; + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} +#endif } // namespace Graphics } // namespace Msp diff --git a/source/window.h b/source/window.h index 2999a78..e85f86a 100644 --- a/source/window.h +++ b/source/window.h @@ -42,7 +42,9 @@ protected: Display &display; WindowOptions options; WindowHandle window; +#ifndef WIN32 Atom wm_delete_window; +#endif public: Window(Display &, unsigned w, unsigned h, bool fs=false); @@ -52,6 +54,7 @@ public: void set_title(const std::string &); void reconfigure(const WindowOptions &); + Display &get_display() const { return display; } const WindowOptions &get_options() const { return options; } unsigned get_width() const { return options.width; } unsigned get_height() const { return options.height; } @@ -60,9 +63,15 @@ public: void show(); void hide(); +#ifndef WIN32 void event(const XEvent &ev); +#endif protected: void init(); +#ifdef WIN32 + int wndproc(UINT, WPARAM, LPARAM); + static LRESULT CALLBACK wndproc_(HWND, UINT, WPARAM, LPARAM); +#endif }; } // namespace Graphics -- 2.45.2