|
View:
New views
8 Messages
—
Rating Filter:
Alert me
|
|
|
Linux spaceball patchHello,
I've just implemented the missing spaceball stuff on linux. See attached spaceball.patch file. The code is compatible with both the proprietary 3Dconnexion driver and the free replacement I've written (http://spacenav.sourceforge.net). Let me know if you need any changes or if I overlooked any important bits. I've also included a new demo program demonstrating the use of the spaceball callbacks. Finally, I don't have access to any windows machines so I can't test that I haven't broken anything there. At the very least I think the new file freeglut_spaceball.c should be added to the visual studio project files to make everything compile properly. The functions in freeglut_spaceball.c aren't doing anything for windows at the moment, but they still have to be compiled to avoid unresolved symbols. Obviously I could just wrap the function calls in TARGET_UNIX_X11 conditional blocks, but I thought that it's better to call no-ops so that somebody may just drop in the appropriate code in the existing functions to implement spaceball on windows as well. -- John Tsiombikas http://nuclear.sdf-eu.org/ Index: src/freeglut_window.c =================================================================== --- src/freeglut_window.c (revision 832) +++ src/freeglut_window.c (working copy) @@ -592,13 +592,17 @@ void fgSetWindow ( SFG_Window *window ) { #if TARGET_HOST_POSIX_X11 - if ( window ) + if ( window ) { glXMakeContextCurrent( fgDisplay.Display, window->Window.Handle, window->Window.Handle, window->Window.Context ); + + /* also register this window to receive spaceball events */ + fgSpaceballSetWindow(window); + } #elif TARGET_HOST_MS_WINDOWS if( fgStructure.CurrentWindow ) ReleaseDC( fgStructure.CurrentWindow->Window.Handle, Index: src/freeglut_callbacks.c =================================================================== --- src/freeglut_callbacks.c (revision 832) +++ src/freeglut_callbacks.c (working copy) @@ -301,6 +301,8 @@ void FGAPIENTRY glutSpaceballMotionFunc( void (* callback)( int, int, int ) ) { FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballMotionFunc" ); + fgInitialiseSpaceball(); + SET_CALLBACK( SpaceMotion ); } @@ -310,6 +312,8 @@ void FGAPIENTRY glutSpaceballRotateFunc( void (* callback)( int, int, int ) ) { FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballRotateFunc" ); + fgInitialiseSpaceball(); + SET_CALLBACK( SpaceRotation ); } @@ -319,6 +323,8 @@ void FGAPIENTRY glutSpaceballButtonFunc( void (* callback)( int, int ) ) { FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballButtonFunc" ); + fgInitialiseSpaceball(); + SET_CALLBACK( SpaceButton ); } Index: src/freeglut_state.c =================================================================== --- src/freeglut_state.c (revision 832) +++ src/freeglut_state.c (working copy) @@ -647,10 +647,14 @@ return 0; case GLUT_HAS_SPACEBALL: + return fgHasSpaceball(); + case GLUT_HAS_TABLET: return 0; case GLUT_NUM_SPACEBALL_BUTTONS: + return fgSpaceballNumButtons(); + case GLUT_NUM_TABLET_BUTTONS: return 0; Index: src/freeglut_internal.h =================================================================== --- src/freeglut_internal.h (revision 832) +++ src/freeglut_internal.h (working copy) @@ -564,9 +564,9 @@ /* Presently ignored */ CB_Select, CB_OverlayDisplay, - CB_SpaceMotion, - CB_SpaceRotation, - CB_SpaceButton, + CB_SpaceMotion, /* implemented only on UNIX/X11 */ + CB_SpaceRotation, /* implemented only on UNIX/X11 */ + CB_SpaceButton, /* implemented only on UNIX/X11 */ CB_Dials, CB_ButtonBox, CB_TabletMotion, @@ -853,6 +853,19 @@ void fgInitialiseInputDevices( void ); void fgInputDeviceClose( void ); +/* spaceball device functions, defined in freeglut_spaceball.c */ +void fgInitialiseSpaceball( void ); +void fgSpaceballClose( void ); +void fgSpaceballSetWindow( SFG_Window *window ); + +int fgHasSpaceball( void ); +int fgSpaceballNumButtons( void ); + +#if TARGET_HOST_POSIX_X11 +int fgIsSpaceballXEvent( const XEvent *ev ); +void fgSpaceballHandleXEvent( const XEvent *ev ); +#endif + /* Setting the cursor for a given window */ void fgSetCursor ( SFG_Window *window, int cursorID ); Index: src/freeglut_main.c =================================================================== --- src/freeglut_main.c (revision 832) +++ src/freeglut_main.c (working copy) @@ -976,6 +976,10 @@ switch( event.type ) { case ClientMessage: + if(fgIsSpaceballXEvent(&event)) { + fgSpaceballHandleXEvent(&event); + break; + } /* Destroy the window when the WM_DELETE_WINDOW message arrives */ if( (Atom) event.xclient.data.l[ 0 ] == fgDisplay.DeleteWindow ) { Index: src/freeglut_spaceball.c =================================================================== --- src/freeglut_spaceball.c (revision 0) +++ src/freeglut_spaceball.c (revision 0) @@ -0,0 +1,456 @@ +/* Spaceball support for Linux. + * Written by John Tsiombikas <nuclear@...> + * + * This code supports 3Dconnexion's 6-dof space-whatever devices. + * It can communicate with either the proprietary 3Dconnexion daemon (3dxsrv) + * free spacenavd (http://spacenav.sourceforge.net), through the "standard" + * magellan X-based protocol. + */ + +#include <GL/freeglut.h> +#include "freeglut_internal.h" + +#if TARGET_HOST_POSIX_X11 +#include <X11/Xlib.h> + +enum { + SPNAV_EVENT_ANY, /* used by spnav_remove_events() */ + SPNAV_EVENT_MOTION, + SPNAV_EVENT_BUTTON /* includes both press and release */ +}; + +struct spnav_event_motion { + int type; + int x, y, z; + int rx, ry, rz; + unsigned int period; + int *data; +}; + +struct spnav_event_button { + int type; + int press; + int bnum; +}; + +typedef union spnav_event { + int type; + struct spnav_event_motion motion; + struct spnav_event_button button; +} spnav_event; + + +static int spnav_x11_open(Display *dpy, Window win); +static int spnav_x11_window(Window win); +static int spnav_x11_event(const XEvent *xev, spnav_event *event); +static int spnav_close(void); +static int spnav_fd(void); +static int spnav_remove_events(int type); + +static SFG_Window *spnav_win; +#endif + +static int sball_initialized; + + +void fgInitialiseSpaceball(void) +{ + if(sball_initialized) { + return; + } + +#if TARGET_HOST_POSIX_X11 + { + Window w; + + if(!fgStructure.CurrentWindow) { + fgWarning("fgInitialiseSpaceball: no current window!\n"); + return; + } + + w = fgStructure.CurrentWindow->Window.Handle; + if(spnav_x11_open(fgDisplay.Display, w) == -1) { + return; + } + } +#endif + + sball_initialized = 1; +} + +void fgSpaceballClose(void) +{ +#if TARGET_HOST_POSIX_X11 + spnav_close(); +#endif +} + +int fgHasSpaceball(void) +{ + if(!sball_initialized) { + fgInitialiseSpaceball(); + if(!sball_initialized) { + fgWarning("fgInitialiseSpaceball failed\n"); + return 0; + } + } + +#if TARGET_HOST_POSIX_X11 + /* XXX this function should somehow query the driver if there's a device + * plugged in, as opposed to just checking if there's a driver to talk to. + */ + return spnav_fd() == -1 ? 0 : 1; +#else + return 0; +#endif +} + +int fgSpaceballNumButtons(void) +{ + if(!sball_initialized) { + fgInitialiseSpaceball(); + if(!sball_initialized) { + fgWarning("fgInitialiseSpaceball failed\n"); + return 0; + } + } + +#if TARGET_HOST_POSIX_X11 + return 2; /* TODO implement this properly */ +#else + return 0; +#endif +} + +void fgSpaceballSetWindow(SFG_Window *window) +{ + if(!sball_initialized) { + fgInitialiseSpaceball(); + if(!sball_initialized) { + return; + } + } + +#if TARGET_HOST_POSIX_X11 + if(spnav_win != window) { + spnav_x11_window(window->Window.Handle); + spnav_win = window; + } +#endif +} + + +#if TARGET_HOST_POSIX_X11 +int fgIsSpaceballXEvent(const XEvent *xev) +{ + spnav_event sev; + + if(!sball_initialized) { + fgInitialiseSpaceball(); + if(!sball_initialized) { + return 0; + } + } + + return spnav_x11_event(xev, &sev); +} + +void fgSpaceballHandleXEvent(const XEvent *xev) +{ + spnav_event sev; + + if(!sball_initialized) { + fgInitialiseSpaceball(); + if(!sball_initialized) { + return; + } + } + + if(spnav_x11_event(xev, &sev)) { + switch(sev.type) { + case SPNAV_EVENT_MOTION: + if(sev.motion.x | sev.motion.y | sev.motion.z) { + INVOKE_WCB(*spnav_win, SpaceMotion, (sev.motion.x, sev.motion.y, sev.motion.z)); + } + if(sev.motion.rx | sev.motion.ry | sev.motion.rz) { + INVOKE_WCB(*spnav_win, SpaceRotation, (sev.motion.rx, sev.motion.ry, sev.motion.rz)); + } + spnav_remove_events(SPNAV_EVENT_MOTION); + break; + + case SPNAV_EVENT_BUTTON: + INVOKE_WCB(*spnav_win, SpaceButton, (sev.button.bnum, sev.button.press ? GLUT_DOWN : GLUT_UP)); + break; + + default: + break; + } + } +} + +/* +The following code is part of libspnav, part of the spacenav project (spacenav.sf.net) +Copyright (C) 2007-2009 John Tsiombikas <nuclear@...> + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +static Window get_daemon_window(Display *dpy); +static int catch_badwin(Display *dpy, XErrorEvent *err); + +static Display *dpy; +static Window app_win; +static Atom motion_event, button_press_event, button_release_event, command_event; + +enum { + CMD_APP_WINDOW = 27695, + CMD_APP_SENS +}; + +#define IS_OPEN dpy + +struct event_node { + spnav_event event; + struct event_node *next; +}; + +static int spnav_x11_open(Display *display, Window win) +{ + if(IS_OPEN) { + return -1; + } + + dpy = display; + + motion_event = XInternAtom(dpy, "MotionEvent", True); + button_press_event = XInternAtom(dpy, "ButtonPressEvent", True); + button_release_event = XInternAtom(dpy, "ButtonReleaseEvent", True); + command_event = XInternAtom(dpy, "CommandEvent", True); + + if(!motion_event || !button_press_event || !button_release_event || !command_event) { + dpy = 0; + return -1; /* daemon not started */ + } + + if(spnav_x11_window(win) == -1) { + dpy = 0; + return -1; /* daemon not started */ + } + + app_win = win; + return 0; +} + +static int spnav_close(void) +{ + if(dpy) { + spnav_x11_window(DefaultRootWindow(dpy)); + app_win = 0; + dpy = 0; + return 0; + } + return -1; +} + +static int spnav_x11_window(Window win) +{ + int (*prev_xerr_handler)(Display*, XErrorEvent*); + XEvent xev; + Window daemon_win; + + if(!IS_OPEN) { + return -1; + } + + if(!(daemon_win = get_daemon_window(dpy))) { + return -1; + } + + prev_xerr_handler = XSetErrorHandler(catch_badwin); + + xev.type = ClientMessage; + xev.xclient.send_event = False; + xev.xclient.display = dpy; + xev.xclient.window = win; + xev.xclient.message_type = command_event; + xev.xclient.format = 16; + xev.xclient.data.s[0] = ((unsigned int)win & 0xffff0000) >> 16; + xev.xclient.data.s[1] = (unsigned int)win & 0xffff; + xev.xclient.data.s[2] = CMD_APP_WINDOW; + + XSendEvent(dpy, daemon_win, False, 0, &xev); + XSync(dpy, False); + + XSetErrorHandler(prev_xerr_handler); + return 0; +} + +static int spnav_fd(void) +{ + if(dpy) { + return ConnectionNumber(dpy); + } + return -1; +} + +/*static int spnav_wait_event(spnav_event *event) +{ + if(dpy) { + for(;;) { + XEvent xev; + XNextEvent(dpy, &xev); + + if(spnav_x11_event(&xev, event) > 0) { + return event->type; + } + } + } + return 0; +} + +static int spnav_poll_event(spnav_event *event) +{ + if(dpy) { + if(XPending(dpy)) { + XEvent xev; + XNextEvent(dpy, &xev); + + return spnav_x11_event(&xev, event); + } + } + return 0; +}*/ + +static Bool match_events(Display *dpy, XEvent *xev, char *arg) +{ + int evtype = *(int*)arg; + + if(xev->type != ClientMessage) { + return False; + } + + if(xev->xclient.message_type == motion_event) { + return !evtype || evtype == SPNAV_EVENT_MOTION ? True : False; + } + if(xev->xclient.message_type == button_press_event || + xev->xclient.message_type == button_release_event) { + return !evtype || evtype == SPNAV_EVENT_BUTTON ? True : False; + } + return False; +} + +static int spnav_remove_events(int type) +{ + int rm_count = 0; + + if(dpy) { + XEvent xev; + + while(XCheckIfEvent(dpy, &xev, match_events, (char*)&type)) { + rm_count++; + } + return rm_count; + } + return 0; +} + +static int spnav_x11_event(const XEvent *xev, spnav_event *event) +{ + int i; + int xmsg_type; + + if(xev->type != ClientMessage) { + return 0; + } + + xmsg_type = xev->xclient.message_type; + + if(xmsg_type != motion_event && xmsg_type != button_press_event && + xmsg_type != button_release_event) { + return 0; + } + + if(xmsg_type == motion_event) { + event->type = SPNAV_EVENT_MOTION; + event->motion.data = &event->motion.x; + + for(i=0; i<6; i++) { + event->motion.data[i] = xev->xclient.data.s[i + 2]; + } + event->motion.period = xev->xclient.data.s[8]; + } else { + event->type = SPNAV_EVENT_BUTTON; + event->button.press = xmsg_type == button_press_event ? 1 : 0; + event->button.bnum = xev->xclient.data.s[2]; + } + return event->type; +} + + +static Window get_daemon_window(Display *dpy) +{ + Window win, root_win; + XTextProperty wname; + Atom type; + int fmt; + unsigned long nitems, bytes_after; + unsigned char *prop; + + root_win = DefaultRootWindow(dpy); + + XGetWindowProperty(dpy, root_win, command_event, 0, 1, False, AnyPropertyType, &type, &fmt, &nitems, &bytes_after, &prop); + if(!prop) { + return 0; + } + + win = *(Window*)prop; + XFree(prop); + + if(!XGetWMName(dpy, win, &wname) || strcmp("Magellan Window", (char*)wname.value) != 0) { + return 0; + } + + return win; +} + +static int catch_badwin(Display *dpy, XErrorEvent *err) +{ + char buf[256]; + + if(err->error_code == BadWindow) { + /* do nothing? */ + } else { + XGetErrorText(dpy, err->error_code, buf, sizeof buf); + fprintf(stderr, "Caught unexpected X error: %s\n", buf); + } + return 0; +} + +#endif /* TARGET_HOST_POSIX_X11 */ Index: src/Makefile.am =================================================================== --- src/Makefile.am (revision 832) +++ src/Makefile.am (working copy) @@ -28,6 +28,7 @@ freeglut_geometry.c \ freeglut_init.c \ freeglut_input_devices.c \ + freeglut_spaceball.c \ freeglut_joystick.c \ freeglut_main.c \ freeglut_menu.c \ Index: progs/demos/spaceball/vmath.c =================================================================== --- progs/demos/spaceball/vmath.c (revision 0) +++ progs/demos/spaceball/vmath.c (revision 0) @@ -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); +} Index: progs/demos/spaceball/vmath.inl =================================================================== --- progs/demos/spaceball/vmath.inl (revision 0) +++ progs/demos/spaceball/vmath.inl (revision 0) @@ -0,0 +1,68 @@ +/* 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 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; +} Index: progs/demos/spaceball/vmath.h =================================================================== --- progs/demos/spaceball/vmath.h (revision 0) +++ progs/demos/spaceball/vmath.h (revision 0) @@ -0,0 +1,31 @@ +#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 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_ */ Index: progs/demos/spaceball/spaceball.c =================================================================== --- progs/demos/spaceball/spaceball.c (revision 0) +++ progs/demos/spaceball/spaceball.c (revision 0) @@ -0,0 +1,173 @@ +/* Spaceball demo + * + * Written by John Tsiombikas <nuclear@...> + * (converted from the libspnav cube example) + * + * Use the spaceball to move and rotate the colored cube. + * Pressing any button will reset the cube at its original location. + * + * Press escape or q to exit. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <GL/freeglut.h> +#include "vmath.h" + +void draw_cube(void); + +/* callbacks */ +void disp(void); +void reshape(int x, int y); +void keyb(unsigned char key, int x, int y); +void sbmot(int x, int y, int z); /* spaceball translation */ +void sbrot(int x, int y, int z); /* spaceball rotation */ +void sbbut(int bn, int state); /* spaceball button */ + +vec3_t pos = {0, 0, -6}; +quat_t rot = {0, 0, 0, 1}; + +int main(int argc, char **argv) +{ + glutInit(&argc, argv); + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); + glutCreateWindow("spaceball demo"); + + glutDisplayFunc(disp); + glutReshapeFunc(reshape); + glutKeyboardFunc(keyb); + glutSpaceballMotionFunc(sbmot); + glutSpaceballRotateFunc(sbrot); + glutSpaceballButtonFunc(sbbut); + + glEnable(GL_CULL_FACE); + + glutMainLoop(); + return 0; +} + +void disp(void) +{ + mat4_t xform; + + quat_to_mat(xform, rot); + + glClear(GL_COLOR_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(pos.x, pos.y, pos.z); + glMultTransposeMatrixf((float*)xform); + + draw_cube(); + + glutSwapBuffers(); +} + +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(); +} + +/* 45deg fov */ +#define FOV (M_PI / 4.0) + +void reshape(int x, int y) +{ + float aspect = (float)x / (float)y; + float halfy = tan(FOV / 2.0); + float halfx = halfy * aspect; + + glViewport(0, 0, x, y); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-halfx, halfx, -halfy, halfy, 1.0, 1000.0); +} + +void keyb(unsigned char key, int x, int y) +{ + switch(key) { + case 'q': + case 'Q': + case 27: + exit(0); + + case ' ': + /* reset initial view */ + pos = v3_cons(0, 0, -6); + rot = quat_cons(1, 0, 0, 0); + glutPostRedisplay(); + + default: + break; + } +} + +void sbmot(int x, int y, int z) +{ + pos.x += x * 0.001; + pos.y += y * 0.001; + pos.z -= z * 0.001; + glutPostRedisplay(); +} + +void sbrot(int x, int y, int z) +{ + float axis_len = sqrt(x * x + y * y + z * z); + rot = quat_rotate(rot, axis_len * 0.001, -x / axis_len, -y / axis_len, z / axis_len); + glutPostRedisplay(); +} + +void sbbut(int bn, int state) +{ + if(state == GLUT_DOWN) { + pos = v3_cons(0, 0, -6); + rot = quat_cons(1, 0, 0, 0); + glutPostRedisplay(); + } +} Index: progs/demos/spaceball/Makefile.am =================================================================== --- progs/demos/spaceball/Makefile.am (revision 0) +++ progs/demos/spaceball/Makefile.am (revision 0) @@ -0,0 +1,6 @@ +EXTRA_DIST = spaceball.c vmath.c vmath.h vmath.inl + +noinst_PROGRAMS = spaceball +spaceball_SOURCES = spaceball.c vmath.c +spaceball_LDFLAGS = -export-dynamic ../../../src/lib@LIBRARY@.la +spaceball_CFLAGS = -I$(top_srcdir)/include $(X_CFLAGS) Index: progs/demos/Makefile.am =================================================================== --- progs/demos/Makefile.am (revision 832) +++ progs/demos/Makefile.am (working copy) @@ -1,2 +1,2 @@ EXTRA_DIST = demos.dsw -SUBDIRS = CallbackMaker Fractals Fractals_random Lorenz One shapes smooth_opengl3 +SUBDIRS = CallbackMaker Fractals Fractals_random Lorenz One shapes smooth_opengl3 spaceball Index: configure.ac =================================================================== --- configure.ac (revision 832) +++ configure.ac (working copy) @@ -95,5 +95,5 @@ fi # Generate output. -AC_CONFIG_FILES([Makefile doc/Makefile include/GL/Makefile include/Makefile progs/Makefile progs/demos/CallbackMaker/Makefile progs/demos/Fractals/Makefile progs/demos/Fractals_random/Makefile progs/demos/Lorenz/Makefile progs/demos/Makefile progs/demos/One/Makefile progs/demos/shapes/Makefile progs/demos/smooth_opengl3/Makefile src/Makefile]) +AC_CONFIG_FILES([Makefile doc/Makefile include/GL/Makefile include/Makefile progs/Makefile progs/demos/CallbackMaker/Makefile progs/demos/Fractals/Makefile progs/demos/Fractals_random/Makefile progs/demos/Lorenz/Makefile progs/demos/Makefile progs/demos/One/Makefile progs/demos/shapes/Makefile progs/demos/smooth_opengl3/Makefile progs/demos/spaceball/Makefile src/Makefile]) AC_OUTPUT ------------------------------------------------------------------------------ Come build with us! The BlackBerry(R) Developer Conference in SF, CA is the only developer event you need to attend this year. Jumpstart your developing skills, take BlackBerry mobile applications to market and stay ahead of the curve. Join us from November 9 - 12, 2009. Register now! http://p.sf.net/sfu/devconference _______________________________________________ Freeglut-developer mailing list Freeglut-developer@... https://lists.sourceforge.net/lists/listinfo/freeglut-developer |
|
|
Re: Linux spaceball patchJohn,
I've not had the time to give your patch the attention it needs, but I am concerned about the statement that it is compatible with the proprietary driver. Does it have any external dependencies on proprietary code? - John F. At 09:43 AM 10/15/2009, you wrote: >Hello, > >I've just implemented the missing spaceball stuff on linux. See attached >spaceball.patch file. > >The code is compatible with both the proprietary 3Dconnexion driver and >the free replacement I've written (http://spacenav.sourceforge.net). > >Let me know if you need any changes or if I overlooked any important >bits. I've also included a new demo program demonstrating the use of >the spaceball callbacks. > >Finally, I don't have access to any windows machines so I can't test >that I haven't broken anything there. At the very least I think the new >file freeglut_spaceball.c should be added to the visual studio project >files to make everything compile properly. > >The functions in freeglut_spaceball.c aren't doing anything for windows >at the moment, but they still have to be compiled to avoid unresolved >symbols. Obviously I could just wrap the function calls in >TARGET_UNIX_X11 conditional blocks, but I thought that it's better to >call no-ops so that somebody may just drop in the appropriate code in >the existing functions to implement spaceball on windows as well. > >-- >John Tsiombikas >http://nuclear.sdf-eu.org/ > > >------------------------------------------------------------------------------ >Come build with us! The BlackBerry(R) Developer Conference in SF, CA >is the only developer event you need to attend this year. Jumpstart your >developing skills, take BlackBerry mobile applications to market and stay >ahead of the curve. Join us from November 9 - 12, 2009. Register now! >http://p.sf.net/sfu/devconference >_______________________________________________ >Freeglut-developer mailing list >Freeglut-developer@... >https://lists.sourceforge.net/lists/listinfo/freeglut-developer ------------------------------------------------------------------------------ Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july _______________________________________________ Freeglut-developer mailing list Freeglut-developer@... https://lists.sourceforge.net/lists/listinfo/freeglut-developer |
|
|
Re: Linux spaceball patchOn Wed, Nov 04, 2009 at 06:51:11AM -0600, John F. Fay wrote:
> John, > > I've not had the time to give your patch the attention it > needs, but I am concerned about the statement that it is compatible > with the proprietary driver. Does it have any external dependencies > on proprietary code? Hi, None at all. It's based on my work on the replacement compatible driver and SDK for these devices (spacenav.sourceforge.net) but in order to simplify matters for freeglut, I've made sure it doesn't even depend on my project, I've included all the necessary code and it should just work as it is, no dependencies. -- John Tsiombikas http://nuclear.sdf-eu.org/ ------------------------------------------------------------------------------ Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july _______________________________________________ Freeglut-developer mailing list Freeglut-developer@... https://lists.sourceforge.net/lists/listinfo/freeglut-developer |
|
|
Re: Linux spaceball patchOK, I've put that in. Please check it out ASAP as it is rather
MASSIVE and I am sure I have broken something else. - John At 09:43 AM 10/15/2009, you wrote: >Hello, > >I've just implemented the missing spaceball stuff on linux. See attached >spaceball.patch file. > >The code is compatible with both the proprietary 3Dconnexion driver and >the free replacement I've written (http://spacenav.sourceforge.net). > >Let me know if you need any changes or if I overlooked any important >bits. I've also included a new demo program demonstrating the use of >the spaceball callbacks. > >Finally, I don't have access to any windows machines so I can't test >that I haven't broken anything there. At the very least I think the new >file freeglut_spaceball.c should be added to the visual studio project >files to make everything compile properly. > >The functions in freeglut_spaceball.c aren't doing anything for windows >at the moment, but they still have to be compiled to avoid unresolved >symbols. Obviously I could just wrap the function calls in >TARGET_UNIX_X11 conditional blocks, but I thought that it's better to >call no-ops so that somebody may just drop in the appropriate code in >the existing functions to implement spaceball on windows as well. > >-- >John Tsiombikas >http://nuclear.sdf-eu.org/ > > >------------------------------------------------------------------------------ >Come build with us! The BlackBerry(R) Developer Conference in SF, CA >is the only developer event you need to attend this year. Jumpstart your >developing skills, take BlackBerry mobile applications to market and stay >ahead of the curve. Join us from November 9 - 12, 2009. Register now! >http://p.sf.net/sfu/devconference >_______________________________________________ >Freeglut-developer mailing list >Freeglut-developer@... >https://lists.sourceforge.net/lists/listinfo/freeglut-developer ------------------------------------------------------------------------------ Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july _______________________________________________ Freeglut-developer mailing list Freeglut-developer@... https://lists.sourceforge.net/lists/listinfo/freeglut-developer |
|
|
Re: Linux spaceball patchIn particular please check the line endings. I was editing some
Makefile.am and configure.ac files in Windows. Also a bunch of tab characters need expanding to spaces; I started but ran out of time and my editor didn't do it automatically. - John ------------------------------------------------------------------------------ Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july _______________________________________________ Freeglut-developer mailing list Freeglut-developer@... https://lists.sourceforge.net/lists/listinfo/freeglut-developer |
|
|
Re: Linux spaceball patchOn Fri, Nov 06, 2009 at 07:24:22AM -0600, John F. Fay wrote:
> OK, I've put that in. Please check it out ASAP as it is rather > MASSIVE and I am sure I have broken something else. I've just tried it and it works just fine. One minor thing though, please remove the fgWarning in freeglut_spaceball.c line 67, as it's apparently producing spurious output. -- John Tsiombikas http://nuclear.sdf-eu.org/ ------------------------------------------------------------------------------ Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july _______________________________________________ Freeglut-developer mailing list Freeglut-developer@... https://lists.sourceforge.net/lists/listinfo/freeglut-developer |
|
|
Re: Linux spaceball patchOn Fri, Nov 06, 2009 at 07:53:09AM -0600, John F. Fay wrote:
> In particular please check the line endings. I was editing some > Makefile.am and configure.ac files in Windows. Also a bunch of tab > characters need expanding to spaces; I started but ran out of time > and my editor didn't do it automatically. I've just mass converted all tabs to spaces and all newlines to UNIX newlines (I take it that's what you meant), here's the patch: -- John Tsiombikas http://nuclear.sdf-eu.org/ Index: src/freeglut_spaceball.c =================================================================== --- src/freeglut_spaceball.c (revision 837) +++ src/freeglut_spaceball.c (working copy) @@ -1,456 +1,455 @@ -/* Spaceball support for Linux. - * Written by John Tsiombikas <nuclear@...> - * - * This code supports 3Dconnexion's 6-dof space-whatever devices. - * It can communicate with either the proprietary 3Dconnexion daemon (3dxsrv) - * free spacenavd (http://spacenav.sourceforge.net), through the "standard" - * magellan X-based protocol. - */ - -#include <GL/freeglut.h> -#include "freeglut_internal.h" - -#if TARGET_HOST_POSIX_X11 -#include <X11/Xlib.h> - -enum { - SPNAV_EVENT_ANY, /* used by spnav_remove_events() */ - SPNAV_EVENT_MOTION, - SPNAV_EVENT_BUTTON /* includes both press and release */ -}; - -struct spnav_event_motion { - int type; - int x, y, z; - int rx, ry, rz; - unsigned int period; - int *data; -}; - -struct spnav_event_button { - int type; - int press; - int bnum; -}; - -typedef union spnav_event { - int type; - struct spnav_event_motion motion; - struct spnav_event_button button; -} spnav_event; - - -static int spnav_x11_open(Display *dpy, Window win); -static int spnav_x11_window(Window win); -static int spnav_x11_event(const XEvent *xev, spnav_event *event); -static int spnav_close(void); -static int spnav_fd(void); -static int spnav_remove_events(int type); - -static SFG_Window *spnav_win; -#endif - -static int sball_initialized; - - -void fgInitialiseSpaceball(void) -{ - if(sball_initialized) { - return; - } - -#if TARGET_HOST_POSIX_X11 - { - Window w; - - if(!fgStructure.CurrentWindow) { - fgWarning("fgInitialiseSpaceball: no current window!\n"); - return; - } - - w = fgStructure.CurrentWindow->Window.Handle; - if(spnav_x11_open(fgDisplay.Display, w) == -1) { - return; - } - } -#endif - - sball_initialized = 1; -} - -void fgSpaceballClose(void) -{ -#if TARGET_HOST_POSIX_X11 - spnav_close(); -#endif -} - -int fgHasSpaceball(void) -{ - if(!sball_initialized) { - fgInitialiseSpaceball(); - if(!sball_initialized) { - fgWarning("fgInitialiseSpaceball failed\n"); - return 0; - } - } - -#if TARGET_HOST_POSIX_X11 - /* XXX this function should somehow query the driver if there's a device - * plugged in, as opposed to just checking if there's a driver to talk to. - */ - return spnav_fd() == -1 ? 0 : 1; -#else - return 0; -#endif -} - -int fgSpaceballNumButtons(void) -{ - if(!sball_initialized) { - fgInitialiseSpaceball(); - if(!sball_initialized) { - fgWarning("fgInitialiseSpaceball failed\n"); - return 0; - } - } - -#if TARGET_HOST_POSIX_X11 - return 2; /* TODO implement this properly */ -#else - return 0; -#endif -} - -void fgSpaceballSetWindow(SFG_Window *window) -{ - if(!sball_initialized) { - fgInitialiseSpaceball(); - if(!sball_initialized) { - return; - } - } - -#if TARGET_HOST_POSIX_X11 - if(spnav_win != window) { - spnav_x11_window(window->Window.Handle); - spnav_win = window; - } -#endif -} - - -#if TARGET_HOST_POSIX_X11 -int fgIsSpaceballXEvent(const XEvent *xev) -{ - spnav_event sev; - - if(!sball_initialized) { - fgInitialiseSpaceball(); - if(!sball_initialized) { - return 0; - } - } - - return spnav_x11_event(xev, &sev); -} - -void fgSpaceballHandleXEvent(const XEvent *xev) -{ - spnav_event sev; - - if(!sball_initialized) { - fgInitialiseSpaceball(); - if(!sball_initialized) { - return; - } - } - - if(spnav_x11_event(xev, &sev)) { - switch(sev.type) { - case SPNAV_EVENT_MOTION: - if(sev.motion.x | sev.motion.y | sev.motion.z) { - INVOKE_WCB(*spnav_win, SpaceMotion, (sev.motion.x, sev.motion.y, sev.motion.z)); - } - if(sev.motion.rx | sev.motion.ry | sev.motion.rz) { - INVOKE_WCB(*spnav_win, SpaceRotation, (sev.motion.rx, sev.motion.ry, sev.motion.rz)); - } - spnav_remove_events(SPNAV_EVENT_MOTION); - break; - - case SPNAV_EVENT_BUTTON: - INVOKE_WCB(*spnav_win, SpaceButton, (sev.button.bnum, sev.button.press ? GLUT_DOWN : GLUT_UP)); - break; - - default: - break; - } - } -} - -/* -The following code is part of libspnav, part of the spacenav project (spacenav.sf.net) -Copyright (C) 2007-2009 John Tsiombikas <nuclear@...> - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. -3. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. -*/ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -#include <X11/Xlib.h> -#include <X11/Xutil.h> - -static Window get_daemon_window(Display *dpy); -static int catch_badwin(Display *dpy, XErrorEvent *err); - -static Display *dpy; -static Window app_win; -static Atom motion_event, button_press_event, button_release_event, command_event; - -enum { - CMD_APP_WINDOW = 27695, - CMD_APP_SENS -}; - -#define IS_OPEN dpy - -struct event_node { - spnav_event event; - struct event_node *next; -}; - -static int spnav_x11_open(Display *display, Window win) -{ - if(IS_OPEN) { - return -1; - } - - dpy = display; - - motion_event = XInternAtom(dpy, "MotionEvent", True); - button_press_event = XInternAtom(dpy, "ButtonPressEvent", True); - button_release_event = XInternAtom(dpy, "ButtonReleaseEvent", True); - command_event = XInternAtom(dpy, "CommandEvent", True); - - if(!motion_event || !button_press_event || !button_release_event || !command_event) { - dpy = 0; - return -1; /* daemon not started */ - } - - if(spnav_x11_window(win) == -1) { - dpy = 0; - return -1; /* daemon not started */ - } - - app_win = win; - return 0; -} - -static int spnav_close(void) -{ - if(dpy) { - spnav_x11_window(DefaultRootWindow(dpy)); - app_win = 0; - dpy = 0; - return 0; - } - return -1; -} - -static int spnav_x11_window(Window win) -{ - int (*prev_xerr_handler)(Display*, XErrorEvent*); - XEvent xev; - Window daemon_win; - - if(!IS_OPEN) { - return -1; - } - - if(!(daemon_win = get_daemon_window(dpy))) { - return -1; - } - - prev_xerr_handler = XSetErrorHandler(catch_badwin); - - xev.type = ClientMessage; - xev.xclient.send_event = False; - xev.xclient.display = dpy; - xev.xclient.window = win; - xev.xclient.message_type = command_event; - xev.xclient.format = 16; - xev.xclient.data.s[0] = ((unsigned int)win & 0xffff0000) >> 16; - xev.xclient.data.s[1] = (unsigned int)win & 0xffff; - xev.xclient.data.s[2] = CMD_APP_WINDOW; - - XSendEvent(dpy, daemon_win, False, 0, &xev); - XSync(dpy, False); - - XSetErrorHandler(prev_xerr_handler); - return 0; -} - -static int spnav_fd(void) -{ - if(dpy) { - return ConnectionNumber(dpy); - } - return -1; -} - -/*static int spnav_wait_event(spnav_event *event) -{ - if(dpy) { - for(;;) { - XEvent xev; - XNextEvent(dpy, &xev); - - if(spnav_x11_event(&xev, event) > 0) { - return event->type; - } - } - } - return 0; -} - -static int spnav_poll_event(spnav_event *event) -{ - if(dpy) { - if(XPending(dpy)) { - XEvent xev; - XNextEvent(dpy, &xev); - - return spnav_x11_event(&xev, event); - } - } - return 0; -}*/ - -static Bool match_events(Display *dpy, XEvent *xev, char *arg) -{ - int evtype = *(int*)arg; - - if(xev->type != ClientMessage) { - return False; - } - - if(xev->xclient.message_type == motion_event) { - return !evtype || evtype == SPNAV_EVENT_MOTION ? True : False; - } - if(xev->xclient.message_type == button_press_event || - xev->xclient.message_type == button_release_event) { - return !evtype || evtype == SPNAV_EVENT_BUTTON ? True : False; - } - return False; -} - -static int spnav_remove_events(int type) -{ - int rm_count = 0; - - if(dpy) { - XEvent xev; - - while(XCheckIfEvent(dpy, &xev, match_events, (char*)&type)) { - rm_count++; - } - return rm_count; - } - return 0; -} - -static int spnav_x11_event(const XEvent *xev, spnav_event *event) -{ - int i; - int xmsg_type; - - if(xev->type != ClientMessage) { - return 0; - } - - xmsg_type = xev->xclient.message_type; - - if(xmsg_type != motion_event && xmsg_type != button_press_event && - xmsg_type != button_release_event) { - return 0; - } - - if(xmsg_type == motion_event) { - event->type = SPNAV_EVENT_MOTION; - event->motion.data = &event->motion.x; - - for(i=0; i<6; i++) { - event->motion.data[i] = xev->xclient.data.s[i + 2]; - } - event->motion.period = xev->xclient.data.s[8]; - } else { - event->type = SPNAV_EVENT_BUTTON; - event->button.press = xmsg_type == button_press_event ? 1 : 0; - event->button.bnum = xev->xclient.data.s[2]; - } - return event->type; -} - - -static Window get_daemon_window(Display *dpy) -{ - Window win, root_win; - XTextProperty wname; - Atom type; - int fmt; - unsigned long nitems, bytes_after; - unsigned char *prop; - - root_win = DefaultRootWindow(dpy); - - XGetWindowProperty(dpy, root_win, command_event, 0, 1, False, AnyPropertyType, &type, &fmt, &nitems, &bytes_after, &prop); - if(!prop) { - return 0; - } - - win = *(Window*)prop; - XFree(prop); - - if(!XGetWMName(dpy, win, &wname) || strcmp("Magellan Window", (char*)wname.value) != 0) { - return 0; - } - - return win; -} - -static int catch_badwin(Display *dpy, XErrorEvent *err) -{ - char buf[256]; - - if(err->error_code == BadWindow) { - /* do nothing? */ - } else { - XGetErrorText(dpy, err->error_code, buf, sizeof buf); - fprintf(stderr, "Caught unexpected X error: %s\n", buf); - } - return 0; -} - -#endif /* TARGET_HOST_POSIX_X11 */ +/* Spaceball support for Linux. + * Written by John Tsiombikas <nuclear@...> + * + * This code supports 3Dconnexion's 6-dof space-whatever devices. + * It can communicate with either the proprietary 3Dconnexion daemon (3dxsrv) + * free spacenavd (http://spacenav.sourceforge.net), through the "standard" + * magellan X-based protocol. + */ + +#include <GL/freeglut.h> +#include "freeglut_internal.h" + +#if TARGET_HOST_POSIX_X11 +#include <X11/Xlib.h> + +enum { + SPNAV_EVENT_ANY, /* used by spnav_remove_events() */ + SPNAV_EVENT_MOTION, + SPNAV_EVENT_BUTTON /* includes both press and release */ +}; + +struct spnav_event_motion { + int type; + int x, y, z; + int rx, ry, rz; + unsigned int period; + int *data; +}; + +struct spnav_event_button { + int type; + int press; + int bnum; +}; + +typedef union spnav_event { + int type; + struct spnav_event_motion motion; + struct spnav_event_button button; +} spnav_event; + + +static int spnav_x11_open(Display *dpy, Window win); +static int spnav_x11_window(Window win); +static int spnav_x11_event(const XEvent *xev, spnav_event *event); +static int spnav_close(void); +static int spnav_fd(void); +static int spnav_remove_events(int type); + +static SFG_Window *spnav_win; +#endif + +static int sball_initialized; + + +void fgInitialiseSpaceball(void) +{ + if(sball_initialized) { + return; + } + +#if TARGET_HOST_POSIX_X11 + { + Window w; + + if(!fgStructure.CurrentWindow) { + return; + } + + w = fgStructure.CurrentWindow->Window.Handle; + if(spnav_x11_open(fgDisplay.Display, w) == -1) { + return; + } + } +#endif + + sball_initialized = 1; +} + +void fgSpaceballClose(void) +{ +#if TARGET_HOST_POSIX_X11 + spnav_close(); +#endif +} + +int fgHasSpaceball(void) +{ + if(!sball_initialized) { + fgInitialiseSpaceball(); + if(!sball_initialized) { + fgWarning("fgInitialiseSpaceball failed\n"); + return 0; + } + } + +#if TARGET_HOST_POSIX_X11 + /* XXX this function should somehow query the driver if there's a device + * plugged in, as opposed to just checking if there's a driver to talk to. + */ + return spnav_fd() == -1 ? 0 : 1; +#else + return 0; +#endif +} + +int fgSpaceballNumButtons(void) +{ + if(!sball_initialized) { + fgInitialiseSpaceball(); + if(!sball_initialized) { + fgWarning("fgInitialiseSpaceball failed\n"); + return 0; + } + } + +#if TARGET_HOST_POSIX_X11 + return 2; /* TODO implement this properly */ +#else + return 0; +#endif +} + +void fgSpaceballSetWindow(SFG_Window *window) +{ + if(!sball_initialized) { + fgInitialiseSpaceball(); + if(!sball_initialized) { + return; + } + } + +#if TARGET_HOST_POSIX_X11 + if(spnav_win != window) { + spnav_x11_window(window->Window.Handle); + spnav_win = window; + } +#endif +} + + +#if TARGET_HOST_POSIX_X11 +int fgIsSpaceballXEvent(const XEvent *xev) +{ + spnav_event sev; + + if(!sball_initialized) { + fgInitialiseSpaceball(); + if(!sball_initialized) { + return 0; + } + } + + return spnav_x11_event(xev, &sev); +} + +void fgSpaceballHandleXEvent(const XEvent *xev) +{ + spnav_event sev; + + if(!sball_initialized) { + fgInitialiseSpaceball(); + if(!sball_initialized) { + return; + } + } + + if(spnav_x11_event(xev, &sev)) { + switch(sev.type) { + case SPNAV_EVENT_MOTION: + if(sev.motion.x | sev.motion.y | sev.motion.z) { + INVOKE_WCB(*spnav_win, SpaceMotion, (sev.motion.x, sev.motion.y, sev.motion.z)); + } + if(sev.motion.rx | sev.motion.ry | sev.motion.rz) { + INVOKE_WCB(*spnav_win, SpaceRotation, (sev.motion.rx, sev.motion.ry, sev.motion.rz)); + } + spnav_remove_events(SPNAV_EVENT_MOTION); + break; + + case SPNAV_EVENT_BUTTON: + INVOKE_WCB(*spnav_win, SpaceButton, (sev.button.bnum, sev.button.press ? GLUT_DOWN : GLUT_UP)); + break; + + default: + break; + } + } +} + +/* +The following code is part of libspnav, part of the spacenav project (spacenav.sf.net) +Copyright (C) 2007-2009 John Tsiombikas <nuclear@...> + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +static Window get_daemon_window(Display *dpy); +static int catch_badwin(Display *dpy, XErrorEvent *err); + +static Display *dpy; +static Window app_win; +static Atom motion_event, button_press_event, button_release_event, command_event; + +enum { + CMD_APP_WINDOW = 27695, + CMD_APP_SENS +}; + +#define IS_OPEN dpy + +struct event_node { + spnav_event event; + struct event_node *next; +}; + +static int spnav_x11_open(Display *display, Window win) +{ + if(IS_OPEN) { + return -1; + } + + dpy = display; + + motion_event = XInternAtom(dpy, "MotionEvent", True); + button_press_event = XInternAtom(dpy, "ButtonPressEvent", True); + button_release_event = XInternAtom(dpy, "ButtonReleaseEvent", True); + command_event = XInternAtom(dpy, "CommandEvent", True); + + if(!motion_event || !button_press_event || !button_release_event || !command_event) { + dpy = 0; + return -1; /* daemon not started */ + } + + if(spnav_x11_window(win) == -1) { + dpy = 0; + return -1; /* daemon not started */ + } + + app_win = win; + return 0; +} + +static int spnav_close(void) +{ + if(dpy) { + spnav_x11_window(DefaultRootWindow(dpy)); + app_win = 0; + dpy = 0; + return 0; + } + return -1; +} + +static int spnav_x11_window(Window win) +{ + int (*prev_xerr_handler)(Display*, XErrorEvent*); + XEvent xev; + Window daemon_win; + + if(!IS_OPEN) { + return -1; + } + + if(!(daemon_win = get_daemon_window(dpy))) { + return -1; + } + + prev_xerr_handler = XSetErrorHandler(catch_badwin); + + xev.type = ClientMessage; + xev.xclient.send_event = False; + xev.xclient.display = dpy; + xev.xclient.window = win; + xev.xclient.message_type = command_event; + xev.xclient.format = 16; + xev.xclient.data.s[0] = ((unsigned int)win & 0xffff0000) >> 16; + xev.xclient.data.s[1] = (unsigned int)win & 0xffff; + xev.xclient.data.s[2] = CMD_APP_WINDOW; + + XSendEvent(dpy, daemon_win, False, 0, &xev); + XSync(dpy, False); + + XSetErrorHandler(prev_xerr_handler); + return 0; +} + +static int spnav_fd(void) +{ + if(dpy) { + return ConnectionNumber(dpy); + } + return -1; +} + +/*static int spnav_wait_event(spnav_event *event) +{ + if(dpy) { + for(;;) { + XEvent xev; + XNextEvent(dpy, &xev); + + if(spnav_x11_event(&xev, event) > 0) { + return event->type; + } + } + } + return 0; +} + +static int spnav_poll_event(spnav_event *event) +{ + if(dpy) { + if(XPending(dpy)) { + XEvent xev; + XNextEvent(dpy, &xev); + + return spnav_x11_event(&xev, event); + } + } + return 0; +}*/ + +static Bool match_events(Display *dpy, XEvent *xev, char *arg) +{ + int evtype = *(int*)arg; + + if(xev->type != ClientMessage) { + return False; + } + + if(xev->xclient.message_type == motion_event) { + return !evtype || evtype == SPNAV_EVENT_MOTION ? True : False; + } + if(xev->xclient.message_type == button_press_event || + xev->xclient.message_type == button_release_event) { + return !evtype || evtype == SPNAV_EVENT_BUTTON ? True : False; + } + return False; +} + +static int spnav_remove_events(int type) +{ + int rm_count = 0; + + if(dpy) { + XEvent xev; + + while(XCheckIfEvent(dpy, &xev, match_events, (char*)&type)) { + rm_count++; + } + return rm_count; + } + return 0; +} + +static int spnav_x11_event(const XEvent *xev, spnav_event *event) +{ + int i; + int xmsg_type; + + if(xev->type != ClientMessage) { + return 0; + } + + xmsg_type = xev->xclient.message_type; + + if(xmsg_type != motion_event && xmsg_type != button_press_event && + xmsg_type != button_release_event) { + return 0; + } + + if(xmsg_type == motion_event) { + event->type = SPNAV_EVENT_MOTION; + event->motion.data = &event->motion.x; + + for(i=0; i<6; i++) { + event->motion.data[i] = xev->xclient.data.s[i + 2]; + } + event->motion.period = xev->xclient.data.s[8]; + } else { + event->type = SPNAV_EVENT_BUTTON; + event->button.press = xmsg_type == button_press_event ? 1 : 0; + event->button.bnum = xev->xclient.data.s[2]; + } + return event->type; +} + + +static Window get_daemon_window(Display *dpy) +{ + Window win, root_win; + XTextProperty wname; + Atom type; + int fmt; + unsigned long nitems, bytes_after; + unsigned char *prop; + + root_win = DefaultRootWindow(dpy); + + XGetWindowProperty(dpy, root_win, command_event, 0, 1, False, AnyPropertyType, &type, &fmt, &nitems, &bytes_after, &prop); + if(!prop) { + return 0; + } + + win = *(Window*)prop; + XFree(prop); + + if(!XGetWMName(dpy, win, &wname) || strcmp("Magellan Window", (char*)wname.value) != 0) { + return 0; + } + + return win; +} + +static int catch_badwin(Display *dpy, XErrorEvent *err) +{ + char buf[256]; + + if(err->error_code == BadWindow) { + /* do nothing? */ + } else { + XGetErrorText(dpy, err->error_code, buf, sizeof buf); + fprintf(stderr, "Caught unexpected X error: %s\n", buf); + } + return 0; +} + +#endif /* TARGET_HOST_POSIX_X11 */ Index: progs/demos/spaceball/vmath.c =================================================================== --- progs/demos/spaceball/vmath.c (revision 837) +++ progs/demos/spaceball/vmath.c (working copy) @@ -3,14 +3,14 @@ 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); + 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; + 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); + return quat_mul(q, rq); } Index: progs/demos/spaceball/vmath.inl =================================================================== --- progs/demos/spaceball/vmath.inl (revision 837) +++ progs/demos/spaceball/vmath.inl (working copy) @@ -1,68 +1,68 @@ -/* 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 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; -} +/* 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 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; +} Index: progs/demos/spaceball/vmath.h =================================================================== --- progs/demos/spaceball/vmath.h (revision 837) +++ progs/demos/spaceball/vmath.h (working copy) @@ -1,31 +1,31 @@ -#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 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_ */ +#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 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_ */ Index: progs/demos/spaceball/spaceball.c =================================================================== --- progs/demos/spaceball/spaceball.c (revision 837) +++ progs/demos/spaceball/spaceball.c (working copy) @@ -1,173 +1,173 @@ -/* Spaceball demo - * - * Written by John Tsiombikas <nuclear@...> - * (converted from the libspnav cube example) - * - * Use the spaceball to move and rotate the colored cube. - * Pressing any button will reset the cube at its original location. - * - * Press escape or q to exit. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <math.h> -#include <GL/freeglut.h> -#include "vmath.h" - -void draw_cube(void); - -/* callbacks */ -void disp(void); -void reshape(int x, int y); -void keyb(unsigned char key, int x, int y); -void sbmot(int x, int y, int z); /* spaceball translation */ -void sbrot(int x, int y, int z); /* spaceball rotation */ -void sbbut(int bn, int state); /* spaceball button */ - -vec3_t pos = {0, 0, -6}; -quat_t rot = {0, 0, 0, 1}; - -int main(int argc, char **argv) -{ - glutInit(&argc, argv); - glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); - glutCreateWindow("spaceball demo"); - - glutDisplayFunc(disp); - glutReshapeFunc(reshape); - glutKeyboardFunc(keyb); - glutSpaceballMotionFunc(sbmot); - glutSpaceballRotateFunc(sbrot); - glutSpaceballButtonFunc(sbbut); - - glEnable(GL_CULL_FACE); - - glutMainLoop(); - return 0; -} - -void disp(void) -{ - mat4_t xform; - - quat_to_mat(xform, rot); - - glClear(GL_COLOR_BUFFER_BIT); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glTranslatef(pos.x, pos.y, pos.z); - glMultTransposeMatrixf((float*)xform); - - draw_cube(); - - glutSwapBuffers(); -} - -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(); -} - -/* 45deg fov */ -#define FOV (M_PI / 4.0) - -void reshape(int x, int y) -{ - float aspect = (float)x / (float)y; - float halfy = tan(FOV / 2.0); - float halfx = halfy * aspect; - - glViewport(0, 0, x, y); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glFrustum(-halfx, halfx, -halfy, halfy, 1.0, 1000.0); -} - -void keyb(unsigned char key, int x, int y) -{ - switch(key) { - case 'q': - case 'Q': - case 27: - exit(0); - - case ' ': - /* reset initial view */ - pos = v3_cons(0, 0, -6); - rot = quat_cons(1, 0, 0, 0); - glutPostRedisplay(); - - default: - break; - } -} - -void sbmot(int x, int y, int z) -{ - pos.x += x * 0.001; - pos.y += y * 0.001; - pos.z -= z * 0.001; - glutPostRedisplay(); -} - -void sbrot(int x, int y, int z) -{ - float axis_len = sqrt(x * x + y * y + z * z); - rot = quat_rotate(rot, axis_len * 0.001, -x / axis_len, -y / axis_len, z / axis_len); - glutPostRedisplay(); -} - -void sbbut(int bn, int state) -{ - if(state == GLUT_DOWN) { - pos = v3_cons(0, 0, -6); - rot = quat_cons(1, 0, 0, 0); - glutPostRedisplay(); - } -} +/* Spaceball demo + * + * Written by John Tsiombikas <nuclear@...> + * (converted from the libspnav cube example) + * + * Use the spaceball to move and rotate the colored cube. + * Pressing any button will reset the cube at its original location. + * + * Press escape or q to exit. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <GL/freeglut.h> +#include "vmath.h" + +void draw_cube(void); + +/* callbacks */ +void disp(void); +void reshape(int x, int y); +void keyb(unsigned char key, int x, int y); +void sbmot(int x, int y, int z); /* spaceball translation */ +void sbrot(int x, int y, int z); /* spaceball rotation */ +void sbbut(int bn, int state); /* spaceball button */ + +vec3_t pos = {0, 0, -6}; +quat_t rot = {0, 0, 0, 1}; + +int main(int argc, char **argv) +{ + glutInit(&argc, argv); + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); + glutCreateWindow("spaceball demo"); + + glutDisplayFunc(disp); + glutReshapeFunc(reshape); + glutKeyboardFunc(keyb); + glutSpaceballMotionFunc(sbmot); + glutSpaceballRotateFunc(sbrot); + glutSpaceballButtonFunc(sbbut); + + glEnable(GL_CULL_FACE); + + glutMainLoop(); + return 0; +} + +void disp(void) +{ + mat4_t xform; + + quat_to_mat(xform, rot); + + glClear(GL_COLOR_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(pos.x, pos.y, pos.z); + glMultTransposeMatrixf((float*)xform); + + draw_cube(); + + glutSwapBuffers(); +} + +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(); +} + +/* 45deg fov */ +#define FOV (M_PI / 4.0) + +void reshape(int x, int y) +{ + float aspect = (float)x / (float)y; + float halfy = tan(FOV / 2.0); + float halfx = halfy * aspect; + + glViewport(0, 0, x, y); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-halfx, halfx, -halfy, halfy, 1.0, 1000.0); +} + +void keyb(unsigned char key, int x, int y) +{ + switch(key) { + case 'q': + case 'Q': + case 27: + exit(0); + + case ' ': + /* reset initial view */ + pos = v3_cons(0, 0, -6); + rot = quat_cons(1, 0, 0, 0); + glutPostRedisplay(); + + default: + break; + } +} + +void sbmot(int x, int y, int z) +{ + pos.x += x * 0.001; + pos.y += y * 0.001; + pos.z -= z * 0.001; + glutPostRedisplay(); +} + +void sbrot(int x, int y, int z) +{ + float axis_len = sqrt(x * x + y * y + z * z); + rot = quat_rotate(rot, axis_len * 0.001, -x / axis_len, -y / axis_len, z / axis_len); + glutPostRedisplay(); +} + +void sbbut(int bn, int state) +{ + if(state == GLUT_DOWN) { + pos = v3_cons(0, 0, -6); + rot = quat_cons(1, 0, 0, 0); + glutPostRedisplay(); + } +} ------------------------------------------------------------------------------ Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july _______________________________________________ Freeglut-developer mailing list Freeglut-developer@... https://lists.sourceforge.net/lists/listinfo/freeglut-developer |
|
|
Re: Linux spaceball patchJohn,
Regarding the Windows newlines, the patch isn't going to help much. I still do my editing on a Windows box and Windows newlines are put in pretty much automatically. Let me see what I can do tonight. John F. Fay Technical Fellow Jacobs Technology TEAS Group 850-883-1294 -----Original Message----- From: John Tsiombikas [mailto:nuclear@...] Sent: Friday, November 06, 2009 12:22 PM To: freeglut-developer@... Subject: Re: [Freeglut-developer] Linux spaceball patch On Fri, Nov 06, 2009 at 07:53:09AM -0600, John F. Fay wrote: > In particular please check the line endings. I was editing some > Makefile.am and configure.ac files in Windows. Also a bunch of tab > characters need expanding to spaces; I started but ran out of time and > my editor didn't do it automatically. I've just mass converted all tabs to spaces and all newlines to UNIX newlines (I take it that's what you meant), here's the patch: -- John Tsiombikas http://nuclear.sdf-eu.org/ ------------------------------------------------------------------------------ Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july _______________________________________________ Freeglut-developer mailing list Freeglut-developer@... https://lists.sourceforge.net/lists/listinfo/freeglut-developer |
| Free embeddable forum powered by Nabble | Forum Help |