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));
193 fprintf(stderr, "%s: out of memory\n", progname);
198 tb = &tbs[MI_SCREEN(mi)];
200 tb->glx_context = init_GL(mi);
202 reshape_topBlock (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
204 if (wire) { drawNipples=False; }
205 tb->numFallingBlocks=0;
207 if (size>10) { size = 10; }
208 if (size<1) { size = 2; }
209 tb->carpetWidth = 8 * size;
210 tb->carpetLength = tb->carpetWidth;
214 if (spawn<4) { spawn=4; }
215 if (spawn>1000) { spawn=1000; }
217 if (rotateSpeed<1) {rotateSpeed=1; }
218 if (rotateSpeed>1000) {rotateSpeed=1000;}
221 if (resolution<4) {resolution=4;}
222 if (resolution>20) {resolution=20;}
225 if (maxColors<1) {maxColors=1;}
226 if (maxColors>8) {maxColors=8;}
228 if (dropSpeed<1) {dropSpeed=1;}
229 if (dropSpeed>9) {dropSpeed=9;} /* 10+ produces blocks that can pass through each other */
231 dropSpeed = 80/dropSpeed;
232 dropSpeed = (blockHeight/dropSpeed);
234 reshape_topBlock (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
236 glClearColor(1.0f, 1.0f, 1.0f, 0.5f);
238 glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
242 GLfloat pos[4] = {10.0, 10.0, 1.0, 0.0};
243 GLfloat amb[4] = {0.1, 0.1, 0.1, 1.0};
244 GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
245 GLfloat spc[4] = {0.0, 1.0, 1.0, 1.0};
247 glEnable(GL_LIGHTING);
249 glLightfv(GL_LIGHT0, GL_POSITION, pos);
250 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
251 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
252 glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
254 glDepthFunc(GL_LEQUAL);
255 glEnable(GL_DEPTH_TEST);
256 glDisable(GL_CULL_FACE); /* all objects exhibit a reverse side */
262 buildBlock(mi); /* build the display list holding the simple block */
264 buildCarpet(mi); /* build the base */
266 tb->highestFalling=0;
267 tb->eyeLine=tb->highest;
276 tb->rotation=random() % 360;
281 /* override camera settings */
292 tb->trackball = gltrackball_init ();
295 /* provides the per frame entertainment */
297 draw_topBlock (ModeInfo *mi)
299 Display *dpy = MI_DISPLAY(mi);
300 Window window = MI_WINDOW(mi);
303 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
304 GLfloat spcN1x,spcN1y,spcN2x,spcN2y;
305 GLfloat spcC1x,spcC1y,spcC2x,spcC2y;
306 int wire = MI_IS_WIREFRAME(mi);
309 if (!tb->glx_context)
311 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(tb->glx_context));
312 mi->polygon_count = 0;
314 generateNewBlock(mi);
316 if (rotate && (!tb->button_down_p)) { tb->rotation += rotateSpeed; }
317 if (tb->rotation>=360) { tb->rotation=tb->rotation-360; }
319 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* clear current */
320 glLoadIdentity(); /* resets directions, do it every time ! */
322 if (tb->highest>tb->eyeLine) { tb->eyeLine+=((tb->highest-tb->eyeLine)/100); } /* creates a smooth camera transition */
323 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 */
324 glRotatef(90, 1.0, 0.0, 0.0); /* x axis */
326 glRotatef(90, 0.0, 0.0, 1.0); /* z axis */
329 glRotatef(-90, 1.0, 0.0, 0.0);
330 gltrackball_rotate (tb->trackball);
331 glRotatef(90, 1.0, 0.0, 0.0);
333 /* rotate the world */
334 glRotatef(tb->rotation, 0.0, 0.0, 1.0);
336 llCurrent = tb->blockNodeRoot;
339 glTranslatef(0.0-(tb->carpetWidth/2),0.0-(tb->carpetLength/2),0.0);
340 glCallList(tb->carpet);
341 mi->polygon_count += tb->carpet_polys;
342 glTranslatef(0.0+(tb->carpetWidth/2),0.0+(tb->carpetLength/2),0.0);
343 glTranslatef(0.0,0.0,-0.55);
345 tb->highestFalling=0;
346 while (llCurrent != NULL) { /* for each block */
347 glPushMatrix(); /* save state */
349 switch (llCurrent->color) {
399 if (wire) { glColor3fv(color); }
400 else { glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); }
402 if (llCurrent->falling==1) {
407 if (llCurrent->height>tb->highestFalling) {tb->highestFalling=llCurrent->height;}
408 /* all blocks fall at the same rate to avoid mid air collisions */
409 llCurrent->height-=dropSpeed;
410 if (llCurrent->height<=0) {
411 llCurrent->falling=0;
412 if (tb->highest==0) {
413 tb->highest+=blockHeight;
416 if ( (llCurrent->height<=tb->highest+1) && (llCurrent->falling==1) ) {
417 /* check for collision */
418 llNode = tb->blockNodeRoot;
419 spcC1x = llCurrent->x;
420 spcC1y = llCurrent->y;
421 switch(llCurrent->rotation) {
422 case getOrientation(0):
426 case getOrientation(1):
430 case getOrientation(2):
434 case getOrientation(3):
439 while (llNode != NULL) {
440 if ( (llNode->falling==0) && (llCurrent->falling==1) ) {
443 switch(llNode->rotation) {
444 case getOrientation(0):
448 case getOrientation(1):
452 case getOrientation(2):
456 case getOrientation(3):
462 ( (spcC1x==spcN1x) && (spcC1y==spcN1y) ) ||
463 ( (spcC1x==spcN2x) && (spcC1y==spcN2y) ) ||
464 ( (spcC2x==spcN2x) && (spcC2y==spcN2y) ) ||
465 ( (spcC2x==spcN1x) && (spcC2y==spcN1y) )
467 if ( fabs(llCurrent->height-(llNode->height+blockHeight)) <= TOLERANCE) {
469 llCurrent->falling=0;
470 llCurrent->height=llNode->height+blockHeight; /* if this is missing then small errors build up until the model fails */
471 if ( fabs(llCurrent->height-tb->highest) <= TOLERANCE+blockHeight ) {
472 tb->highest+=blockHeight;
481 /* set location in space */
482 glTranslatef(llCurrent->x,llCurrent->y,-llCurrent->height);
484 glRotatef(llCurrent->rotation, 0.0f, 0.0f, 1.0f);
485 if ((tb->followMode==0) && (llCurrent->next==NULL)) {
486 tb->blockNodeFollow = llCurrent;
489 llCurrent = llCurrent->next;
491 glCallList(tb->block);
492 mi->polygon_count += tb->block_polys;
493 glPopMatrix(); /* restore state */
495 if (mi->fps_p) do_fps (mi);
498 if (tb->highest>(5*maxFalling)) { drawCarpet=False; }
499 glXSwapBuffers(dpy, window);
504 /* camera is in follow mode, work out where we should be looking */
505 static void followBlock(ModeInfo *mi)
507 GLfloat xLen,yLen,cx,cy,rangle,xTarget,yTarget;
508 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
510 if ((tb->blockNodeFollow!=NULL) && (tb->followMode==1)){
512 if (tb->highest>tb->eyeLine) { tb->eyeLine+= ((tb->highest-tb->eyeLine)/100); }
513 /*tb->blockNodeFollow->color=1; only noticable if you set the colors to 1 */
515 if (tb->blockNodeFollow->height > tb->eyeZ) { tb->eyeZ+= ((tb->blockNodeFollow->height - tb->eyeZ)/100); }
516 if (tb->blockNodeFollow->height < tb->eyeZ) { tb->eyeZ-= ((tb->eyeZ - tb->blockNodeFollow->height)/100); }
519 /* when the scene is rotated we need to know where the block is in the 2 dimensional coordinates of the carpet area
520 (see http://www.jumpstation.co.uk/rotation/)
523 if (tb->followRadius==0) {
524 xLen = tb->blockNodeFollow->x-cx;
525 yLen = tb->blockNodeFollow->y-cy;
526 tb->followRadius=sqrt( (xLen*xLen) + (yLen*yLen) );
527 tb->followAngle = (180/M_PI) * asin(xLen/tb->followRadius);
528 tb->followAngle = quadrantCorrection(tb->followAngle,(int)cx,(int)cy,(int)tb->blockNodeFollow->x,(int)tb->blockNodeFollow->y);
530 rangle = (tb->followAngle+tb->rotation) * M_PI /180;
531 xTarget = cos(rangle) * tb->followRadius + cx;
532 yTarget = sin(rangle) * tb->followRadius + cy;
533 if (tb->followAngle>360) { tb->followAngle=tb->followAngle-360; }
535 if (xTarget < tb->eyeX) { tb->eyeX-= ((tb->eyeX - xTarget)/100); }
536 if (xTarget > tb->eyeX) { tb->eyeX+= ((xTarget - tb->eyeX)/100); }
538 if (yTarget < tb->eyeY) { tb->eyeY-= ((tb->eyeY - yTarget)/100); }
539 if (yTarget > tb->eyeY) { tb->eyeY+= ((yTarget - tb->eyeY)/100); }
540 if (!tb->blockNodeFollow->falling) {
542 /*tb->blockNodeFollow->color=2; only noticable if you set the colors to 1 */
546 gluLookAt(camX, camY, camZ-tb->eyeLine, tb->eyeX, tb->eyeY, -tb->eyeZ,-1.0,0.0,0.0);
549 /* each quater of the circle has to be adjusted for */
550 static double quadrantCorrection(double angle,int cx,int cy,int x,int y)
552 if ((x>=cx) && (y>=cy)) {
553 angle += (90-(angle-90) * 2);
554 } else if ((x>=cx) && (y<=cy)) {
556 } else if ((x<=cx) && (y<=cy)) {
558 } else if ((x<=cx) && (y>=cy)) {
559 angle += (90-(angle-90) * 2);
564 /* if random chance then create a new falling block */
565 static void generateNewBlock(ModeInfo *mi)
567 NODE *llCurrent, *llTail;
568 GLfloat startOffx, startOffy;
569 int endOffx, endOffy;
570 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
571 if ( ((random() % spawn) == 1) && (tb->highestFalling<getHeight((tb->plusheight-blockHeight)+tb->highest)) ) {
576 tb->numFallingBlocks++;
577 llTail = tb->blockNodeRoot;
578 if (llTail == NULL) {
579 if ((llCurrent = ((NODE*) malloc(sizeof(NODE)))) == NULL) { fprintf(stderr, "%s: out of memory.\n", progname); }
581 tb->blockNodeRoot = llCurrent;
583 if (tb->numFallingBlocks>=maxFalling) {
585 llCurrent=llTail->next;
586 tb->blockNodeRoot=llCurrent->next;
588 if ((llCurrent = ((NODE*) malloc(sizeof(NODE)))) == NULL) { fprintf(stderr, "%s: out of memory..\n", progname); }
590 while (llTail->next != NULL) { llTail = llTail->next; } /* find last item in list */
592 llCurrent->falling=1;
593 llCurrent->rotation=getOrientation(random() % 4);
594 if (llCurrent->rotation==getOrientation(0)) {
599 } else if (llCurrent->rotation==getOrientation(1)) {
604 } else if (llCurrent->rotation==getOrientation(2)) {
609 } else if (llCurrent->rotation==getOrientation(3)) {
616 llCurrent->x=(startOffx-(tb->carpetLength/2)) + getLocation(random() % ((tb->carpetLength/2)+endOffx) );
617 llCurrent->y=(startOffy-(tb->carpetLength/2)) + getLocation(random() % ((tb->carpetLength/2)+endOffy) );
618 llCurrent->color=(random() % maxColors);
619 llCurrent->height=getHeight(tb->plusheight+tb->highest);
620 if (tb->numFallingBlocks>=maxFalling) {
621 tb->numFallingBlocks--;
622 tb->numFallingBlocks--;
624 llTail->next = llCurrent;
631 /* called at init this creates the 'carpet' display list item */
632 static void buildCarpet(ModeInfo *mi)
636 int wire = MI_IS_WIREFRAME(mi);
637 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
638 GLUquadricObj *quadratic;
643 tb->carpet=glGenLists(1); /* only one */
644 glNewList(tb->carpet,GL_COMPILE);
646 glPushMatrix(); /* save state */
649 if (wire) { glColor3fv(color); }
650 else { glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); }
651 /* draw carpet plane */
652 glBegin( wire ? GL_LINE_LOOP : GL_QUADS );
654 glNormal3f( 0, 0, -1 );
655 glVertex3f(0.0,0.0,0.0);
656 glVertex3f(x,0.0,0.0);
658 glVertex3f(0.0,y,0.0);
660 if (wire) { glEnd(); }
662 /* add edge pieces */
664 glNormal3f( 0, -1, 0 );
665 glVertex3f(0.0,0.0,0.0);
666 glVertex3f(x,0.0,0.0);
667 glVertex3f(x,0,singleThick);
668 glVertex3f(0.0,0,singleThick);
671 glNormal3f( -1, 0, 0 );
672 glVertex3f(0.0,0.0,0.0);
674 glVertex3f(0,y,singleThick);
675 glVertex3f(0.0,0,singleThick);
678 glNormal3f( 1, 0, 0 );
679 glVertex3f(x,0.0,0.0);
681 glVertex3f(x,y,singleThick);
682 glVertex3f(x,0,singleThick);
685 glNormal3f( 0, 1, 0 );
688 glVertex3f(x,y,singleThick);
689 glVertex3f(0,y,singleThick);
695 quadratic=gluNewQuadric(); /* Create A Pointer To The Quadric Object */
696 gluQuadricNormals(quadratic, GLU_SMOOTH); /* Create Smooth Normals */
697 gluQuadricTexture(quadratic, GL_TRUE); /* Create Texture Coords */
698 glTranslatef(0.5f,0.5f,-.25); /* move to the cylinder center */
700 glPushMatrix(); /* save state */
702 gluCylinder(quadratic, cylSize, cylSize, 0.25f, resolution, resolution); /* quad, radius(bottom, radius(top), height, subdivisions (around Z), subdevisions (along Z) */
703 tb->carpet_polys += resolution*resolution;
704 glRotatef(180, 0.0f, 1.0f, 0.0f); /* they are upside down */
705 gluDisk(quadratic, 0.0f, cylSize, resolution, resolution ); /* inner size (cd hole), outer size (radius), subdivisions radial, subdivisions circular */
706 tb->carpet_polys += resolution*resolution;
707 glRotatef(180, 0.0f, 1.0f, 0.0f); /* recover */
708 glTranslatef(0.0f,1.0f,0.0f); /* move to the next cylinder center (backward) */
710 glPopMatrix(); /* save state */
711 glTranslatef(1.0f,0.0f,0.0f); /* reset */
714 glPopMatrix(); /* restore state */
718 /* using the verticies arrays builds the plane, now with normals */
719 static void polygonPlane(int wire, int a, int b, int c , int d, int i)
721 GLfloat topBlockNormals[5][3] = { {0,0,-1}, {0,1,0}, {1,0,0}, {0,0,1}, {0,-1,0} };
722 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} };
723 glBegin( wire ? GL_LINE_LOOP : GL_POLYGON);
724 glNormal3fv(topBlockNormals[i] );
725 glVertex3fv(topBlockVertices[a]);
726 glVertex3fv(topBlockVertices[b]);
727 glVertex3fv(topBlockVertices[c]);
728 glVertex3fv(topBlockVertices[d]);
732 /* called at init this creates the 'block' display list item */
733 /* the spheres came about originaly as quick way to test the directional lighting/normals */
734 static void buildBlock(ModeInfo *mi)
737 int wire = MI_IS_WIREFRAME(mi);
738 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
739 GLUquadricObj *quadratic;
740 tb->block=glGenLists(1); /* only one */
741 glNewList(tb->block,GL_COMPILE);
743 glPushMatrix(); /* save state */
744 glRotatef(90, 0.0f, 1.0f, 0.0f);
746 polygonPlane(wire, 0,3,2,1,0); tb->block_polys++;
747 polygonPlane(wire, 2,3,7,6,1); tb->block_polys++;
748 polygonPlane(wire, 1,2,6,5,2); tb->block_polys++;
749 polygonPlane(wire, 4,5,6,7,3); tb->block_polys++;
750 polygonPlane(wire, 0,1,5,4,4); tb->block_polys++;
753 /* draw 8 cylinders each with a disk cap */
754 quadratic=gluNewQuadric(); /* Create A Pointer To The Quadric Object */
755 gluQuadricNormals(quadratic, GLU_SMOOTH); /* Create Smooth Normals */
756 glRotatef(90, 0.0f, 1.0f, 0.0f); /* 'aim' the pointer ready for the cylinder */
757 glTranslatef(0.5f,0.5f,0.99f); /* move to the cylinder center */
760 gluCylinder(quadratic, cylSize, cylSize, 0.25f, resolution, resolution); /* quad, radius(bottom, radius(top), height, subdivisions (around Z), subdevisions (along Z) */
761 tb->block_polys += resolution*resolution;
762 glTranslatef(0.0f,0.0f,0.25f); /* move to the cylinder cap */
763 gluDisk(quadratic, 0.0f, cylSize, resolution, resolution ); /* inner size (cd hole), outer size (radius), subdivisions radial, subdivisions circular */
764 tb->block_polys += resolution*resolution;
765 glTranslatef(0.0f,0.0f,-0.25f); /* move back from the cylinder cap */
767 glTranslatef(0.0f,-1.0f,0.0f); /* move to the next cylinder center (forward) */
769 glTranslatef(0.0f,1.0f,0.0f); /* move to the next cylinder center (backward) */
772 glTranslatef(-1.0f,1.0f,0.0f); /* move to the cylinder center */
775 /* 3 cylinders on the underside */
776 glTranslatef(1.5f,-2.5f,-1.5f); /* move to the center, under the top of the brick */
778 gluCylinder(quadratic, uddSize, uddSize, 1.5f, resolution, resolution); /* quad, radius(bottom, radius(top), height, subdivisions (around Z), subdevisions (along Z) */
779 tb->block_polys += resolution*resolution;
780 glTranslatef(0.0f,-1.0f,0.0f); /* move to the center */
783 glPopMatrix(); /* restore state */
788 rip off of the builBlock() function creating the GL compilied pointer "block" but only creates two spheres.
789 spheres are created with unit_sphere from spheres.h to allow wire frame
791 static void buildBlobBlock(ModeInfo *mi)
793 int wire = MI_IS_WIREFRAME(mi);
794 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
795 tb->block=glGenLists(1); /* only one */
796 glNewList(tb->block,GL_COMPILE);
798 glScalef(1.4,1.4,1.4);
799 unit_sphere (resolution/2,resolution, wire);
801 glTranslatef(0.0f,-2.0f,0.0f);
802 glScalef(1.4,1.4,1.4);
803 unit_sphere (resolution/2,resolution, wire);
808 /* handle input events or not if daemon running the show */
810 topBlock_handle_event (ModeInfo *mi, XEvent *event)
812 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
813 if (event->xany.type == KeyPress) {
816 XLookupString (&event->xkey, &c, 1, &keysym, 0);
820 } else if (c == 'z') {
823 } else if (c == 's') {
826 } else if (c == 'x') {
829 } else if (c == 'd') {
832 } else if (c == 'c') {
835 } else if (c == 'f') {
838 } else if (c == 'v') {
841 } else if (c == 'g') {
844 } else if (c == 'b') {
847 } else if (c == 'h') {
850 } else if (c == 'n') {
853 } else if (c == 'r') {
858 if (event->xany.type == ButtonPress &&
859 event->xbutton.button == Button1)
861 tb->button_down_p = True;
862 gltrackball_start (tb->trackball,
863 event->xbutton.x, event->xbutton.y,
864 MI_WIDTH (mi), MI_HEIGHT (mi));
867 else if (event->xany.type == ButtonRelease &&
868 event->xbutton.button == Button1)
870 tb->button_down_p = False;
873 else if (event->xany.type == ButtonPress &&
874 (event->xbutton.button == Button4 ||
875 event->xbutton.button == Button5 ||
876 event->xbutton.button == Button6 ||
877 event->xbutton.button == Button7))
879 gltrackball_mousewheel (tb->trackball, event->xbutton.button, 10,
880 !!event->xbutton.state);
883 else if (event->xany.type == MotionNotify &&
886 gltrackball_track (tb->trackball,
887 event->xmotion.x, event->xmotion.y,
888 MI_WIDTH (mi), MI_HEIGHT (mi));
894 /* this is tha main change for v5 compatability and acompanying ENTRYPOINTS */
895 XSCREENSAVER_MODULE_2 ("TopBlock", topblock, topBlock)