X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Funix%2Fmain.c;fp=src%2Funix%2Fmain.c;h=a936a74ed76fd03f05a812abbbb5b3c9b22ff71a;hb=92425a8479e97441a268816e701d2cee1c4c9604;hp=0000000000000000000000000000000000000000;hpb=73bea7d1e29dd28c6c0096d4ed95cd15bb76776d;p=smouse diff --git a/src/unix/main.c b/src/unix/main.c new file mode 100644 index 0000000..a936a74 --- /dev/null +++ b/src/unix/main.c @@ -0,0 +1,340 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vmath.h" +#include "device.h" + +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); +int handle_dev_event(device_event *ev); + +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}; /* that's 1 + 0i + 0j + 0k */ + +int redisplay; + +/* serial 6dof device */ +struct device *dev; + +int main(void) +{ + int xsock, devfd, maxfd; + + register_all(); + set_port("/dev/ttyS0"); + + if(!(dev = dev_init(0))) { + fprintf(stderr, "failed to initialize 6dof serial device at /dev/ttyS0\n"); + return 1; + } + if((devfd = dev->start()) == -1) { + return 1; + } + + if(!(dpy = XOpenDisplay(0))) { + fprintf(stderr, "failed to connect to the X server\n"); + return 1; + } + xsock = ConnectionNumber(dpy); + + if(create_gfx(512, 512) == -1) { + return 1; + } + + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + + maxfd = xsock > devfd ? xsock : devfd; + + for(;;) { + fd_set rdset; + + FD_ZERO(&rdset); + FD_SET(xsock, &rdset); + FD_SET(devfd, &rdset); + + while(select(maxfd + 1, &rdset, 0, 0, 0) == -1 && errno == EINTR); + + if(FD_ISSET(xsock, &rdset)) { + while(XPending(dpy)) { + XEvent xev; + XNextEvent(dpy, &xev); + + if(handle_event(&xev) != 0) { + goto end; + } + } + } + + if(FD_ISSET(devfd, &rdset)) { + device_event ev; + + while(dev->getevent(&ev)) { + handle_dev_event(&ev); + } + } + + if(redisplay) { + redraw(); + redisplay = 0; + } + } + +end: + destroy_gfx(); + XCloseDisplay(dpy); + 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; + + 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 KeyPress: + sym = XLookupKeysym((XKeyEvent*)&xev->xkey, 0); + if((sym & 0xff) == 27) { + return 1; + } + break; + + 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; +} + +#define TX(ev) ((ev)->motion.motion[0]) +#define TY(ev) ((ev)->motion.motion[1]) +#define TZ(ev) ((ev)->motion.motion[2]) +#define RX(ev) ((ev)->motion.motion[3]) +#define RY(ev) ((ev)->motion.motion[4]) +#define RZ(ev) ((ev)->motion.motion[5]) + +int handle_dev_event(device_event *ev) +{ + switch(ev->type) { + case DEV_EV_MOTION: + if(RX(ev) | RY(ev) | RZ(ev)) { + float axis_len = sqrt(RX(ev) * RX(ev) + RY(ev) * RY(ev) + RZ(ev) * RZ(ev)); + if(axis_len != 0.0) { + rot = quat_rotate(rot, axis_len * 0.001, -RX(ev) / axis_len, + -RY(ev) / axis_len, -RZ(ev) / axis_len); + } + } + + pos.x += TX(ev) * 0.001; + pos.y += TY(ev) * 0.001; + pos.z += TZ(ev) * 0.001; + redisplay = 1; + break; + + case DEV_EV_BUTTON: + if(ev->button.pressed) { + pos = v3_cons(0, 0, -6); + rot = quat_cons(1, 0, 0, 0); + redisplay = 1; + } + break; + } + + return 0; +}