1 /************************************************************************
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 ************************************************************************/
21 #define _WM_EXPOSE_ALL
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
,
43 /* initialise the game window */
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
);
73 /* exit the game window */
78 XCloseDisplay(wm_data
.dpy
);
87 unsigned int borderDummy
;
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
)
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
);
114 /* set best mode to current */
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
)) {
124 /* create a color map */
125 cmap
= XCreateColormap(
127 RootWindow(wm_data
.dpy
, wm_data
.vi
->screen
),
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(
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
,
153 CWBorderPixel
| CWColormap
| CWEventMask
| CWOverrideRedirect
,
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
);
163 /* create a window */
164 wm_data
.win
= XCreateWindow(
166 RootWindow(wm_data
.dpy
, wm_data
.vi
->screen
),
175 CWBorderPixel
| CWColormap
| CWEventMask
,
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
);
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
);
216 wm_data
.size
.width
= (int)w
;
217 wm_data
.size
.height
= (int)h
;
219 if (glXIsDirect(wm_data
.dpy
, wm_data
.ctx
)) {
223 glGetIntegerv(GL_MAJOR_VERSION
, &major
);
224 glGetIntegerv(GL_MINOR_VERSION
, &minor
);
227 db
= "Double Buffered ";
229 vlprintf(CN_INFO
"%sDirect Rendering: OpenGL %d.%d",db
,major
,minor
);
235 /* resize the screen, fullscreen or windowed */
241 XResizeWindow(wm_data
.dpy
, wm_data
.win
, wm_data
.size
.width
, wm_data
.size
.height
);
246 /* flush graphics through and flip buffers */
250 /* update the screen */
252 glXSwapBuffers(wm_data
.dpy
, wm_data
.glxwin
);
256 /* destroy the current window */
260 glXMakeContextCurrent(wm_data
.dpy
, None
, None
, NULL
);
262 glXDestroyContext(wm_data
.dpy
, wm_data
.ctx
);
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
)
280 if (!wm_data
.isinit
) {
281 wm_data
.fullscreen
= fs
;
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 */
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
;
306 static char noData
[] = { 0,0,0,0,0,0,0,0 };
309 if (!wm_data
.cursor
.mat
)
312 wm_data
.cursor
.mat
= NULL
;
313 XUndefineCursor(wm_data
.dpy
, wm_data
.win
);
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
)
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
);
341 Cursor invisibleCursor
;
344 static char noData
[] = { 0,0,0,0,0,0,0,0 };
346 /* TODO: uncomment this
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
366 /* stop grabbing the mouse */
369 /* TODO: uncomment this
373 XUndefineCursor(wm_data
.dpy
, wm_data
.win
);
374 if (!wm_data
.fullscreen
)
375 XUngrabPointer(wm_data
.dpy
, CurrentTime
);
377 /* TODO: uncomment this
381 /* set the window title */
382 void wm_title(char* title
)
387 wm_data
.title
= strdup(title
);
392 XStoreName(wm_data
.dpy
, wm_data
.win
, wm_data
.title
);