~ubuntu-branches/ubuntu/trusty/libspnav/trusty

« back to all changes in this revision

Viewing changes to examples/cube/cube.c

  • Committer: Bazaar Package Importer
  • Author(s): Scott Kitterman
  • Date: 2010-12-31 10:37:07 UTC
  • mfrom: (0.1.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 6.
  • Revision ID: james.westby@ubuntu.com-20101231103707-7me9nn62lfhsobpr
Tags: upstream-0.2.2
ImportĀ upstreamĀ versionĀ 0.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This example demonstrates how to use libspnav to get space navigator input,
 
2
 * and use that to rotate and translate a 3D cube. The magellan X11 protocol is
 
3
 * used (spnav_x11_open) which is compatible with both spacenavd and
 
4
 * 3Dconnexion's 3dxsrv.
 
5
 *
 
6
 * The code is a bit cluttered with X11 and GLX calls, so the interesting bits
 
7
 * are marked with XXX comments.
 
8
 */
 
9
 
 
10
#include <stdio.h>
 
11
#include <stdlib.h>
 
12
#include <math.h>
 
13
#include <X11/Xlib.h>
 
14
#include <GL/gl.h>
 
15
#include <GL/glu.h>
 
16
#include <GL/glx.h>
 
17
#include <spnav.h>
 
18
#include "vmath.h"
 
19
 
 
20
#define SQ(x)   ((x) * (x))
 
21
 
 
22
int create_gfx(int xsz, int ysz);
 
23
void destroy_gfx(void);
 
24
void set_window_title(const char *title);
 
25
void redraw(void);
 
26
void draw_cube(void);
 
27
int handle_event(XEvent *xev);
 
28
 
 
29
 
 
30
Display *dpy;
 
31
Atom wm_prot, wm_del_win;
 
32
GLXContext ctx;
 
33
Window win;
 
34
 
 
35
vec3_t pos = {0, 0, -6};
 
36
quat_t rot = {0, 0, 0, 1};      /* that's 1 + 0i + 0j + 0k */
 
37
 
 
38
int redisplay;
 
39
 
 
40
int main(void)
 
41
{
 
42
        if(!(dpy = XOpenDisplay(0))) {
 
43
                fprintf(stderr, "failed to connect to the X server");
 
44
                return 1;
 
45
        }
 
46
 
 
47
        if(create_gfx(512, 512) == -1) {
 
48
                return 1;
 
49
        }
 
50
 
 
51
        /* XXX: This actually registers our window with the driver for receiving
 
52
         * motion/button events through the 3dxsrv-compatible X11 protocol.
 
53
         */
 
54
        if(spnav_x11_open(dpy, win) == -1) {
 
55
                fprintf(stderr, "failed to connect to the space navigator daemon\n");
 
56
                return 1;
 
57
        }
 
58
 
 
59
        glEnable(GL_DEPTH_TEST);
 
60
        glEnable(GL_CULL_FACE);
 
61
 
 
62
        for(;;) {
 
63
                XEvent xev;
 
64
                XNextEvent(dpy, &xev);
 
65
 
 
66
                if(handle_event(&xev) != 0) {
 
67
                        destroy_gfx();
 
68
                        XCloseDisplay(dpy);
 
69
                        return 0;
 
70
                }
 
71
 
 
72
                if(redisplay) {
 
73
                        redraw();
 
74
                        redisplay = 0;
 
75
                }
 
76
        }
 
77
        return 0;
 
78
}
 
79
 
 
80
int create_gfx(int xsz, int ysz)
 
81
{
 
82
        int scr;
 
83
        Window root;
 
84
        XVisualInfo *vis;
 
85
        XSetWindowAttributes xattr;
 
86
        unsigned int events;
 
87
        XClassHint class_hint;
 
88
 
 
89
        int attr[] = {
 
90
                GLX_RGBA, GLX_DOUBLEBUFFER,
 
91
                GLX_RED_SIZE, 8,
 
92
                GLX_GREEN_SIZE, 8,
 
93
                GLX_BLUE_SIZE, 8,
 
94
                GLX_DEPTH_SIZE, 24,
 
95
                None
 
96
        };
 
97
 
 
98
        wm_prot = XInternAtom(dpy, "WM_PROTOCOLS", False);
 
99
        wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
 
100
 
 
101
        scr = DefaultScreen(dpy);
 
102
        root = RootWindow(dpy, scr);
 
103
 
 
104
        if(!(vis = glXChooseVisual(dpy, scr, attr))) {
 
105
                fprintf(stderr, "requested GLX visual is not available\n");
 
106
                return -1;
 
107
        }
 
108
 
 
109
        if(!(ctx = glXCreateContext(dpy, vis, 0, True))) {
 
110
                fprintf(stderr, "failed to create GLX context\n");
 
111
                XFree(vis);
 
112
                return -1;
 
113
        }
 
114
 
 
115
        xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr);
 
116
        xattr.colormap = XCreateColormap(dpy, root, vis->visual, AllocNone);
 
117
 
 
118
        if(!(win = XCreateWindow(dpy, root, 0, 0, xsz, ysz, 0, vis->depth, InputOutput,
 
119
                                        vis->visual, CWColormap | CWBackPixel | CWBorderPixel, &xattr))) {
 
120
                fprintf(stderr, "failed to create X window\n");
 
121
                return -1;
 
122
        }
 
123
        XFree(vis);
 
124
 
 
125
        /* set the window event mask */
 
126
        events = ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask |
 
127
                ButtonReleaseMask |     ButtonPressMask | PointerMotionMask;
 
128
        XSelectInput(dpy, win, events);
 
129
 
 
130
        XSetWMProtocols(dpy, win, &wm_del_win, 1);
 
131
 
 
132
        set_window_title("libspnav cube");
 
133
 
 
134
        class_hint.res_name = "cube";
 
135
        class_hint.res_class = "cube";
 
136
        XSetClassHint(dpy, win, &class_hint);
 
137
 
 
138
        if(glXMakeCurrent(dpy, win, ctx) == False) {
 
139
                fprintf(stderr, "glXMakeCurrent failed\n");
 
140
                glXDestroyContext(dpy, ctx);
 
141
                XDestroyWindow(dpy, win);
 
142
                return -1;
 
143
        }
 
144
 
 
145
        XMapWindow(dpy, win);
 
146
        XFlush(dpy);
 
147
 
 
148
        return 0;
 
149
}
 
150
 
 
151
void destroy_gfx(void)
 
152
{
 
153
        glXDestroyContext(dpy, ctx);
 
154
        XDestroyWindow(dpy, win);
 
155
        glXMakeCurrent(dpy, None, 0);
 
156
}
 
157
 
 
158
void set_window_title(const char *title)
 
159
{
 
160
        XTextProperty wm_name;
 
161
 
 
162
        XStringListToTextProperty((char**)&title, 1, &wm_name);
 
163
        XSetWMName(dpy, win, &wm_name);
 
164
        XSetWMIconName(dpy, win, &wm_name);
 
165
        XFree(wm_name.value);
 
166
}
 
167
 
 
168
void redraw(void)
 
169
{
 
170
        mat4_t xform;
 
171
 
 
172
        quat_to_mat(xform, rot);
 
173
 
 
174
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
175
 
 
176
        glMatrixMode(GL_MODELVIEW);
 
177
        glLoadIdentity();
 
178
        glTranslatef(pos.x, pos.y, pos.z);
 
179
        glMultTransposeMatrixf((float*)xform);
 
180
 
 
181
        draw_cube();
 
182
 
 
183
        glXSwapBuffers(dpy, win);
 
184
}
 
185
 
 
186
void draw_cube(void)
 
187
{
 
188
        glBegin(GL_QUADS);
 
189
        /* face +Z */
 
190
        glNormal3f(0, 0, 1);
 
191
        glColor3f(1, 0, 0);
 
192
        glVertex3f(-1, -1, 1);
 
193
        glVertex3f(1, -1, 1);
 
194
        glVertex3f(1, 1, 1);
 
195
        glVertex3f(-1, 1, 1);
 
196
        /* face +X */
 
197
        glNormal3f(1, 0, 0);
 
198
        glColor3f(0, 1, 0);
 
199
        glVertex3f(1, -1, 1);
 
200
        glVertex3f(1, -1, -1);
 
201
        glVertex3f(1, 1, -1);
 
202
        glVertex3f(1, 1, 1);
 
203
        /* face -Z */
 
204
        glNormal3f(0, 0, -1);
 
205
        glColor3f(0, 0, 1);
 
206
        glVertex3f(1, -1, -1);
 
207
        glVertex3f(-1, -1, -1);
 
208
        glVertex3f(-1, 1, -1);
 
209
        glVertex3f(1, 1, -1);
 
210
        /* face -X */
 
211
        glNormal3f(-1, 0, 0);
 
212
        glColor3f(1, 1, 0);
 
213
        glVertex3f(-1, -1, -1);
 
214
        glVertex3f(-1, -1, 1);
 
215
        glVertex3f(-1, 1, 1);
 
216
        glVertex3f(-1, 1, -1);
 
217
        /* face +Y */
 
218
        glNormal3f(0, 1, 0);
 
219
        glColor3f(0, 1, 1);
 
220
        glVertex3f(-1, 1, 1);
 
221
        glVertex3f(1, 1, 1);
 
222
        glVertex3f(1, 1, -1);
 
223
        glVertex3f(-1, 1, -1);
 
224
        /* face -Y */
 
225
        glNormal3f(0, -1, 0);
 
226
        glColor3f(1, 0, 1);
 
227
        glVertex3f(-1, -1, -1);
 
228
        glVertex3f(1, -1, -1);
 
229
        glVertex3f(1, -1, 1);
 
230
        glVertex3f(-1, -1, 1);
 
231
        glEnd();
 
232
}
 
233
 
 
234
int handle_event(XEvent *xev)
 
235
{
 
236
        static int win_mapped;
 
237
        KeySym sym;
 
238
        spnav_event spev;
 
239
 
 
240
        switch(xev->type) {
 
241
        case MapNotify:
 
242
                win_mapped = 1;
 
243
                break;
 
244
 
 
245
        case UnmapNotify:
 
246
                win_mapped = 0;
 
247
                break;
 
248
 
 
249
        case Expose:
 
250
                if(win_mapped && xev->xexpose.count == 0) {
 
251
                        redraw();
 
252
                }
 
253
                break;
 
254
 
 
255
        case ClientMessage:
 
256
                /* XXX check if the event is a spacenav event */
 
257
                if(spnav_x11_event(xev, &spev)) {
 
258
                        /* if so deal with motion and button events */
 
259
                        if(spev.type == SPNAV_EVENT_MOTION) {
 
260
                                /* apply axis/angle rotation to the quaternion */
 
261
                                float axis_len = sqrt(SQ(spev.motion.rx) + SQ(spev.motion.ry) + SQ(spev.motion.rz));
 
262
                                rot = quat_rotate(rot, axis_len * 0.001, -spev.motion.rx / axis_len,
 
263
                                                -spev.motion.ry / axis_len, spev.motion.rz / axis_len);
 
264
 
 
265
                                /* add translation */
 
266
                                pos.x += spev.motion.x * 0.001;
 
267
                                pos.y += spev.motion.y * 0.001;
 
268
                                pos.z -= spev.motion.z * 0.001;
 
269
 
 
270
                                redisplay = 1;
 
271
                        } else {
 
272
                                /* on button press, reset the cube */
 
273
                                if(spev.button.press) {
 
274
                                        pos = v3_cons(0, 0, -6);
 
275
                                        rot = quat_cons(1, 0, 0, 0);
 
276
 
 
277
                                        redisplay = 1;
 
278
                                }
 
279
                        }
 
280
                        /* finally remove any other queued motion events */
 
281
                        spnav_remove_events(SPNAV_EVENT_MOTION);
 
282
 
 
283
                } else if(xev->xclient.message_type == wm_prot) {
 
284
                        if(xev->xclient.data.l[0] == wm_del_win) {
 
285
                                return 1;
 
286
                        }
 
287
                }
 
288
                break;
 
289
 
 
290
        case KeyPress:
 
291
                sym = XLookupKeysym((XKeyEvent*)&xev->xkey, 0);
 
292
                if((sym & 0xff) == 27) {
 
293
                        return 1;
 
294
                }
 
295
                break;
 
296
 
 
297
        case ConfigureNotify:
 
298
                {
 
299
                        int x = xev->xconfigure.width;
 
300
                        int y = xev->xconfigure.height;
 
301
 
 
302
                        glMatrixMode(GL_PROJECTION);
 
303
                        glLoadIdentity();
 
304
                        gluPerspective(45.0, (float)x / (float)y, 1.0, 1000.0);
 
305
 
 
306
                        glViewport(0, 0, x, y);
 
307
                }
 
308
                break;
 
309
 
 
310
        default:
 
311
                break;
 
312
        }
 
313
        return 0;
 
314
}