+/*
+ * The whole interface between GLWindow and the configuration stuff is rather
+ * icky, and _should_ be rewritten. It appears to work somehow, though ;-)
+ */
+
+#include <stdio.h>
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#ifdef __linux__
+#include <unistd.h>
+#include <GL/glx.h>
+#include <X11/extensions/xf86vmode.h>
+#include <X11/keysym.h>
+#endif
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+
+#include "glwindow.h"
+
+#ifdef WIN32
+LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
+
+/* this is ugly, but so is Win32 ;-) */
+GLWindow *win;
+#endif
+
+#define DEMOLIB_XASPECT 4.0
+#define DEMOLIB_YASPECT 3.0
+
+void GLWindow::resize(int x, int y, int w, int h)
+{
+ /* Prevent division by zero */
+ if (h == 0) {
+ h = 1;
+ }
+
+ float aspect = (float)w / (float)h;
+ if (aspect > DEMOLIB_XASPECT / DEMOLIB_YASPECT) {
+ int new_w = (int)((float)h * DEMOLIB_XASPECT / DEMOLIB_YASPECT);
+ x += (w - new_w) / 2;
+ w = new_w;
+ } else if (aspect < DEMOLIB_XASPECT / DEMOLIB_YASPECT) {
+ int new_h = (int)((float)w * DEMOLIB_YASPECT / DEMOLIB_XASPECT);
+ y += (h - new_h) / 2;
+ h = new_h;
+ }
+
+ glViewport(x, y, w, h);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gluPerspective(53.0f, (GLfloat)w / (GLfloat)h, 1.0f, 500.0f);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+#ifdef __linux__
+// XClearWindow(this->dpy, this->win);
+#endif
+}
+
+GLWindow::GLWindow(const char *title, int width, int height, int bpp, bool fullscreen, int zbuffer, int visual_id)
+{
+#ifdef WIN32
+ GLuint PixelFormat;
+ WNDCLASS wc;
+ DWORD dwExStyle;
+ DWORD dwStyle;
+ DEVMODE dmScreenSettings;
+
+ if (visual_id != -1) {
+ EnumDisplaySettings(NULL, visual_id, &dmScreenSettings);
+ width = dmScreenSettings.dmPelsWidth;
+ height = dmScreenSettings.dmPelsHeight;
+ bpp = dmScreenSettings.dmBitsPerPel;
+ } else {
+ memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
+ dmScreenSettings.dmSize = sizeof(dmScreenSettings);
+ dmScreenSettings.dmPelsWidth = width;
+ dmScreenSettings.dmPelsHeight = height;
+ dmScreenSettings.dmBitsPerPel = bpp;
+ dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
+ }
+ win = this;
+
+ RECT WindowRect;
+ WindowRect.left = (long)0;
+ WindowRect.right = (long)width;
+ WindowRect.top = (long)0;
+ WindowRect.bottom = (long)height;
+
+#endif /* WIN32 */
+#ifdef __linux__
+ XVisualInfo *vi;
+ int dpyWidth = 0, dpyHeight = 0;
+ int i;
+ XF86VidModeModeInfo **modes;
+ int modeNum;
+ int bestMode;
+ Atom wmDelete;
+ Window winDummy;
+ unsigned int borderDummy;
+
+ static int attrList[] = {
+ GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ GLX_DEPTH_SIZE, zbuffer,
+ GLX_STENCIL_SIZE, 4,
+ None
+ };
+#endif /* __linux__ */
+
+ this->x = 0;
+ this->y = 0;
+ this->width = width;
+ this->height = height;
+ this->bpp = bpp;
+ this->fullscreen = fullscreen;
+ this->zbuffer = zbuffer;
+ this->done = 0;
+
+#ifdef WIN32
+ this->hInstance = GetModuleHandle(NULL);
+ wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
+ wc.lpfnWndProc = WndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = this->hInstance;
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = "Excess-OGL";
+
+ if( !RegisterClass(&wc) ) throw "Couldn't register Window Class";
+
+#endif /* WIN32 */
+#ifdef __linux__
+ /* set best mode to current */
+ bestMode = 0;
+
+ /* get a connection */
+ this->dpy = XOpenDisplay(0);
+ this->screen = DefaultScreen(this->dpy);
+
+ if (fullscreen) {
+ XF86VidModeGetAllModeLines(this->dpy, this->screen, &modeNum, &modes);
+
+ /* save desktop-resolution before switching modes */
+ this->deskMode = *modes[0];
+
+ /* look for mode with requested resolution */
+ for (i = 0; i < modeNum; i++) {
+ if ((modes[i]->hdisplay == width) && (modes[i]->vdisplay == height)) {
+ bestMode = i;
+ }
+ }
+
+ /* if we don't have it, bomb out */
+ if (bestMode == 0 && (modes[0]->hdisplay != width || modes[0]->vdisplay != height)) {
+ throw "Couldn't set requested screen mode.";
+ }
+ }
+
+ if (visual_id != -1) {
+ XVisualInfo tmplate;
+ int nret;
+
+ tmplate.visualid = visual_id;
+ vi = XGetVisualInfo(this->dpy, VisualIDMask, &tmplate, &nret);
+ if (vi == NULL) {
+ throw "Couldn't get selected visual!";
+ }
+ } else {
+ /* get an appropriate visual */
+ vi = glXChooseVisual(this->dpy, this->screen, attrList);
+ if (vi == NULL) {
+ throw "Couldn't get double-buffered visual";
+ }
+ }
+
+ /* create a GLX context */
+ this->ctx = glXCreateContext(this->dpy, vi, NULL, GL_TRUE);
+
+ /* create a color map (umm, needed?) */
+ Colormap cmap = XCreateColormap(this->dpy, RootWindow(this->dpy, vi->screen),
+ vi->visual, AllocNone);
+ this->attr.colormap = cmap;
+
+ /* make a blank cursor */
+ {
+ static char data[1] = {0};
+ Cursor cursor;
+ Pixmap blank;
+ XColor dummy;
+
+ blank = XCreateBitmapFromData(this->dpy, RootWindow(this->dpy, vi->screen), data, 1, 1);
+ if (blank == None)
+ throw "Out of memory!";
+ cursor = XCreatePixmapCursor(this->dpy, blank, blank, &dummy, &dummy, 0, 0);
+ XFreePixmap(this->dpy, blank);
+ this->attr.cursor = cursor;
+ }
+
+ this->attr.border_pixel = 0;
+#endif /* __linux__ */
+
+ /* change screen mode */
+ if (fullscreen) {
+#ifdef WIN32
+ if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
+ throw "Couldn't set requested screen mode.";
+ }
+#endif /* WIN32 */
+#ifdef __linux__
+ XF86VidModeSwitchToMode(this->dpy, this->screen, modes[bestMode]);
+ XF86VidModeSetViewPort(this->dpy, this->screen, 0, 0);
+ dpyWidth = modes[bestMode]->hdisplay;
+ dpyHeight = modes[bestMode]->vdisplay;
+ XFree(modes);
+#endif /* __linux__ */
+ }
+
+ /* create the window */
+#ifdef WIN32
+ if (fullscreen) {
+ dwExStyle = WS_EX_APPWINDOW;
+ dwStyle = WS_POPUP;
+ ShowCursor(FALSE);
+ } else {
+ dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
+ dwStyle = WS_OVERLAPPEDWINDOW;
+ }
+
+ AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
+
+ if (!(hWnd = CreateWindowEx(dwExStyle,
+ "Excess-OGL",
+ title,
+ dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
+ 0, 0,
+ WindowRect.right - WindowRect.left,
+ WindowRect.bottom - WindowRect.top,
+ NULL,
+ NULL,
+ this->hInstance,
+ NULL))) {
+ delete this;
+ throw "Could not change screenmode";
+ }
+#endif
+#ifdef __linux__
+ this->attr.background_pixel = 0;
+
+ if (fullscreen) {
+ /* create a fullscreen window */
+ this->attr.override_redirect = True;
+ this->attr.event_mask = KeyPressMask | ButtonPressMask |
+ StructureNotifyMask;
+
+ this->win = XCreateWindow(this->dpy, RootWindow(this->dpy, vi->screen),
+ 0, 0, dpyWidth, dpyHeight, 0, vi->depth, InputOutput, vi->visual,
+ CWColormap | CWCursor | CWEventMask | CWOverrideRedirect,
+ &this->attr);
+ XWarpPointer(this->dpy, None, this->win, 0, 0, 0, 0, 0, 0);
+ XMapRaised(this->dpy, this->win);
+ XGrabKeyboard(this->dpy, this->win, True, GrabModeAsync,
+ GrabModeAsync, CurrentTime);
+ XGrabPointer(this->dpy, this->win, True, ButtonPressMask,
+ GrabModeAsync, GrabModeAsync, this->win, None, CurrentTime);
+ } else {
+ /* create a window in window mode*/
+ this->attr.event_mask = KeyPressMask | ButtonPressMask |
+ StructureNotifyMask;
+ this->win = XCreateWindow(this->dpy, RootWindow(this->dpy, vi->screen),
+ 0, 0, width, height, 0, vi->depth, InputOutput, vi->visual,
+ CWColormap | CWBorderPixel | CWEventMask, &this->attr);
+
+ /* only set window title and handle wm_delete_events if in windowed mode */
+ wmDelete = XInternAtom(this->dpy, "WM_DELETE_WINDOW", True);
+ XSetWMProtocols(this->dpy, this->win, &wmDelete, 1);
+ XSetStandardProperties(this->dpy, this->win, title,
+ title, None, NULL, 0, NULL);
+ XMapRaised(this->dpy, this->win);
+ }
+#endif /* __linux__ */
+
+#ifdef WIN32
+ static PIXELFORMATDESCRIPTOR pfd = {
+ sizeof(PIXELFORMATDESCRIPTOR),
+ 1,
+ PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
+ PFD_TYPE_RGBA,
+ bpp,
+ 0, 0, 0, 0, 0, 0,
+ 0,
+ 0,
+ 0,
+ 0, 0, 0, 0,
+ zbuffer,
+ 8,
+ 0,
+ PFD_MAIN_PLANE,
+ 0,
+ 0, 0, 0
+ };
+
+ hDC = GetDC(hWnd);
+ PixelFormat = ChoosePixelFormat(hDC, &pfd);
+ if (PixelFormat == 0) {
+ throw "Could not find a usable pixelformat";
+ }
+ SetPixelFormat(hDC, PixelFormat, &pfd);
+ hRC = wglCreateContext(hDC);
+ wglMakeCurrent(hDC, hRC);
+ ShowWindow(hWnd, SW_SHOW);
+ SetForegroundWindow(hWnd);
+ SetFocus(hWnd);
+
+ SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
+#endif /* WIN32 */
+#ifdef __linux__
+ /* connect the glx-context to the window */
+ glXMakeCurrent(this->dpy, this->win, this->ctx);
+ XClearWindow(this->dpy, this->win);
+ XGetGeometry(this->dpy, this->win, &winDummy, &this->x, &this->y,
+ &this->width, &this->height, &borderDummy, &this->bpp);
+ if (!glXIsDirect(this->dpy, this->ctx)) {
+ throw "No direct rendering (hardware acceleration) available!";
+ }
+
+ nice(-7);
+#endif /* __linux__ */
+
+ this->resize(0, 0, this->width, this->height);
+}
+
+GLWindow::~GLWindow()
+{
+#ifdef __linux__
+ if (this->ctx) {
+ if (!glXMakeCurrent(this->dpy, None, NULL)) {
+ throw "Could not release drawing context.";
+ }
+ glXDestroyContext(this->dpy, this->ctx);
+ this->ctx = NULL;
+ }
+#endif
+
+ if (fullscreen) {
+#ifdef __linux__
+ XF86VidModeSwitchToMode(this->dpy, this->screen, &this->deskMode);
+ XF86VidModeSetViewPort(this->dpy, this->screen, 0, 0);
+#endif
+#ifdef WIN32
+ ChangeDisplaySettings(NULL,0);
+ ShowCursor(TRUE);
+#endif
+ }
+
+#ifdef __linux__
+ XCloseDisplay(this->dpy);
+#endif
+
+#ifdef WIN32
+ if (hRC) {
+ wglMakeCurrent(NULL, NULL);
+ wglDeleteContext(hRC);
+ hRC = NULL;
+ }
+
+ if (hDC != NULL && ReleaseDC(hWnd, hDC)) hDC = NULL;
+ if (hWnd != NULL && DestroyWindow(hWnd)) hWnd = NULL;
+ UnregisterClass("Excess-OGL", hInstance);
+#endif
+}
+
+void GLWindow::flip()
+{
+#ifdef WIN32
+ MSG msg;
+ if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ if (msg.message == WM_QUIT) {
+ this->done = TRUE;
+ } else {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ SwapBuffers(this->hDC);
+#endif
+#ifdef __linux__
+ glXSwapBuffers(this->dpy, this->win);
+#endif
+}
+
+bool GLWindow::is_done()
+{
+ return this->done;
+}
+
+#ifdef WIN32
+LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg) {
+ case WM_SYSCOMMAND:
+ switch (wParam) {
+ case SC_SCREENSAVE:
+ case SC_MONITORPOWER:
+ return 0;
+ }
+ break;
+
+ case WM_CLOSE:
+ PostQuitMessage(0);
+ return 0;
+
+ case WM_KEYUP:
+ if (wParam == VK_ESCAPE)
+ PostQuitMessage(0);
+ return 0;
+
+ case WM_SIZE:
+ win->resize(0, 0, LOWORD(lParam), HIWORD(lParam));
+ return 0;
+ }
+
+ return DefWindowProc(hWnd, uMsg, wParam, lParam);
+}
+#endif //WIN32