X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=hacks%2Fglx%2Fbouncingcow.c;h=6f9b45d7032a1108f7f204bc7009c377c6f5979e;hb=HEAD;hp=e96bc647982d449c6a72b5b0493cf3db607c450d;hpb=49f5b54f312fe4ac2e9bc47581a72451bd0e8439;p=xscreensaver diff --git a/hacks/glx/bouncingcow.c b/hacks/glx/bouncingcow.c index e96bc647..29baa46f 100644 --- a/hacks/glx/bouncingcow.c +++ b/hacks/glx/bouncingcow.c @@ -1,4 +1,4 @@ -/* bouncingcow, Copyright (c) 2003-2006 Jamie Zawinski +/* bouncingcow, Copyright (c) 2003-2019 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -16,16 +16,10 @@ "*showFPS: False \n" \ "*wireframe: False \n" \ -/* #define DEBUG */ - - -# define refresh_cow 0 # define release_cow 0 #define DEF_SPEED "1.0" #define DEF_TEXTURE "(none)" - -#undef countof -#define countof(x) (sizeof((x))/sizeof((*x))) +#define DEF_MATHEMATICAL "False" #undef BELLRAND #define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3) @@ -35,7 +29,7 @@ #include "xlockmore.h" #include "rotator.h" #include "gltrackball.h" -#include "xpm-ximage.h" +#include "ximage-loader.h" #include #ifdef USE_GL /* whole file */ @@ -72,6 +66,8 @@ typedef struct { GLuint *dlists; GLuint texture; + enum { BOUNCE, INFLATE, DEFLATE } mode; + GLfloat ratio; int nfloaters; floater *floaters; @@ -82,16 +78,20 @@ static cow_configuration *bps = NULL; static GLfloat speed; static const char *do_texture; +static Bool mathematical; static XrmOptionDescRec opts[] = { { "-speed", ".speed", XrmoptionSepArg, 0 }, {"-texture", ".texture", XrmoptionSepArg, 0 }, {"+texture", ".texture", XrmoptionNoArg, "(none)" }, + {"-mathematical", ".mathematical", XrmoptionNoArg, "True" }, + {"+mathematical", ".mathematical", XrmoptionNoArg, "False" }, }; static argtype vars[] = { {&speed, "speed", "Speed", DEF_SPEED, t_Float}, {&do_texture, "texture", "Texture", DEF_TEXTURE, t_String}, + {&mathematical,"mathematical","Mathematical",DEF_MATHEMATICAL,t_Bool}, }; ENTRYPOINT ModeSpecOpt cow_opts = {countof(opts), opts, countof(vars), vars, NULL}; @@ -159,8 +159,15 @@ ENTRYPOINT void reshape_cow (ModeInfo *mi, int width, int height) { GLfloat h = (GLfloat) height / (GLfloat) width; + int y = 0; + + if (width > height * 5) { /* tiny window: show middle */ + height = width * 9/16; + y = -height/2; + h = height / (GLfloat) width; + } - glViewport (0, 0, (GLint) width, (GLint) height); + glViewport (0, y, (GLint) width, (GLint) height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -181,37 +188,10 @@ cow_handle_event (ModeInfo *mi, XEvent *event) { cow_configuration *bp = &bps[MI_SCREEN(mi)]; - if (event->xany.type == ButtonPress && - event->xbutton.button == Button1) - { - bp->button_down_p = True; - gltrackball_start (bp->trackball, - event->xbutton.x, event->xbutton.y, - MI_WIDTH (mi), MI_HEIGHT (mi)); - return True; - } - else if (event->xany.type == ButtonRelease && - event->xbutton.button == Button1) - { - bp->button_down_p = False; - return True; - } - else if (event->xany.type == ButtonPress && - (event->xbutton.button == Button4 || - event->xbutton.button == Button5)) - { - gltrackball_mousewheel (bp->trackball, event->xbutton.button, 10, - !event->xbutton.state); - return True; - } - else if (event->xany.type == MotionNotify && - bp->button_down_p) - { - gltrackball_track (bp->trackball, - event->xmotion.x, event->xmotion.y, - MI_WIDTH (mi), MI_HEIGHT (mi)); - return True; - } + if (gltrackball_event_handler (event, bp->trackball, + MI_WIDTH (mi), MI_HEIGHT (mi), + &bp->button_down_p)) + return True; return False; } @@ -220,109 +200,60 @@ cow_handle_event (ModeInfo *mi, XEvent *event) /* Textures */ -static Bool +static void load_texture (ModeInfo *mi, const char *filename) { + cow_configuration *bp = &bps[MI_SCREEN(mi)]; Display *dpy = mi->dpy; Visual *visual = mi->xgwa.visual; - Colormap cmap = mi->xgwa.colormap; char buf[1024]; XImage *image; + bp->texture = 0; if (MI_IS_WIREFRAME(mi)) - return False; + return; if (!filename || !*filename || !strcasecmp (filename, "(none)")) { glDisable (GL_TEXTURE_2D); - return False; + return; } - image = xpm_file_to_ximage (dpy, visual, cmap, filename); + image = file_to_ximage (dpy, visual, filename); + if (!image) return; clear_gl_error(); + glGenTextures (1, &bp->texture); + glBindTexture (GL_TEXTURE_2D, bp->texture); glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, image->width, image->height, 0, - GL_RGBA, - /* GL_UNSIGNED_BYTE, */ - GL_UNSIGNED_INT_8_8_8_8_REV, - image->data); + GL_RGBA, GL_UNSIGNED_BYTE, image->data); sprintf (buf, "texture: %.100s (%dx%d)", filename, image->width, image->height); check_gl_error(buf); glPixelStorei (GL_UNPACK_ALIGNMENT, 4); glPixelStorei (GL_UNPACK_ROW_LENGTH, image->width); - glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - glEnable(GL_TEXTURE_GEN_S); - glEnable(GL_TEXTURE_GEN_T); - glEnable(GL_TEXTURE_2D); - return True; } -ENTRYPOINT void -init_cow (ModeInfo *mi) +static void +render_cow (ModeInfo *mi, GLfloat ratio) { - cow_configuration *bp; + cow_configuration *bp = &bps[MI_SCREEN(mi)]; int wire = MI_IS_WIREFRAME(mi); int i; - - if (!bps) { - bps = (cow_configuration *) - calloc (MI_NUM_SCREENS(mi), sizeof (cow_configuration)); - if (!bps) { - fprintf(stderr, "%s: out of memory\n", progname); - exit(1); - } - - bp = &bps[MI_SCREEN(mi)]; - } - - bp = &bps[MI_SCREEN(mi)]; - - bp->glx_context = init_GL(mi); - - reshape_cow (mi, MI_WIDTH(mi), MI_HEIGHT(mi)); - - glShadeModel(GL_SMOOTH); - - glEnable(GL_DEPTH_TEST); - glEnable(GL_NORMALIZE); - glEnable(GL_CULL_FACE); - - if (!wire) + if (! bp->dlists) + bp->dlists = (GLuint *) calloc (countof(all_objs)+1, sizeof(GLuint)); + for (i = 0; i < countof(all_objs); i++) { - GLfloat pos[4] = {0.4, 0.2, 0.4, 0.0}; -/* GLfloat amb[4] = {0.0, 0.0, 0.0, 1.0};*/ - GLfloat amb[4] = {0.2, 0.2, 0.2, 1.0}; - GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0}; - GLfloat spc[4] = {1.0, 1.0, 1.0, 1.0}; - - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - - glLightfv(GL_LIGHT0, GL_POSITION, pos); - glLightfv(GL_LIGHT0, GL_AMBIENT, amb); - glLightfv(GL_LIGHT0, GL_DIFFUSE, dif); - glLightfv(GL_LIGHT0, GL_SPECULAR, spc); + if (bp->dlists[i]) + glDeleteLists (bp->dlists[i], 1); + bp->dlists[i] = glGenLists (1); } - bp->trackball = gltrackball_init (); - - bp->dlists = (GLuint *) calloc (countof(all_objs)+1, sizeof(GLuint)); - for (i = 0; i < countof(all_objs); i++) - bp->dlists[i] = glGenLists (1); - for (i = 0; i < countof(all_objs); i++) { GLfloat black[4] = {0, 0, 0, 1}; @@ -330,40 +261,39 @@ init_cow (ModeInfo *mi) glNewList (bp->dlists[i], GL_COMPILE); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glMatrixMode(GL_TEXTURE); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - - glBindTexture (GL_TEXTURE_2D, 0); + glDisable (GL_TEXTURE_2D); if (i == HIDE) { GLfloat color[4] = {0.63, 0.43, 0.36, 1.00}; - - if (load_texture (mi, do_texture)) + if (bp->texture) { - glBindTexture (GL_TEXTURE_2D, bp->texture); - glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); - glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - /* approximately line it up with ../images/earth.xpm */ - glMatrixMode(GL_TEXTURE); - glTranslatef(0.45, 0.58, 0); - glScalef(0.08, 0.16, 1); - glRotatef(-5, 0, 0, 1); - glMatrixMode(GL_MODELVIEW); - /* if we have a texture, make the base color be white. */ color[0] = color[1] = color[2] = 1.0; - } + glTexGeni (GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); + glTexGeni (GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); + glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); + glEnable(GL_TEXTURE_2D); + + /* approximately line it up with ../images/earth.png */ + glMatrixMode (GL_TEXTURE); + glLoadIdentity(); + glTranslatef (0.45, 0.58, 0); + glScalef (0.08, 0.16, 1); + glRotatef (-5, 0, 0, 1); + glMatrixMode (GL_MODELVIEW); + } glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, black); - glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 128); - } + glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 128); + } else if (i == TAIL) { GLfloat color[4] = {0.63, 0.43, 0.36, 1.00}; @@ -406,16 +336,121 @@ init_cow (ModeInfo *mi) glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shiny); } - renderList (gll, wire); + if (ratio == 0) + renderList (gll, wire); + else + { + /* Transition between a physics cow (cow-shaped) and a + mathematical cow (spherical). + */ + struct gllist *gll2 = (struct gllist *) malloc (sizeof(*gll2)); + GLfloat *p = (GLfloat *) malloc (gll->points * 6 * sizeof(*p)); + GLfloat scale2 = 0.5 + (0.5 * (1-ratio)); + const GLfloat *pin = (GLfloat *) gll->data; + GLfloat *pout = p; + int j; + GLfloat scale = 10.46; + + memcpy (gll2, gll, sizeof(*gll2)); + gll2->next = 0; + gll2->data = p; + + for (j = 0; j < gll2->points; j++) + { + const GLfloat *ppi; + GLfloat *ppo, d; + int k; + switch (gll2->format) { + case GL_N3F_V3F: + + /* Verts transition from cow-shaped to the surface of + the enclosing sphere. */ + ppi = &pin[3]; + ppo = &pout[3]; + d = sqrt (ppi[0]*ppi[0] + ppi[1]*ppi[1] + ppi[2]*ppi[2]); + for (k = 0; k < 3; k++) + { + GLfloat min = ppi[k]; + GLfloat max = ppi[k] / d * scale; + ppo[k] = (min + ratio * (max - min)) * scale2; + } + + /* Normals are the ratio between original normals and + the radial coordinates. */ + ppi = &pin[0]; + ppo = &pout[0]; + for (k = 0; k < 3; k++) + { + GLfloat min = ppi[k]; + GLfloat max = ppi[k] / d; + ppo[k] = (min + ratio * (max - min)); + } + + pin += 6; + pout += 6; + break; + default: abort(); break; /* write me */ + } + } - glMatrixMode(GL_TEXTURE); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); + renderList (gll2, wire); + free (gll2); + free (p); + } glEndList (); } +} + + +ENTRYPOINT void +init_cow (ModeInfo *mi) +{ + cow_configuration *bp; + int wire = MI_IS_WIREFRAME(mi); + int i; + + MI_INIT (mi, bps); + + bp = &bps[MI_SCREEN(mi)]; + + bp->glx_context = init_GL(mi); + + reshape_cow (mi, MI_WIDTH(mi), MI_HEIGHT(mi)); + + glShadeModel(GL_SMOOTH); + + glEnable(GL_DEPTH_TEST); + glEnable(GL_NORMALIZE); + glEnable(GL_CULL_FACE); + + if (!wire) + { + GLfloat pos[4] = {0.4, 0.2, 0.4, 0.0}; +/* GLfloat amb[4] = {0.0, 0.0, 0.0, 1.0};*/ + GLfloat amb[4] = {0.2, 0.2, 0.2, 1.0}; + GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0}; + GLfloat spc[4] = {1.0, 1.0, 1.0, 1.0}; + + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + + glLightfv(GL_LIGHT0, GL_POSITION, pos); + glLightfv(GL_LIGHT0, GL_AMBIENT, amb); + glLightfv(GL_LIGHT0, GL_DIFFUSE, dif); + glLightfv(GL_LIGHT0, GL_SPECULAR, spc); + } + + bp->trackball = gltrackball_init (False); + load_texture (mi, do_texture); + + bp->ratio = 0; + render_cow (mi, bp->ratio); + + bp->mode = BOUNCE; bp->nfloaters = MI_COUNT (mi); bp->floaters = (floater *) calloc (bp->nfloaters, sizeof (floater)); @@ -457,6 +492,8 @@ draw_floater (ModeInfo *mi, floater *f) glPushMatrix(); glTranslatef (f->x, f->y, f->z); + gltrackball_rotate (bp->trackball); + glRotatef (y * 360, 0.0, 1.0, 0.0); if (f->spinner_p) { @@ -505,17 +542,57 @@ draw_cow (ModeInfo *mi) if (!bp->glx_context) return; - glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context)); + glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *bp->glx_context); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix (); - gltrackball_rotate (bp->trackball); + + { + GLfloat s = (MI_WIDTH(mi) < MI_HEIGHT(mi) + ? (MI_WIDTH(mi) / (GLfloat) MI_HEIGHT(mi)) + : 1); + glRotatef(current_device_rotation(), 0, 0, 1); + glScalef (s, s, s); + } glScalef (0.5, 0.5, 0.5); mi->polygon_count = 0; + if (mathematical) + { + switch (bp->mode) { + case BOUNCE: + if (bp->ratio == 0 && !(random() % 400)) + bp->mode = INFLATE; + else if (bp->ratio > 0 && !(random() % 2000)) + bp->mode = DEFLATE; + break; + case INFLATE: + bp->ratio += 0.01; + if (bp->ratio >= 1) + { + bp->ratio = 1; + bp->mode = BOUNCE; + } + break; + case DEFLATE: + bp->ratio -= 0.01; + if (bp->ratio <= 0) + { + bp->ratio = 0; + bp->mode = BOUNCE; + } + break; + default: + abort(); + } + + if (bp->ratio > 0) + render_cow (mi, bp->ratio); + } + # if 0 { floater F; @@ -547,6 +624,25 @@ draw_cow (ModeInfo *mi) glXSwapBuffers(dpy, window); } + +ENTRYPOINT void +free_cow (ModeInfo *mi) +{ + cow_configuration *bp = &bps[MI_SCREEN(mi)]; + int i; + if (!bp->glx_context) return; + glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *bp->glx_context); + if (bp->floaters) { + for (i = 0; i < bp->nfloaters; i++) + free_rotator (bp->floaters[i].rot); + free (bp->floaters); + } + for (i = 0; i < countof(all_objs); i++) + if (glIsList(bp->dlists[i])) glDeleteLists(bp->dlists[i], 1); + if (bp->trackball) gltrackball_free (bp->trackball); + if (bp->dlists) free (bp->dlists); +} + XSCREENSAVER_MODULE_2 ("BouncingCow", bouncingcow, cow) #endif /* USE_GL */