/* sballs --- balls spinning like crazy in GL */
#if 0
static const char sccsid[] = "@(#)sballs.c 5.02 2001/03/10 xlockmore";
#endif
/* Copyright (c) E. Lassauge, 2001. */
/*
* 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.
*
* The original code for this mode was written by
* Mustata Bogdan (LoneRunner) <lonerunner@planetquake.com>
* and can be found at http://www.cfxweb.net/lonerunner/
*
* Eric Lassauge (November-07-2000) <lassauge@users.sourceforge.net>
* http://lassauge.free.fr/linux.html
*
* REVISION HISTORY:
*
* E.Lassauge - 03-Oct-2001:
* - minor bugfixes - get ready for xscreensaver
* E.Lassauge - 09-Mar-2001:
* - get rid of my framerate options to use showfps
* E.Lassauge - 28-Nov-2000:
* - add handling of polyhedrons (like in ico)
* - modified release part to add freeing of GL objects
* E.Lassauge - 14-Nov-2000:
* - use new common xpm_to_ximage function
*
*/
#ifdef STANDALONE /* xscreensaver mode */
#define DEFAULTS "*delay: 30000 \n" \
"*size: 0 \n" \
"*cycles: 4 \n" \
"*showFPS: False \n" \
"*wireframe: False \n" \
# define release_sballs 0
#define MODE_sballs
#include "xlockmore.h" /* from the xscreensaver distribution */
#include "gltrackball.h"
#else /* !STANDALONE */
#include "xlock.h" /* from the xlockmore distribution */
#include "visgl.h"
#endif /* !STANDALONE */
#define MINSIZE 32 /* minimal viewport size */
#define FRAME 50 /* frame count interval */
#define MAX_OBJ 8 /* number of 3D objects */
#if defined( USE_XPM ) || defined( USE_XPMINC ) || defined( STANDALONE )
/* USE_XPM & USE_XPMINC in xlock mode ; HAVE_XPM in xscreensaver mode */
# include "ximage-loader.h"
# define I_HAVE_XPM
# include "images/gen/sball_png.h"
# include "images/gen/sball-bg_png.h"
/* Manage option vars */
#define DEF_TEXTURE "True"
#define DEF_OBJECT "0"
static Bool do_texture;
static int object, object_arg;
static int spheres;
static XrmOptionDescRec opts[] = {
{"-texture", ".sballs.texture", XrmoptionNoArg, "on"},
{"+texture", ".sballs.texture", XrmoptionNoArg, "off"},
{"-object", ".sballs.object", XrmoptionSepArg, 0},
};
static argtype vars[] = {
{&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
{&object_arg, "object", "Object", DEF_OBJECT, t_Int},
};
static OptionStruct desc[] = {
/*{"-count spheres", "set number of spheres"},*/
/*{"-cycles speed", "set ball speed value"},*/
{"-/+texture", "turn on/off texturing"},
{"-object num", "number of the 3D object (0 means random)"},
};
ENTRYPOINT ModeSpecOpt sballs_opts =
{ sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc };
#ifdef USE_MODULES
ModStruct sballs_description =
{ "sballs", "init_sballs", "draw_sballs", NULL,
"draw_sballs", "change_sballs", "free_sballs", &sballs_opts,
/*
delay,count,cycles,size,ncolors,sat
*/
10000, 0, 10, 400, 64, 1.0, "",
"balls spinning like crazy in GL", 0, NULL
};
#endif /* USE_MODULES */
/* misc types and defines */
#define vinit(a,i,j,k) {\
(a)[0]=i;\
(a)[1]=j;\
(a)[2]=k;\
}
typedef float vec_t;
typedef vec_t vec3_t[3];
#define MAX_BALLS 20
/* the mode struct, contains all per screen variables */
typedef struct {
GLint WIDTH, HEIGHT; /* display dimensions */
GLXContext *glx_context;
XImage *btexture; /* back texture image bits */
XImage *ftexture; /* face texture image bits */
GLuint backid; /* back texture id: GL world */
GLuint faceid; /* face texture id: GL world */
vec3_t eye;
vec3_t rotm;
int speed;
float radius[MAX_BALLS];
trackball_state *trackball;
Bool button_down_p;
} sballsstruct;
/* array of sballsstruct indexed by screen number */
static sballsstruct *sballs = (sballsstruct *) NULL;
/* lights */
static const float LightAmbient[]= { 1.0f, 1.0f, 1.0f, 1.0f };
static const float LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f };
static const float LightPosition[]= { 0.0f, 0.0f, 4.0f, 1.0f };
/* structure of the polyhedras */
typedef struct {
const char *longname; /* long name of object */
const char *shortname; /* short name of object */
int numverts; /* number of vertices */
float radius; /* radius */
vec3_t v[MAX_BALLS];/* the vertices */
} Polyinfo;
static const Polyinfo polygons[] =
{
/* 0: objtetra - structure values for tetrahedron */
{
"tetrahedron", "tetra", /* long and short names */
4, /* number of vertices */
0.8,
{ /* vertices (x,y,z) */
/* all points must be within radius 2 of the origin */
#define T 1.0
{T, T, T},
{T, -T, -T},
{-T, T, -T},
{-T, -T, T},
#undef T
}
},
/* 1: objcube - structure values for cube */
{
"hexahedron", "cube", /* long and short names */
8, /* number of vertices, edges, and faces */
0.6,
{ /* vertices (x,y,z) */
/* all points must be within radius 2 of the origin */
#define T 1.0
{T, T, T},
{T, T, -T},
{T, -T, -T},
{T, -T, T},
{-T, T, T},
{-T, T, -T},
{-T, -T, -T},
{-T, -T, T},
#undef T
}
},
/* 2: objocta - structure values for octahedron */
{
"octahedron", "octa", /* long and short names */
6, /* number of vertices */
0.6,
{ /* vertices (x,y,z) */
/* all points must be within radius 2 of the origin */
#define T 1.5
{T, 0, 0},
{-T, 0, 0},
{0, T, 0},
{0, -T, 0},
{0, 0, T},
{0, 0, -T},
#undef T
}
},
/* 3: objdodec - structure values for dodecahedron */
{
"dodecahedron", "dodeca", /* long and short names */
20, /* number of vertices */
0.35,
{ /* vertices (x,y,z) */
/* all points must be within radius 2 of the origin */
{0.000000, 0.500000, 1.000000},
{0.000000, -0.500000, 1.000000},
{0.000000, -0.500000, -1.000000},
{0.000000, 0.500000, -1.000000},
{1.000000, 0.000000, 0.500000},
{-1.000000, 0.000000, 0.500000},
{-1.000000, 0.000000, -0.500000},
{1.000000, 0.000000, -0.500000},
{0.500000, 1.000000, 0.000000},
{-0.500000, 1.000000, 0.000000},
{-0.500000, -1.000000, 0.000000},
{0.500000, -1.000000, 0.000000},
{0.750000, 0.750000, 0.750000},
{-0.750000, 0.750000, 0.750000},
{-0.750000, -0.750000, 0.750000},
{0.750000, -0.750000, 0.750000},
{0.750000, -0.750000, -0.750000},
{0.750000, 0.750000, -0.750000},
{-0.750000, 0.750000, -0.750000},
{-0.750000, -0.750000, -0.750000},
}
},
/* 4: objicosa - structure values for icosahedron */
{
"icosahedron", "icosa", /* long and short names */
12, /* number of vertices */
0.4,
{ /* vertices (x,y,z) */
/* all points must be within radius 2 of the origin */
{0.00000000, 0.00000000, -0.95105650},
{0.00000000, 0.85065080, -0.42532537},
{0.80901698, 0.26286556, -0.42532537},
{0.50000000, -0.68819095, -0.42532537},
{-0.50000000, -0.68819095, -0.42532537},
{-0.80901698, 0.26286556, -0.42532537},
{0.50000000, 0.68819095, 0.42532537},
{0.80901698, -0.26286556, 0.42532537},
{0.00000000, -0.85065080, 0.42532537},
{-0.80901698, -0.26286556, 0.42532537},
{-0.50000000, 0.68819095, 0.42532537},
{0.00000000, 0.00000000, 0.95105650}
}
},
/* 5: objplane - structure values for plane */
{
"plane", "plane", /* long and short names */
4, /* number of vertices */
0.7,
{ /* vertices (x,y,z) */
/* all points must be within radius 2 of the origin */
#define T 1.1
{T, 0, 0},
{-T, 0, 0},
{0, T, 0},
{0, -T, 0},
#undef T
}
},
/* 6: objpyr - structure values for pyramid */
{
"pyramid", "pyramid", /* long and short names */
5, /* number of vertices */
0.5,
{ /* vertices (x,y,z) */
/* all points must be within radius 1 of the origin */
#define T 1.0
{T, 0, 0},
{-T, 0, 0},
{0, T, 0},
{0, -T, 0},
{0, 0, T},
#undef T
}
},
/* 7: objstar - structure values for octahedron star (stellated octahedron?) */
{
"star", "star", /* long and short names */
8, /* number of vertices */
0.7,
{ /* vertices (x,y,z) */
/* all points must be within radius 1 of the origin */
#define T 0.9
{T, T, T},
{T, -T, -T},
{-T, T, -T},
{-T, -T, T},
{-T, -T, -T},
{-T, T, T},
{T, -T, T},
{T, T, -T},
#undef T
}
},
};
/*
*-----------------------------------------------------------------------------
*-----------------------------------------------------------------------------
* Misc funcs.
*-----------------------------------------------------------------------------
*-----------------------------------------------------------------------------
*/
/* initialise textures */
static void inittextures(ModeInfo * mi)
{
sballsstruct *sb = &sballs[MI_SCREEN(mi)];
#if defined( I_HAVE_XPM )
if (do_texture) {
glGenTextures(1, &sb->backid);
#ifdef HAVE_GLBINDTEXTURE
glBindTexture(GL_TEXTURE_2D, sb->backid);
#endif /* HAVE_GLBINDTEXTURE */
sb->btexture = image_data_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
sball_bg_png,
sizeof(sball_bg_png));
if (!(sb->btexture)) {
(void) fprintf(stderr, "Error reading the background texture.\n");
glDeleteTextures(1, &sb->backid);
do_texture = False;
sb->faceid = 0; /* default textures */
sb->backid = 0;
return;
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
clear_gl_error();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
sb->btexture->width, sb->btexture->height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, sb->btexture->data);
check_gl_error("texture");
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(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);
Let's pixellate it instead:
*/
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glGenTextures(1, &sb->faceid);
#ifdef HAVE_GLBINDTEXTURE
glBindTexture(GL_TEXTURE_2D, sb->faceid);
#endif /* HAVE_GLBINDTEXTURE */
sb->ftexture = image_data_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
sball_png, sizeof(sball_png));
if (!(sb->ftexture)) {
(void) fprintf(stderr, "Error reading the face texture.\n");
glDeleteTextures(1, &sb->faceid);
sb->faceid = 0;
return;
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
clear_gl_error();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
sb->ftexture->width, sb->ftexture->height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, sb->ftexture->data);
check_gl_error("texture");
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(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);
Let's pixellate it instead:
*/
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}
else
{
sb->faceid = 0; /* default textures */
sb->backid = 0;
}
#else /* !I_HAVE_XPM */
do_texture = False;
sb->faceid = 0; /* default textures */
sb->backid = 0;
#endif /* !I_HAVE_XPM */
}
static void drawSphere(ModeInfo * mi,int sphere_num)
{
sballsstruct *sb = &sballs[MI_SCREEN(mi)];
float x = polygons[object].v[sphere_num][0];
float y = polygons[object].v[sphere_num][1];
float z = polygons[object].v[sphere_num][2];
int numMajor = 15;
int numMinor = 30;
float radius = sb->radius[sphere_num];
double majorStep = (M_PI / numMajor);
double minorStep = (2.0 * M_PI / numMinor);
int i, j;
glPushMatrix();
glTranslatef(x, y, z);
glColor4f(1, 1, 1, 1);
for (i = 0; i < numMajor; ++i)
{
double a = i * majorStep;
double b = a + majorStep;
double r0 = radius * sin(a);
double r1 = radius * sin(b);
GLfloat z0 = radius * cos(a);
GLfloat z1 = radius * cos(b);
glBegin(MI_IS_WIREFRAME(mi) ? GL_LINE_STRIP: GL_TRIANGLE_STRIP);
for (j = 0; j <= numMinor; ++j)
{
double c = j * minorStep;
GLfloat x = cos(c);
GLfloat y = sin(c);
glNormal3f((x * r0) / radius, (y * r0) / radius, z0 / radius);
glTexCoord2f(j / (GLfloat) numMinor, i / (GLfloat) numMajor);
glVertex3f(x * r0, y * r0, z0);
glNormal3f((x * r1) / radius, (y * r1) / radius, z1 / radius);
glTexCoord2f(j / (GLfloat) numMinor, (i + 1) / (GLfloat) numMajor);
glVertex3f(x * r1, y * r1, z1);
mi->polygon_count++;
}
glEnd();
}
glPopMatrix();
}
/*
*-----------------------------------------------------------------------------
*-----------------------------------------------------------------------------
* GL funcs.
*-----------------------------------------------------------------------------
*-----------------------------------------------------------------------------
*/
#ifndef STANDALONE
static void Reshape(ModeInfo * mi)
#else
ENTRYPOINT void reshape_sballs(ModeInfo * mi, int width, int height)
#endif
{
sballsstruct *sb = &sballs[MI_SCREEN(mi)];
int size = MI_SIZE(mi);
/* Viewport is specified size if size >= MINSIZE && size < screensize */
if (size <= 1) {
sb->WIDTH = MI_WIDTH(mi);
sb->HEIGHT = MI_HEIGHT(mi);
} else if (size < MINSIZE) {
sb->WIDTH = MINSIZE;
sb->HEIGHT = MINSIZE;
} else {
sb->WIDTH = (size > MI_WIDTH(mi)) ? MI_WIDTH(mi) : size;
sb->HEIGHT = (size > MI_HEIGHT(mi)) ? MI_HEIGHT(mi) : size;
}
if (width > height * 5) { /* tiny window: show middle */
sb->WIDTH = width;
sb->HEIGHT = sb->WIDTH*0.75;
}
glViewport((MI_WIDTH(mi) - sb->WIDTH) / 2, (MI_HEIGHT(mi) - sb->HEIGHT) / 2, sb->WIDTH, sb->HEIGHT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(55.0, (float)sb->WIDTH / (float) sb->HEIGHT, 1.0, 300.0);
glMatrixMode(GL_MODELVIEW);
}
static void Draw(ModeInfo * mi)
{
sballsstruct *sb = &sballs[MI_SCREEN(mi)];
int sphere;
mi->polygon_count = 0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glEnable(GL_DEPTH_TEST);
/* move eyes */
glTranslatef (-sb->eye[0], -sb->eye[1], -sb->eye[2]);
/* draw background */
if (do_texture)
{
glEnable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
glColor3f(1, 1, 1);
#ifdef HAVE_GLBINDTEXTURE
glBindTexture(GL_TEXTURE_2D, sb->backid);
#endif /* HAVE_GLBINDTEXTURE */
}
else
{
glColor3f(0, 0, 0);
}
glBegin(GL_QUAD_STRIP);
#ifndef HAVE_MOBILE
/* Letterbox the background image */
glNormal3f(0, 0, 1); glTexCoord2f(0,0); glVertex3f(8, 4.1, -4);
glNormal3f(0, 0, 1); glTexCoord2f(0,1); glVertex3f(8, -4.1, -4);
glNormal3f(0, 0, 1); glTexCoord2f(1,0); glVertex3f(-8, 4.1, -4);
glNormal3f(0, 0, 1); glTexCoord2f(1,1); glVertex3f(-8, -4.1, -4);
#else
/* Fill the iPhone screen. Letterboxing looks dumb there. */
glNormal3f(0, 0, 1); glTexCoord2f(0,0); glVertex3f(4, 5.2, -4);
glNormal3f(0, 0, 1); glTexCoord2f(0,1); glVertex3f(4, -5.2, -4);
glNormal3f(0, 0, 1); glTexCoord2f(1,0); glVertex3f(-4, 5.2, -4);
glNormal3f(0, 0, 1); glTexCoord2f(1,1); glVertex3f(-4, -5.2, -4);
#endif
glEnd();
mi->polygon_count++;
gltrackball_rotate (sb->trackball);
/* rotate the balls */
glRotatef(sb->rotm[0], 1.0f, 0.0f, 0.0f);
glRotatef(sb->rotm[1], 0.0f, 1.0f, 0.0f);
glRotatef(sb->rotm[2], 0.0f, 0.0f, 1.0f);
if (! sb->button_down_p) {
sb->rotm[0] += sb->speed;
sb->rotm[1] += -(sb->speed);
sb->rotm[2] += 0;
}
/* draw the balls */
if (do_texture)
#ifdef HAVE_GLBINDTEXTURE
glBindTexture(GL_TEXTURE_2D, sb->faceid);
else
#endif /* HAVE_GLBINDTEXTURE */
glEnable(GL_LIGHTING);
for (sphere=0;sphere<spheres;sphere++)
{
drawSphere(mi,sphere);
}
glDisable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
/* manage framerate display */
if (MI_IS_FPS(mi)) do_fps (mi);
glPopMatrix();
}
static void Init(ModeInfo * mi)
{
sballsstruct *sb = &sballs[MI_SCREEN(mi)];
int i;
/* Default settings */
if (MI_IS_WIREFRAME(mi))
do_texture = False;
if (do_texture)
inittextures(mi);
else
{
sb->btexture = (XImage*) NULL;
sb->ftexture = (XImage*) NULL;
}
vinit(sb->eye ,0.0f, 0.0f, 6.0f);
vinit(sb->rotm ,0.0f, 0.0f, 0.0f);
sb->speed = MI_CYCLES(mi);
/* initialise object number */
object = object_arg-1;
if (object < 0 || object >= MAX_OBJ)
object = NRAND(MAX_OBJ);
/* initialise sphere number */
spheres = MI_COUNT(mi);
if (MI_COUNT(mi) > polygons[object].numverts)
spheres = polygons[object].numverts;
if (MI_COUNT(mi) < 1)
spheres = polygons[object].numverts;
/* initialise sphere radius */
for(i=0; i < spheres;i++)
{
#if RANDOM_RADIUS
sb->radius[i] = ((float) LRAND() / (float) MAXRAND);
if (sb->radius[i] < 0.3)
sb->radius[i] = 0.3;
if (sb->radius[i] > 0.7)
sb->radius[i] = 0.7;
#else
sb->radius[i] = polygons[object].radius;
#endif
}
if (MI_IS_DEBUG(mi)) {
(void) fprintf(stderr,
"%s:\n\tobject=%s\n\tspheres=%d\n\tspeed=%d\n\ttexture=%s\n",
MI_NAME(mi),
polygons[object].shortname,
spheres,
(int) MI_CYCLES(mi),
do_texture ? "on" : "off"
);
}
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
glLightfv(GL_LIGHT1, GL_POSITION,LightPosition);
glEnable(GL_LIGHT1);
}
/*
*-----------------------------------------------------------------------------
*-----------------------------------------------------------------------------
* Xlock hooks.
*-----------------------------------------------------------------------------
*-----------------------------------------------------------------------------
*/
/*
*-----------------------------------------------------------------------------
* Initialize sballs. Called each time the window changes.
*-----------------------------------------------------------------------------
*/
ENTRYPOINT void init_sballs(ModeInfo * mi)
{
sballsstruct *sb;
MI_INIT(mi, sballs);
sb = &sballs[MI_SCREEN(mi)];
sb->trackball = gltrackball_init (True);
if ((sb->glx_context = init_GL(mi)) != NULL) {
#ifndef STANDALONE
Reshape(mi); /* xlock mode */
#else
reshape_sballs(mi,MI_WIDTH(mi),MI_HEIGHT(mi)); /* xscreensaver mode */
#endif
glDrawBuffer(GL_BACK);
Init(mi);
} else {
MI_CLEARWINDOW(mi);
}
}
/*
*-----------------------------------------------------------------------------
* Called by the mainline code periodically to update the display.
*-----------------------------------------------------------------------------
*/
ENTRYPOINT void draw_sballs(ModeInfo * mi)
{
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
sballsstruct *sb;
if (sballs == NULL)
return;
sb = &sballs[MI_SCREEN(mi)];
MI_IS_DRAWN(mi) = True;
if (!sb->glx_context)
return;
glXMakeCurrent(display, window, *sb->glx_context);
Draw(mi);
#ifndef STANDALONE
Reshape(mi); /* xlock mode */
#else
reshape_sballs(mi,MI_WIDTH(mi),MI_HEIGHT(mi)); /* xscreensaver mode */
#endif
glFinish();
glXSwapBuffers(display, window);
}
/*
*-----------------------------------------------------------------------------
* The display is being taken away from us. Free up malloc'ed
* memory and X resources that we've alloc'ed.
*-----------------------------------------------------------------------------
*/
ENTRYPOINT void free_sballs(ModeInfo * mi)
{
sballsstruct *sb = &sballs[MI_SCREEN(mi)];
if (!sb->glx_context) return;
glXMakeCurrent (MI_DISPLAY(mi), MI_WINDOW(mi), *sb->glx_context);
gltrackball_free (sb->trackball);
if (sb->btexture)
{
glDeleteTextures(1,&sb->backid);
XDestroyImage(sb->btexture);
sb->btexture = 0;
}
if (sb->ftexture)
{
glDeleteTextures(1,&sb->faceid);
XDestroyImage(sb->ftexture);
sb->ftexture = 0;
}
}
ENTRYPOINT Bool
sballs_handle_event (ModeInfo *mi, XEvent *event)
{
sballsstruct *sb = &sballs[MI_SCREEN(mi)];
if (gltrackball_event_handler (event, sb->trackball,
MI_WIDTH (mi), MI_HEIGHT (mi),
&sb->button_down_p))
return True;
return False;
}
#ifndef STANDALONE
ENTRYPOINT void change_sballs(ModeInfo * mi)
{
sballsstruct *sb;
if (sballs == NULL)
return;
sb = &sballs[MI_SCREEN(mi)];
if (!sb->glx_context)
return;
/* initialise object number */
if ((object == 0) || (object > MAX_OBJ))
object = NRAND(MAX_OBJ-1)+1;
object--;
/* correct sphere number */
spheres = MI_COUNT(mi);
if (MI_COUNT(mi) > polygons[object].numverts)
spheres = polygons[object].numverts;
if (MI_COUNT(mi) < 1)
spheres = polygons[object].numverts;
if (MI_IS_DEBUG(mi)) {
(void) fprintf(stderr,
"%s:\n\tobject=%s\n\tspheres=%d\n\tspeed=%d\n\ttexture=%s\n",
MI_NAME(mi),
polygons[object].shortname,
spheres,
(int) MI_CYCLES(mi),
do_texture ? "on" : "off"
);
}
glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *sb->glx_context);
}
#endif /* !STANDALONE */
XSCREENSAVER_MODULE ("SBalls", sballs)
#endif /* MODE_sballs */