sgl
changeset 4:648f8604d2b2
cont. x11 module
author | John Tsiombikas <nuclear@siggraph.org> |
---|---|
date | Thu, 12 May 2011 11:04:10 +0300 |
parents | 1b6c5dadb460 |
children | 0570e27e5ebc |
files | include/sgl.h src/cb.c src/log.c src/log.h src/sgl.c src/wsys.h src/wsys_x11.c |
diffstat | 7 files changed, 447 insertions(+), 24 deletions(-) [+] |
line diff
1.1 --- a/include/sgl.h Wed May 11 09:09:43 2011 +0300 1.2 +++ b/include/sgl.h Thu May 12 11:04:10 2011 +0300 1.3 @@ -5,6 +5,7 @@ 1.4 #define SGL_DEPTH 2 1.5 #define SGL_STENCIL 4 1.6 #define SGL_STEREO 8 1.7 +#define SGL_MULTISAMPLE 16 1.8 1.9 enum { 1.10 SGL_CREATE, 1.11 @@ -23,15 +24,22 @@ 1.12 int sgl_init(void); 1.13 void sgl_shutdown(void); 1.14 1.15 -int sgl_set_video_mode(int xsz, int ysz, int bpp); 1.16 -int sgl_get_video_mode(int *xsz, int *ysz, int *bpp); 1.17 +int sgl_set_video_mode(int xsz, int ysz); 1.18 +int sgl_get_video_mode(int *xsz, int *ysz); 1.19 1.20 -int sgl_window(int xsz, int ysz, unsigned int mode); 1.21 +int sgl_create_window(int xsz, int ysz, unsigned int mode); 1.22 void sgl_close_window(int win); 1.23 1.24 +int sgl_set_active(int id); 1.25 +int sgl_set_title(const char *str); 1.26 + 1.27 +int sgl_process_events(void); 1.28 +int sgl_event_loop(void); 1.29 + 1.30 int sgl_push_callbacks(void); 1.31 int sgl_pop_callbacks(void); 1.32 void sgl_clear_callbacks(void); 1.33 -void (*sgl_callback(int idx, void (*func)()))(); 1.34 +void sgl_set_callback(int idx, void (*func)()); 1.35 +void (*sgl_get_callback(int idx))(); 1.36 1.37 #endif /* SGL_H_ */
2.1 --- a/src/cb.c Wed May 11 09:09:43 2011 +0300 2.2 +++ b/src/cb.c Thu May 12 11:04:10 2011 +0300 2.3 @@ -1,12 +1,15 @@ 2.4 #include <stdlib.h> 2.5 #include <string.h> 2.6 #include "sgl.h" 2.7 +#include "wsys.h" 2.8 2.9 struct cbnode { 2.10 void (*func[SGL_NUM_CALLBACKS])(); 2.11 struct cbnode *next; 2.12 }; 2.13 2.14 +static void notify_wsys(void); 2.15 + 2.16 struct cbnode first_cbnode; 2.17 struct cbnode *cb = &first_cbnode; 2.18 2.19 @@ -34,17 +37,36 @@ 2.20 node = cb; 2.21 cb = cb->next; 2.22 free(node); 2.23 + 2.24 + notify_wsys(); 2.25 return 0; 2.26 } 2.27 2.28 void sgl_clear_callbacks(void) 2.29 { 2.30 memset(cb->func, 0, sizeof cb->func); 2.31 + notify_wsys(); 2.32 } 2.33 2.34 -void (*sgl_callback(int idx, void (*func)()))() 2.35 +void sgl_callback(int idx, void (*func)()) 2.36 { 2.37 - void (*prev)() = cb->func[idx]; 2.38 cb->func[idx] = func; 2.39 - return prev; 2.40 } 2.41 + 2.42 +void (*sgl_get_callback(int idx))() 2.43 +{ 2.44 + return cb->func[idx]; 2.45 +} 2.46 + 2.47 +/* notify the window system module as to which events are active */ 2.48 +static void notify_wsys(void) 2.49 +{ 2.50 + int i; 2.51 + struct wsys_module *ws; 2.52 + 2.53 + if((ws = sgl_wsys_module())) { 2.54 + for(i=0; i<SGL_NUM_CALLBACKS; i++) { 2.55 + ws->set_event(i, cb->func[i] != 0); 2.56 + } 2.57 + } 2.58 +}
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/src/log.c Thu May 12 11:04:10 2011 +0300 3.3 @@ -0,0 +1,21 @@ 3.4 +#include <stdio.h> 3.5 +#include <stdlib.h> 3.6 +#include <stdarg.h> 3.7 +#include "log.h" 3.8 + 3.9 +void sgl_log(const char *fmt, ...) 3.10 +{ 3.11 + va_list ap; 3.12 + const char *logfile; 3.13 + FILE *fp; 3.14 + 3.15 + if(!(logfile = getenv("SGL_LOG")) || !(fp = fopen(logfile, "a"))) { 3.16 + fp = stderr; 3.17 + } 3.18 + 3.19 + va_start(ap, fmt); 3.20 + vfprintf(fp, fmt, ap); 3.21 + va_end(ap); 3.22 + 3.23 + fclose(fp); 3.24 +}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/src/log.h Thu May 12 11:04:10 2011 +0300 4.3 @@ -0,0 +1,6 @@ 4.4 +#ifndef LOG_H_ 4.5 +#define LOG_H_ 4.6 + 4.7 +void sgl_log(const char *fmt, ...); 4.8 + 4.9 +#endif /* LOG_H_ */
5.1 --- a/src/sgl.c Wed May 11 09:09:43 2011 +0300 5.2 +++ b/src/sgl.c Thu May 12 11:04:10 2011 +0300 5.3 @@ -1,29 +1,57 @@ 5.4 #include "sgl.h" 5.5 +#include "wsys.h" 5.6 5.7 void sgl_register_modules(void); 5.8 5.9 +static struct wsys_module *ws; 5.10 + 5.11 int sgl_init(void) 5.12 { 5.13 sgl_register_modules(); 5.14 sgl_sort_modules(); 5.15 - return 0; 5.16 + 5.17 + if(!(ws = sgl_wsys_module())) { 5.18 + return -1; 5.19 + } 5.20 + return ws->init(); 5.21 } 5.22 5.23 -int sgl_set_video_mode(int xsz, int ysz, int bpp) 5.24 +void sgl_shutdown(void) 5.25 { 5.26 - return 0; 5.27 + ws->shutdown(); 5.28 } 5.29 5.30 -int sgl_get_video_mode(int *xsz, int *ysz, int *bpp) 5.31 +int sgl_set_video_mode(int xsz, int ysz) 5.32 { 5.33 - return 0; 5.34 + return ws->set_vidmode(xsz, ysz); 5.35 } 5.36 5.37 -int sgl_window(int x, int y, unsigned int mode) 5.38 +int sgl_get_video_mode(int *xsz, int *ysz) 5.39 { 5.40 - return 0; 5.41 + return ws->get_vidmode(xsz, ysz); 5.42 } 5.43 5.44 -void sgl_close(int win) 5.45 +int sgl_create_window(int xsz, int ysz, unsigned int mode) 5.46 { 5.47 + return ws->create_window(xsz, ysz, mode); 5.48 } 5.49 + 5.50 +void sgl_close_window(int win) 5.51 +{ 5.52 + ws->close_window(win); 5.53 +} 5.54 + 5.55 +int sgl_set_active(int id) 5.56 +{ 5.57 + return ws->set_active(id); 5.58 +} 5.59 + 5.60 +int sgl_set_title(const char *str) 5.61 +{ 5.62 + return ws->set_title(str); 5.63 +} 5.64 + 5.65 +int sgl_process_events(void) 5.66 +{ 5.67 + return ws->process_events(); 5.68 +}
6.1 --- a/src/wsys.h Wed May 11 09:09:43 2011 +0300 6.2 +++ b/src/wsys.h Thu May 12 11:04:10 2011 +0300 6.3 @@ -8,11 +8,21 @@ 6.4 int (*init)(void); 6.5 void (*shutdown)(void); 6.6 6.7 - int (*set_vidmode)(int, int, int); 6.8 - int (*get_vidmode)(int*, int*, int*); 6.9 + int (*set_vidmode)(int, int); 6.10 + int (*get_vidmode)(int*, int*); 6.11 + 6.12 int (*create_window)(int, int, unsigned int); 6.13 void (*close_window)(int); 6.14 6.15 + int (*set_active)(int); 6.16 + int (*set_title)(const char*); 6.17 + 6.18 + void (*set_event)(int idx, int enable); 6.19 + int (*process_events)(void); 6.20 + 6.21 + void (*redisplay)(void); 6.22 + void (*swap_buffers)(void); 6.23 + 6.24 struct wsys_module *next; 6.25 }; 6.26
7.1 --- a/src/wsys_x11.c Wed May 11 09:09:43 2011 +0300 7.2 +++ b/src/wsys_x11.c Thu May 12 11:04:10 2011 +0300 7.3 @@ -1,20 +1,43 @@ 7.4 +#include <stdlib.h> 7.5 #include <X11/Xlib.h> 7.6 #include <GL/glx.h> 7.7 +#include "sgl.h" 7.8 #include "wsys.h" 7.9 +#include "log.h" 7.10 7.11 struct window { 7.12 Window win; 7.13 GLXContext ctx; 7.14 + long evmask; 7.15 struct window *next; 7.16 }; 7.17 7.18 static int init(void); 7.19 static void shutdown(void); 7.20 -static int set_vidmode(int xsz, int ysz, int bpp); 7.21 -static int get_vidmode(int *xsz, int *ysz, int *bpp); 7.22 + 7.23 +/* video mode switching */ 7.24 +static int set_vidmode(int xsz, int ysz); 7.25 +static int get_vidmode(int *xsz, int *ysz); 7.26 + 7.27 +/* create/destroy windows */ 7.28 static int create_window(int xsz, int ysz, unsigned int flags); 7.29 +static void fill_attr(int *attr, unsigned int flags); 7.30 +static void print_visual_info(XVisualInfo *vis); 7.31 static void close_window(int id); 7.32 7.33 +/* window management */ 7.34 +static int set_active(int id); 7.35 +static int set_title(const char *str); 7.36 +static void redisplay(void); 7.37 +static void swap_buffers(void); 7.38 + 7.39 +/* event handling and friends */ 7.40 +static void set_bits(long *mask, long bits); 7.41 +static void clear_bits(long *mask, long bits); 7.42 +static void set_event(int idx, int enable); 7.43 +static int process_events(void); 7.44 + 7.45 + 7.46 static struct wsys_module ws = { 7.47 "x11-glx", 0, 7.48 init, 7.49 @@ -23,14 +46,23 @@ 7.50 get_vidmode, 7.51 create_window, 7.52 close_window, 7.53 + set_active, 7.54 + set_title, 7.55 + redisplay, 7.56 + swap_buffers, 7.57 + set_event, 7.58 + process_events, 7.59 0 7.60 }; 7.61 7.62 static Display *dpy; 7.63 +static Window root; 7.64 static int scr; 7.65 +static Atom xa_wm_prot, xa_wm_del_win; 7.66 static struct window *winlist; 7.67 +static struct window *active_win; 7.68 7.69 - 7.70 +/* this is the only exported function, everything else should be static */ 7.71 void sgl_register_x11(void) 7.72 { 7.73 sgl_register_module(&ws); 7.74 @@ -41,9 +73,14 @@ 7.75 winlist = 0; 7.76 7.77 if(!(dpy = XOpenDisplay(0))) { 7.78 + sgl_log("failed to open X display: %s\n", XDisplayName(0)); 7.79 return -1; 7.80 } 7.81 scr = DefaultScreen(dpy); 7.82 + root = RootWindow(dpy, scr); 7.83 + 7.84 + xa_wm_prot = XInternAtom(dpy, "WM_PROTOCOLS", False); 7.85 + xa_wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False); 7.86 7.87 return 0; 7.88 } 7.89 @@ -55,25 +92,151 @@ 7.90 winlist = winlist->next; 7.91 7.92 glXDestroyContext(dpy, win->ctx); 7.93 - XCloseWindow(dpy, win->win); 7.94 + XDestroyWindow(dpy, win->win); 7.95 free(win); 7.96 } 7.97 XCloseDisplay(dpy); 7.98 dpy = 0; 7.99 } 7.100 7.101 -static int set_vidmode(int xsz, int ysz, int bpp) 7.102 +static int set_vidmode(int xsz, int ysz) 7.103 { 7.104 /* TODO */ 7.105 + return 0; 7.106 } 7.107 7.108 -static int get_vidmode(int *xsz, int *ysz, int *bpp) 7.109 +static int get_vidmode(int *xsz, int *ysz) 7.110 { 7.111 /* TODO */ 7.112 + return 0; 7.113 } 7.114 7.115 static int create_window(int xsz, int ysz, unsigned int flags) 7.116 { 7.117 + int attr[32]; 7.118 + Window win; 7.119 + GLXContext ctx; 7.120 + XVisualInfo *vis; 7.121 + XClassHint chint; 7.122 + XSetWindowAttributes xattr; 7.123 + unsigned int attr_valid; 7.124 + long evmask; 7.125 + struct window *wnode; 7.126 + 7.127 + if(!(wnode = malloc(sizeof *wnode))) { 7.128 + return -1; 7.129 + } 7.130 + 7.131 + fill_attr(attr, flags); 7.132 + 7.133 + if(!(vis = glXChooseVisual(dpy, scr, attr))) { 7.134 + sgl_log("failed to find a suitable visual\n"); 7.135 + free(wnode); 7.136 + return -1; 7.137 + } 7.138 + print_visual_info(vis); 7.139 + 7.140 + if(!(ctx = glXCreateContext(dpy, vis, 0, True))) { 7.141 + sgl_log("failed to create OpenGL context\n"); 7.142 + XFree(vis); 7.143 + free(wnode); 7.144 + return -1; 7.145 + } 7.146 + 7.147 + xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr); 7.148 + xattr.colormap = XCreateColormap(dpy, root, vis->visual, AllocNone); 7.149 + attr_valid = CWColormap | CWBackPixel | CWBorderPixel; 7.150 + 7.151 + if(!(win = XCreateWindow(dpy, root, 0, 0, xsz, ysz, 0, vis->depth, InputOutput, 7.152 + vis->visual, attr_valid, &xattr))) { 7.153 + sgl_log("failed to create window\n"); 7.154 + glXDestroyContext(dpy, ctx); 7.155 + XFree(vis); 7.156 + free(wnode); 7.157 + return -1; 7.158 + } 7.159 + XFree(vis); 7.160 + 7.161 + evmask = StructureNotifyMask | VisibilityChangeMask; 7.162 + XSelectInput(dpy, win, evmask); 7.163 + 7.164 + XSetWMProtocols(dpy, win, &xa_wm_del_win, 1); 7.165 + 7.166 + set_title("OpenGL/X11"); 7.167 + 7.168 + chint.res_name = chint.res_class = "simplygl"; 7.169 + XSetClassHint(dpy, win, &chint); 7.170 + 7.171 + XMapWindow(dpy, win); 7.172 + 7.173 + wnode->win = win; 7.174 + wnode->ctx = ctx; 7.175 + wnode->evmask = evmask; 7.176 + wnode->next = winlist; 7.177 + winlist->next = wnode; 7.178 + 7.179 + if(!active_win) { 7.180 + set_active(win); 7.181 + } 7.182 + return win; 7.183 +} 7.184 + 7.185 +static void fill_attr(int *attr, unsigned int flags) 7.186 +{ 7.187 + int i = 0; 7.188 + 7.189 + attr[i++] = GLX_RGBA; 7.190 + attr[i++] = GLX_RED_SIZE; attr[i++] = 1; 7.191 + attr[i++] = GLX_GREEN_SIZE; attr[i++] = 1; 7.192 + attr[i++] = GLX_BLUE_SIZE; attr[i++] = 1; 7.193 + 7.194 + if(flags & SGL_DOUBLE) { 7.195 + attr[i++] = GLX_DOUBLEBUFFER; 7.196 + } 7.197 + if(flags & SGL_DEPTH) { 7.198 + attr[i++] = GLX_DEPTH_SIZE; 7.199 + attr[i++] = 1; 7.200 + } 7.201 + if(flags & SGL_STENCIL) { 7.202 + attr[i++] = GLX_STENCIL_SIZE; 7.203 + attr[i++] = 1; 7.204 + } 7.205 + if(flags & SGL_STEREO) { 7.206 + attr[i++] = GLX_STEREO; 7.207 + } 7.208 +#if defined(GLX_VERSION_1_4) || defined(GLX_ARB_multisample) 7.209 + if(flags & SGL_MULTISAMPLE) { 7.210 + attr[i++] = GLX_SAMPLE_BUFFERS_ARB; 7.211 + attr[i++] = 1; 7.212 + attr[i++] = GLX_SAMPLES_ARB; 7.213 + attr[i++] = 1; 7.214 + } 7.215 +#endif /* defined GLX_VERSION_1_4 || GLX_ARB_multisample */ 7.216 + attr[i] = None; 7.217 +} 7.218 + 7.219 +static void print_visual_info(XVisualInfo *vis) 7.220 +{ 7.221 + int rbits, gbits, bbits, zbits, sbits, stereo, aa, samples; 7.222 + 7.223 + glXGetConfig(dpy, vis, GLX_RED_SIZE, &rbits); 7.224 + glXGetConfig(dpy, vis, GLX_GREEN_SIZE, &gbits); 7.225 + glXGetConfig(dpy, vis, GLX_BLUE_SIZE, &bbits); 7.226 + glXGetConfig(dpy, vis, GLX_DEPTH_SIZE, &zbits); 7.227 + glXGetConfig(dpy, vis, GLX_STENCIL_SIZE, &sbits); 7.228 + glXGetConfig(dpy, vis, GLX_STEREO, &stereo); 7.229 +#if defined(GLX_VERSION_1_4) || defined(GLX_ARB_multisample) 7.230 + glXGetConfig(dpy, vis, GLX_SAMPLE_BUFFERS_ARB, &aa); 7.231 + if(aa) { 7.232 + glXGetConfig(dpy, vis, GLX_SAMPLES_ARB, &samples); 7.233 + } else { 7.234 + samples = 1; 7.235 + } 7.236 +#endif /* defined GLX_VERSION_1_4 || GLX_ARB_multisample */ 7.237 + 7.238 + sgl_log("got visual: %d%d%d d:%d s:%d", rbits, gbits, bbits, zbits, sbits); 7.239 + sgl_log(" %s", stereo ? "stereo" : "mono"); 7.240 + sgl_log(" samples/pixel: %d\n", samples); 7.241 } 7.242 7.243 static void close_window(int id) 7.244 @@ -87,7 +250,7 @@ 7.245 while(win) { 7.246 if(win->win == id) { 7.247 glXDestroyContext(dpy, win->ctx); 7.248 - XCloseWindow(dpy, win->win); 7.249 + XDestroyWindow(dpy, win->win); 7.250 prev->next = win->next; 7.251 free(win); 7.252 return; 7.253 @@ -95,3 +258,168 @@ 7.254 win = win->next; 7.255 } 7.256 } 7.257 + 7.258 +static int set_active(int id) 7.259 +{ 7.260 + struct window *win = winlist; 7.261 + 7.262 + while(win) { 7.263 + if(win->win == id) { 7.264 + if(glXMakeCurrent(dpy, win->win, win->ctx) == False) { 7.265 + sgl_log("failed to activate window %d\n", id); 7.266 + return -1; 7.267 + } 7.268 + active_win = win; 7.269 + return 0; 7.270 + } 7.271 + win = win->next; 7.272 + } 7.273 + 7.274 + sgl_log("no such window: %d\n", id); 7.275 + return -1; 7.276 +} 7.277 + 7.278 +static int set_title(const char *str) 7.279 +{ 7.280 + XTextProperty wm_name; 7.281 + 7.282 + if(!str || !active_win) { 7.283 + return -1; 7.284 + } 7.285 + XStringListToTextProperty((char**)&str, 1, &wm_name); 7.286 + XSetWMName(dpy, active_win->win, &wm_name); 7.287 + XSetWMIconName(dpy, active_win->win, &wm_name); 7.288 + XFree(wm_name.value); 7.289 + return 0; 7.290 +} 7.291 + 7.292 +static void redisplay(void) 7.293 +{ 7.294 + active_win->redisp_pending = 1; 7.295 +} 7.296 + 7.297 +static void swap_buffers(void) 7.298 +{ 7.299 + glXSwapBuffers(dpy, active_win->ctx); 7.300 +} 7.301 + 7.302 +static void set_bits(long *mask, long bits) 7.303 +{ 7.304 + *mask |= bits; 7.305 +} 7.306 + 7.307 +static void clear_bits(long *mask, long bits) 7.308 +{ 7.309 + *mask &= ~bits; 7.310 +} 7.311 + 7.312 +static void set_event(int idx, int enable) 7.313 +{ 7.314 + void (*op)(long*, long); 7.315 + op = enable ? set_bits : clear_bits; 7.316 + 7.317 + switch(idx) { 7.318 + case SGL_DISPLAY: 7.319 + op(&active_win->evmask, ExposureMask); 7.320 + break; 7.321 + 7.322 + case SGL_KEYBOARD: 7.323 + op(&active_win->evmask, KeyPressMask | KeyReleaseMask); 7.324 + break; 7.325 + 7.326 + case SGL_MOUSE: 7.327 + op(&active_win->evmask, ButtonPressMask | ButtonReleaseMask); 7.328 + break; 7.329 + 7.330 + case SGL_MOTION: 7.331 + op(&active_win->evmask, ButtonMotionMask); 7.332 + break; 7.333 + 7.334 + case SGL_PASSIVE: 7.335 + op(&active_win->evmask, PointerMotionMask); 7.336 + break; 7.337 + 7.338 + default: 7.339 + return; 7.340 + } 7.341 + 7.342 + XSelectInput(dpy, active_win->win, active_win->evmask); 7.343 +} 7.344 + 7.345 +static int process_events(void) 7.346 +{ 7.347 + XEvent xev; 7.348 + void (*func)(); 7.349 + int state; 7.350 + 7.351 + while(XPending(dpy)) { 7.352 + XNextEvent(dpy, &xev); 7.353 + 7.354 + switch(xev.type) { 7.355 + case Expose: 7.356 + if(xev.xexpose.count == 0) { 7.357 + if((func = sgl_get_callback(SGL_DISPLAY))) { 7.358 + func(); 7.359 + active_win->redisp_pending = 0; 7.360 + } 7.361 + } 7.362 + break; 7.363 + 7.364 + case MotionNotify: 7.365 + if(xev.xmotion.state) { 7.366 + func = sgl_get_callback(SGL_MOTION); 7.367 + } else { 7.368 + func = sgl_get_callback(SGL_PASSIVE); 7.369 + } 7.370 + if(func) { 7.371 + func(xev.xmotion.x, xev.xmotion.y); 7.372 + } 7.373 + break; 7.374 + 7.375 + case ButtonPress: 7.376 + if(1) { 7.377 + state = 1; 7.378 + } else { 7.379 + case ButtonRelease: 7.380 + state = 0; 7.381 + } 7.382 + if((func = sgl_get_callback(SGL_MOUSE))) { 7.383 + int bn = xev.xbutton.button - 1; 7.384 + func(bn, state, xev.xbutton.x, xev.xbutton.y); 7.385 + } 7.386 + break; 7.387 + 7.388 + case KeyPress: 7.389 + if(1) { 7.390 + state = 1; 7.391 + } else { 7.392 + case KeyRelease: 7.393 + state = 0; 7.394 + } 7.395 + if((func = sgl_get_callback(SGL_KEYBOARD))) { 7.396 + KeySym sym = XLookupKeysym(xev.xkey, 0); 7.397 + func(sym, state); 7.398 + /* XXX */ 7.399 + } 7.400 + break; 7.401 + 7.402 + case ConfigureNotify: 7.403 + if((func = sgl_get_callback(SGL_RESHAPE))) { 7.404 + func(xev.xconfigure.width, xev.xconfigure.height); 7.405 + } 7.406 + break; 7.407 + } 7.408 + 7.409 + case ClientMessage: 7.410 + if(xev.xclient.message_type == xa_wm_prot) { 7.411 + if(xev.xclient.data.l[0] == xa_wm_del_win) { 7.412 + close_window(active_win->win); 7.413 + if(!active_win) { 7.414 + return 1; 7.415 + } 7.416 + } 7.417 + } 7.418 + break; 7.419 + } 7.420 + return 0; 7.421 +}