1 /* topblock, Copyright (c) 2006-2009
2 * rednuht <topblock.xscreensaver@jumpstation.co.uk>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
15 topBlock - a simple openGL 3D hack of falling blocks
16 based on jwz's dangerball hack
18 The proporations of the blocks and their features is not even close to the commercial building block products offered by a variety companies.
20 information on this hack might be found at
21 http://www.jumpstation.co.uk/xscreensaver/topblock/
24 25/02/2006 v1.0 release
25 29/04/2006 v1.11 updated to better fit with xscreensaver v5
26 colors defaults to 7 (no black)
27 19/06/2006 v1.2 fixed dropSpeed = 7 bug, added gltrackball support and some code neatening, thanks to Valdis Kletnieks and JWZ for their input.
32 # define refresh_topBlock 0
34 #define DEFAULTS "*delay: 10000 \n" \
36 "*showFPS: False \n" \
37 "*wireframe: False \n" \
40 #define countof(x) (sizeof((x))/sizeof((*x)))
42 #include "xlockmore.h"
45 #include "gltrackball.h"
48 #ifdef USE_GL /* whole file */
51 # include <OpenGL/glu.h>
58 GLXContext *glx_context;
59 trackball_state *trackball;
62 GLfloat highest,highestFalling;
63 GLfloat eyeLine,eyeX,eyeY,eyeZ;
64 int carpetWidth, carpetLength;
66 GLfloat followRadius,followAngle;
70 int carpet_polys, block_polys;
72 NODE *blockNodeFollow;
94 static XrmOptionDescRec opts[] = {
95 { "-size", ".size", XrmoptionSepArg, 0 },
96 { "-spawn", ".spawn", XrmoptionSepArg, 0 },
97 { "-camX", ".camX", XrmoptionSepArg, 0 },
98 { "-camY", ".camY", XrmoptionSepArg, 0 },
99 { "-camZ", ".camZ", XrmoptionSepArg, 0 },
100 { "+rotate", ".rotate", XrmoptionNoArg, "False" },
101 { "-rotate", ".rotate", XrmoptionNoArg, "True" },
102 { "+carpet", ".carpet", XrmoptionNoArg, "False" },
103 { "+nipples", ".nipples", XrmoptionNoArg, "False" },
104 { "-blob", ".blob", XrmoptionNoArg, "True" },
105 { "-rotateSpeed", ".rotateSpeed", XrmoptionSepArg, 0 },
106 { "-follow", ".follow", XrmoptionNoArg, "True" },
107 { "-maxFalling", ".maxFalling", XrmoptionSepArg, 0 },
108 { "-resolution", ".resolution", XrmoptionSepArg, 0 },
109 { "-maxColors", ".maxColors", XrmoptionSepArg, 0 },
110 { "-dropSpeed", ".dropSpeed", XrmoptionSepArg, 0 },
111 { "-override", ".override", XrmoptionNoArg, "True" },
114 #define DEF_OVERRIDE "False"
115 #define DEF_ROTATE "True"
116 #define DEF_FOLLOW "False"
117 #define DEF_CARPET "True"
118 #define DEF_BLOB "False"
119 #define DEF_NIPPLES "True"
120 #define DEF_ROTATE_SPEED "10"
121 #define DEF_MAX_FALLING "500"
122 #define DEF_MAX_COLORS "7"
124 #define DEF_SPAWN "50"
125 #define DEF_RESOLUTION "4"
126 #define DEF_CAM_X "1"
127 #define DEF_CAM_Y "20"
128 #define DEF_CAM_Z "25"
129 #define DEF_DROP_SPEED "4"
131 static argtype vars[] = {
132 {&override, "override", "Override", DEF_OVERRIDE, t_Bool},
133 {&rotate, "rotate", "Rotate", DEF_ROTATE, t_Bool},
134 {&drawCarpet, "carpet", "Carpet", DEF_CARPET, t_Bool},
135 {&drawNipples, "nipples", "Nipples", DEF_NIPPLES, t_Bool},
136 {&drawBlob, "blob", "Blob", DEF_BLOB, t_Bool},
137 {&rotateSpeed, "rotateSpeed", "RotateSpeed", DEF_ROTATE_SPEED, t_Float},
138 {&follow, "follow", "Follow", DEF_FOLLOW, t_Bool},
139 {&camX, "camX", "camX", DEF_CAM_X, t_Float},
140 {&camY, "camY", "camY", DEF_CAM_Y, t_Float},
141 {&camZ, "camZ", "camZ", DEF_CAM_Z, t_Float},
142 {&size, "size", "size", DEF_SIZE, t_Int},
143 {&spawn, "spawn", "spawn", DEF_SPAWN, t_Int},
144 {&maxFalling, "maxFalling", "maxFalling", DEF_MAX_FALLING, t_Int},
145 {&resolution, "resolution", "resolution", DEF_RESOLUTION, t_Int},
146 {&maxColors, "maxColors", "maxColors", DEF_MAX_COLORS, t_Int},
147 {&dropSpeed, "dropSpeed", "DropSpeed", DEF_DROP_SPEED, t_Float},
150 static topBlockSTATE *tbs = NULL;
152 ModeSpecOpt topBlock_opts = {countof(opts), opts, countof(vars), vars, NULL};
154 /* Window management, etc */
156 reshape_topBlock (ModeInfo *mi, int width, int height)
158 GLfloat h = (GLfloat) height / (GLfloat) width;
159 glViewport (0, 0, (GLint) width, (GLint) height);
160 glMatrixMode(GL_PROJECTION);
162 gluPerspective (60.0, 1/h, 1.0, 1000.0);
163 glMatrixMode(GL_MODELVIEW);
165 glClear(GL_COLOR_BUFFER_BIT);
168 /* clean up on exit, not required ... */
170 release_topBlock(ModeInfo *mi)
172 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
173 NODE *llCurrent, *llOld;
174 llCurrent = tb->blockNodeRoot;
175 while (llCurrent != NULL) {
177 llCurrent = llCurrent->next;
184 init_topBlock (ModeInfo *mi)
187 int wire = MI_IS_WIREFRAME(mi);
190 tbs = (topBlockSTATE *)
191 calloc (MI_NUM_SCREENS(mi), sizeof (topBlockSTATE));
195 tb = &tbs[MI_SCREEN(mi)];
197 tb->glx_context = init_GL(mi);
199 reshape_topBlock (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
201 if (wire) { drawNipples=False; }
202 tb->numFallingBlocks=0;
204 if (size>10) { size = 10; }
205 if (size<1) { size = 2; }
206 tb->carpetWidth = 8 * size;
207 tb->carpetLength = tb->carpetWidth;
211 if (spawn<4) { spawn=4; }
212 if (spawn>1000) { spawn=1000; }
214 if (rotateSpeed<1) {rotateSpeed=1; }
215 if (rotateSpeed>1000) {rotateSpeed=1000;}
218 if (resolution<4) {resolution=4;}
219 if (resolution>20) {resolution=20;}
222 if (maxColors<1) {maxColors=1;}
223 if (maxColors>8) {maxColors=8;}
225 if (dropSpeed<1) {dropSpeed=1;}
226 if (dropSpeed>9) {dropSpeed=9;} /* 10+ produces blocks that can pass through each other */
228 dropSpeed = 80/dropSpeed;
229 dropSpeed = (blockHeight/dropSpeed);
231 reshape_topBlock (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
234 GLfloat pos[4] = {10.0, 10.0, 1.0, 0.0};
235 GLfloat amb[4] = {0.1, 0.1, 0.1, 1.0};
236 GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
237 GLfloat spc[4] = {0.0, 1.0, 1.0, 1.0};
239 glEnable(GL_LIGHTING);
241 glLightfv(GL_LIGHT0, GL_POSITION, pos);
242 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
243 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
244 glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
246 glDepthFunc(GL_LEQUAL);
247 glEnable(GL_DEPTH_TEST);
248 glDisable(GL_CULL_FACE); /* all objects exhibit a reverse side */
254 buildBlock(mi); /* build the display list holding the simple block */
256 buildCarpet(mi); /* build the base */
258 tb->highestFalling=0;
259 tb->eyeLine=tb->highest;
268 tb->rotation=random() % 360;
273 /* override camera settings */
284 tb->trackball = gltrackball_init ();
287 /* provides the per frame entertainment */
289 draw_topBlock (ModeInfo *mi)
291 Display *dpy = MI_DISPLAY(mi);
292 Window window = MI_WINDOW(mi);
295 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
296 GLfloat spcN1x,spcN1y,spcN2x,spcN2y;
297 GLfloat spcC1x,spcC1y,spcC2x,spcC2y;
298 int wire = MI_IS_WIREFRAME(mi);
301 if (!tb->glx_context)
303 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(tb->glx_context));
304 mi->polygon_count = 0;
306 generateNewBlock(mi);
308 if (rotate && (!tb->button_down_p)) { tb->rotation += rotateSpeed; }
309 if (tb->rotation>=360) { tb->rotation=tb->rotation-360; }
311 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* clear current */
312 glLoadIdentity(); /* resets directions, do it every time ! */
314 if (tb->highest>tb->eyeLine) { tb->eyeLine+=((tb->highest-tb->eyeLine)/100); } /* creates a smooth camera transition */
315 gluLookAt(camX, camY+tb->eyeLine, camZ, tb->eyeX, tb->eyeY+tb->eyeLine, tb->eyeZ, 0.0, 1.0, 0.0); /* setup viewer, xyz cam, xyz looking at and where is up normaly 0,1,0 */
316 glRotatef(90, 1.0, 0.0, 0.0); /* x axis */
318 glRotatef(90, 0.0, 0.0, 1.0); /* z axis */
321 glRotatef(-90, 1.0, 0.0, 0.0);
322 gltrackball_rotate (tb->trackball);
323 glRotatef(90, 1.0, 0.0, 0.0);
325 /* rotate the world */
326 glRotatef(tb->rotation, 0.0, 0.0, 1.0);
328 llCurrent = tb->blockNodeRoot;
331 glTranslatef(0.0-(tb->carpetWidth/2),0.0-(tb->carpetLength/2),0.0);
332 glCallList(tb->carpet);
333 mi->polygon_count += tb->carpet_polys;
334 glTranslatef(0.0+(tb->carpetWidth/2),0.0+(tb->carpetLength/2),0.0);
335 glTranslatef(0.0,0.0,-0.55);
337 tb->highestFalling=0;
338 while (llCurrent != NULL) { /* for each block */
339 glPushMatrix(); /* save state */
341 switch (llCurrent->color) {
391 if (wire) { glColor3fv(color); }
392 else { glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); }
394 if (llCurrent->falling==1) {
399 if (llCurrent->height>tb->highestFalling) {tb->highestFalling=llCurrent->height;}
400 /* all blocks fall at the same rate to avoid mid air collisions */
401 llCurrent->height-=dropSpeed;
402 if (llCurrent->height<=0) {
403 llCurrent->falling=0;
404 if (tb->highest==0) {
405 tb->highest+=blockHeight;
408 if ( (llCurrent->height<=tb->highest+1) && (llCurrent->falling==1) ) {
409 /* check for collision */
410 llNode = tb->blockNodeRoot;
411 spcC1x = llCurrent->x;
412 spcC1y = llCurrent->y;
413 switch(llCurrent->rotation) {
414 case getOrientation(0):
418 case getOrientation(1):
422 case getOrientation(2):
426 case getOrientation(3):
431 while (llNode != NULL) {
432 if ( (llNode->falling==0) && (llCurrent->falling==1) ) {
435 switch(llNode->rotation) {
436 case getOrientation(0):
440 case getOrientation(1):
444 case getOrientation(2):
448 case getOrientation(3):
454 ( (spcC1x==spcN1x) && (spcC1y==spcN1y) ) ||
455 ( (spcC1x==spcN2x) && (spcC1y==spcN2y) ) ||
456 ( (spcC2x==spcN2x) && (spcC2y==spcN2y) ) ||
457 ( (spcC2x==spcN1x) && (spcC2y==spcN1y) )
459 if ( fabs(llCurrent->height-(llNode->height+blockHeight)) <= TOLERANCE) {
461 llCurrent->falling=0;
462 llCurrent->height=llNode->height+blockHeight; /* if this is missing then small errors build up until the model fails */
463 if ( fabs(llCurrent->height-tb->highest) <= TOLERANCE+blockHeight ) {
464 tb->highest+=blockHeight;
473 /* set location in space */
474 glTranslatef(llCurrent->x,llCurrent->y,-llCurrent->height);
476 glRotatef(llCurrent->rotation, 0.0f, 0.0f, 1.0f);
477 if ((tb->followMode==0) && (llCurrent->next==NULL)) {
478 tb->blockNodeFollow = llCurrent;
481 llCurrent = llCurrent->next;
483 glCallList(tb->block);
484 mi->polygon_count += tb->block_polys;
485 glPopMatrix(); /* restore state */
487 if (mi->fps_p) do_fps (mi);
490 if (tb->highest>(5*maxFalling)) { drawCarpet=False; }
491 glXSwapBuffers(dpy, window);
496 /* camera is in follow mode, work out where we should be looking */
497 static void followBlock(ModeInfo *mi)
499 GLfloat xLen,yLen,cx,cy,rangle,xTarget,yTarget;
500 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
502 if ((tb->blockNodeFollow!=NULL) && (tb->followMode==1)){
504 if (tb->highest>tb->eyeLine) { tb->eyeLine+= ((tb->highest-tb->eyeLine)/100); }
505 /*tb->blockNodeFollow->color=1; only noticable if you set the colors to 1 */
507 if (tb->blockNodeFollow->height > tb->eyeZ) { tb->eyeZ+= ((tb->blockNodeFollow->height - tb->eyeZ)/100); }
508 if (tb->blockNodeFollow->height < tb->eyeZ) { tb->eyeZ-= ((tb->eyeZ - tb->blockNodeFollow->height)/100); }
511 /* when the scene is rotated we need to know where the block is in the 2 dimensional coordinates of the carpet area
512 (see http://www.jumpstation.co.uk/rotation/)
515 if (tb->followRadius==0) {
516 xLen = tb->blockNodeFollow->x-cx;
517 yLen = tb->blockNodeFollow->y-cy;
518 tb->followRadius=sqrt( (xLen*xLen) + (yLen*yLen) );
519 tb->followAngle = (180/M_PI) * asin(xLen/tb->followRadius);
520 tb->followAngle = quadrantCorrection(tb->followAngle,(int)cx,(int)cy,(int)tb->blockNodeFollow->x,(int)tb->blockNodeFollow->y);
522 rangle = (tb->followAngle+tb->rotation) * M_PI /180;
523 xTarget = cos(rangle) * tb->followRadius + cx;
524 yTarget = sin(rangle) * tb->followRadius + cy;
525 if (tb->followAngle>360) { tb->followAngle=tb->followAngle-360; }
527 if (xTarget < tb->eyeX) { tb->eyeX-= ((tb->eyeX - xTarget)/100); }
528 if (xTarget > tb->eyeX) { tb->eyeX+= ((xTarget - tb->eyeX)/100); }
530 if (yTarget < tb->eyeY) { tb->eyeY-= ((tb->eyeY - yTarget)/100); }
531 if (yTarget > tb->eyeY) { tb->eyeY+= ((yTarget - tb->eyeY)/100); }
532 if (!tb->blockNodeFollow->falling) {
534 /*tb->blockNodeFollow->color=2; only noticable if you set the colors to 1 */
538 gluLookAt(camX, camY, camZ-tb->eyeLine, tb->eyeX, tb->eyeY, -tb->eyeZ,-1.0,0.0,0.0);
541 /* each quater of the circle has to be adjusted for */
542 static double quadrantCorrection(double angle,int cx,int cy,int x,int y)
544 if ((x>=cx) && (y>=cy)) {
545 angle += (90-(angle-90) * 2);
546 } else if ((x>=cx) && (y<=cy)) {
548 } else if ((x<=cx) && (y<=cy)) {
550 } else if ((x<=cx) && (y>=cy)) {
551 angle += (90-(angle-90) * 2);
556 /* if random chance then create a new falling block */
557 static void generateNewBlock(ModeInfo *mi)
559 NODE *llCurrent, *llTail;
560 GLfloat startOffx, startOffy;
561 int endOffx, endOffy;
562 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
563 if ( ((random() % spawn) == 1) && (tb->highestFalling<getHeight((tb->plusheight-blockHeight)+tb->highest)) ) {
568 tb->numFallingBlocks++;
569 llTail = tb->blockNodeRoot;
570 if (llTail == NULL) {
571 llCurrent = ((NODE*) malloc(sizeof(NODE)));
572 if (!llCurrent) abort();
574 tb->blockNodeRoot = llCurrent;
576 if (tb->numFallingBlocks>=maxFalling) {
578 llCurrent=llTail->next;
579 tb->blockNodeRoot=llCurrent->next;
581 llCurrent = ((NODE*) malloc(sizeof(NODE)));
582 if (!llCurrent) abort();
584 while (llTail->next != NULL) { llTail = llTail->next; } /* find last item in list */
586 llCurrent->falling=1;
587 llCurrent->rotation=getOrientation(random() % 4);
588 if (llCurrent->rotation==getOrientation(0)) {
593 } else if (llCurrent->rotation==getOrientation(1)) {
598 } else if (llCurrent->rotation==getOrientation(2)) {
603 } else if (llCurrent->rotation==getOrientation(3)) {
610 llCurrent->x=(startOffx-(tb->carpetLength/2)) + getLocation(random() % ((tb->carpetLength/2)+endOffx) );
611 llCurrent->y=(startOffy-(tb->carpetLength/2)) + getLocation(random() % ((tb->carpetLength/2)+endOffy) );
612 llCurrent->color=(random() % maxColors);
613 llCurrent->height=getHeight(tb->plusheight+tb->highest);
614 if (tb->numFallingBlocks>=maxFalling) {
615 tb->numFallingBlocks--;
616 tb->numFallingBlocks--;
618 llTail->next = llCurrent;
625 /* called at init this creates the 'carpet' display list item */
626 static void buildCarpet(ModeInfo *mi)
630 int wire = MI_IS_WIREFRAME(mi);
631 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
632 GLUquadricObj *quadratic;
637 tb->carpet=glGenLists(1); /* only one */
638 glNewList(tb->carpet,GL_COMPILE);
640 glPushMatrix(); /* save state */
643 if (wire) { glColor3fv(color); }
644 else { glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); }
645 /* draw carpet plane */
646 glBegin( wire ? GL_LINE_LOOP : GL_QUADS );
648 glNormal3f( 0, 0, -1 );
649 glVertex3f(0.0,0.0,0.0);
650 glVertex3f(x,0.0,0.0);
652 glVertex3f(0.0,y,0.0);
654 if (wire) { glEnd(); }
656 /* add edge pieces */
658 glNormal3f( 0, -1, 0 );
659 glVertex3f(0.0,0.0,0.0);
660 glVertex3f(x,0.0,0.0);
661 glVertex3f(x,0,singleThick);
662 glVertex3f(0.0,0,singleThick);
665 glNormal3f( -1, 0, 0 );
666 glVertex3f(0.0,0.0,0.0);
668 glVertex3f(0,y,singleThick);
669 glVertex3f(0.0,0,singleThick);
672 glNormal3f( 1, 0, 0 );
673 glVertex3f(x,0.0,0.0);
675 glVertex3f(x,y,singleThick);
676 glVertex3f(x,0,singleThick);
679 glNormal3f( 0, 1, 0 );
682 glVertex3f(x,y,singleThick);
683 glVertex3f(0,y,singleThick);
689 quadratic=gluNewQuadric(); /* Create A Pointer To The Quadric Object */
690 gluQuadricNormals(quadratic, GLU_SMOOTH); /* Create Smooth Normals */
691 gluQuadricTexture(quadratic, GL_TRUE); /* Create Texture Coords */
692 glTranslatef(0.5f,0.5f,-.25); /* move to the cylinder center */
694 glPushMatrix(); /* save state */
696 gluCylinder(quadratic, cylSize, cylSize, 0.25f, resolution, resolution); /* quad, radius(bottom, radius(top), height, subdivisions (around Z), subdevisions (along Z) */
697 tb->carpet_polys += resolution*resolution;
698 glRotatef(180, 0.0f, 1.0f, 0.0f); /* they are upside down */
699 gluDisk(quadratic, 0.0f, cylSize, resolution, resolution ); /* inner size (cd hole), outer size (radius), subdivisions radial, subdivisions circular */
700 tb->carpet_polys += resolution*resolution;
701 glRotatef(180, 0.0f, 1.0f, 0.0f); /* recover */
702 glTranslatef(0.0f,1.0f,0.0f); /* move to the next cylinder center (backward) */
704 glPopMatrix(); /* save state */
705 glTranslatef(1.0f,0.0f,0.0f); /* reset */
708 glPopMatrix(); /* restore state */
712 /* using the verticies arrays builds the plane, now with normals */
713 static void polygonPlane(int wire, int a, int b, int c , int d, int i)
715 GLfloat topBlockNormals[5][3] = { {0,0,-1}, {0,1,0}, {1,0,0}, {0,0,1}, {0,-1,0} };
716 GLfloat topBlockVertices[8][3] = { {-0.49,-2.97,-0.99}, {0.99,-2.97,-0.99}, {0.99,0.99,-0.99} , {-0.49,0.99,-0.99}, {-0.49,-2.97,0.99} , {0.99,-2.97,0.99}, {0.99,0.99,0.99} , {-0.49,0.99,0.99} };
717 glBegin( wire ? GL_LINE_LOOP : GL_POLYGON);
718 glNormal3fv(topBlockNormals[i] );
719 glVertex3fv(topBlockVertices[a]);
720 glVertex3fv(topBlockVertices[b]);
721 glVertex3fv(topBlockVertices[c]);
722 glVertex3fv(topBlockVertices[d]);
726 /* called at init this creates the 'block' display list item */
727 /* the spheres came about originaly as quick way to test the directional lighting/normals */
728 static void buildBlock(ModeInfo *mi)
731 int wire = MI_IS_WIREFRAME(mi);
732 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
733 GLUquadricObj *quadratic;
734 tb->block=glGenLists(1); /* only one */
735 glNewList(tb->block,GL_COMPILE);
737 glPushMatrix(); /* save state */
738 glRotatef(90, 0.0f, 1.0f, 0.0f);
740 polygonPlane(wire, 0,3,2,1,0); tb->block_polys++;
741 polygonPlane(wire, 2,3,7,6,1); tb->block_polys++;
742 polygonPlane(wire, 1,2,6,5,2); tb->block_polys++;
743 polygonPlane(wire, 4,5,6,7,3); tb->block_polys++;
744 polygonPlane(wire, 0,1,5,4,4); tb->block_polys++;
747 /* draw 8 cylinders each with a disk cap */
748 quadratic=gluNewQuadric(); /* Create A Pointer To The Quadric Object */
749 gluQuadricNormals(quadratic, GLU_SMOOTH); /* Create Smooth Normals */
750 glRotatef(90, 0.0f, 1.0f, 0.0f); /* 'aim' the pointer ready for the cylinder */
751 glTranslatef(0.5f,0.5f,0.99f); /* move to the cylinder center */
754 gluCylinder(quadratic, cylSize, cylSize, 0.25f, resolution, resolution); /* quad, radius(bottom, radius(top), height, subdivisions (around Z), subdevisions (along Z) */
755 tb->block_polys += resolution*resolution;
756 glTranslatef(0.0f,0.0f,0.25f); /* move to the cylinder cap */
757 gluDisk(quadratic, 0.0f, cylSize, resolution, resolution ); /* inner size (cd hole), outer size (radius), subdivisions radial, subdivisions circular */
758 tb->block_polys += resolution*resolution;
759 glTranslatef(0.0f,0.0f,-0.25f); /* move back from the cylinder cap */
761 glTranslatef(0.0f,-1.0f,0.0f); /* move to the next cylinder center (forward) */
763 glTranslatef(0.0f,1.0f,0.0f); /* move to the next cylinder center (backward) */
766 glTranslatef(-1.0f,1.0f,0.0f); /* move to the cylinder center */
769 /* 3 cylinders on the underside */
770 glTranslatef(1.5f,-2.5f,-1.5f); /* move to the center, under the top of the brick */
772 gluCylinder(quadratic, uddSize, uddSize, 1.5f, resolution, resolution); /* quad, radius(bottom, radius(top), height, subdivisions (around Z), subdevisions (along Z) */
773 tb->block_polys += resolution*resolution;
774 glTranslatef(0.0f,-1.0f,0.0f); /* move to the center */
777 glPopMatrix(); /* restore state */
782 rip off of the builBlock() function creating the GL compilied pointer "block" but only creates two spheres.
783 spheres are created with unit_sphere from spheres.h to allow wire frame
785 static void buildBlobBlock(ModeInfo *mi)
787 int wire = MI_IS_WIREFRAME(mi);
788 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
789 tb->block=glGenLists(1); /* only one */
790 glNewList(tb->block,GL_COMPILE);
792 glScalef(1.4,1.4,1.4);
793 unit_sphere (resolution/2,resolution, wire);
795 glTranslatef(0.0f,-2.0f,0.0f);
796 glScalef(1.4,1.4,1.4);
797 unit_sphere (resolution/2,resolution, wire);
802 /* handle input events or not if daemon running the show */
804 topBlock_handle_event (ModeInfo *mi, XEvent *event)
806 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
807 if (event->xany.type == KeyPress) {
810 XLookupString (&event->xkey, &c, 1, &keysym, 0);
814 } else if (c == 'z') {
817 } else if (c == 's') {
820 } else if (c == 'x') {
823 } else if (c == 'd') {
826 } else if (c == 'c') {
829 } else if (c == 'f') {
832 } else if (c == 'v') {
835 } else if (c == 'g') {
838 } else if (c == 'b') {
841 } else if (c == 'h') {
844 } else if (c == 'n') {
847 } else if (c == 'r') {
852 if (event->xany.type == ButtonPress &&
853 event->xbutton.button == Button1)
855 tb->button_down_p = True;
856 gltrackball_start (tb->trackball,
857 event->xbutton.x, event->xbutton.y,
858 MI_WIDTH (mi), MI_HEIGHT (mi));
861 else if (event->xany.type == ButtonRelease &&
862 event->xbutton.button == Button1)
864 tb->button_down_p = False;
867 else if (event->xany.type == ButtonPress &&
868 (event->xbutton.button == Button4 ||
869 event->xbutton.button == Button5 ||
870 event->xbutton.button == Button6 ||
871 event->xbutton.button == Button7))
873 gltrackball_mousewheel (tb->trackball, event->xbutton.button, 10,
874 !!event->xbutton.state);
877 else if (event->xany.type == MotionNotify &&
880 gltrackball_track (tb->trackball,
881 event->xmotion.x, event->xmotion.y,
882 MI_WIDTH (mi), MI_HEIGHT (mi));
888 /* this is tha main change for v5 compatability and acompanying ENTRYPOINTS */
889 XSCREENSAVER_MODULE_2 ("TopBlock", topblock, topBlock)