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"
*/
#include <iostream>
+#ifndef WIN32
#include <X11/Xlib.h>
#include <X11/extensions/xf86vmode.h>
+#endif
#include <msp/core/except.h>
#include <msp/strings/formatter.h>
#include <msp/strings/lexicalcast.h>
bool error_flag=false;
std::string error_msg;
+#ifndef WIN32
int x_error_handler(Display *display, XErrorEvent *event)
{
char err[128];
return 0;
}
+#endif
}
Display::Display(const string &disp_name)
{
+#ifndef WIN32
if(disp_name.empty())
display=XOpenDisplay(0);
else
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)
void Display::set_mode(const VideoMode &mode)
{
+#ifndef WIN32
int screen=DefaultScreen(display);
int nmodes;
}
throw InvalidParameterValue("Requested mode not supported");
+#else
+ (void)mode;
+#endif
}
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;
if(j!=windows.end())
j->second->event(event);
}
+#endif
}
}
class Display
{
private:
+#ifndef WIN32
::Display *display;
+#endif
std::list<VideoMode> modes;
VideoMode orig_mode;
std::map<WindowHandle, Window *> windows;
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 *);
*/
#include <vector>
+#ifdef WIN32
+#include <windows.h>
+#endif
+#include <GL/gl.h>
+#include <msp/core/application.h>
#include <msp/core/except.h>
#include "display.h"
#include "glcontext.h"
#include "window.h"
+#include <iostream>
+using namespace std;
+
namespace Msp {
namespace Graphics {
{ }
-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<int> attribs;
attribs.push_back(GLX_RGBA);
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);
}
#ifndef MSP_GBASE_GLCONTEXT_H_
#define MSP_GBASE_GLCONTEXT_H_
+#ifndef WIN32
#include <GL/glx.h>
+#endif
#include "types.h"
namespace Msp {
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);
#ifndef MSP_GBASE_TYPES_H_
#define MSP_GBASE_TYPES_H_
+#ifdef WIN32
+#include <windows.h>
+#else
#include <X11/Xlib.h>
+#endif
namespace Msp {
namespace Graphics {
+#ifdef WIN32
+typedef HWND WindowHandle;
+#else
typedef ::Window WindowHandle;
+#endif
} // namespace Graphics
} // namespace Msp
*/
#include <vector>
+#ifndef WIN32
#include <X11/Xatom.h>
#include <X11/Xutil.h>
+#else
+#include <windowsx.h>
+#endif
+#include <msp/core/application.h>
#include <msp/core/except.h>
#include "display.h"
#include "window.h"
using namespace std;
+#include <iostream>
+
namespace Msp {
namespace Graphics {
Window::~Window()
{
if(window)
+#ifdef WIN32
+ CloseWindow(window);
+#else
XDestroyWindow(display.get_display(), window);
+#endif
display.remove_window(this);
void Window::set_title(const string &title)
{
+#ifdef WIN32
+ SetWindowText(window, title.c_str());
+#else
vector<unsigned char> buf(title.begin(), title.end());
XTextProperty prop;
prop.value=&buf[0];
prop.nitems=title.size();
XSetWMName(display.get_display(), window, &prop);
display.check_error();
+#endif
}
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);
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<HINSTANCE>(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<HINSTANCE>(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);
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);
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)
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<CREATESTRUCT *>(lparam);
+ SetWindowLong(hwnd, 0, reinterpret_cast<LONG>(cs->lpCreateParams));
+ }
+ else
+ {
+ Window *wnd=reinterpret_cast<Window *>(GetWindowLong(hwnd, 0));
+ if(wnd && wnd->wndproc(msg, wparam, lparam))
+ return 0;
+ }
+
+ return DefWindowProc(hwnd, msg, wparam, lparam);
+}
+#endif
} // namespace Graphics
} // namespace Msp
Display &display;
WindowOptions options;
WindowHandle window;
+#ifndef WIN32
Atom wm_delete_window;
+#endif
public:
Window(Display &, unsigned w, unsigned h, bool fs=false);
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; }
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