X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fglx%2Fstonerview-view.c;fp=hacks%2Fglx%2Fstonerview-view.c;h=a72478123ca94141925b6f61379603dfb3ab3f6c;hb=ebc241816cc8e3eec7270a594bb1a607df32bcd6;hp=0000000000000000000000000000000000000000;hpb=de041722414a2e31c1c04caa10aaec9d6952e9b4;p=xscreensaver diff --git a/hacks/glx/stonerview-view.c b/hacks/glx/stonerview-view.c new file mode 100644 index 00000000..a7247812 --- /dev/null +++ b/hacks/glx/stonerview-view.c @@ -0,0 +1,482 @@ +/* StonerView: An eccentric visual toy. + Copyright 1998-2001 by Andrew Plotkin (erkyrath@eblong.com) + http://www.eblong.com/zarf/stonerview.html + + Permission to use, copy, modify, distribute, and sell this software and its + documentation for any purpose is hereby granted without fee, provided that + the above copyright notice appear in all copies and that both that + copyright notice and this permission notice appear in supporting + documentation. No representations are made about the suitability of this + software for any purpose. It is provided "as is" without express or + implied warranty. +*/ + +/* Ported away from GLUT (so that it can do `-root' and work with xscreensaver) + by Jamie Zawinski , 22-Jan-2001. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "vroot.h" /* handle virtual root windows --- very important */ + +#include "version.h" /* get the xscreensaver package's version number */ +#include "yarandom.h" /* use xscreensaver's RNG */ + +#include "stonerview-osc.h" +#include "stonerview-move.h" + +static char *progclass = "StonerView"; +static char *progname = 0; + +#define FRAMERATE (50) /* milliseconds per frame */ + +static GLfloat view_rotx = -45.0, view_roty = 0.0, view_rotz = 0.0; +static GLfloat view_scale = 4.0; +/* static GLint prevtime = 0; / * for timing */ + +static void setup_window(void); + +void win_draw(void); +static void win_reshape(int width, int height); +/* static void win_visible(int vis); */ +/* static void win_idle(void); */ +static void handle_events(void); + +static Display *dpy; +static Window window; +static int wireframe = 0; + +static Atom XA_WM_PROTOCOLS, XA_WM_DELETE_WINDOW; + + +static void +usage (void) +{ + fprintf (stderr, + "usage: %s [--geom =WxH+X+Y | --fullscreen | --root] [--wire]\n", + progname); + exit (1); +} + + +/* mostly lifted from xscreensaver/utils/visual.c... */ +static int +visual_depth (Display *dpy, int screen, Visual *visual) +{ + XVisualInfo vi_in, *vi_out; + int out_count, d; + vi_in.screen = screen; + vi_in.visualid = XVisualIDFromVisual (visual); + vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask, + &vi_in, &out_count); + if (! vi_out) abort (); + d = vi_out [0].depth; + XFree ((char *) vi_out); + return d; +} + + +/* mostly lifted from xscreensaver/hacks/screenhack.c... */ +static char *make_title_string (void) +{ + char version[255]; + char *v = (char *) strdup(strchr(screensaver_id, ' ')); + char *s1, *s2, *s3, *s4; + s1 = (char *) strchr(v, ' '); s1++; + s2 = (char *) strchr(s1, ' '); + s3 = (char *) strchr(v, '('); s3++; + s4 = (char *) strchr(s3, ')'); + *s2 = 0; + *s4 = 0; + sprintf (version, "%s: from the XScreenSaver %s distribution (%s.)", + progclass, s1, s3); + return (strdup(version)); +} + + +int init_view(int *argc, char *argv[]) +{ + int ix; + int fullscreen = 0; + int on_root = 0; + + int undef = -65536; + int x = undef, y = undef; + int w = 500, h = 500; + char *dpystr = (char *) getenv ("DISPLAY"); + char *geom = 0; + int screen; + Visual *visual; + XWindowAttributes xgwa; + XSetWindowAttributes xswa; + unsigned long xswa_mask = 0; + XSizeHints hints; + GLXContext glx_context = 0; + + memset (&hints, 0, sizeof(hints)); + + for (ix=1; ix<*argc; ix++) + { + if (argv[ix][0] == '-' && argv[ix][1] == '-') + argv[ix]++; + if (!strcmp(argv[ix], "-geometry") || + !strcmp(argv[ix], "-geom")) + { + if (on_root || fullscreen) usage(); + geom = argv[++ix]; + } + else if (!strcmp(argv[ix], "-display") || + !strcmp(argv[ix], "-disp") || + !strcmp(argv[ix], "-dpy") || + !strcmp(argv[ix], "-d")) + dpystr = argv[++ix]; + else if (!strcmp(argv[ix], "-root")) + { + if (geom || fullscreen) usage(); + on_root = 1; + } + else if (!strcmp(argv[ix], "-fullscreen") || + !strcmp(argv[ix], "-full")) + { + if (on_root || geom) usage(); + fullscreen = 1; + } + else if (!strcmp(argv[ix], "-wireframe") || + !strcmp(argv[ix], "-wire")) + { + wireframe = 1; + } + else + { + usage(); + } + } + + dpy = XOpenDisplay (dpystr); + if (!dpy) exit (1); + + screen = DefaultScreen (dpy); + + XA_WM_PROTOCOLS = XInternAtom (dpy, "WM_PROTOCOLS", False); + XA_WM_DELETE_WINDOW = XInternAtom (dpy, "WM_DELETE_WINDOW", False); + + if (on_root) + { + window = RootWindow (dpy, screen); + XGetWindowAttributes (dpy, window, &xgwa); + visual = xgwa.visual; + w = xgwa.width; + h = xgwa.height; + } + else + { + int ww = WidthOfScreen (DefaultScreenOfDisplay (dpy)); + int hh = HeightOfScreen (DefaultScreenOfDisplay (dpy)); + + if (fullscreen) + { + w = ww; + h = hh; + } + else if (geom) + { + /* Since we're not linking against Xt or GLUT, we get to parse + the `-geometry' argument ourselves. YAY. + */ + char c; + if (4 == sscanf (geom, "=%dx%d+%d+%d%c", &w, &h, &x, &y, &c)) + ; + else if (4 == sscanf (geom, "=%dx%d-%d+%d%c", &w, &h, &x, &y, &c)) + x = ww-w-x; + else if (4 == sscanf (geom, "=%dx%d+%d-%d%c", &w, &h, &x, &y, &c)) + y = hh-h-y; + else if (4 == sscanf (geom, "=%dx%d-%d-%d%c", &w, &h, &x, &y, &c)) + x = ww-w-x, y = hh-h-y; + else if (2 == sscanf (geom, "=%dx%d%c", &w, &h, &c)) + ; + else if (2 == sscanf (geom, "+%d+%d%c", &x, &y, &c)) + ; + else if (2 == sscanf (geom, "-%d+%d%c", &x, &y, &c)) + x = ww-w-x; + else if (2 == sscanf (geom, "+%d-%d%c", &x, &y, &c)) + y = hh-h-y; + else if (2 == sscanf (geom, "-%d-%d%c", &x, &y, &c)) + x = ww-w-x, y = hh-h-y; + else + { + fprintf (stderr, "%s: unparsable geometry: %s\n", + progname, geom); + exit (1); + } + + hints.flags = USSize; + hints.width = w; + hints.height = h; + if (x != undef && y != undef) + { + hints.flags |= USPosition; + hints.x = x; + hints.y = y; + } + } + + /* Pick a good GL visual */ + { +# define R GLX_RED_SIZE +# define G GLX_GREEN_SIZE +# define B GLX_BLUE_SIZE +# define D GLX_DEPTH_SIZE +# define I GLX_BUFFER_SIZE +# define DB GLX_DOUBLEBUFFER + + int attrs[][20] = { + { GLX_RGBA, R, 8, G, 8, B, 8, D, 8, DB, 0 }, /* rgb double */ + { GLX_RGBA, R, 4, G, 4, B, 4, D, 4, DB, 0 }, + { GLX_RGBA, R, 2, G, 2, B, 2, D, 2, DB, 0 }, + { GLX_RGBA, R, 8, G, 8, B, 8, D, 8, 0 }, /* rgb single */ + { GLX_RGBA, R, 4, G, 4, B, 4, D, 4, 0 }, + { GLX_RGBA, R, 2, G, 2, B, 2, D, 2, 0 }, + { I, 8, D, 8, DB, 0 }, /* cmap double */ + { I, 4, D, 4, DB, 0 }, + { I, 8, D, 8, 0 }, /* cmap single */ + { I, 4, D, 4, 0 }, + { GLX_RGBA, R, 1, G, 1, B, 1, D, 1, 0 } /* monochrome */ + }; + + int i; + for (i = 0; i < sizeof(attrs)/sizeof(*attrs); i++) + { + XVisualInfo *vi = glXChooseVisual (dpy, screen, attrs[i]); + if (vi) + { + visual = vi->visual; + XFree (vi); + break; + } + } + if (!visual) + { + fprintf (stderr, "%s: unable to find a GL visual\n", progname); + exit (1); + } + } + + + if (x == undef) x = 0; + if (y == undef) y = 0; + + xswa_mask = (CWEventMask | CWColormap | + CWBackPixel | CWBackingPixel | CWBorderPixel ); + xswa.colormap = XCreateColormap (dpy, RootWindow (dpy, screen), + visual, AllocNone); + xswa.background_pixel = BlackPixel (dpy, screen); + xswa.backing_pixel = xswa.background_pixel; + xswa.border_pixel = xswa.background_pixel; + xswa.event_mask = (KeyPressMask | ButtonPressMask | StructureNotifyMask); + + window = XCreateWindow (dpy, RootWindow (dpy, screen), + x, y, w, h, 0, + visual_depth (dpy, screen, visual), + InputOutput, visual, + xswa_mask, &xswa); + + { + XWMHints wmhints; + + XTextProperty tp1, tp2; + char *v = make_title_string (); + XStringListToTextProperty (&v, 1, &tp1); + XStringListToTextProperty (&progclass, 1, &tp2); + wmhints.flags = InputHint; + wmhints.input = True; + XSetWMProperties (dpy, window, &tp1, &tp2, argv, *argc, &hints, + &wmhints, 0); + free (v); + } + + XChangeProperty (dpy, window, XA_WM_PROTOCOLS, XA_ATOM, 32, + PropModeReplace, + (unsigned char *) &XA_WM_DELETE_WINDOW, 1); + + XMapRaised (dpy, window); + XSync (dpy, False); + } + + + /* Now hook up to GLX */ + { + XVisualInfo vi_in, *vi_out; + int out_count; + vi_in.screen = screen; + vi_in.visualid = XVisualIDFromVisual (visual); + vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask, + &vi_in, &out_count); + if (! vi_out) abort (); + + glx_context = glXCreateContext (dpy, vi_out, 0, GL_TRUE); + XFree((char *) vi_out); + + if (!glx_context) + { + fprintf(stderr, "%s: couldn't create GL context for root window.\n", + progname); + exit(1); + } + + glXMakeCurrent (dpy, window, glx_context); + } + + setup_window(); + win_reshape(w, h); + + return 1; +} + +static void setup_window() +{ + glEnable(GL_CULL_FACE); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_DEPTH_TEST); + + glEnable(GL_NORMALIZE); +} + +/* callback: draw everything */ +void win_draw(void) +{ + int ix; + static GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 }; + + glDrawBuffer(GL_BACK); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glPushMatrix(); + glScalef(view_scale, view_scale, view_scale); + glRotatef(view_rotx, 1.0, 0.0, 0.0); + glRotatef(view_roty, 0.0, 1.0, 0.0); + glRotatef(view_rotz, 0.0, 0.0, 1.0); + + for (ix=0; ixcol)); + glShadeModel(GL_FLAT); + glBegin(wireframe ? GL_LINE_LOOP : GL_QUADS); + + glNormal3f(0.0, 0.0, 1.0); + glVertex3f(el->pos[0] - el->vervec[0], el->pos[1] - el->vervec[1], + el->pos[2]); + glVertex3f(el->pos[0] + el->vervec[1], el->pos[1] - el->vervec[0], + el->pos[2]); + glVertex3f(el->pos[0] + el->vervec[0], el->pos[1] + el->vervec[1], + el->pos[2]); + glVertex3f(el->pos[0] - el->vervec[1], el->pos[1] + el->vervec[0], + el->pos[2]); + + glEnd(); + + glPopMatrix(); + } + + glPopMatrix(); + + glFinish(); + glXSwapBuffers(dpy, window); + + handle_events(); +} + + +/* callback: new window size or exposure */ +static void win_reshape(int width, int height) +{ + GLfloat h = (GLfloat) height / (GLfloat) width; + + glViewport(0, 0, (GLint) width, (GLint) height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0.0, 0.0, -40.0); +} + + +static void +handle_events (void) +{ + while (XPending (dpy)) + { + XEvent E; + XEvent *event = &E; + XNextEvent (dpy, event); + switch (event->xany.type) + { + case ConfigureNotify: + { + XWindowAttributes xgwa; + XGetWindowAttributes (dpy, window, &xgwa); + win_reshape (xgwa.width, xgwa.height); + break; + } + case KeyPress: + { + KeySym keysym; + char c = 0; + XLookupString (&event->xkey, &c, 1, &keysym, 0); + if (c == 'q' || + c == 'Q' || + c == 3 || /* ^C */ + c == 27) /* ESC */ + exit (0); + else if (! (keysym >= XK_Shift_L && keysym <= XK_Hyper_R)) + XBell (dpy, 0); /* beep for non-chord keys */ + } + break; + case ButtonPress: + XBell (dpy, 0); + break; + case ClientMessage: + { + if (event->xclient.message_type != XA_WM_PROTOCOLS) + { + char *s = XGetAtomName(dpy, event->xclient.message_type); + if (!s) s = "(null)"; + fprintf (stderr, "%s: unknown ClientMessage %s received!\n", + progname, s); + } + else if (event->xclient.data.l[0] != XA_WM_DELETE_WINDOW) + { + char *s1 = XGetAtomName(dpy, event->xclient.message_type); + char *s2 = XGetAtomName(dpy, event->xclient.data.l[0]); + if (!s1) s1 = "(null)"; + if (!s2) s2 = "(null)"; + fprintf (stderr,"%s: unknown ClientMessage %s[%s] received!\n", + progname, s1, s2); + } + else + { + exit (0); + } + } + break; + } + } +}