and now we actually can render stuff, partially
[voxelands-alt.git] / src / graphics / wm_x11.c
bloba450c6f72744149b0cdd1f0bcaffeedb7d49d652
1 /************************************************************************
2 * wm_x11.c
3 * voxelands - 3d voxel world sandbox game
4 * Copyright (C) Lisa 'darkrose' Milne 2016 <lisa@ltmnet.com>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>
18 ************************************************************************/
20 #include "common.h"
21 #define _WM_EXPOSE_ALL
22 #include "wm.h"
24 #ifndef WIN32
26 #include <X11/Xatom.h>
28 /* attributes for a double buffered visual in RGBA format with at least
29 * 4 bits per color and a 16 bit depth buffer */
30 static int attr_list[] = {
31 GLX_RENDER_TYPE, GLX_RGBA_BIT,
32 GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
33 GLX_DOUBLEBUFFER, True,
34 GLX_X_RENDERABLE, True,
35 GLX_RED_SIZE, 4,
36 GLX_GREEN_SIZE, 4,
37 GLX_BLUE_SIZE, 4,
38 GLX_ALPHA_SIZE, 4,
39 GLX_DEPTH_SIZE, 16,
40 None
43 /* initialise the game window */
44 int wm_init()
46 int min;
47 int max;
48 char* glXv;
50 wm_data.isinit = 1;
52 /* get a connection */
53 wm_data.dpy = XOpenDisplay(0);
54 wm_data.screen = DefaultScreen(wm_data.dpy);
55 wm_data.fb_cfg = NULL;
56 /* TODO: uncomment this
57 wm_data.cursor.mat = NULL; */
59 /* get a connection */
60 XF86VidModeQueryVersion(wm_data.dpy, &max, &min);
61 vlprintf(CN_INFO "XF86VidModeExtension version: %d.%d", max, min);
62 XF86VidModeGetAllModeLines(wm_data.dpy, wm_data.screen, &wm_data.mode_count, &wm_data.modes);
64 /* save desktop resolution before switching modes */
65 wm_data.deskMode = *wm_data.modes[0];
67 glXv = (char*)glXGetClientString(wm_data.dpy, GLX_VERSION);
68 vlprintf(CN_INFO "glX version: %s",glXv,max,min);
70 return wm_create();
73 /* exit the game window */
74 void wm_exit()
76 wm_destroy();
77 XFree(wm_data.modes);
78 XCloseDisplay(wm_data.dpy);
81 /* create a window */
82 int wm_create()
84 Colormap cmap;
85 Atom wmDelete;
86 Window winDummy;
87 unsigned int borderDummy;
88 int x;
89 int y;
90 unsigned int w;
91 unsigned int h;
92 unsigned int d;
93 int i;
95 if (!wm_data.fb_cfg) {
96 GLXFBConfig *fb_configs = NULL;
97 int num_fb_configs = 0;
99 fb_configs = glXChooseFBConfig(wm_data.dpy, wm_data.screen, attr_list, &num_fb_configs);
100 if (!fb_configs || !num_fb_configs) {
101 fb_configs = glXGetFBConfigs(wm_data.dpy, wm_data.screen, &num_fb_configs);
102 if (!fb_configs || !num_fb_configs)
103 return 1;
105 wm_data.fb_cfg = fb_configs[0];
106 glXGetFBConfigAttrib(wm_data.dpy, wm_data.fb_cfg, GLX_DOUBLEBUFFER, &wm_data.dblbuff);
107 wm_data.vi = glXGetVisualFromFBConfig(wm_data.dpy, wm_data.fb_cfg);
109 wm_data.ctx = glXCreateNewContext(wm_data.dpy, wm_data.fb_cfg, GLX_RGBA_TYPE, 0, True);
110 if (!wm_data.ctx)
111 return 1;
114 /* set best mode to current */
115 wm_data.mode = 0;
116 /* look for mode with requested resolution */
117 for (i=0; i<wm_data.mode_count; i++) {
118 if ((wm_data.modes[i]->hdisplay == wm_data.size.width) && (wm_data.modes[i]->vdisplay == wm_data.size.height)) {
119 wm_data.mode = i;
120 break;
124 /* create a color map */
125 cmap = XCreateColormap(
126 wm_data.dpy,
127 RootWindow(wm_data.dpy, wm_data.vi->screen),
128 wm_data.vi->visual,
129 AllocNone
132 wm_data.attr.colormap = cmap;
133 wm_data.attr.border_pixel = 0;
134 wm_data.attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask;
136 if (wm_data.fullscreen) {
137 XF86VidModeSwitchToMode(wm_data.dpy, wm_data.screen, wm_data.modes[wm_data.mode]);
138 XF86VidModeSetViewPort(wm_data.dpy, wm_data.screen, 0, 0);
140 /* create a fullscreen window */
141 wm_data.attr.override_redirect = True;
142 wm_data.win = XCreateWindow(
143 wm_data.dpy,
144 RootWindow(wm_data.dpy, wm_data.vi->screen),
147 wm_data.modes[wm_data.mode]->hdisplay,
148 wm_data.modes[wm_data.mode]->vdisplay,
150 wm_data.vi->depth,
151 InputOutput,
152 wm_data.vi->visual,
153 CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect,
154 &wm_data.attr
157 XWarpPointer(wm_data.dpy, None, wm_data.win, 0, 0, 0, 0, 0, 0);
158 XMapRaised(wm_data.dpy, wm_data.win);
159 XGrabKeyboard(wm_data.dpy, wm_data.win, True, GrabModeAsync, GrabModeAsync, CurrentTime);
160 XGrabPointer(wm_data.dpy, wm_data.win, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, wm_data.win, None, CurrentTime);
161 }else{
162 XSizeHints *hints;
163 /* create a window */
164 wm_data.win = XCreateWindow(
165 wm_data.dpy,
166 RootWindow(wm_data.dpy, wm_data.vi->screen),
169 wm_data.size.width,
170 wm_data.size.height,
172 wm_data.vi->depth,
173 InputOutput,
174 wm_data.vi->visual,
175 CWBorderPixel | CWColormap | CWEventMask,
176 &wm_data.attr
179 /* handle wm_delete_events */
180 wmDelete = XInternAtom(wm_data.dpy, "WM_DELETE_WINDOW", True);
181 XSetWMProtocols(wm_data.dpy, wm_data.win, &wmDelete, 1);
182 XMapRaised(wm_data.dpy, wm_data.win);
184 /* set window title */
185 XStoreName(wm_data.dpy, wm_data.win, wm_data.title);
187 /* prevent window resizing */
188 hints = XAllocSizeHints();
189 hints->min_width = hints->max_width = wm_data.size.width;
190 hints->min_height = hints->max_height = wm_data.size.height;
191 hints->flags = PMinSize | PMaxSize;
192 XSetWMNormalHints(wm_data.dpy, wm_data.win, hints);
193 XFree(hints);
196 wm_data.glxwin = glXCreateWindow(wm_data.dpy, wm_data.fb_cfg, wm_data.win, NULL);
198 /* make OpenGL context current */
199 if (!glXMakeContextCurrent(wm_data.dpy, wm_data.glxwin, wm_data.glxwin, wm_data.ctx)) {
200 glXDestroyContext(wm_data.dpy, wm_data.ctx);
201 return 1;
204 XGetGeometry(
205 wm_data.dpy,
206 wm_data.win,
207 &winDummy,
212 &borderDummy,
216 wm_data.size.width = (int)w;
217 wm_data.size.height = (int)h;
219 if (glXIsDirect(wm_data.dpy, wm_data.ctx)) {
220 int major;
221 int minor;
222 char* db = "";
223 glGetIntegerv(GL_MAJOR_VERSION, &major);
224 glGetIntegerv(GL_MINOR_VERSION, &minor);
226 if (wm_data.dblbuff)
227 db = "Double Buffered ";
229 vlprintf(CN_INFO "%sDirect Rendering: OpenGL %d.%d",db,major,minor);
232 return 0;
235 /* resize the screen, fullscreen or windowed */
236 int wm_resize()
238 if (!wm_data.isinit)
239 return 0;
241 XResizeWindow(wm_data.dpy, wm_data.win, wm_data.size.width, wm_data.size.height);
243 return 0;
246 /* flush graphics through and flip buffers */
247 int wm_update()
249 glFlush();
250 /* update the screen */
251 if (wm_data.dblbuff)
252 glXSwapBuffers(wm_data.dpy, wm_data.glxwin);
253 return 0;
256 /* destroy the current window */
257 void wm_destroy()
259 if (wm_data.ctx) {
260 glXMakeContextCurrent(wm_data.dpy, None, None, NULL);
262 glXDestroyContext(wm_data.dpy, wm_data.ctx);
263 wm_data.ctx = NULL;
264 glXDestroyWindow(wm_data.dpy,wm_data.glxwin);
266 /* switch back to original desktop resolution if we were in fs */
267 if (wm_data.fullscreen) {
268 XF86VidModeSwitchToMode(wm_data.dpy, wm_data.screen, &wm_data.deskMode);
269 XF86VidModeSetViewPort(wm_data.dpy, wm_data.screen, 0, 0);
274 /* set fullscreen on/off */
275 void wm_toggle_fullscreen(int fs)
277 if (fs == wm_data.fullscreen)
278 return;
280 if (!wm_data.isinit) {
281 wm_data.fullscreen = fs;
282 return;
284 if (wm_data.ctx) {
285 glXMakeContextCurrent(wm_data.dpy, None, None, NULL);
286 glXDestroyWindow(wm_data.dpy,wm_data.glxwin);
288 /* switch back to original desktop resolution if we were in fs */
289 if (wm_data.fullscreen) {
290 XF86VidModeSwitchToMode(wm_data.dpy, wm_data.screen, &wm_data.deskMode);
291 XF86VidModeSetViewPort(wm_data.dpy, wm_data.screen, 0, 0);
293 wm_data.fullscreen = fs;
294 /* TODO: this isn't working in glX */
295 wm_create();
298 /* use file as a cursor texture */
299 void wm_cursor(char* file, int width, int height, int offset_x, int offset_y)
301 /* TODO: once the rest of the graphics are in, do it */
302 #ifdef DONT_DO_IT_FOR_FUCKS_SAKE
303 Cursor invisibleCursor;
304 Pixmap bitmapNoData;
305 XColor black;
306 static char noData[] = { 0,0,0,0,0,0,0,0 };
308 if (!file) {
309 if (!wm_data.cursor.mat)
310 return;
312 wm_data.cursor.mat = NULL;
313 XUndefineCursor(wm_data.dpy, wm_data.win);
315 return;
318 wm_data.cursor.mat = mat_from_image(file);
319 wm_data.cursor.w = width;
320 wm_data.cursor.h = height;
321 wm_data.cursor.x = offset_x;
322 wm_data.cursor.y = offset_y;
324 if (!wm_data.cursor.mat)
325 return;
327 black.red = 0;
328 black.green = 0;
329 black.blue = 0;
331 bitmapNoData = XCreateBitmapFromData(wm_data.dpy, wm_data.win, noData, 8, 8);
332 invisibleCursor = XCreatePixmapCursor(wm_data.dpy, bitmapNoData, bitmapNoData, &black, &black, 0, 0);
333 XDefineCursor(wm_data.dpy, wm_data.win, invisibleCursor);
334 XFreeCursor(wm_data.dpy, invisibleCursor);
335 #endif
338 /* grab the mouse */
339 void wm_grab()
341 Cursor invisibleCursor;
342 Pixmap bitmapNoData;
343 XColor black;
344 static char noData[] = { 0,0,0,0,0,0,0,0 };
346 /* TODO: uncomment this
347 if (mouse[MGRAB])
348 return; */
350 black.red = 0;
351 black.green = 0;
352 black.blue = 0;
354 bitmapNoData = XCreateBitmapFromData(wm_data.dpy, wm_data.win, noData, 8, 8);
355 invisibleCursor = XCreatePixmapCursor(wm_data.dpy, bitmapNoData, bitmapNoData, &black, &black, 0, 0);
356 XDefineCursor(wm_data.dpy, wm_data.win, invisibleCursor);
357 XFreeCursor(wm_data.dpy, invisibleCursor);
359 if (!wm_data.fullscreen)
360 XGrabPointer(wm_data.dpy, wm_data.win, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, wm_data.win, None, CurrentTime);
362 /* TODO: uncomment this
363 mouse[MGRAB] = 1; */
366 /* stop grabbing the mouse */
367 void wm_ungrab()
369 /* TODO: uncomment this
370 if (!mouse[MGRAB])
371 return; */
373 XUndefineCursor(wm_data.dpy, wm_data.win);
374 if (!wm_data.fullscreen)
375 XUngrabPointer(wm_data.dpy, CurrentTime);
377 /* TODO: uncomment this
378 mouse[MGRAB] = 0; */
381 /* set the window title */
382 void wm_title(char* title)
384 if (title) {
385 if (wm_data.title)
386 free(wm_data.title);
387 wm_data.title = strdup(title);
389 if (!wm_data.isinit)
390 return;
392 XStoreName(wm_data.dpy, wm_data.win, wm_data.title);
395 #endif