]> git.sesse.net Git - sproing/blob - glwindow.cpp
Initial checkin for move to Git (no prior version history available).
[sproing] / glwindow.cpp
1 /*
2  * The whole interface between GLWindow and the configuration stuff is rather
3  * icky, and _should_ be rewritten. It appears to work somehow, though ;-)
4  */
5
6 #include <stdio.h>
7
8 #ifdef WIN32
9 #include <windows.h>
10 #endif
11
12 #ifdef __linux__
13 #include <unistd.h>
14 #include <GL/glx.h>
15 #include <X11/extensions/xf86vmode.h>
16 #include <X11/keysym.h>
17 #endif
18
19 #include <GL/gl.h>
20 #include <GL/glu.h>
21
22 #include "glwindow.h"
23
24 #ifdef WIN32
25 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
26
27 /* this is ugly, but so is Win32 ;-) */
28 GLWindow *win;
29 #endif
30
31 #define DEMOLIB_XASPECT 4.0
32 #define DEMOLIB_YASPECT 3.0
33
34 void GLWindow::resize(int x, int y, int w, int h)
35 {
36         /* Prevent division by zero */
37         if (h == 0) {
38                 h = 1;
39         }
40
41         float aspect = (float)w / (float)h;
42         if (aspect > DEMOLIB_XASPECT / DEMOLIB_YASPECT) {
43                 int new_w = (int)((float)h * DEMOLIB_XASPECT / DEMOLIB_YASPECT);
44                 x += (w - new_w) / 2;
45                 w = new_w;
46         } else if (aspect < DEMOLIB_XASPECT / DEMOLIB_YASPECT) {
47                 int new_h = (int)((float)w * DEMOLIB_YASPECT / DEMOLIB_XASPECT);
48                 y += (h - new_h) / 2;
49                 h = new_h;
50         }
51  
52         glViewport(x, y, w, h);
53
54         glMatrixMode(GL_PROJECTION);
55         glLoadIdentity();
56         gluPerspective(53.0f, (GLfloat)w / (GLfloat)h, 1.0f, 500.0f);
57         glMatrixMode(GL_MODELVIEW);
58         glLoadIdentity();
59
60 #ifdef __linux__
61 //      XClearWindow(this->dpy, this->win);
62 #endif
63 }
64
65 GLWindow::GLWindow(const char *title, int width, int height, int bpp, bool fullscreen, int zbuffer, int visual_id)
66 {
67 #ifdef WIN32
68         GLuint PixelFormat;
69         WNDCLASS wc;
70         DWORD dwExStyle;
71         DWORD dwStyle;
72         DEVMODE dmScreenSettings;
73
74         if (visual_id != -1) {
75                 EnumDisplaySettings(NULL, visual_id, &dmScreenSettings);
76                 width = dmScreenSettings.dmPelsWidth;
77                 height = dmScreenSettings.dmPelsHeight;
78                 bpp = dmScreenSettings.dmBitsPerPel;
79         } else {
80                 memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
81                 dmScreenSettings.dmSize = sizeof(dmScreenSettings);
82                 dmScreenSettings.dmPelsWidth = width;
83                 dmScreenSettings.dmPelsHeight = height;
84                 dmScreenSettings.dmBitsPerPel = bpp;
85                 dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
86         }
87         win = this;
88         
89         RECT WindowRect;
90         WindowRect.left = (long)0;
91         WindowRect.right = (long)width;
92         WindowRect.top = (long)0;
93         WindowRect.bottom = (long)height;
94         
95 #endif /* WIN32 */      
96 #ifdef __linux__
97         XVisualInfo *vi;
98         int dpyWidth = 0, dpyHeight = 0;
99         int i;
100         XF86VidModeModeInfo **modes;
101         int modeNum;
102         int bestMode;
103         Atom wmDelete;
104         Window winDummy;
105         unsigned int borderDummy;
106
107         static int attrList[] = {
108                 GLX_RGBA, 
109                 GLX_RED_SIZE, 1,
110                 GLX_GREEN_SIZE, 1,
111                 GLX_BLUE_SIZE, 1,
112                 GLX_DOUBLEBUFFER,
113                 GLX_DEPTH_SIZE, zbuffer,
114                 GLX_STENCIL_SIZE, 4,
115                 None
116         };
117 #endif /* __linux__ */
118
119         this->x = 0;
120         this->y = 0;
121         this->width = width;
122         this->height = height;
123         this->bpp = bpp;
124         this->fullscreen = fullscreen;
125         this->zbuffer = zbuffer;
126         this->done = 0;
127         
128 #ifdef WIN32
129         this->hInstance = GetModuleHandle(NULL);
130         wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
131         wc.lpfnWndProc = WndProc;
132         wc.cbClsExtra = 0;
133         wc.cbWndExtra = 0;
134         wc.hInstance = this->hInstance;
135         wc.hIcon = NULL;
136         wc.hCursor = NULL;
137         wc.hbrBackground = NULL;
138         wc.lpszMenuName = NULL;
139         wc.lpszClassName = "Excess-OGL";
140
141         if( !RegisterClass(&wc) ) throw "Couldn't register Window Class";
142
143 #endif /* WIN32 */
144 #ifdef __linux__
145         /* set best mode to current */
146         bestMode = 0;
147
148         /* get a connection */
149         this->dpy = XOpenDisplay(0);
150         this->screen = DefaultScreen(this->dpy);
151
152         if (fullscreen) {
153                 XF86VidModeGetAllModeLines(this->dpy, this->screen, &modeNum, &modes);
154
155                 /* save desktop-resolution before switching modes */
156                 this->deskMode = *modes[0];
157
158                 /* look for mode with requested resolution */
159                 for (i = 0; i < modeNum; i++) {
160                         if ((modes[i]->hdisplay == width) && (modes[i]->vdisplay == height)) {
161                                 bestMode = i;
162                         }
163                 }
164
165                 /* if we don't have it, bomb out */
166                 if (bestMode == 0 && (modes[0]->hdisplay != width || modes[0]->vdisplay != height)) {
167                         throw "Couldn't set requested screen mode.";
168                 }
169         }
170
171         if (visual_id != -1) {
172                 XVisualInfo tmplate;
173                 int nret;
174                 
175                 tmplate.visualid = visual_id;
176                 vi = XGetVisualInfo(this->dpy, VisualIDMask, &tmplate, &nret);
177                 if (vi == NULL) {
178                         throw "Couldn't get selected visual!";
179                 }
180         } else {
181                 /* get an appropriate visual */
182                 vi = glXChooseVisual(this->dpy, this->screen, attrList);
183                 if (vi == NULL) {
184                         throw "Couldn't get double-buffered visual";
185                 }
186         }
187
188         /* create a GLX context */
189         this->ctx = glXCreateContext(this->dpy, vi, NULL, GL_TRUE);
190
191         /* create a color map (umm, needed?) */
192         Colormap cmap = XCreateColormap(this->dpy, RootWindow(this->dpy, vi->screen),
193                 vi->visual, AllocNone);
194         this->attr.colormap = cmap;
195
196         /* make a blank cursor */
197         {
198                 static char data[1] = {0};
199                 Cursor cursor;
200                 Pixmap blank;
201                 XColor dummy;
202
203                 blank = XCreateBitmapFromData(this->dpy, RootWindow(this->dpy, vi->screen), data, 1, 1);
204                 if (blank == None)
205                         throw "Out of memory!";
206                 cursor = XCreatePixmapCursor(this->dpy, blank, blank, &dummy, &dummy, 0, 0);
207                 XFreePixmap(this->dpy, blank);
208                 this->attr.cursor = cursor;
209         }
210                 
211         this->attr.border_pixel = 0;
212 #endif /* __linux__ */
213
214         /* change screen mode */        
215         if (fullscreen) {
216 #ifdef WIN32
217                 if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
218                         throw "Couldn't set requested screen mode.";
219                 }
220 #endif /* WIN32 */
221 #ifdef __linux__
222                 XF86VidModeSwitchToMode(this->dpy, this->screen, modes[bestMode]);
223                 XF86VidModeSetViewPort(this->dpy, this->screen, 0, 0);
224                 dpyWidth = modes[bestMode]->hdisplay;
225                 dpyHeight = modes[bestMode]->vdisplay;
226                 XFree(modes);
227 #endif /* __linux__ */
228         }
229
230         /* create the window */
231 #ifdef WIN32
232         if (fullscreen) {
233                 dwExStyle = WS_EX_APPWINDOW;
234                 dwStyle = WS_POPUP;
235                 ShowCursor(FALSE);
236         } else {
237                 dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
238                 dwStyle = WS_OVERLAPPEDWINDOW;
239         }
240
241         AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
242
243         if (!(hWnd = CreateWindowEx(dwExStyle,
244                                     "Excess-OGL",
245                                     title,
246                                     dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
247                                     0, 0,
248                                     WindowRect.right - WindowRect.left,
249                                     WindowRect.bottom - WindowRect.top,
250                                     NULL,
251                                     NULL,
252                                     this->hInstance,
253                                     NULL))) {
254                 delete this;
255                 throw "Could not change screenmode";
256         }
257 #endif
258 #ifdef __linux__
259         this->attr.background_pixel = 0;
260
261         if (fullscreen) {
262                 /* create a fullscreen window */
263                 this->attr.override_redirect = True;
264                 this->attr.event_mask = KeyPressMask | ButtonPressMask |
265                                         StructureNotifyMask;
266
267                 this->win = XCreateWindow(this->dpy, RootWindow(this->dpy, vi->screen),
268                         0, 0, dpyWidth, dpyHeight, 0, vi->depth, InputOutput, vi->visual,
269                         CWColormap | CWCursor | CWEventMask | CWOverrideRedirect,
270                         &this->attr);
271                 XWarpPointer(this->dpy, None, this->win, 0, 0, 0, 0, 0, 0);
272                 XMapRaised(this->dpy, this->win);
273                 XGrabKeyboard(this->dpy, this->win, True, GrabModeAsync,
274                         GrabModeAsync, CurrentTime);
275                 XGrabPointer(this->dpy, this->win, True, ButtonPressMask,
276                         GrabModeAsync, GrabModeAsync, this->win, None, CurrentTime);
277         } else {
278                 /* create a window in window mode*/
279                 this->attr.event_mask = KeyPressMask | ButtonPressMask |
280                         StructureNotifyMask;
281                 this->win = XCreateWindow(this->dpy, RootWindow(this->dpy, vi->screen),
282                         0, 0, width, height, 0, vi->depth, InputOutput, vi->visual,
283                         CWColormap | CWBorderPixel | CWEventMask, &this->attr);
284
285                 /* only set window title and handle wm_delete_events if in windowed mode */
286                 wmDelete = XInternAtom(this->dpy, "WM_DELETE_WINDOW", True);
287                 XSetWMProtocols(this->dpy, this->win, &wmDelete, 1);
288                 XSetStandardProperties(this->dpy, this->win, title,
289                         title, None, NULL, 0, NULL);
290                 XMapRaised(this->dpy, this->win);
291         }
292 #endif /* __linux__ */
293
294 #ifdef WIN32
295         static PIXELFORMATDESCRIPTOR pfd = {
296                 sizeof(PIXELFORMATDESCRIPTOR),
297                 1,
298                 PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
299                 PFD_TYPE_RGBA,
300                 bpp,
301                 0, 0, 0, 0, 0, 0,
302                 0,
303                 0,
304                 0,
305                 0, 0, 0, 0,
306                 zbuffer,
307                 8,
308                 0,
309                 PFD_MAIN_PLANE,
310                 0,
311                 0, 0, 0
312         };
313         
314         hDC = GetDC(hWnd);
315         PixelFormat = ChoosePixelFormat(hDC, &pfd);
316         if (PixelFormat == 0) {
317                 throw "Could not find a usable pixelformat";
318         }
319         SetPixelFormat(hDC, PixelFormat, &pfd);
320         hRC = wglCreateContext(hDC);
321         wglMakeCurrent(hDC, hRC);
322         ShowWindow(hWnd, SW_SHOW);
323         SetForegroundWindow(hWnd);
324         SetFocus(hWnd);
325
326         SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
327 #endif /* WIN32 */
328 #ifdef __linux__
329         /* connect the glx-context to the window */
330         glXMakeCurrent(this->dpy, this->win, this->ctx);
331         XClearWindow(this->dpy, this->win);
332         XGetGeometry(this->dpy, this->win, &winDummy, &this->x, &this->y,
333                 &this->width, &this->height, &borderDummy, &this->bpp);
334         if (!glXIsDirect(this->dpy, this->ctx)) {
335                 throw "No direct rendering (hardware acceleration) available!";
336         }
337
338         nice(-7);
339 #endif /* __linux__ */
340
341         this->resize(0, 0, this->width, this->height);
342 }
343
344 GLWindow::~GLWindow()
345 {
346 #ifdef __linux__
347         if (this->ctx) {
348                 if (!glXMakeCurrent(this->dpy, None, NULL)) {
349                         throw "Could not release drawing context.";
350                 }
351                 glXDestroyContext(this->dpy, this->ctx);
352                 this->ctx = NULL;
353         }
354 #endif
355
356         if (fullscreen) {
357 #ifdef __linux__
358                 XF86VidModeSwitchToMode(this->dpy, this->screen, &this->deskMode);
359                 XF86VidModeSetViewPort(this->dpy, this->screen, 0, 0);
360 #endif
361 #ifdef WIN32
362                 ChangeDisplaySettings(NULL,0);
363                 ShowCursor(TRUE);
364 #endif
365         }
366
367 #ifdef __linux__
368         XCloseDisplay(this->dpy);
369 #endif
370
371 #ifdef WIN32
372         if (hRC) {
373                 wglMakeCurrent(NULL, NULL);
374                 wglDeleteContext(hRC);
375                 hRC = NULL;
376         }
377         
378         if (hDC != NULL && ReleaseDC(hWnd, hDC)) hDC = NULL;
379         if (hWnd != NULL && DestroyWindow(hWnd)) hWnd = NULL;
380         UnregisterClass("Excess-OGL", hInstance);
381 #endif
382 }
383
384 void GLWindow::flip()
385 {
386 #ifdef WIN32
387         MSG msg;
388         if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
389                 if (msg.message == WM_QUIT) {
390                         this->done = TRUE;
391                 } else {
392                         TranslateMessage(&msg);
393                         DispatchMessage(&msg);
394                 }
395         }
396         SwapBuffers(this->hDC);
397 #endif
398 #ifdef __linux__
399         glXSwapBuffers(this->dpy, this->win);
400 #endif
401 }
402
403 bool GLWindow::is_done()
404 {
405         return this->done;
406 }
407
408 #ifdef WIN32
409 LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
410 {
411         switch (uMsg) {
412         case WM_SYSCOMMAND:
413                 switch (wParam) {
414                 case SC_SCREENSAVE:
415                 case SC_MONITORPOWER:
416                         return 0;
417                 }
418                 break;
419
420         case WM_CLOSE:
421                 PostQuitMessage(0);
422                 return 0;
423
424         case WM_KEYUP:
425                 if (wParam == VK_ESCAPE)
426                         PostQuitMessage(0);
427                 return 0;
428
429         case WM_SIZE:
430                 win->resize(0, 0, LOWORD(lParam), HIWORD(lParam));
431                 return 0;
432         }
433
434         return DefWindowProc(hWnd, uMsg, wParam, lParam);
435 }
436 #endif //WIN32