1 /* topblock, Copyright (c) 2006-2012 rednuht <topblock.xscreensaver@jumpstation.co.uk>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
14 topBlock - a simple openGL 3D hack of falling blocks
15 based on jwz's dangerball hack
17 The proporations of the blocks and their features is not even close to the commercial building block products offered by a variety companies.
19 information on this hack might be found at
20 http://www.jumpstation.co.uk/xscreensaver/topblock/
23 25/02/2006 v1.0 release
24 29/04/2006 v1.11 updated to better fit with xscreensaver v5
25 colors defaults to 7 (no black)
26 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.
31 # define release_topBlock 0
33 #define DEFAULTS "*delay: 10000 \n" \
35 "*showFPS: False \n" \
36 "*wireframe: False \n" \
39 #define countof(x) (sizeof((x))/sizeof((*x)))
41 #include "xlockmore.h"
45 #include "gltrackball.h"
48 #ifdef USE_GL /* whole file */
56 GLXContext *glx_context;
57 trackball_state *trackball;
64 GLfloat highest,highestFalling;
65 GLfloat eyeLine,eyeX,eyeY,eyeZ;
66 int carpetWidth, carpetLength;
68 GLfloat followRadius,followAngle;
72 int carpet_polys, block_polys;
74 NODE *blockNodeFollow;
82 static Bool drawCarpet;
84 static Bool drawNipples;
85 static GLfloat rotateSpeed;
89 static GLfloat dropSpeed;
90 static int maxFalling;
94 static int resolution;
96 static XrmOptionDescRec opts[] = {
97 { "-size", ".size", XrmoptionSepArg, 0 },
98 { "-spawn", ".spawn", XrmoptionSepArg, 0 },
99 { "-camX", ".camX", XrmoptionSepArg, 0 },
100 { "-camY", ".camY", XrmoptionSepArg, 0 },
101 { "-camZ", ".camZ", XrmoptionSepArg, 0 },
102 { "+rotate", ".rotate", XrmoptionNoArg, "False" },
103 { "-rotate", ".rotate", XrmoptionNoArg, "True" },
104 { "+carpet", ".carpet", XrmoptionNoArg, "False" },
105 { "+nipples", ".nipples", XrmoptionNoArg, "False" },
106 { "-blob", ".blob", XrmoptionNoArg, "True" },
107 { "-rotateSpeed", ".rotateSpeed", XrmoptionSepArg, 0 },
108 { "-follow", ".follow", XrmoptionNoArg, "True" },
109 { "-maxFalling", ".maxFalling", XrmoptionSepArg, 0 },
110 { "-resolution", ".resolution", XrmoptionSepArg, 0 },
111 { "-maxColors", ".maxColors", XrmoptionSepArg, 0 },
112 { "-dropSpeed", ".dropSpeed", XrmoptionSepArg, 0 },
113 { "-override", ".override", XrmoptionNoArg, "True" },
116 #define DEF_OVERRIDE "False"
117 #define DEF_ROTATE "True"
118 #define DEF_FOLLOW "False"
119 #define DEF_CARPET "True"
120 #define DEF_BLOB "False"
121 #define DEF_NIPPLES "True"
122 #define DEF_ROTATE_SPEED "10"
123 #define DEF_MAX_FALLING "500"
124 #define DEF_MAX_COLORS "7"
126 #define DEF_SPAWN "50"
127 #define DEF_RESOLUTION "4"
128 #define DEF_CAM_X "1"
129 #define DEF_CAM_Y "20"
130 #define DEF_CAM_Z "25"
131 #define DEF_DROP_SPEED "4"
133 static argtype vars[] = {
134 {&override, "override", "Override", DEF_OVERRIDE, t_Bool},
135 {&rotate, "rotate", "Rotate", DEF_ROTATE, t_Bool},
136 {&drawCarpet, "carpet", "Carpet", DEF_CARPET, t_Bool},
137 {&drawNipples, "nipples", "Nipples", DEF_NIPPLES, t_Bool},
138 {&drawBlob, "blob", "Blob", DEF_BLOB, t_Bool},
139 {&rotateSpeed, "rotateSpeed", "RotateSpeed", DEF_ROTATE_SPEED, t_Float},
140 {&follow, "follow", "Follow", DEF_FOLLOW, t_Bool},
141 {&camX, "camX", "camX", DEF_CAM_X, t_Float},
142 {&camY, "camY", "camY", DEF_CAM_Y, t_Float},
143 {&camZ, "camZ", "camZ", DEF_CAM_Z, t_Float},
144 {&size, "size", "size", DEF_SIZE, t_Int},
145 {&spawn, "spawn", "spawn", DEF_SPAWN, t_Int},
146 {&maxFalling, "maxFalling", "maxFalling", DEF_MAX_FALLING, t_Int},
147 {&resolution, "resolution", "resolution", DEF_RESOLUTION, t_Int},
148 {&maxColors, "maxColors", "maxColors", DEF_MAX_COLORS, t_Int},
149 {&dropSpeed, "dropSpeed", "DropSpeed", DEF_DROP_SPEED, t_Float},
152 static topBlockSTATE *tbs = NULL;
154 static ModeSpecOpt topBlock_opts = {countof(opts), opts, countof(vars), vars, NULL};
156 /* Window management, etc */
158 reshape_topBlock (ModeInfo *mi, int width, int height)
160 GLfloat h = (GLfloat) height / (GLfloat) width;
163 if (width > height * 5) { /* tiny window: show middle */
166 h = height / (GLfloat) width;
168 glViewport (0, y, (GLint) width, (GLint) height);
169 glMatrixMode(GL_PROJECTION);
171 gluPerspective (60.0, 1/h, 1.0, 1000.0);
172 glMatrixMode(GL_MODELVIEW);
174 glClear(GL_COLOR_BUFFER_BIT);
177 /* clean up on exit, not required ... */
179 free_topBlock(ModeInfo *mi)
181 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
182 NODE *llCurrent, *llOld;
183 llCurrent = tb->blockNodeRoot;
184 while (llCurrent != NULL) {
186 llCurrent = llCurrent->next;
193 init_topBlock (ModeInfo *mi)
196 int wire = MI_IS_WIREFRAME(mi);
200 tb = &tbs[MI_SCREEN(mi)];
202 tb->glx_context = init_GL(mi);
204 reshape_topBlock (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
206 /* if (wire) { drawNipples=False; }*/
207 tb->numFallingBlocks=0;
209 if (size>10) { size = 10; }
210 if (size<1) { size = 2; }
211 tb->carpetWidth = 8 * size;
212 tb->carpetLength = tb->carpetWidth;
214 tb->maxFalling = maxFalling;
215 tb->maxFalling*=size;
217 if (spawn<4) { spawn=4; }
218 if (spawn>1000) { spawn=1000; }
220 tb->rotateSpeed = rotateSpeed;
221 if (tb->rotateSpeed<1) {tb->rotateSpeed=1; }
222 if (tb->rotateSpeed>1000) {tb->rotateSpeed=1000;}
223 tb->rotateSpeed /= 100;
225 tb->resolution = resolution;
226 if (tb->resolution<4) {tb->resolution=4;}
227 if (tb->resolution>20) {tb->resolution=20;}
230 if (maxColors<1) {maxColors=1;}
231 if (maxColors>8) {maxColors=8;}
233 tb->dropSpeed = dropSpeed;
234 if (tb->dropSpeed<1) {tb->dropSpeed=1;}
235 if (tb->dropSpeed>9) {tb->dropSpeed=9;} /* 10+ produces blocks that can pass through each other */
237 tb->dropSpeed = 80/tb->dropSpeed;
238 tb->dropSpeed = (blockHeight/tb->dropSpeed);
240 reshape_topBlock (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
243 GLfloat pos[4] = {10.0, 10.0, 1.0, 0.0};
244 GLfloat amb[4] = {0.1, 0.1, 0.1, 1.0};
245 GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
246 GLfloat spc[4] = {0.0, 1.0, 1.0, 1.0};
248 glEnable(GL_LIGHTING);
250 glLightfv(GL_LIGHT0, GL_POSITION, pos);
251 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
252 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
253 glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
255 glDepthFunc(GL_LEQUAL);
256 glEnable(GL_DEPTH_TEST);
257 glDisable(GL_CULL_FACE); /* all objects exhibit a reverse side */
263 buildBlock(mi); /* build the display list holding the simple block */
265 buildCarpet(mi); /* build the base */
267 tb->highestFalling=0;
268 tb->eyeLine=tb->highest;
277 tb->rotation=random() % 360;
282 /* override camera settings */
293 tb->trackball = gltrackball_init (False);
296 /* provides the per frame entertainment */
298 draw_topBlock (ModeInfo *mi)
300 Display *dpy = MI_DISPLAY(mi);
301 Window window = MI_WINDOW(mi);
304 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
305 GLfloat spcN1x,spcN1y,spcN2x,spcN2y;
306 GLfloat spcC1x,spcC1y,spcC2x,spcC2y;
307 int wire = MI_IS_WIREFRAME(mi);
310 if (!tb->glx_context)
312 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(tb->glx_context));
313 mi->polygon_count = 0;
315 generateNewBlock(mi);
317 if (rotate && (!tb->button_down_p)) { tb->rotation += tb->rotateSpeed; }
318 if (tb->rotation>=360) { tb->rotation=tb->rotation-360; }
320 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* clear current */
321 glLoadIdentity(); /* resets directions, do it every time ! */
322 glRotatef(current_device_rotation(), 0, 0, 1);
325 if (tb->highest>tb->eyeLine) { tb->eyeLine+=((tb->highest-tb->eyeLine)/100); } /* creates a smooth camera transition */
326 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 */
327 glRotatef(90, 1.0, 0.0, 0.0); /* x axis */
329 glRotatef(90, 0.0, 0.0, 1.0); /* z axis */
333 /* Rotate the scene around a point that's a little higher up. */
334 glTranslatef (0, 0, -5);
335 gltrackball_rotate (tb->trackball);
336 glTranslatef (0, 0, 5);
338 /* rotate the world */
339 glRotatef(tb->rotation, 0.0, 0.0, 1.0);
341 # ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */
343 GLfloat h = MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi);
344 int o = (int) current_device_rotation();
345 if (o != 0 && o != 180 && o != -180)
346 glScalef (1/h, 1/h, 1/h);
350 llCurrent = tb->blockNodeRoot;
353 glTranslatef(0.0-(tb->carpetWidth/2),0.0-(tb->carpetLength/2),0.0);
354 glCallList(tb->carpet);
355 mi->polygon_count += tb->carpet_polys;
356 glTranslatef(0.0+(tb->carpetWidth/2),0.0+(tb->carpetLength/2),0.0);
357 glTranslatef(0.0,0.0,-0.55);
359 tb->highestFalling=0;
360 while (llCurrent != NULL) { /* for each block */
361 glPushMatrix(); /* save state */
363 switch (llCurrent->color) {
413 if (wire) { glColor3fv(color); }
414 else { glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); }
416 if (llCurrent->falling==1) {
421 if (llCurrent->height>tb->highestFalling) {tb->highestFalling=llCurrent->height;}
422 /* all blocks fall at the same rate to avoid mid air collisions */
423 llCurrent->height-=tb->dropSpeed;
424 if (llCurrent->height<=0) {
425 llCurrent->falling=0;
426 if (tb->highest==0) {
427 tb->highest+=blockHeight;
430 if ( (llCurrent->height<=tb->highest+1) && (llCurrent->falling==1) ) {
431 /* check for collision */
432 llNode = tb->blockNodeRoot;
433 spcC1x = llCurrent->x;
434 spcC1y = llCurrent->y;
435 switch(llCurrent->rotation) {
436 case getOrientation(0):
440 case getOrientation(1):
444 case getOrientation(2):
448 case getOrientation(3):
453 while (llNode != NULL) {
454 if ( (llNode->falling==0) && (llCurrent->falling==1) ) {
457 switch(llNode->rotation) {
458 case getOrientation(0):
462 case getOrientation(1):
466 case getOrientation(2):
470 case getOrientation(3):
476 ( (spcC1x==spcN1x) && (spcC1y==spcN1y) ) ||
477 ( (spcC1x==spcN2x) && (spcC1y==spcN2y) ) ||
478 ( (spcC2x==spcN2x) && (spcC2y==spcN2y) ) ||
479 ( (spcC2x==spcN1x) && (spcC2y==spcN1y) )
481 if ( fabs(llCurrent->height-(llNode->height+blockHeight)) <= TOLERANCE) {
483 llCurrent->falling=0;
484 llCurrent->height=llNode->height+blockHeight; /* if this is missing then small errors build up until the model fails */
485 if ( fabs(llCurrent->height-tb->highest) <= TOLERANCE+blockHeight ) {
486 tb->highest+=blockHeight;
495 /* set location in space */
496 glTranslatef(llCurrent->x,llCurrent->y,-llCurrent->height);
498 glRotatef(llCurrent->rotation, 0.0f, 0.0f, 1.0f);
499 if ((tb->followMode==0) && (llCurrent->next==NULL)) {
500 tb->blockNodeFollow = llCurrent;
503 llCurrent = llCurrent->next;
505 glCallList(tb->block);
506 mi->polygon_count += tb->block_polys;
507 glPopMatrix(); /* restore state */
509 if (mi->fps_p) do_fps (mi);
512 if (tb->highest>(5*tb->maxFalling)) { drawCarpet=False; }
513 glXSwapBuffers(dpy, window);
518 /* camera is in follow mode, work out where we should be looking */
519 static void followBlock(ModeInfo *mi)
521 GLfloat xLen,yLen,cx,cy,rangle,xTarget,yTarget;
522 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
524 if ((tb->blockNodeFollow!=NULL) && (tb->followMode==1)){
526 if (tb->highest>tb->eyeLine) { tb->eyeLine+= ((tb->highest-tb->eyeLine)/100); }
527 /*tb->blockNodeFollow->color=1; only noticable if you set the colors to 1 */
529 if (tb->blockNodeFollow->height > tb->eyeZ) { tb->eyeZ+= ((tb->blockNodeFollow->height - tb->eyeZ)/100); }
530 if (tb->blockNodeFollow->height < tb->eyeZ) { tb->eyeZ-= ((tb->eyeZ - tb->blockNodeFollow->height)/100); }
533 /* when the scene is rotated we need to know where the block is in the 2 dimensional coordinates of the carpet area
534 (see http://www.jumpstation.co.uk/rotation/)
537 if (tb->followRadius==0) {
538 xLen = tb->blockNodeFollow->x-cx;
539 yLen = tb->blockNodeFollow->y-cy;
540 tb->followRadius=sqrt( (xLen*xLen) + (yLen*yLen) );
541 tb->followAngle = (180/M_PI) * asin(xLen/tb->followRadius);
542 tb->followAngle = quadrantCorrection(tb->followAngle,(int)cx,(int)cy,(int)tb->blockNodeFollow->x,(int)tb->blockNodeFollow->y);
544 rangle = (tb->followAngle+tb->rotation) * M_PI /180;
545 xTarget = cos(rangle) * tb->followRadius + cx;
546 yTarget = sin(rangle) * tb->followRadius + cy;
547 if (tb->followAngle>360) { tb->followAngle=tb->followAngle-360; }
549 if (xTarget < tb->eyeX) { tb->eyeX-= ((tb->eyeX - xTarget)/100); }
550 if (xTarget > tb->eyeX) { tb->eyeX+= ((xTarget - tb->eyeX)/100); }
552 if (yTarget < tb->eyeY) { tb->eyeY-= ((tb->eyeY - yTarget)/100); }
553 if (yTarget > tb->eyeY) { tb->eyeY+= ((yTarget - tb->eyeY)/100); }
554 if (!tb->blockNodeFollow->falling) {
556 /*tb->blockNodeFollow->color=2; only noticable if you set the colors to 1 */
560 gluLookAt(camX, camY, camZ-tb->eyeLine, tb->eyeX, tb->eyeY, -tb->eyeZ,-1.0,0.0,0.0);
563 /* each quater of the circle has to be adjusted for */
564 static double quadrantCorrection(double angle,int cx,int cy,int x,int y)
566 if ((x>=cx) && (y>=cy)) {
567 angle += (90-(angle-90) * 2);
568 } else if ((x>=cx) && (y<=cy)) {
570 } else if ((x<=cx) && (y<=cy)) {
572 } else if ((x<=cx) && (y>=cy)) {
573 angle += (90-(angle-90) * 2);
578 /* if random chance then create a new falling block */
579 static void generateNewBlock(ModeInfo *mi)
581 NODE *llCurrent, *llTail;
582 GLfloat startOffx, startOffy;
583 int endOffx, endOffy;
584 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
585 if ( ((random() % spawn) == 1) && (tb->highestFalling<getHeight((tb->plusheight-blockHeight)+tb->highest)) ) {
590 tb->numFallingBlocks++;
591 llTail = tb->blockNodeRoot;
592 if (llTail == NULL) {
593 llCurrent = ((NODE*) malloc(sizeof(NODE)));
594 if (!llCurrent) abort();
596 tb->blockNodeRoot = llCurrent;
598 if (tb->numFallingBlocks>=tb->maxFalling) {
600 llCurrent=llTail->next;
601 tb->blockNodeRoot=llCurrent->next;
603 llCurrent = ((NODE*) malloc(sizeof(NODE)));
604 if (!llCurrent) abort();
606 while (llTail->next != NULL) { llTail = llTail->next; } /* find last item in list */
608 llCurrent->falling=1;
609 llCurrent->rotation=getOrientation(random() % 4);
610 if (llCurrent->rotation==getOrientation(0)) {
615 } else if (llCurrent->rotation==getOrientation(1)) {
620 } else if (llCurrent->rotation==getOrientation(2)) {
625 } else if (llCurrent->rotation==getOrientation(3)) {
632 llCurrent->x=(startOffx-(tb->carpetLength/2)) + getLocation(random() % ((tb->carpetLength/2)+endOffx) );
633 llCurrent->y=(startOffy-(tb->carpetLength/2)) + getLocation(random() % ((tb->carpetLength/2)+endOffy) );
634 llCurrent->color=(random() % maxColors);
635 llCurrent->height=getHeight(tb->plusheight+tb->highest);
636 if (tb->numFallingBlocks>=tb->maxFalling) {
637 tb->numFallingBlocks--;
638 tb->numFallingBlocks--;
640 llTail->next = llCurrent;
647 /* called at init this creates the 'carpet' display list item */
648 static void buildCarpet(ModeInfo *mi)
652 int wire = MI_IS_WIREFRAME(mi);
653 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
658 tb->carpet=glGenLists(1); /* only one */
659 glNewList(tb->carpet,GL_COMPILE);
661 glPushMatrix(); /* save state */
664 if (wire) { glColor3fv(color); }
665 else { glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); }
666 /* draw carpet plane */
667 glBegin( wire ? GL_LINE_LOOP : GL_QUADS );
669 glNormal3f( 0, 0, -1 );
670 glVertex3f(0.0,0.0,0.0);
671 glVertex3f(x,0.0,0.0);
673 glVertex3f(0.0,y,0.0);
676 /* add edge pieces */
678 glNormal3f( 0, -1, 0 );
679 glVertex3f(0.0,0.0,0.0);
680 glVertex3f(x,0.0,0.0);
681 glVertex3f(x,0,singleThick);
682 glVertex3f(0.0,0,singleThick);
685 glNormal3f( -1, 0, 0 );
686 glVertex3f(0.0,0.0,0.0);
688 glVertex3f(0,y,singleThick);
689 glVertex3f(0.0,0,singleThick);
692 glNormal3f( 1, 0, 0 );
693 glVertex3f(x,0.0,0.0);
695 glVertex3f(x,y,singleThick);
696 glVertex3f(x,0,singleThick);
699 glNormal3f( 0, 1, 0 );
702 glVertex3f(x,y,singleThick);
703 glVertex3f(0,y,singleThick);
709 glTranslatef(0.5f,0.5f,-.25); /* move to the cylinder center */
711 glPushMatrix(); /* save state */
713 tb->carpet_polys += tube(0, 0, -0.1,
716 tb->resolution, True, True,
718 glRotatef(180, 0.0f, 1.0f, 0.0f); /* they are upside down */
719 glRotatef(180, 0.0f, 1.0f, 0.0f); /* recover */
720 glTranslatef(0.0f,1.0f,0.0f); /* move to the next cylinder center (backward) */
722 glPopMatrix(); /* save state */
723 glTranslatef(1.0f,0.0f,0.0f); /* reset */
726 glPopMatrix(); /* restore state */
730 /* using the verticies arrays builds the plane, now with normals */
731 static void polygonPlane(int wire, int a, int b, int c , int d, int i)
733 GLfloat topBlockNormals[5][3] = { {0,0,-1}, {0,1,0}, {1,0,0}, {0,0,1}, {0,-1,0} };
734 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} };
735 glBegin( wire ? GL_LINE_LOOP : GL_POLYGON);
736 glNormal3fv(topBlockNormals[i] );
737 glVertex3fv(topBlockVertices[a]);
738 glVertex3fv(topBlockVertices[b]);
739 glVertex3fv(topBlockVertices[c]);
740 glVertex3fv(topBlockVertices[d]);
744 /* called at init this creates the 'block' display list item */
745 /* the spheres came about originaly as quick way to test the directional lighting/normals */
746 static void buildBlock(ModeInfo *mi)
749 int wire = MI_IS_WIREFRAME(mi);
750 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
751 tb->block=glGenLists(1); /* only one */
752 glNewList(tb->block,GL_COMPILE);
754 glPushMatrix(); /* save state */
755 glRotatef(90, 0.0f, 1.0f, 0.0f);
757 polygonPlane(wire, 0,3,2,1,0); tb->block_polys++;
758 polygonPlane(wire, 2,3,7,6,1); tb->block_polys++;
759 polygonPlane(wire, 1,2,6,5,2); tb->block_polys++;
760 polygonPlane(wire, 4,5,6,7,3); tb->block_polys++;
761 polygonPlane(wire, 0,1,5,4,4); tb->block_polys++;
764 /* draw 8 cylinders each with a disk cap */
765 glRotatef(90, 0.0f, 1.0f, 0.0f); /* 'aim' the pointer ready for the cylinder */
766 glTranslatef(0.5f,0.5f,0.99f); /* move to the cylinder center */
769 tb->block_polys += tube(0, 0, 0,
772 tb->resolution, True, True,
774 glTranslatef(0.0f,0.0f,0.25f); /* move to the cylinder cap */
775 glTranslatef(0.0f,0.0f,-0.25f); /* move back from the cylinder cap */
777 glTranslatef(0.0f,-1.0f,0.0f); /* move to the next cylinder center (forward) */
779 glTranslatef(0.0f,1.0f,0.0f); /* move to the next cylinder center (backward) */
782 glTranslatef(-1.0f,1.0f,0.0f); /* move to the cylinder center */
785 /* 3 cylinders on the underside */
786 glTranslatef(1.5f,-2.5f,-1.5f); /* move to the center, under the top of the brick */
789 tb->block_polys += tube(0, 0, 0.1,
792 tb->resolution, True, True, wire);
793 glTranslatef(0.0f,-1.0f,0.0f); /* move to the center */
796 glPopMatrix(); /* restore state */
801 rip off of the builBlock() function creating the GL compilied pointer "block" but only creates two spheres.
802 spheres are created with unit_sphere from spheres.h to allow wire frame
804 static void buildBlobBlock(ModeInfo *mi)
806 int wire = MI_IS_WIREFRAME(mi);
807 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
808 tb->block=glGenLists(1); /* only one */
809 glNewList(tb->block,GL_COMPILE);
811 glScalef(1.4,1.4,1.4);
812 unit_sphere (tb->resolution/2,tb->resolution, wire);
814 glTranslatef(0.0f,-2.0f,0.0f);
815 glScalef(1.4,1.4,1.4);
816 unit_sphere (tb->resolution/2,tb->resolution, wire);
821 /* handle input events or not if daemon running the show */
823 topBlock_handle_event (ModeInfo *mi, XEvent *event)
825 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
827 if (gltrackball_event_handler (event, tb->trackball,
828 MI_WIDTH (mi), MI_HEIGHT (mi),
831 else if (event->xany.type == KeyPress) {
834 XLookupString (&event->xkey, &c, 1, &keysym, 0);
838 } else if (c == 'z') {
841 } else if (c == 's') {
844 } else if (c == 'x') {
847 } else if (c == 'd') {
850 } else if (c == 'c') {
853 } else if (c == 'f') {
856 } else if (c == 'v') {
859 } else if (c == 'g') {
862 } else if (c == 'b') {
865 } else if (c == 'h') {
868 } else if (c == 'n') {
871 } else if (c == 'r') {
880 /* this is tha main change for v5 compatability and acompanying ENTRYPOINTS */
881 XSCREENSAVER_MODULE_2 ("TopBlock", topblock, topBlock)