6 #include <sys/select.h>
14 int create_gfx(int xsz, int ysz);
15 void destroy_gfx(void);
16 void set_window_title(const char *title);
19 int handle_event(XEvent *xev);
20 int handle_dev_event(device_event *ev);
23 Atom wm_prot, wm_del_win;
27 vec3_t pos = {0, 0, -6};
28 quat_t rot = {0, 0, 0, 1}; /* that's 1 + 0i + 0j + 0k */
32 /* serial 6dof device */
37 int xsock, devfd, maxfd;
40 set_port("/dev/ttyS0");
42 if(!(dev = dev_init(0))) {
43 fprintf(stderr, "failed to initialize 6dof serial device at /dev/ttyS0\n");
46 if((devfd = dev->start()) == -1) {
50 if(!(dpy = XOpenDisplay(0))) {
51 fprintf(stderr, "failed to connect to the X server\n");
54 xsock = ConnectionNumber(dpy);
56 if(create_gfx(512, 512) == -1) {
60 glEnable(GL_DEPTH_TEST);
61 glEnable(GL_CULL_FACE);
63 maxfd = xsock > devfd ? xsock : devfd;
69 FD_SET(xsock, &rdset);
70 FD_SET(devfd, &rdset);
72 while(select(maxfd + 1, &rdset, 0, 0, 0) == -1 && errno == EINTR);
74 if(FD_ISSET(xsock, &rdset)) {
75 while(XPending(dpy)) {
77 XNextEvent(dpy, &xev);
79 if(handle_event(&xev) != 0) {
85 if(FD_ISSET(devfd, &rdset)) {
88 while(dev->getevent(&ev)) {
89 handle_dev_event(&ev);
105 int create_gfx(int xsz, int ysz)
110 XSetWindowAttributes xattr;
112 XClassHint class_hint;
115 GLX_RGBA, GLX_DOUBLEBUFFER,
123 wm_prot = XInternAtom(dpy, "WM_PROTOCOLS", False);
124 wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
126 scr = DefaultScreen(dpy);
127 root = RootWindow(dpy, scr);
129 if(!(vis = glXChooseVisual(dpy, scr, attr))) {
130 fprintf(stderr, "requested GLX visual is not available\n");
134 if(!(ctx = glXCreateContext(dpy, vis, 0, True))) {
135 fprintf(stderr, "failed to create GLX context\n");
140 xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr);
141 xattr.colormap = XCreateColormap(dpy, root, vis->visual, AllocNone);
143 if(!(win = XCreateWindow(dpy, root, 0, 0, xsz, ysz, 0, vis->depth, InputOutput,
144 vis->visual, CWColormap | CWBackPixel | CWBorderPixel, &xattr))) {
145 fprintf(stderr, "failed to create X window\n");
150 /* set the window event mask */
151 events = ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask |
152 ButtonReleaseMask | ButtonPressMask | PointerMotionMask;
153 XSelectInput(dpy, win, events);
155 XSetWMProtocols(dpy, win, &wm_del_win, 1);
157 set_window_title("libspnav cube");
159 class_hint.res_name = "cube";
160 class_hint.res_class = "cube";
161 XSetClassHint(dpy, win, &class_hint);
163 if(glXMakeCurrent(dpy, win, ctx) == False) {
164 fprintf(stderr, "glXMakeCurrent failed\n");
165 glXDestroyContext(dpy, ctx);
166 XDestroyWindow(dpy, win);
170 XMapWindow(dpy, win);
176 void destroy_gfx(void)
178 glXDestroyContext(dpy, ctx);
179 XDestroyWindow(dpy, win);
180 glXMakeCurrent(dpy, None, 0);
183 void set_window_title(const char *title)
185 XTextProperty wm_name;
187 XStringListToTextProperty((char**)&title, 1, &wm_name);
188 XSetWMName(dpy, win, &wm_name);
189 XSetWMIconName(dpy, win, &wm_name);
190 XFree(wm_name.value);
197 quat_to_mat(xform, rot);
199 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
201 glMatrixMode(GL_MODELVIEW);
203 glTranslatef(pos.x, pos.y, pos.z);
204 glMultTransposeMatrixf((float*)xform);
208 glXSwapBuffers(dpy, win);
217 glVertex3f(-1, -1, 1);
218 glVertex3f(1, -1, 1);
220 glVertex3f(-1, 1, 1);
224 glVertex3f(1, -1, 1);
225 glVertex3f(1, -1, -1);
226 glVertex3f(1, 1, -1);
229 glNormal3f(0, 0, -1);
231 glVertex3f(1, -1, -1);
232 glVertex3f(-1, -1, -1);
233 glVertex3f(-1, 1, -1);
234 glVertex3f(1, 1, -1);
236 glNormal3f(-1, 0, 0);
238 glVertex3f(-1, -1, -1);
239 glVertex3f(-1, -1, 1);
240 glVertex3f(-1, 1, 1);
241 glVertex3f(-1, 1, -1);
245 glVertex3f(-1, 1, 1);
247 glVertex3f(1, 1, -1);
248 glVertex3f(-1, 1, -1);
250 glNormal3f(0, -1, 0);
252 glVertex3f(-1, -1, -1);
253 glVertex3f(1, -1, -1);
254 glVertex3f(1, -1, 1);
255 glVertex3f(-1, -1, 1);
259 int handle_event(XEvent *xev)
261 static int win_mapped;
274 if(win_mapped && xev->xexpose.count == 0) {
280 sym = XLookupKeysym((XKeyEvent*)&xev->xkey, 0);
281 if((sym & 0xff) == 27) {
286 case ConfigureNotify:
288 int x = xev->xconfigure.width;
289 int y = xev->xconfigure.height;
291 glMatrixMode(GL_PROJECTION);
293 gluPerspective(45.0, (float)x / (float)y, 1.0, 1000.0);
295 glViewport(0, 0, x, y);
305 #define TX(ev) ((ev)->motion.motion[0])
306 #define TY(ev) ((ev)->motion.motion[1])
307 #define TZ(ev) ((ev)->motion.motion[2])
308 #define RX(ev) ((ev)->motion.motion[3])
309 #define RY(ev) ((ev)->motion.motion[4])
310 #define RZ(ev) ((ev)->motion.motion[5])
312 int handle_dev_event(device_event *ev)
316 if(RX(ev) | RY(ev) | RZ(ev)) {
317 float axis_len = sqrt(RX(ev) * RX(ev) + RY(ev) * RY(ev) + RZ(ev) * RZ(ev));
318 if(axis_len != 0.0) {
319 rot = quat_rotate(rot, axis_len * 0.001, -RX(ev) / axis_len,
320 -RY(ev) / axis_len, -RZ(ev) / axis_len);
324 pos.x += TX(ev) * 0.001;
325 pos.y += TY(ev) * 0.001;
326 pos.z += TZ(ev) * 0.001;
331 if(ev->button.pressed) {
332 pos = v3_cons(0, 0, -6);
333 rot = quat_cons(1, 0, 0, 0);