/* -*- Mode: C; tab-width: 4 -*- */ /* bubble3d.c - 3D bubbles */ #if !defined( lint ) && !defined( SABER ) static const char sccsid[] = "@(#)bubble3d.c 4.11 98/06/16 xlockmore"; #endif /*- * BUBBLE3D (C) 1998 Richard W.M. Jones. * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation. * * This file is provided AS IS with no warranties of any kind. The author * shall have no liability with respect to the infringement of copyrights, * trade secrets or any patents by this file or any part thereof. In no * event will the author be liable for any lost revenue or profits or * other special, indirect and consequential damages. * * Revision History: * 16-Jun-98: Written. * * bubble.c: This code is responsible for creating and managing * bubbles over their lifetime. * The bubbles may be drawn inside out. */ #include "bubble3d.h" typedef struct bubble { GLfloat *contributions; /* List of contributions from each * nudge to each vertex. This list has * length nr_vertices * nr_nudge_axes. */ GLfloat x, y, z; /* (x,y,z) location of the bubble. */ GLfloat scale; /* Scaling factor applied to bubble. */ GLfloat y_incr, scale_incr; /* Change in y and scale each frame. */ GLfloat rotx, roty, rotz; /* Current rotation. */ GLfloat rotx_incr, roty_incr, rotz_incr; /* Amount by which we increase * rotation each step. */ GLfloat *nudge_angle; /* Current angle (radians) of each * nudge. This list has length nr_nudge_axes. */ GLfloat *nudge_angle_incr; /* Amount by which we increase each nudge * angle in each frame. */ } bubble; /* Should be taken care of already... but just in case */ #if !defined( __GNUC__ ) && !defined(__cplusplus) && !defined(c_plusplus) #undef inline #define inline /* */ #endif static inline void normalize(GLfloat v[3]) { GLfloat d = (GLfloat) sqrt((double) (v[0] * v[0] + v[1] * v[1] + v[2] * v[2])); if (d != 0) { v[0] /= d; v[1] /= d; v[2] /= d; } else { v[0] = v[1] = v[2] = 0; } } static inline GLfloat dotprod(GLfloat * v1, GLfloat * v2) { return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; } static inline GLfloat max(GLfloat a, GLfloat b) { return a > b ? a : b; } /* Create a new bubble. */ void * glb_bubble_new(GLfloat x, GLfloat y, GLfloat z, GLfloat scale, GLfloat y_incr, GLfloat scale_incr) { int i, j; /* GLfloat axes [glb_config.nr_nudge_axes][3]; */ GLfloat axes[5][3]; /* HARD CODED for SunCC */ int nr_vertices; glb_vertex *vertices = glb_sphere_get_vertices(&nr_vertices); bubble *b = (bubble *) malloc(sizeof *b); if (b == 0) return 0; b->contributions = (GLfloat *) malloc(sizeof (GLfloat) * nr_vertices * glb_config.nr_nudge_axes); if (b->contributions == 0) { free(b); return 0; } b->nudge_angle = (GLfloat *) malloc(sizeof (GLfloat) * glb_config.nr_nudge_axes); if (b->nudge_angle == 0) { free(b->contributions); free(b); return 0; } b->nudge_angle_incr = (GLfloat *) malloc(sizeof (GLfloat) * glb_config.nr_nudge_axes); if (b->nudge_angle_incr == 0) { free(b->nudge_angle); free(b->contributions); free(b); return 0; } /* Initialize primitive elements. */ b->x = x; b->y = y; b->z = z; b->scale = scale; b->y_incr = y_incr; b->scale_incr = scale_incr; b->rotx = b->roty = b->rotz = 0; b->rotx_incr = glb_drand() * glb_config.rotation_factor * 2 - glb_config.rotation_factor; b->roty_incr = glb_drand() * glb_config.rotation_factor * 2 - glb_config.rotation_factor; b->rotz_incr = glb_drand() * glb_config.rotation_factor * 2 - glb_config.rotation_factor; /* Initialize the nudge angle arrays. */ for (i = 0; i < glb_config.nr_nudge_axes; ++i) { b->nudge_angle[i] = 0; b->nudge_angle_incr[i] = glb_drand() * glb_config.nudge_angle_factor; } /* Choose some random nudge axes. */ for (i = 0; i < glb_config.nr_nudge_axes; ++i) { axes[i][0] = glb_drand() * 2 - 1; axes[i][1] = glb_drand() * 2 - 1; axes[i][2] = glb_drand() * 2 - 1; normalize(axes[i]); } /* Calculate the contribution that each nudge axis has on each vertex. */ for (i = 0; i < nr_vertices; ++i) for (j = 0; j < glb_config.nr_nudge_axes; ++j) b->contributions[i * glb_config.nr_nudge_axes + j] = max(0.0, dotprod(vertices[i], axes[j])); return (void *) b; } /* Delete a bubble and free up all memory. */ void glb_bubble_delete(void *bb) { bubble *b = (bubble *) bb; if (b != NULL) { if (b->nudge_angle_incr) { free(b->nudge_angle_incr); } if (b->nudge_angle) { free(b->nudge_angle); } if (b->contributions) { free(b->contributions); } free(b); b = (bubble *) NULL; } } /* Rotate and wobble a bubble by a single step. */ void glb_bubble_step(void *bb) { int i; bubble *b = (bubble *) bb; /* Update the rotation. */ b->rotx += b->rotx_incr; b->roty += b->roty_incr; b->rotz += b->rotz_incr; /* Update the nudge angles. */ for (i = 0; i < glb_config.nr_nudge_axes; ++i) b->nudge_angle[i] += b->nudge_angle_incr[i]; /* Move it upwards & outwards. */ b->y += b->y_incr; b->scale += b->scale_incr; } /* Draw a bubble. */ void glb_bubble_draw(void *bb) { int i, j; bubble *b = (bubble *) bb; int nr_vertices; glb_vertex *vertices = glb_sphere_get_vertices(&nr_vertices); int nr_triangles; glb_triangle *triangles = glb_sphere_get_triangles(&nr_triangles); glb_vertex *new_vertices; new_vertices = (glb_vertex *) malloc(sizeof (glb_vertex) * nr_vertices); /* Calculate the vertices of this bubble, factoring in each nudge axis. */ for (i = 0; i < nr_vertices; ++i) { GLfloat s = 0; for (j = 0; j < glb_config.nr_nudge_axes; ++j) s += ((GLfloat) cos((double) (b->nudge_angle[j])) * glb_config.nudge_factor - glb_config.nudge_factor / 2) * b->contributions[i * glb_config.nr_nudge_axes + j]; new_vertices[i][0] = vertices[i][0] * (s + 1); new_vertices[i][1] = vertices[i][1] * (s + 1); new_vertices[i][2] = vertices[i][2] * (s + 1); } glPushMatrix(); /* Apply translation, rotation and scalings. */ glTranslatef(b->x, b->y, b->z); glRotatef(b->rotx, 1, 0, 0); glRotatef(b->roty, 0, 1, 0); glRotatef(b->rotz, 0, 0, 1); glScalef(b->scale, b->scale, b->scale); /* Draw the bubble. */ glBegin(GL_TRIANGLES); for (i = 0; i < nr_triangles; ++i) { glNormal3fv(new_vertices[triangles[i][0]]); glVertex3fv(new_vertices[triangles[i][0]]); glNormal3fv(new_vertices[triangles[i][1]]); glVertex3fv(new_vertices[triangles[i][1]]); glNormal3fv(new_vertices[triangles[i][2]]); glVertex3fv(new_vertices[triangles[i][2]]); } glEnd(); glPopMatrix(); free(new_vertices); } /* Return y value. */ GLfloat glb_bubble_get_y(void *bb) { bubble *b = (bubble *) bb; return b->y; }