- added new libspnav spinning cube example

git-svn-id: svn+ssh://svn.code.sf.net/p/spacenav/code/trunk/libspnav@80 ef983eb1-d774-4af8-acfd-baaf7b16a646
pull/2/head
John Tsiombikas 2009-02-10 21:36:31 +00:00
rodzic e02450d6d5
commit f250cf1598
7 zmienionych plików z 454 dodań i 2 usunięć

Wyświetl plik

@ -0,0 +1,13 @@
obj = cube.o vmath.o
bin = cube
CC = gcc
CFLAGS = -pedantic -Wall -g -I../..
LDFLAGS = -L../.. -lX11 -lGL -lGLU -lm -lspnav
$(bin): $(obj)
$(CC) -o $@ $(obj) $(LDFLAGS)
.PHONY: clean
clean:
rm -f $(obj) $(bin)

Wyświetl plik

@ -0,0 +1,313 @@
/* This example demonstrates how to use libspnav to get space navigator input,
* and use that to rotate and translate a 3D cube. The magellan X11 protocol is
* used (spnav_x11_open) which is compatible with both spacenavd and
* 3Dconnexion's 3dxsrv.
*
* The code is a bit cluttered with X11 and GLX calls, so the interesting bits
* are marked with XXX comments.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <X11/Xlib.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glx.h>
#include <spnav.h>
#include "vmath.h"
#define SQ(x) ((x) * (x))
int create_gfx(int xsz, int ysz);
void destroy_gfx(void);
void set_window_title(const char *title);
void redraw(void);
void draw_cube(void);
int handle_event(XEvent *xev);
Display *dpy;
Atom wm_prot, wm_del_win;
GLXContext ctx;
Window win;
vec3_t pos = {0, 0, -6};
quat_t rot = {0, 0, 0, 1};
int redisplay;
int main(void)
{
if(!(dpy = XOpenDisplay(0))) {
fprintf(stderr, "failed to connect to the X server");
return 1;
}
if(create_gfx(512, 512) == -1) {
return 1;
}
/* XXX: This actually registers our window with the driver for receiving
* motion/button events through the 3dxsrv-compatible X11 protocol.
*/
if(spnav_x11_open(dpy, win) == -1) {
fprintf(stderr, "failed to connect to the space navigator daemon\n");
return 1;
}
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
for(;;) {
XEvent xev;
XNextEvent(dpy, &xev);
if(handle_event(&xev) != 0) {
destroy_gfx();
XCloseDisplay(dpy);
return 0;
}
if(redisplay) {
redraw();
redisplay = 0;
}
}
return 0;
}
int create_gfx(int xsz, int ysz)
{
int scr;
Window root;
XVisualInfo *vis;
XSetWindowAttributes xattr;
unsigned int events;
XClassHint class_hint;
int attr[] = {
GLX_RGBA, GLX_DOUBLEBUFFER,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_DEPTH_SIZE, 24,
None
};
wm_prot = XInternAtom(dpy, "WM_PROTOCOLS", False);
wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
scr = DefaultScreen(dpy);
root = RootWindow(dpy, scr);
if(!(vis = glXChooseVisual(dpy, scr, attr))) {
fprintf(stderr, "requested GLX visual is not available\n");
return -1;
}
if(!(ctx = glXCreateContext(dpy, vis, 0, True))) {
fprintf(stderr, "failed to create GLX context\n");
XFree(vis);
return -1;
}
xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr);
xattr.colormap = XCreateColormap(dpy, root, vis->visual, AllocNone);
if(!(win = XCreateWindow(dpy, root, 0, 0, xsz, ysz, 0, vis->depth, InputOutput,
vis->visual, CWColormap | CWBackPixel | CWBorderPixel, &xattr))) {
fprintf(stderr, "failed to create X window\n");
return -1;
}
XFree(vis);
/* set the window event mask */
events = ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask |
ButtonReleaseMask | ButtonPressMask | PointerMotionMask;
XSelectInput(dpy, win, events);
XSetWMProtocols(dpy, win, &wm_del_win, 1);
set_window_title("libspnav cube");
class_hint.res_name = "cube";
class_hint.res_class = "cube";
XSetClassHint(dpy, win, &class_hint);
if(glXMakeCurrent(dpy, win, ctx) == False) {
fprintf(stderr, "glXMakeCurrent failed\n");
glXDestroyContext(dpy, ctx);
XDestroyWindow(dpy, win);
return -1;
}
XMapWindow(dpy, win);
XFlush(dpy);
return 0;
}
void destroy_gfx(void)
{
glXDestroyContext(dpy, ctx);
XDestroyWindow(dpy, win);
glXMakeCurrent(dpy, None, 0);
}
void set_window_title(const char *title)
{
XTextProperty wm_name;
XStringListToTextProperty((char**)&title, 1, &wm_name);
XSetWMName(dpy, win, &wm_name);
XSetWMIconName(dpy, win, &wm_name);
XFree(wm_name.value);
}
void redraw(void)
{
mat4_t xform;
quat_to_mat(xform, rot);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(pos.x, pos.y, pos.z);
glMultTransposeMatrixf((float*)xform);
draw_cube();
glXSwapBuffers(dpy, win);
}
void draw_cube(void)
{
glBegin(GL_QUADS);
/* face +Z */
glNormal3f(0, 0, 1);
glColor3f(1, 0, 0);
glVertex3f(-1, -1, 1);
glVertex3f(1, -1, 1);
glVertex3f(1, 1, 1);
glVertex3f(-1, 1, 1);
/* face +X */
glNormal3f(1, 0, 0);
glColor3f(0, 1, 0);
glVertex3f(1, -1, 1);
glVertex3f(1, -1, -1);
glVertex3f(1, 1, -1);
glVertex3f(1, 1, 1);
/* face -Z */
glNormal3f(0, 0, -1);
glColor3f(0, 0, 1);
glVertex3f(1, -1, -1);
glVertex3f(-1, -1, -1);
glVertex3f(-1, 1, -1);
glVertex3f(1, 1, -1);
/* face -X */
glNormal3f(-1, 0, 0);
glColor3f(1, 1, 0);
glVertex3f(-1, -1, -1);
glVertex3f(-1, -1, 1);
glVertex3f(-1, 1, 1);
glVertex3f(-1, 1, -1);
/* face +Y */
glNormal3f(0, 1, 0);
glColor3f(0, 1, 1);
glVertex3f(-1, 1, 1);
glVertex3f(1, 1, 1);
glVertex3f(1, 1, -1);
glVertex3f(-1, 1, -1);
/* face -Y */
glNormal3f(0, -1, 0);
glColor3f(1, 0, 1);
glVertex3f(-1, -1, -1);
glVertex3f(1, -1, -1);
glVertex3f(1, -1, 1);
glVertex3f(-1, -1, 1);
glEnd();
}
int handle_event(XEvent *xev)
{
static int win_mapped;
KeySym sym;
spnav_event spev;
switch(xev->type) {
case MapNotify:
win_mapped = 1;
break;
case UnmapNotify:
win_mapped = 0;
break;
case Expose:
if(win_mapped && xev->xexpose.count == 0) {
redraw();
}
break;
case ClientMessage:
/* XXX check if the event is a spacenav event */
if(spnav_x11_event(xev, &spev)) {
/* if so deal with motion and button events */
if(spev.type == SPNAV_EVENT_MOTION) {
/* apply axis/angle rotation to the quaternion */
float angle = 0.000005 * sqrt(SQ(spev.motion.rx) + SQ(spev.motion.ry) + SQ(spev.motion.rz));
rot = quat_rotate(rot, angle, -spev.motion.rx, -spev.motion.ry, spev.motion.rz);
rot = quat_normalize(rot);
/* add translation */
pos.x += spev.motion.x * 0.001;
pos.y += spev.motion.y * 0.001;
pos.z -= spev.motion.z * 0.001;
redisplay = 1;
} else {
/* on button press, reset the cube */
if(spev.button.press) {
pos = v3_cons(0, 0, -6);
rot = quat_cons(1, 0, 0, 0);
redisplay = 1;
}
}
/* finally remove any other queued motion events */
spnav_remove_events(SPNAV_EVENT_MOTION);
} else if(xev->xclient.message_type == wm_prot) {
if(xev->xclient.data.l[0] == wm_del_win) {
return 1;
}
}
break;
case KeyPress:
sym = XLookupKeysym((XKeyEvent*)&xev->xkey, 0);
if((sym & 0xff) == 27) {
return 1;
}
case ConfigureNotify:
{
int x = xev->xconfigure.width;
int y = xev->xconfigure.height;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (float)x / (float)y, 1.0, 1000.0);
glViewport(0, 0, x, y);
}
break;
default:
break;
}
return 0;
}

Wyświetl plik

@ -0,0 +1,16 @@
#include <math.h>
#include "vmath.h"
quat_t quat_rotate(quat_t q, float angle, float x, float y, float z)
{
quat_t rq;
float half_angle = angle * 0.5;
float sin_half = sin(half_angle);
rq.w = cos(half_angle);
rq.x = x * sin_half;
rq.y = y * sin_half;
rq.z = z * sin_half;
return quat_mul(q, rq);
}

Wyświetl plik

@ -0,0 +1,32 @@
#ifndef VMATH_H_
#define VMATH_H_
typedef struct { float x, y, z; } vec3_t;
typedef struct { float x, y, z, w; } vec4_t;
typedef vec4_t quat_t;
typedef float mat4_t[4][4];
/* vector functions */
static inline vec3_t v3_cons(float x, float y, float z);
static inline float v3_dot(vec3_t v1, vec3_t v2);
/* quaternion functions */
static inline quat_t quat_cons(float s, float x, float y, float z);
static inline vec3_t quat_vec(quat_t q);
static inline quat_t quat_mul(quat_t q1, quat_t q2);
static inline quat_t quat_normalize(quat_t q);
static inline void quat_to_mat(mat4_t res, quat_t q);
quat_t quat_rotate(quat_t q, float angle, float x, float y, float z);
/* matrix functions */
static inline void m4_cons(mat4_t m,
float m11, float m12, float m13, float m14,
float m21, float m22, float m23, float m24,
float m31, float m32, float m33, float m34,
float m41, float m42, float m43, float m44);
#include "vmath.inl"
#endif /* VMATH_H_ */

Wyświetl plik

@ -0,0 +1,78 @@
/* vector functions */
static inline vec3_t v3_cons(float x, float y, float z)
{
vec3_t res;
res.x = x;
res.y = y;
res.z = z;
return res;
}
static inline vec3_t quat_vec(quat_t q)
{
vec3_t v;
v.x = q.x;
v.y = q.y;
v.z = q.z;
return v;
}
static inline float v3_dot(vec3_t v1, vec3_t v2)
{
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
/* quaternion functions */
static inline quat_t quat_cons(float s, float x, float y, float z)
{
quat_t q;
q.x = x;
q.y = y;
q.z = z;
q.w = s;
return q;
}
static inline quat_t quat_mul(quat_t q1, quat_t q2)
{
quat_t res;
vec3_t v1 = quat_vec(q1);
vec3_t v2 = quat_vec(q2);
res.w = q1.w * q2.w - v3_dot(v1, v2);
res.x = v2.x * q1.w + v1.x * q2.w + (v1.y * v2.z - v1.z * v2.y);
res.y = v2.y * q1.w + v1.y * q2.w + (v1.z * v2.x - v1.x * v2.z);
res.z = v2.z * q1.w + v1.z * q2.w + (v1.x * v2.y - v1.y * v2.x);
return res;
}
static inline quat_t quat_normalize(quat_t q)
{
float len = sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w);
q.x /= len;
q.y /= len;
q.z /= len;
q.w /= len;
return q;
}
static inline void quat_to_mat(mat4_t res, quat_t q)
{
m4_cons(res, 1.0 - 2.0 * q.y*q.y - 2.0 * q.z*q.z, 2.0 * q.x * q.y + 2.0 * q.w * q.z, 2.0 * q.z * q.x - 2.0 * q.w * q.y, 0,
2.0 * q.x * q.y - 2.0 * q.w * q.z, 1.0 - 2.0 * q.x*q.x - 2.0 * q.z*q.z, 2.0 * q.y * q.z + 2.0 * q.w * q.x, 0,
2.0 * q.z * q.x + 2.0 * q.w * q.y, 2.0 * q.y * q.z - 2.0 * q.w * q.x, 1.0 - 2.0 * q.x*q.x - 2.0 * q.y*q.y, 0,
0, 0, 0, 1);
}
/* matrix functions */
static inline void m4_cons(mat4_t m,
float m11, float m12, float m13, float m14,
float m21, float m22, float m23, float m24,
float m31, float m32, float m33, float m34,
float m41, float m42, float m43, float m44)
{
m[0][0] = m11; m[0][1] = m12; m[0][2] = m13; m[0][3] = m14;
m[1][0] = m21; m[1][1] = m22; m[1][2] = m23; m[1][3] = m24;
m[2][0] = m31; m[2][1] = m32; m[2][2] = m33; m[2][3] = m34;
m[3][0] = m41; m[3][1] = m42; m[3][2] = m43; m[3][3] = m44;
}

Wyświetl plik

@ -1,6 +1,6 @@
CC = gcc
CFLAGS = -pedantic -Wall -g -I..
LDFLAGS = -L.. -lspnav -lX11
CFLAGS = -pedantic -Wall -g -I../..
LDFLAGS = -L../.. -lspnav -lX11
.PHONY: all
all: simple_x11 simple_af_unix