summaryrefslogtreecommitdiffstats
path: root/hacks/glx/glcells.c
diff options
context:
space:
mode:
authorSimon Rettberg2024-09-06 14:42:37 +0200
committerSimon Rettberg2024-09-06 14:42:37 +0200
commitbadef32037f52f79abc1f1440b786cd71afdf270 (patch)
tree412b792d4cab4a7a110db82fcf74fe8a1ac55ec1 /hacks/glx/glcells.c
parentDelete pre-6.00 files (diff)
downloadxscreensaver-master.tar.gz
xscreensaver-master.tar.xz
xscreensaver-master.zip
Diffstat (limited to 'hacks/glx/glcells.c')
-rw-r--r--hacks/glx/glcells.c1381
1 files changed, 0 insertions, 1381 deletions
diff --git a/hacks/glx/glcells.c b/hacks/glx/glcells.c
deleted file mode 100644
index e46aeed..0000000
--- a/hacks/glx/glcells.c
+++ /dev/null
@@ -1,1381 +0,0 @@
-/* -*- Mode: C; tab-width: 2 -*- */
-/* glcells --- Cells growing on your screen */
-
-/*-
- * Cells growing on your screen
- *
- * Copyright (c) 2007 by Matthias Toussaint
- *
- * 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.
- *
- * 2007: Written by Matthias Toussaint
- * 0.1 Initial version
- * 0.2 Bugfixes (threading) and code cleanup by Jamie Zawinski
- * Window scaling bug + performance bug in tick()
- */
-
-#include <sys/time.h> /* gettimeofday */
-
-#include "xlockmore.h"
-#include <math.h>
-
-/**********************************
- DEFINES
- **********************************/
-
-#define INDEX_OFFSET 100000
-#define NUM_CELL_SHAPES 10
-
-#define release_glcells 0
-#define glcells_handle_event xlockmore_no_events
-
-#define DEF_DELAY "20000"
-#define DEF_MAXCELLS "800"
-#define DEF_RADIUS "40"
-#define DEF_SEEDS "1"
-#define DEF_QUALITY "3"
-#define DEF_KEEPOLD "False"
-#define DEF_MINFOOD "5"
-#define DEF_MAXFOOD "20"
-#define DEF_DIVIDEAGE "20"
-#define DEF_MINDIST "1.4"
-#define DEF_PAUSE "50"
-
-#define DEFAULTS "*delay: 30000 \n" \
- "*showFPS: False \n" \
- "*wireframe: False \n" \
- "*suppressRotationAnimation: True\n" \
-
-#ifndef HAVE_JWZGLES /* glDrawElements unimplemented... */
-# define USE_VERTEX_ARRAY
-#endif
-
-#define TEX_SIZE 64
-
-/**********************************
- TYPEDEFS
- **********************************/
-
-typedef struct /* a 3-D vector */
-{
- double x, y, z; /* 3-D coordinates (we don't need w here) */
-} Vector;
-
-typedef struct /* a triangle (indexes of vertexes in some list) */
-{
- int i[3]; /* the three indexes for the triangle corners */
-} Triangle;
-
-typedef struct
-{
- float *vertex;
- float *normal;
- unsigned *index;
- int num_index;
-} VertexArray;
-
-typedef struct /* an 3-D object without normal vectors */
-{
- Vector *vertex; /* the vertexes */
- Triangle *triangle; /* triangle list */
- int num_vertex; /* number of vertexes */
- int num_triangle; /* number of triangles */
-} Object;
-
-typedef struct /* an 3-D object with smooth normal vectors */
-{
- Vector *vertex; /* the vertexes */
- Vector *normal; /* the vertex normal vectors */
- Triangle *triangle; /* triangle list */
- int num_vertex; /* number of vertexes */
- int num_triangle; /* number of triangles */
-} ObjectSmooth;
-
-typedef struct /* Cell */
-{
- double x, y; /* position */
- double vx, vy; /* movement vector */
- int age; /* cells age */
- double min_dist; /* minimum distance to other cells */
- int energy; /* health */
- double rotation; /* random rot, so they don't look all the same */
- double radius; /* current size of cell */
- double growth; /* current growth rate. might be <1.0 while dividing,
- >1.0 when finished dividing and food is available
- and 1.0 when grown up */
-} Cell;
-
-typedef struct /* hacks state */
-{
- GLXContext *glx_context;
- int width, height; /* current size of viewport */
- double screen_scale; /* we scale content with window size */
- int num_cells; /* current number of cell in list */
- Cell *cell; /* array of cells */
- int cell_polys;
- GLfloat color[4]; /* current cell color */
- double radius; /* cell radius */
- int move_dist; /* min distance from neighbours for forking */
- int max_cells; /* maximum number of cells */
- int num_seeds; /* number of initial seeds */
- int keep_old_cells; /* draw dead cells? */
- int divide_age; /* min age for division */
- /* display lists for the cell stages */
- int cell_list[NUM_CELL_SHAPES];
- int nucleus_list;
- int minfood; /* minimum amount of food per area unit */
- int maxfood; /* maximum amount of food per area unit */
- int pause; /* pause at end (all cells dead) */
- int pause_counter;
- int wire; /* draw wireframe? */
- Object *sphere; /* the raw undisturbed sphere */
- double *disturbance; /* disturbance values for the vertexes */
- int *food; /* our petri dish (e.g. screen) */
- GLubyte *texture; /* texture data for nucleus */
- GLuint texture_name; /* texture name for binding */
-} State;
-
-/**********************************
- STATIC STUFF
- **********************************/
-
-static State *sstate = NULL;
-
-static XrmOptionDescRec opts[] = {
- { "-maxcells", ".maxcells", XrmoptionSepArg, 0 },
- { "-radius", ".radius", XrmoptionSepArg, 0 },
- { "-seeds", ".seeds", XrmoptionSepArg, 0 },
- { "-quality", ".quality", XrmoptionSepArg, 0 },
- { "-minfood", ".minfood", XrmoptionSepArg, 0 },
- { "-maxfood", ".maxfood", XrmoptionSepArg, 0 },
- { "-divideage", ".divideage", XrmoptionSepArg, 0 },
- { "-mindist", ".mindist", XrmoptionSepArg, 0 },
- { "-pause", ".pause", XrmoptionSepArg, 0 },
- { "-keepold", ".keepold", XrmoptionNoArg, "True" }
-};
-
-static int s_maxcells;
-static int s_radius;
-static int s_seeds;
-static int s_quality;
-static int s_minfood;
-static int s_maxfood;
-static int s_divideage;
-static int s_pause;
-static float s_min_dist;
-static Bool s_keepold;
-
-static argtype vars[] = {
- {&s_maxcells, "maxcells", "Max Cells", DEF_MAXCELLS, t_Int},
- {&s_radius, "radius", "Radius", DEF_RADIUS, t_Int},
- {&s_seeds, "seeds", "Seeds", DEF_SEEDS, t_Int},
- {&s_quality, "quality", "Quality", DEF_QUALITY, t_Int},
- {&s_minfood, "minfood", "Min Food", DEF_MINFOOD, t_Int},
- {&s_maxfood, "maxfood", "Max Food", DEF_MAXFOOD, t_Int},
- {&s_pause, "pause", "Pause at end", DEF_PAUSE, t_Int},
- {&s_divideage, "divideage", "Age for duplication (Ticks)", DEF_DIVIDEAGE, t_Int},
- {&s_min_dist, "mindist", "Minimum preferred distance to other cells", DEF_MINDIST, t_Float},
- {&s_keepold, "keepold", "Keep old cells", DEF_KEEPOLD, t_Bool}
-};
-
-/**********************************
- PROTOTYPES
- **********************************/
-
-/* render scene */
-static int render( State *st );
-/* create initial cells and fill petri dish with food */
-static void create_cells( State * );
-/* do one animation step */
-static void tick( State *st );
-/* draw a single cell */
-static void draw_cell( State *st, int shape );
-/* draw cells nucleus */
-static void draw_nucleus( State *st );
-/* return randum number in the interval min-max */
-static int random_interval( int min, int max );
-/* retunr random number in the interval 0-max */
-static int random_max( int max );
-/* create display list for given disturbance weighting factor */
-static int create_list( State *st, double fac );
-/* return length of vector */
-static double vector_length( Vector * );
-/* normalize vector */
-static void vector_normalize( Vector * );
-/* a += b */
-static void vector_add( Vector *a, Vector *b );
-/* a -= b */
-static void vector_sub( Vector *a, Vector *b );
-/* a *= fac */
-static void vector_mul( Vector *a, double fac );
-/* a.x = a.y = a.z = 0 */
-static void vector_clear( Vector *a );
-/* return crossproduct a*b in out */
-static void vector_crossprod( Vector *a, Vector *b, Vector *out );
-/* return 1 if vectors are equal (epsilon compare) otherwise 0 */
-static int vector_compare( Vector *a, Vector *b );
-/* compute normal vector of given triangle and return in out */
-static void triangle_normal( Vector *a, Vector *b, Vector *c, Vector *out );
-/* take an Object and create an ObjectSmooth out of it */
-static ObjectSmooth *create_ObjectSmooth( Object * );
-/* Subdivide the Object once (assuming it's supposed to be a shpere */
-static Object *subdivide( Object *obj );
-/* free an Object */
-static void free_Object( Object * );
-/* free an ObjectSmooth */
-static void free_ObjectSmooth( ObjectSmooth * );
-/* scale an Object. return pointer to the object */
-/*static Object *scale_Object( Object *obj, double scale );*/
-/* create a perfect sphere refining with divisions */
-static Object *create_sphere( State *st, int divisions );
-/* make a copy of the given Object */
-static Object *clone_Object( Object * );
-/* return 1 if cell is capable to divide */
-static int can_divide( State *st, Cell *cell );
-#ifdef USE_VERTEX_ARRAY
-static VertexArray *array_from_ObjectSmooth( ObjectSmooth * );
-#endif
-static void create_nucleus_texture( State *st );
-
-ENTRYPOINT ModeSpecOpt glcells_opts = { countof(opts), opts, countof(vars), vars,
- NULL };
-
-
-/**********************************
- INLINE FUNCTIONS
- **********************************/
-/* create random numbers
-*/
-static inline int random_interval( int min, int max )
-{
- int n = max - min;
- if (n == 0) n = 1;
- return min+(random()%n);
-}
-
-static inline int random_max( int max )
-{
- return random()%max;
-}
-
-/* Vector stuff
-*/
-
-/* a += b */
-static inline void vector_add( Vector *a, Vector *b )
-{
- a->x += b->x;
- a->y += b->y;
- a->z += b->z;
-}
-
-/* a -= b */
-static inline void vector_sub( Vector *a, Vector *b )
-{
- a->x -= b->x;
- a->y -= b->y;
- a->z -= b->z;
-}
-
-/* a *= v */
-static inline void vector_mul( Vector *a, double v )
-{
- a->x *= v;
- a->y *= v;
- a->z *= v;
-}
-
-/* set to 0 */
-static inline void vector_clear( Vector *vec )
-{
- vec->x = vec->y = vec->z = 0;
-}
-
-/* return vector length */
-static inline double vector_length( Vector *vec )
-{
- return sqrt( vec->x*vec->x + vec->y*vec->y + vec->z*vec->z );
-}
-
-/* normalize vector */
-static inline void vector_normalize( Vector *vec )
-{
- double len = vector_length( vec );
-
- if (len != 0.0) {
- vector_mul( vec, 1.0 / len );
- }
-}
-
-/* crossproduct */
-static inline void vector_crossprod( Vector *a, Vector *b, Vector *out )
-{
- out->x = a->y*b->z - a->z*b->y;
- out->y = a->z*b->x - a->x*b->z;
- out->z = a->x*b->y - a->y*b->x;
-}
-
-/* epsilon compare of two vectors */
-static inline int vector_compare( Vector *a, Vector *b )
-{
- const double epsilon = 0.0000001;
- Vector delta = *a;
-
- vector_sub( &delta, b );
- if (fabs(delta.x) < epsilon &&
- fabs(delta.y) < epsilon &&
- fabs(delta.z) < epsilon) {
- return 1;
- }
-
- return 0;
-}
-
-/* check if given cell is capable of dividing
- needs space, must be old enough, grown up and healthy
-*/
-static inline int can_divide( State *st, Cell *cell )
-{
- if (cell->min_dist > st->move_dist &&
- cell->age >= st->divide_age &&
- cell->radius > 0.99 * st->radius &&
- cell->energy > 0) {
- return 1;
- }
-
- return 0;
-}
-
-/**********************************
- FUNCTIONS
- **********************************/
-
-/* compute normal vector of given
- triangle spanned by the points a, b, c
-*/
-static void triangle_normal( Vector *a, Vector *b, Vector *c, Vector *out )
-{
- Vector v1 = *a;
- Vector v2 = *a;
-
- vector_sub( &v1, b );
- vector_sub( &v2, c );
- vector_crossprod( &v1, &v2, out );
-}
-
-/* free */
-static void free_Object( Object *obj )
-{
- free( obj->vertex );
- free( obj->triangle );
- free( obj );
-}
-
-static void free_ObjectSmooth( ObjectSmooth *obj )
-{
- free( obj->vertex );
- free( obj->triangle );
- free( obj->normal );
- free( obj );
-}
-
-/* scale the given Object */
-#if 0
-static Object *scale_Object( Object *obj, double scale )
-{
- int v;
-
- for (v=0; v<obj->num_vertex; ++v) {
- vector_mul( &obj->vertex[v], scale );
- }
-
- return obj;
-}
-#endif
-
-/* create a copy of the given Object */
-static Object *clone_Object( Object *obj )
-{
- /* alloc */
- Object *ret = (Object *) malloc( sizeof( Object ) );
-
- ret->vertex =
- (Vector *) malloc( obj->num_vertex*sizeof(Vector) );
- ret->triangle =
- (Triangle *) malloc( obj->num_triangle*sizeof(Triangle) );
- ret->num_vertex = obj->num_vertex;
- ret->num_triangle = obj->num_triangle;
- /* copy */
- memcpy( ret->vertex, obj->vertex,
- obj->num_vertex*sizeof(Vector) );
- memcpy( ret->triangle, obj->triangle,
- obj->num_triangle*sizeof(Triangle) );
-
- return ret;
-}
-
-#ifdef USE_VERTEX_ARRAY
-static VertexArray *array_from_ObjectSmooth( ObjectSmooth *obj )
-{
- int i, j;
- VertexArray *array = (VertexArray *) malloc( sizeof( VertexArray ) );
-
- array->vertex = (float *) malloc( 3*sizeof(float)*obj->num_vertex );
- array->normal = (float *) malloc( 3*sizeof(float)*obj->num_vertex );
- array->index = (unsigned *) malloc( 3*sizeof(unsigned)*obj->num_triangle );
- array->num_index = obj->num_triangle*3;
-
- for (i=0, j=0; i<obj->num_vertex; ++i) {
- array->vertex[j] = obj->vertex[i].x;
- array->normal[j++] = obj->normal[i].x;
- array->vertex[j] = obj->vertex[i].y;
- array->normal[j++] = obj->normal[i].y;
- array->vertex[j] = obj->vertex[i].z;
- array->normal[j++] = obj->normal[i].z;
- }
-
- for (i=0, j=0; i<obj->num_triangle; ++i) {
- array->index[j++] = obj->triangle[i].i[0];
- array->index[j++] = obj->triangle[i].i[1];
- array->index[j++] = obj->triangle[i].i[2];
- }
-
- return array;
-}
-#endif /* USE_VERTEX_ARRAY */
-
-
-/* create a smoothed version of the given Object
- by computing average normal vectors for the vertexes
-*/
-static ObjectSmooth *create_ObjectSmooth( Object *obj )
-{
- int t, v, i;
- Vector *t_normal =
- (Vector *) malloc( obj->num_triangle*sizeof(Vector) );
- ObjectSmooth *ret =
- (ObjectSmooth *) malloc( sizeof( ObjectSmooth ) );
-
- /* fill in vertexes and triangles */
- ret->num_vertex = obj->num_vertex;
- ret->num_triangle = obj->num_triangle;
- ret->vertex =
- (Vector *) malloc( obj->num_vertex * sizeof( Vector ) );
- ret->normal =
- (Vector *) malloc( obj->num_vertex * sizeof( Vector ) );
- ret->triangle =
- (Triangle *) malloc( obj->num_triangle * sizeof( Triangle ) );
-
- for (v=0; v<obj->num_vertex; ++v) {
- ret->vertex[v] = obj->vertex[v];
- }
-
- for (t=0; t<obj->num_triangle; ++t) {
- ret->triangle[t] = obj->triangle[t];
- }
-
- /* create normals (triangles) */
- for (t=0; t<ret->num_triangle; ++t) {
- triangle_normal( &ret->vertex[ret->triangle[t].i[0]],
- &ret->vertex[ret->triangle[t].i[1]],
- &ret->vertex[ret->triangle[t].i[2]],
- &t_normal[t] );
- }
-
- /* create normals (vertex) by averaging triangle
- normals at vertex
- */
- for (v=0; v<ret->num_vertex; ++v) {
- vector_clear( &ret->normal[v] );
- for (t=0; t<ret->num_triangle; ++t) {
- for (i=0; i<3; ++i) {
- if (ret->triangle[t].i[i] == v) {
- vector_add( &ret->normal[v], &t_normal[t] );
- }
- }
- }
- /* as we have only a half sphere we force the
- normals at the bortder to be perpendicular to z.
- the simple algorithm above makes an error here.
- */
- if (fabs(ret->vertex[v].z) < 0.0001) {
- ret->normal[v].z = 0.0;
- }
-
- vector_normalize( &ret->normal[v] );
- }
-
- free( t_normal );
-
- return ret;
-}
-
-/* subdivide the triangles of the object once
- The order of this algorithm is probably something like O(n^42) :)
- but I can't think of something smarter at the moment
-*/
-static Object *subdivide( Object *obj )
-{
- /* create for worst case (which I dont't know) */
- int start, t, i, v;
- int index_list[1000];
- int index_cnt, index_found;
- Object *tmp = (Object *)malloc( sizeof(Object) );
- Object *ret = (Object *)malloc( sizeof(Object) );
- Object *c_ret;
-
- tmp->vertex =
- (Vector *)malloc( 100*obj->num_vertex*sizeof( Vector ) );
- tmp->triangle =
- (Triangle *)malloc( 4*obj->num_triangle*sizeof( Triangle ) );
- tmp->num_vertex = 0;
- tmp->num_triangle = 0;
- ret->vertex =
- (Vector *)malloc( 100*obj->num_vertex*sizeof( Vector ) );
- ret->triangle =
- (Triangle *)malloc( 4*obj->num_triangle*sizeof( Triangle ) );
- ret->num_vertex = 0;
- ret->num_triangle = 0;
-#ifdef PRINT_STAT
- fprintf( stderr, "in v=%d t=%d\n",
- obj->num_vertex, obj->num_triangle );
-#endif
- /* for each triangle create 3 new vertexes and the 4
- corresponding triangles
- */
- for (t=0; t<obj->num_triangle; ++t) {
- /* copy the three original vertexes */
- for (i=0; i<3; ++i) {
- tmp->vertex[tmp->num_vertex++] =
- obj->vertex[obj->triangle[t].i[i]];
- }
-
- /* create 3 new */
- tmp->vertex[tmp->num_vertex] =
- obj->vertex[obj->triangle[t].i[0]];
- vector_add( &tmp->vertex[tmp->num_vertex],
- &obj->vertex[obj->triangle[t].i[1]] );
- vector_mul( &tmp->vertex[tmp->num_vertex++], 0.5 );
-
- tmp->vertex[tmp->num_vertex] =
- obj->vertex[obj->triangle[t].i[1]];
- vector_add( &tmp->vertex[tmp->num_vertex],
- &obj->vertex[obj->triangle[t].i[2]] );
- vector_mul( &tmp->vertex[tmp->num_vertex++], 0.5 );
-
- tmp->vertex[tmp->num_vertex] =
- obj->vertex[obj->triangle[t].i[2]];
- vector_add( &tmp->vertex[tmp->num_vertex],
- &obj->vertex[obj->triangle[t].i[0]] );
- vector_mul( &tmp->vertex[tmp->num_vertex++], 0.5 );
-
- /* create triangles */
- start = tmp->num_vertex-6;
-
- tmp->triangle[tmp->num_triangle].i[0] = start;
- tmp->triangle[tmp->num_triangle].i[1] = start+3;
- tmp->triangle[tmp->num_triangle++].i[2] = start+5;
-
- tmp->triangle[tmp->num_triangle].i[0] = start+3;
- tmp->triangle[tmp->num_triangle].i[1] = start+1;
- tmp->triangle[tmp->num_triangle++].i[2] = start+4;
-
- tmp->triangle[tmp->num_triangle].i[0] = start+5;
- tmp->triangle[tmp->num_triangle].i[1] = start+4;
- tmp->triangle[tmp->num_triangle++].i[2] = start+2;
-
- tmp->triangle[tmp->num_triangle].i[0] = start+3;
- tmp->triangle[tmp->num_triangle].i[1] = start+4;
- tmp->triangle[tmp->num_triangle++].i[2] = start+5;
- }
-
- /* compress object eliminating double vertexes
- (welcome to the not so smart section)
- */
- /* copy original triangle list */
- for (t=0; t<tmp->num_triangle; ++t) {
- ret->triangle[t] = tmp->triangle[t];
- }
- ret->num_triangle = tmp->num_triangle;
-
- /* copy unique vertexes and correct triangle list */
- for (v=0; v<tmp->num_vertex; ++v) {
- /* create list of vertexes that are the same */
- index_cnt = 0;
- for (i=0; i<tmp->num_vertex; ++i) {
- /* check if i and v are the same
- first in the list is the smallest index
- */
- if (vector_compare( &tmp->vertex[v], &tmp->vertex[i] )) {
- index_list[index_cnt++] = i;
- }
- }
-
- /* check if vertex unknown so far */
- index_found = 0;
- for (i=0; i<ret->num_vertex; ++i) {
- if (vector_compare( &ret->vertex[i],
- &tmp->vertex[index_list[0]] )) {
- index_found = 1;
- break;
- }
- }
-
- if (!index_found) {
- ret->vertex[ret->num_vertex] = tmp->vertex[index_list[0]];
-
- /* correct triangles
- (we add an offset to the index, so we can tell them apart)
- */
- for (t=0; t<ret->num_triangle; ++t) {
- for (i=0; i<index_cnt; ++i) {
- if (ret->triangle[t].i[0] == index_list[i]) {
- ret->triangle[t].i[0] = ret->num_vertex+INDEX_OFFSET;
- }
- if (ret->triangle[t].i[1] == index_list[i]) {
- ret->triangle[t].i[1] = ret->num_vertex+INDEX_OFFSET;
- }
- if (ret->triangle[t].i[2] == index_list[i]) {
- ret->triangle[t].i[2] = ret->num_vertex+INDEX_OFFSET;
- }
- }
- }
- ret->num_vertex++;
- }
- }
-
- free_Object( tmp );
-
- /* correct index offset */
- for (t=0; t<ret->num_triangle; ++t) {
- ret->triangle[t].i[0] -= INDEX_OFFSET;
- ret->triangle[t].i[1] -= INDEX_OFFSET;
- ret->triangle[t].i[2] -= INDEX_OFFSET;
- }
-
- /* normalize vertexes */
- for (v=0; v<ret->num_vertex; ++v) {
- vector_normalize( &ret->vertex[v] );
- }
-#ifdef PRINT_STAT
- fprintf( stderr, "out v=%d t=%d\n",
- ret->num_vertex, ret->num_triangle );
-#endif
- /* shrink the arrays by cloning */
- c_ret = clone_Object( ret );
- free_Object( ret );
-
- return c_ret;
-}
-
-static int render( State *st )
-{
-#ifdef PRINT_STAT
- struct timeval tv1, tv2;
- int usec;
-#endif
- GLfloat LightAmbient[]= { 0.1f, 0.1f, 0.1f, 1.0f };
- GLfloat LightPosition[]= { -20.0f, -10.0f, -100.0f, 0.0f };
- int b;
- int num_paint = 0;
-
- if (0 == st->food) return 0;
-#ifdef PRINT_STAT
- gettimeofday( &tv1, NULL );
-#endif
- /* life goes on... */
- tick( st );
-#ifdef PRINT_STAT
- gettimeofday( &tv2, NULL );
- usec = (tv2.tv_sec-tv1.tv_sec)*1000000+(tv2.tv_usec-tv1.tv_usec);
- fprintf( stderr, "tick %d\n", usec );
- gettimeofday( &tv1, NULL );
-#endif
-
- glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
- glDepthFunc(GL_LESS);
- glEnable(GL_DEPTH_TEST);
- glLightfv( GL_LIGHT0, GL_AMBIENT, LightAmbient );
- glLightfv( GL_LIGHT0, GL_DIFFUSE, st->color );
- glLightfv( GL_LIGHT0, GL_POSITION, LightPosition );
-
- /* prepare lighting vs. wireframe */
- if (!st->wire) {
- glEnable( GL_LIGHT0 );
- glEnable( GL_LIGHTING );
- glEnable( GL_NORMALIZE );
- glPolygonMode( GL_FRONT, GL_FILL );
- } else {
-# ifndef HAVE_JWZGLES /* #### glPolygonMode other than GL_FILL unimplemented */
- glPolygonMode( GL_FRONT, GL_LINE );
-# endif
- }
-
-# if 0
- if (st->wire) {
- glDisable(GL_DEPTH_TEST);
- glColor3f (1, 1, 1);
- glBegin(GL_LINE_LOOP);
- glVertex3f(0, 0, 0); glVertex3f(st->width, 0, 0);
- glVertex3f(st->width, st->height, 0); glVertex3f(0, st->height, 0);
- glVertex3f(0, 0, 0); glVertex3f(st->width/4, 0, 0);
- glVertex3f(st->width/4, st->height/4, 0); glVertex3f(0, st->height/4, 0);
- glEnd();
- }
-# endif
-
- /* draw the dead cells if choosen */
- if (st->keep_old_cells) {
- for (b=0; b<st->num_cells; ++b) {
- if (st->cell[b].energy <= 0) {
- num_paint++;
- glPushMatrix();
- glTranslatef( st->cell[b].x, st->cell[b].y, 0.0 );
- glRotatef( st->cell[b].rotation, 0.0, 0.0, 1.0 );
- glScalef( st->cell[b].radius, st->cell[b].radius, st->cell[b].radius );
- draw_cell( st, 9 );
- glPopMatrix();
- }
- }
- }
-
- /* draw the living cells */
- for (b=0; b<st->num_cells; ++b) {
- if (st->cell[b].energy >0) {
- double fac = (double)st->cell[b].energy / 50.0;
- int shape;
- if (fac < 0.0) fac = 0.0;
- if (fac > 1.0) fac = 1.0;
-
- shape = (int)(9.0*fac);
- num_paint++;
- /*glColor3f( fac, fac, fac );*/
-
-# if 0
- if (st->wire) {
- glBegin(GL_LINES);
- glVertex3f(0, 0, 0);
- glVertex3f(st->cell[b].x, st->cell[b].y, 0);
- glEnd();
- }
-# endif
-
- glPushMatrix();
- glTranslatef( st->cell[b].x, st->cell[b].y, 0.0 );
- glRotatef( st->cell[b].rotation, 0.0, 0.0, 1.0 );
- glScalef( st->cell[b].radius, st->cell[b].radius, st->cell[b].radius );
- draw_cell( st, 9-shape );
- glPopMatrix();
- }
- }
-
- /* draw cell nuclei */
- if (!st->wire)
- {
- glDisable( GL_LIGHT0 );
- glDisable( GL_LIGHTING );
-
- glEnable( GL_BLEND );
- glDisable( GL_DEPTH_TEST );
- glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
- glEnable( GL_TEXTURE_2D );
- glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
- glBindTexture( GL_TEXTURE_2D, st->texture_name );
-
- for (b=0; b<st->num_cells; ++b) {
- if (st->cell[b].energy>0 || st->keep_old_cells) {
- glPushMatrix();
- glTranslatef( st->cell[b].x, st->cell[b].y, 0.0 );
- glScalef( st->cell[b].radius, st->cell[b].radius, st->cell[b].radius );
- draw_nucleus( st );
- glPopMatrix();
- }
- }
-
- glDisable( GL_TEXTURE_2D );
- glDisable( GL_BLEND );
- }
-
-#ifdef PRINT_STAT
- gettimeofday( &tv2, NULL );
- usec = (tv2.tv_sec-tv1.tv_sec)*1000000+(tv2.tv_usec-tv1.tv_usec);
- fprintf( stderr, "OpenGL %d\n", usec );
-#endif
- return num_paint * st->cell_polys;
-}
-
-/* this creates the initial subdivided half-dodecaedron */
-static Object *create_sphere( State *st, int divisions )
-{
- int num_vertex = 9;
- int num_triangle = 10;
- int i, v, t;
- double a, aStep = (double)M_PI / 3.0;
- double e;
- int vi[30] = { 0, 7, 1, 1, 7, 2, 2, 8, 3, 3, 8, 4, 4, 6, 5,
- 5, 6, 0, 0, 6, 7, 2, 7, 8, 4, 8, 6, 6, 8, 7 };
- Object *obj = (Object *)malloc( sizeof( Object ) );
-
- obj->vertex = (Vector *)malloc( num_vertex*sizeof( Vector ) );
- obj->triangle =
- (Triangle *)malloc( num_triangle*sizeof( Triangle ) );
- obj->num_vertex = num_vertex;
- obj->num_triangle = num_triangle;
-
- /* create vertexes for dodecaedron */
- a = 0.0;
- for (v=0; v<6; ++v) {
- obj->vertex[v].x = sin( a );
- obj->vertex[v].y = -cos( a );
- obj->vertex[v].z = 0.0;
-
- a += aStep;
- }
-
- a = -60.0/180.0*(double)M_PI;
- e = 58.2825/180.0 * (double)M_PI;
- for (;v<9; ++v) {
- obj->vertex[v].x = sin( a )*cos( e );
- obj->vertex[v].y = -cos( a )*cos( e );
- obj->vertex[v].z = -sin( e );
-
- a += 2.0*aStep;
- }
-
- /* create triangles */
- for (t=0; t<obj->num_triangle; ++t) {
- obj->triangle[t].i[0] = vi[3*t];
- obj->triangle[t].i[1] = vi[3*t+1];
- obj->triangle[t].i[2] = vi[3*t+2];
- }
-
- /* subdivide as specified */
- for (i=0; i<divisions; ++i) {
- Object *newObj = subdivide( obj );
- free_Object( obj );
- obj = newObj;
- }
-
- st->cell_polys = obj->num_triangle;
-
- return obj;
-}
-
-static int create_list( State *st, double fac )
-{
- int v;
- Object *obj = clone_Object( st->sphere );
- ObjectSmooth *smooth;
-#ifdef USE_VERTEX_ARRAY
- VertexArray *vertex_array;
-#else
- int t, i;
-#endif
- int list = glGenLists(1);
-
- /* apply wrinckle factor */
- for (v=0; v<obj->num_vertex; ++v) {
- vector_mul( &obj->vertex[v], 1.0+fac*st->disturbance[v] );
- }
-
- /* compute normals */
- smooth = create_ObjectSmooth( obj );
- free_Object( obj );
-
- /* Create display list */
- glNewList( list, GL_COMPILE );
-#ifdef USE_VERTEX_ARRAY
- vertex_array = array_from_ObjectSmooth( smooth );
- glEnableClientState( GL_VERTEX_ARRAY );
- glEnableClientState( GL_NORMAL_ARRAY );
- glVertexPointer( 3, GL_FLOAT, 0, vertex_array->vertex );
- glNormalPointer( GL_FLOAT, 0, vertex_array->normal );
- glDrawElements( GL_TRIANGLES, vertex_array->num_index,
- GL_UNSIGNED_INT, vertex_array->index );
- free (vertex_array->vertex);
- free (vertex_array->normal);
- free (vertex_array->index);
- free( vertex_array );
-#else
- glBegin( GL_TRIANGLES );
-
- for (t=0; t<smooth->num_triangle; ++t) {
- for (i=0; i<3; ++i) {
- glNormal3f( smooth->normal[smooth->triangle[t].i[i]].x,
- smooth->normal[smooth->triangle[t].i[i]].y,
- smooth->normal[smooth->triangle[t].i[i]].z );
- glVertex3f( smooth->vertex[smooth->triangle[t].i[i]].x,
- smooth->vertex[smooth->triangle[t].i[i]].y,
- smooth->vertex[smooth->triangle[t].i[i]].z );
- }
- }
-
- glEnd();
-#endif
- glEndList();
-
- free_ObjectSmooth( smooth );
-
- return list;
-}
-
-static void draw_cell( State *st, int shape )
-{
-# ifdef HAVE_JWZGLES /* #### glPolygonMode other than GL_FILL unimplemented */
- if (st->wire) {
- glDisable(GL_DEPTH_TEST);
- glColor3f (1, 1, 1);
- glPushMatrix();
- glScalef (0.33, 0.33, 1);
- glBegin (GL_LINE_LOOP);
- glVertex3f (-1, -1, 0); glVertex3f (-1, 1, 0);
- glVertex3f ( 1, 1, 0); glVertex3f ( 1, -1, 0);
- glEnd();
- if (shape == 9) {
- glBegin (GL_LINES);
- glVertex3f (-1, -1, 0); glVertex3f (1, 1, 0);
- glVertex3f (-1, 1, 0); glVertex3f (1, -1, 0);
- glEnd();
- }
- glPopMatrix();
- return;
- }
-# endif
-
- if (-1 == st->cell_list[shape]) {
- st->cell_list[shape] = create_list( st, (double)shape/10.0 );
- }
-
- glCallList( st->cell_list[shape] );
-}
-
-static void create_nucleus_texture( State *st )
-{
- int x, y;
- int w2 = TEX_SIZE/2;
- float s = w2*w2/4.0;
-
- st->texture = (GLubyte *) malloc( 4*TEX_SIZE*TEX_SIZE );
-
- for (y=0; y<TEX_SIZE; ++y) {
- for (x=0; x<TEX_SIZE; ++x) {
- float r2 = ((x-w2)*(x-w2)+(y-w2)*(y-w2));
- float v = 120.0 * expf( -(r2) / s );
- st->texture[4*(x+y*TEX_SIZE)] = (GLubyte)0;
- st->texture[4*(x+y*TEX_SIZE)+1] = (GLubyte)0;
- st->texture[4*(x+y*TEX_SIZE)+2] = (GLubyte)0;
- st->texture[4*(x+y*TEX_SIZE)+3] = (GLubyte)v;
- }
- }
-
- glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
- glGenTextures( 1, &st->texture_name );
- glBindTexture( GL_TEXTURE_2D, st->texture_name );
-
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, TEX_SIZE, TEX_SIZE, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, st->texture );
-}
-
-static void draw_nucleus( State *st )
-{
- if (-1 == st->nucleus_list) {
- float z = -1.2f;
- float r=1.0/2.0f;
- st->nucleus_list = glGenLists( 1 );
- glNewList( st->nucleus_list, GL_COMPILE );
- glBegin( GL_QUADS );
- glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -r, -r, z );
- glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -r, r, z );
- glTexCoord2f( 1.0f, 1.0f ); glVertex3f( r, r, z );
- glTexCoord2f( 1.0f, 0.0f ); glVertex3f( r, -r, z );
- glEnd();
- glEndList();
- }
-
- glCallList( st->nucleus_list );
-}
-
-static void create_cells( State *st )
-{
- int border = (int)(200.0 * st->screen_scale);
- int i, foodcnt;
- int w = st->width-2*border;
- int h = st->height-2*border;
-
- st->color[0] = 0.5 + random_max( 1000 ) * 0.0005;
- st->color[1] = 0.5 + random_max( 1000 ) * 0.0005;
- st->color[2] = 0.5 + random_max( 1000 ) * 0.0005;
- st->color[3] = 1.0f;
-
- /* allocate if startup */
- if (!st->cell) {
- st->cell = (Cell *) malloc( st->max_cells * sizeof(Cell));
- }
-
- /* fill the screen with random food for our little critters */
- foodcnt = (st->width*st->height)/16;
- for (i=0; i<foodcnt; ++i) {
- st->food[i] = random_interval( st->minfood, st->maxfood );
- }
-
- /* create the requested seed-cells */
- st->num_cells = st->num_seeds;
-
- for (i=0; i<st->num_cells; ++i) {
- st->cell[i].x = border + random_max( w );
- st->cell[i].y = border + random_max( h );
- st->cell[i].vx = 0.0;
- st->cell[i].vy = 0.0;
- st->cell[i].age = random_max( 0x0f );
- st->cell[i].min_dist = 500.0;
- st->cell[i].energy = random_interval( 5, 5+0x3f );
- st->cell[i].rotation = ((double)random()/(double)RAND_MAX)*360.0;
- st->cell[i].radius = st->radius;
- st->cell[i].growth = 1.0;
- }
-}
-
-/* all this is rather expensive :( */
-static void tick( State *st )
-{
- int new_num_cells, num_cells=0;
- int b, j;
- int x, y, w4=st->width/4, h4=st->height/4, offset;
- double min_dist;
- int min_index;
- int num_living = 0;
- const double check_dist = 0.75*st->move_dist;
- const double grow_dist = 0.75*st->radius;
- const double adult_radius = st->radius;
-
- /* find number of cells capable of division
- and count living cells
- */
- for (b=0; b<st->num_cells; ++b) {
- if (st->cell[b].energy > 0) num_living++;
- if (can_divide( st, &st->cell[b] )) num_cells++;
- }
- new_num_cells = st->num_cells + num_cells;
-
- /* end of simulation ? */
- if (0 == num_living || new_num_cells >= st->max_cells) {
- if (st->pause_counter > 0) st->pause_counter--;
- if (st->pause_counter > 0) return;
- create_cells( st );
- st->pause_counter = st->pause;
- } else if (num_cells) { /* any fertile candidates ? */
- for (b=0, j=st->num_cells; b<st->num_cells; ++b) {
- if (can_divide( st, &st->cell[b] )) {
- st->cell[b].vx = random_interval( -50, 50 ) * 0.01;
- st->cell[b].vy = random_interval( -50, 50 ) * 0.01;
- st->cell[b].age = random_max( 0x0f );
- /* half energy for both plus some bonus for forking */
- st->cell[b].energy =
- st->cell[b].energy/2 + random_max( 0x0f );
- /* forking makes me shrink */
- st->cell[b].growth = 0.995;
-
- /* this one initially goes into the oposite direction */
- st->cell[j].vx = -st->cell[b].vx;
- st->cell[j].vy = -st->cell[b].vy;
- /* same center */
- st->cell[j].x = st->cell[b].x;
- st->cell[j].y = st->cell[b].y;
- st->cell[j].age = random_max( 0x0f );
- st->cell[j].energy = (st->cell[b].energy);
- st->cell[j].rotation =
- ((double)random()/(double)RAND_MAX)*360.0;
- st->cell[j].growth = st->cell[b].growth;
- st->cell[j].radius = st->cell[b].radius;
- ++j;
- } else {
- st->cell[b].vx = 0.0;
- st->cell[b].vy = 0.0;
- }
- }
-
- st->num_cells = new_num_cells;
- }
-
- /* for each find a direction to escape */
- if (st->num_cells > 1) {
- for (b=0; b<st->num_cells; ++b) {
- if (st->cell[b].energy > 0) {
- double vx;
- double vy;
- double len;
-
- /* grow or shrink */
- st->cell[b].radius *= st->cell[b].growth;
- /* find closest neighbour */
- min_dist = 100000.0;
- min_index = 0;
- for (j=0; j<st->num_cells; ++j) {
- if (j!=b) {
- const double dx = st->cell[b].x - st->cell[j].x;
- const double dy = st->cell[b].y - st->cell[j].y;
-
- if (fabs(dx) < check_dist || fabs(dy) < check_dist) {
- const double dist = dx*dx+dy*dy;
- /*const double dist = sqrt( dx*dx+dy*dy );*/
- if (dist<min_dist) {
- min_dist = dist;
- min_index = j;
- }
- }
- }
- }
- /* escape step is away from closest normalized with distance */
- vx = st->cell[b].x - st->cell[min_index].x;
- vy = st->cell[b].y - st->cell[min_index].y;
- len = sqrt( vx*vx + vy*vy );
- if (len > 0.0001) {
- st->cell[b].vx = vx/len;
- st->cell[b].vy = vy/len;
- }
- st->cell[b].min_dist = len;
- /* if not adult (radius too small) */
- if (st->cell[b].radius < adult_radius) {
- /* if too small 60% stop shrinking */
- if (st->cell[b].radius < adult_radius * 0.6) {
- st->cell[b].growth = 1.0;
- }
- /* at safe distance we start growing again */
- if (len > grow_dist) {
- if (st->cell[b].energy > 30) {
- st->cell[b].growth = 1.005;
- }
- }
- } else { /* else keep size */
- st->cell[b].growth = 1.0;
- }
- }
- }
- } else {
- st->cell[0].min_dist = 2*st->move_dist;
- }
-
- /* now move em, snack and burn energy */
- for (b=0; b<st->num_cells; ++b) {
- /* if still alive */
- if (st->cell[b].energy > 0) {
- /* agility depends on amount of energy */
- double fac = (double)st->cell[b].energy / 50.0;
- if (fac < 0.0) fac = 0.0;
- if (fac > 1.0) fac = 1.0;
-
- st->cell[b].x += fac*(2.0 -
- (4.0*(double)random() / (double)RAND_MAX) +
- st->cell[b].vx);
- st->cell[b].y += fac*(2.0 -
- (4.0*(double)random() / (double)RAND_MAX) +
- st->cell[b].vy);
-
- /* get older and burn energy */
- if (st->cell[b].energy > 0) {
- st->cell[b].age++;
- st->cell[b].energy--;
- }
-
- /* have a snack */
- x = ((int)st->cell[b].x)/4;
- if (x<0) x=0;
- if (x>=w4) x = w4-1;
- y = ((int)st->cell[b].y)/4;
- if (y<0) y=0;
- if (y>=h4) y = h4-1;
-
- offset = x+y*w4;
-
- /* don't eat if already satisfied */
- if (st->cell[b].energy < 100 &&
- st->food[offset] > 0) {
- st->food[offset]--;
- st->cell[b].energy++;
- /* if you are hungry, eat more */
- if (st->cell[b].energy < 50 &&
- st->food[offset] > 0) {
- st->food[offset]--;
- st->cell[b].energy++;
- }
- }
- }
- }
-}
-
-ENTRYPOINT void
-reshape_glcells( ModeInfo *mi, int width, int height )
-{
- State *st = &sstate[MI_SCREEN(mi)];
- int rot = current_device_rotation();
- st->height = height;
- st->width = width;
-# ifdef HAVE_MOBILE
- st->screen_scale = (double)(width < height ? width : height) / 1600.0;
-# else
- st->screen_scale = (double)width / 1600.0;
-# endif
-
- st->radius = s_radius;
- if (st->radius < 5) st->radius = 5;
- if (st->radius > 200) st->radius = 200;
- st->radius *= st->screen_scale;
-
- st->move_dist = s_min_dist;
- if (st->move_dist < 1.0) st->move_dist = 1.0;
- if (st->move_dist > 3.0) st->move_dist = 3.0;
- st->move_dist *= st->radius;
-
- glViewport (0, 0, (GLint) width, (GLint) height);
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho( 0, width, height, 0, 200, 0 );
- glRotatef (rot, 0, 0, 1);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- if (st->food) free( st->food );
- st->food = (int *)malloc( ((width*height)/16)*sizeof(int) );
- /* create_cells( st );*/
-
-# ifdef HAVE_MOBILE
- glTranslatef (st->width/2, st->height/2, 0);
- if (rot == 90 || rot == -90 || rot == 270 || rot == -270)
- st->width = height, st->height = width;
- glRotatef (rot, 0, 0, 1);
- if (st->wire) glScalef(0.8, 0.8, 1);
- glTranslatef (-st->width/2, -st->height/2, 0);
-# endif
-}
-
-ENTRYPOINT void
-init_glcells( ModeInfo *mi )
-{
- int i, divisions;
- State *st=0;
-
- MI_INIT(mi, sstate);
- st = &sstate[MI_SCREEN(mi)];
-
- st->glx_context = init_GL(mi);
- st->cell = 0;
- st->num_cells = 0;
- st->wire = MI_IS_WIREFRAME(mi);
-
- /* get settings */
- st->max_cells = s_maxcells;;
- if (st->max_cells < 50) st->max_cells = 50;
- if (st->max_cells > 10000) st->max_cells = 10000;
-
- st->pause = s_pause;
- if (st->pause < 0) st->pause = 0;
- if (st->pause > 400) st->pause = 400;
- st->pause_counter = st->pause;
-
- st->radius = s_radius;
- if (st->radius < 5) st->radius = 5;
- if (st->radius > 200) st->radius = 200;
-
- divisions = s_quality;
- if (divisions < 0) divisions = 0;
- if (divisions > 5) divisions = 5;
-
- st->num_seeds = s_seeds;
- if (st->num_seeds < 1) st->num_seeds = 1;
- if (st->num_seeds > 16) st->num_seeds = 16;
-
- st->minfood = s_minfood;
- if (st->minfood < 0) st->minfood = 0;
- if (st->minfood > 1000) st->minfood = 1000;
-
- st->maxfood = s_maxfood;
- if (st->maxfood < 0) st->maxfood = 0;
- if (st->maxfood > 1000) st->maxfood = 1000;
-
- if (st->maxfood < st->minfood) st->maxfood = st->minfood+1;
-
- st->keep_old_cells = s_keepold;
-
- st->divide_age = s_divideage;
- if (st->divide_age < 1) st->divide_age = 1;
- if (st->divide_age > 1000) st->divide_age = 1000;
-
- st->move_dist = s_min_dist;
- if (st->move_dist < 1.0) st->move_dist = 1.0;
- if (st->move_dist > 3.0) st->move_dist = 3.0;
- st->move_dist *= st->radius;
-
- for (i=0; i<NUM_CELL_SHAPES; ++i) st->cell_list[i] = -1;
- st->nucleus_list = -1;
- st->food = 0;
-
- st->sphere = create_sphere( st, divisions );
- st->disturbance =
- (double *) malloc( st->sphere->num_vertex*sizeof(double) );
- for (i=0; i<st->sphere->num_vertex; ++i) {
- st->disturbance[i] =
- 0.05-((double)random()/(double)RAND_MAX*0.1);
- }
-
- create_nucleus_texture( st );
-
- reshape_glcells (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
-}
-
-ENTRYPOINT void
-draw_glcells( ModeInfo *mi )
-{
- State *st = &sstate[MI_SCREEN(mi)];
- Display *dpy = MI_DISPLAY(mi);
- Window window = MI_WINDOW(mi);
-
- if (!st->glx_context) return;
-
- glXMakeCurrent( MI_DISPLAY(mi), MI_WINDOW(mi), *st->glx_context);
-
- mi->polygon_count = render( st );
-
- if (mi->fps_p) do_fps (mi);
-
- glFinish();
- glXSwapBuffers( dpy, window );
-}
-
-ENTRYPOINT void
-free_glcells( ModeInfo *mi )
-{
- int i;
- State *st = &sstate[MI_SCREEN(mi)];
-
- if (!st->glx_context) return;
- glXMakeCurrent( MI_DISPLAY(mi), MI_WINDOW(mi), *st->glx_context);
-
- if (st->sphere) free_Object( st->sphere );
- if (st->food) free( st->food );
- for (i=0; i<NUM_CELL_SHAPES; ++i) {
- if (st->cell_list[i] != -1) {
- glDeleteLists( st->cell_list[i], 1 );
- }
- }
- if (st->cell) free( st->cell );
- free( st->disturbance );
- glDeleteTextures( 1, &st->texture_name );
- free( st->texture );
- if (glIsList(st->nucleus_list)) glDeleteLists(st->nucleus_list, 1);
-}
-
-XSCREENSAVER_MODULE( "GLCells", glcells )