1 /* topblock, Copyright (c) 2006 rednuht <topblock.xscreensaver@jumpstation.co.uk>
\r
3 * Permission to use, copy, modify, distribute, and sell this software and its
\r
4 * documentation for any purpose is hereby granted without fee, provided that
\r
5 * the above copyright notice appear in all copies and that both that
\r
6 * copyright notice and this permission notice appear in supporting
\r
7 * documentation. No representations are made about the suitability of this
\r
8 * software for any purpose. It is provided "as is" without express or
\r
14 topBlock - a simple openGL 3D hack of falling blocks
\r
15 based on jwz's dangerball hack
\r
17 The proporations of the blocks and their features is not even close to the commercial building block products offered by a variety companies.
\r
19 information on this hack might be found at
\r
20 http://www.jumpstation.co.uk/xscreensaver/topblock/
\r
23 25/02/2006 v1.0 release
\r
24 29/04/2006 v1.11 updated to better fit with xscreensaver v5
\r
25 colors defaults to 7 (no black)
\r
30 # define refresh_topBlock 0
\r
32 #define DEFAULTS "*delay: 10000 \n" \
\r
34 "*showFPS: False \n" \
\r
35 "*wireframe: False \n" \
\r
38 #define countof(x) (sizeof((x))/sizeof((*x)))
\r
40 #include "xlockmore.h"
\r
41 #include "topblock.h"
\r
45 #ifdef USE_GL /* whole file */
\r
48 # include <OpenGL/glu.h>
\r
50 # include <GL/glu.h>
\r
55 GLXContext *glx_context;
\r
56 int numFallingBlocks;
\r
57 GLfloat highest,highestFalling;
\r
58 GLfloat eyeLine,eyeX,eyeY,eyeZ;
\r
59 int carpetWidth, carpetLength;
\r
61 GLfloat followRadius,followAngle;
\r
65 NODE *blockNodeRoot;
\r
66 NODE *blockNodeFollow;
\r
70 /* parameter vars */
\r
77 GLfloat rotateSpeed;
\r
88 static XrmOptionDescRec opts[] = {
\r
89 { "-size", ".size", XrmoptionSepArg, 0 },
\r
90 { "-spawn", ".spawn", XrmoptionSepArg, 0 },
\r
91 { "-camX", ".camX", XrmoptionSepArg, 0 },
\r
92 { "-camY", ".camY", XrmoptionSepArg, 0 },
\r
93 { "-camZ", ".camZ", XrmoptionSepArg, 0 },
\r
94 { "+rotate", ".rotate", XrmoptionNoArg, "False" },
\r
95 { "-rotate", ".rotate", XrmoptionNoArg, "True" },
\r
96 { "+carpet", ".carpet", XrmoptionNoArg, "False" },
\r
97 { "+nipples", ".nipples", XrmoptionNoArg, "False" },
\r
98 { "-blob", ".blob", XrmoptionNoArg, "True" },
\r
99 { "-rotateSpeed", ".rotateSpeed", XrmoptionSepArg, 0 },
\r
100 { "-follow", ".follow", XrmoptionNoArg, "True" },
\r
101 { "-maxFalling", ".maxFalling", XrmoptionSepArg, 0 },
\r
102 { "-resolution", ".resolution", XrmoptionSepArg, 0 },
\r
103 { "-maxColors", ".maxColors", XrmoptionSepArg, 0 },
\r
104 { "-dropSpeed", ".dropSpeed", XrmoptionSepArg, 0 },
\r
105 { "-override", ".override", XrmoptionNoArg, "True" },
\r
108 #define DEF_override "False"
\r
109 #define DEF_rotate "True"
\r
110 #define DEF_follow "False"
\r
111 #define DEF_drawCarpet "True"
\r
112 #define DEF_drawBlob "False"
\r
113 #define DEF_drawNipples "True"
\r
114 #define DEF_rotateSpeed "10"
\r
115 #define DEF_maxFalling "500"
\r
116 #define DEF_maxColors "7"
\r
117 #define DEF_size "2"
\r
118 #define DEF_spawn "50"
\r
119 #define DEF_resolution "4"
\r
120 #define DEF_camX "1"
\r
121 #define DEF_camY "20"
\r
122 #define DEF_camZ "25"
\r
123 #define DEF_dropSpeed "4"
\r
125 static argtype vars[] = {
\r
126 {&override, "override", "Override", DEF_override, t_Bool},
\r
127 {&rotate, "rotate", "Rotate", DEF_rotate, t_Bool},
\r
128 {&drawCarpet, "carpet", "Carpet", DEF_drawCarpet, t_Bool},
\r
129 {&drawNipples, "nipples", "Nipples", DEF_drawNipples, t_Bool},
\r
130 {&drawBlob, "blob", "Blob", DEF_drawBlob, t_Bool},
\r
131 {&rotateSpeed, "rotateSpeed", "RotateSpeed", DEF_rotateSpeed, t_Float},
\r
132 {&follow, "follow", "Follow", DEF_follow, t_Bool},
\r
133 {&camX, "camX", "camX", DEF_camX, t_Float},
\r
134 {&camY, "camY", "camY", DEF_camY, t_Float},
\r
135 {&camZ, "camZ", "camZ", DEF_camZ, t_Float},
\r
136 {&size, "size", "size", DEF_size, t_Int},
\r
137 {&spawn, "spawn", "spawn", DEF_spawn, t_Int},
\r
138 {&maxFalling, "maxFalling", "maxFalling", DEF_maxFalling, t_Int},
\r
139 {&resolution, "resolution", "resolution", DEF_resolution, t_Int},
\r
140 {&maxColors, "maxColors", "maxColors", DEF_maxColors, t_Int},
\r
141 {&dropSpeed, "dropSpeed", "DropSpeed", DEF_dropSpeed, t_Float},
\r
144 static topBlockSTATE *tbs = NULL;
\r
146 ModeSpecOpt topBlock_opts = {countof(opts), opts, countof(vars), vars, NULL};
\r
148 /* Window management, etc */
\r
150 reshape_topBlock (ModeInfo *mi, int width, int height) {
\r
151 GLfloat h = (GLfloat) height / (GLfloat) width;
\r
152 glViewport (0, 0, (GLint) width, (GLint) height);
\r
153 glMatrixMode(GL_PROJECTION);
\r
155 gluPerspective (60.0, 1/h, 1.0, 1000.0);
\r
156 glMatrixMode(GL_MODELVIEW);
\r
158 glClear(GL_COLOR_BUFFER_BIT);
\r
161 /* clean up on exit, not required ... */
\r
163 release_topBlock(ModeInfo *mi) {
\r
164 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
\r
165 NODE *llCurrent, *llOld;
\r
166 llCurrent = tb->blockNodeRoot;
\r
167 while (llCurrent != NULL) {
\r
169 llCurrent = llCurrent->next;
\r
176 init_topBlock (ModeInfo *mi)
\r
179 int wire = MI_IS_WIREFRAME(mi);
\r
182 tbs = (topBlockSTATE *)
\r
183 calloc (MI_NUM_SCREENS(mi), sizeof (topBlockSTATE));
\r
185 fprintf(stderr, "%s: out of memory\n", progname);
\r
190 tb = &tbs[MI_SCREEN(mi)];
\r
192 tb->glx_context = init_GL(mi);
\r
194 reshape_topBlock (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
\r
196 if (wire) { drawNipples=False; }
\r
197 tb->numFallingBlocks=0;
\r
199 if (size>10) { size = 10; }
\r
200 if (size<1) { size = 2; }
\r
201 tb->carpetWidth = 8 * size;
\r
202 tb->carpetLength = tb->carpetWidth;
\r
204 maxFalling=maxFalling*size;
\r
206 if (spawn<4) { spawn=4; }
\r
207 if (spawn>1000) { spawn=1000; }
\r
209 if (rotateSpeed<1) {rotateSpeed=1; }
\r
210 if (rotateSpeed>1000) {rotateSpeed=1000;}
\r
211 rotateSpeed = rotateSpeed / 100;
\r
213 if (resolution<4) {resolution=4;}
\r
214 if (resolution>20) {resolution=20;}
\r
215 resolution=resolution*2;
\r
217 if (maxColors<1) {maxColors=1;}
\r
218 if (maxColors>8) {maxColors=8;}
\r
220 if (dropSpeed<1) {dropSpeed=1;}
\r
221 if (dropSpeed>9) {dropSpeed=9;} /* 10+ produces blocks that can pass through each other */
\r
223 dropSpeed = 80/dropSpeed;
\r
224 dropSpeed = (blockHeight/dropSpeed);
\r
226 tb->glx_context = init_GL(mi);
\r
228 reshape_topBlock (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
\r
230 glClearColor(1.0f, 1.0f, 1.0f, 0.5f);
\r
232 glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
\r
234 glClearDepth(1.0f);
\r
236 GLfloat pos[4] = {10.0, 10.0, 1.0, 0.0};
\r
237 GLfloat amb[4] = {0.1, 0.1, 0.1, 1.0};
\r
238 GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
\r
239 GLfloat spc[4] = {0.0, 1.0, 1.0, 1.0};
\r
241 glEnable(GL_LIGHTING);
\r
242 glEnable(GL_LIGHT0);
\r
243 glLightfv(GL_LIGHT0, GL_POSITION, pos);
\r
244 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
\r
245 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
\r
246 glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
\r
248 glDepthFunc(GL_LEQUAL);
\r
249 glEnable(GL_DEPTH_TEST);
\r
250 glDisable(GL_CULL_FACE); /* all objects exhibit a reverse side */
\r
251 glCullFace(GL_BACK);
\r
254 buildBlobBlock(mi);
\r
256 buildBlock(mi); /* build the display list holding the simple block */
\r
258 buildCarpet(mi); /* build the base */
\r
260 tb->highestFalling=0;
\r
261 tb->eyeLine=tb->highest;
\r
267 tb->plusheight=100;
\r
270 tb->rotation=random() % 360;
\r
274 tb->followRadius=0;
\r
275 /* override camera settings */
\r
277 tb->plusheight=100;
\r
288 /* provides the per frame entertainment */
\r
290 draw_topBlock (ModeInfo *mi) {
\r
291 Display *dpy = MI_DISPLAY(mi);
\r
292 Window window = MI_WINDOW(mi);
\r
295 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
\r
296 GLfloat spcN1x,spcN1y,spcN2x,spcN2y;
\r
297 GLfloat spcC1x,spcC1y,spcC2x,spcC2y;
\r
298 int wire = MI_IS_WIREFRAME(mi);
\r
301 if (!tb->glx_context)
\r
303 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(tb->glx_context));
\r
305 generateNewBlock(mi);
\r
307 if (rotate) { tb->rotation += rotateSpeed; }
\r
308 if (tb->rotation>=360) { tb->rotation=tb->rotation-360; }
\r
310 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* clear current */
\r
311 glLoadIdentity(); /* resets directions, do it every time ! */
\r
314 if (tb->highest>tb->eyeLine) { tb->eyeLine=tb->eyeLine + ((tb->highest-tb->eyeLine)/100); } /* creates a smooth camera transition */
\r
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 */
\r
316 glRotatef(90, 1.0, 0.0, 0.0); /* x axis */
\r
318 glRotatef(90, 0.0, 0.0, 1.0); /* z axis */
\r
321 /* rotate the world */
\r
322 glRotatef(tb->rotation, 0.0, 0.0, 1.0);
\r
324 llCurrent = tb->blockNodeRoot;
\r
326 /* center carpet */
\r
327 glTranslatef(0.0-(tb->carpetWidth/2),0.0-(tb->carpetLength/2),0.0);
\r
328 glCallList(tb->carpet);
\r
329 glTranslatef(0.0+(tb->carpetWidth/2),0.0+(tb->carpetLength/2),0.0);
\r
330 glTranslatef(0.0,0.0,-0.55);
\r
332 tb->highestFalling=0;
\r
333 while (llCurrent != NULL) { /* for each block */
\r
334 glPushMatrix(); /* save state */
\r
336 switch (llCurrent->color) {
\r
386 if (wire) { glColor3fv(color); }
\r
387 else { glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); }
\r
389 if (llCurrent->falling==1) {
\r
394 if (llCurrent->height>tb->highestFalling) {tb->highestFalling=llCurrent->height;}
\r
395 /* all blocks fall at the same rate to avoid mid air collisions */
\r
396 llCurrent->height=llCurrent->height-dropSpeed;
\r
397 if (llCurrent->height<=0) {
\r
398 llCurrent->falling=0;
\r
399 if (tb->highest==0) {
\r
400 tb->highest=tb->highest+blockHeight;
\r
403 if ( (llCurrent->height<=tb->highest+1) && (llCurrent->falling==1) ) {
\r
404 /* check for collision */
\r
405 llNode = tb->blockNodeRoot;
\r
406 spcC1x = llCurrent->x;
\r
407 spcC1y = llCurrent->y;
\r
408 switch(llCurrent->rotation) {
\r
409 case getOrientation(0):
\r
413 case getOrientation(1):
\r
417 case getOrientation(2):
\r
421 case getOrientation(3):
\r
426 while (llNode != NULL) {
\r
427 if ( (llNode->falling==0) && (llCurrent->falling==1) ) {
\r
428 spcN1x = llNode->x;
\r
429 spcN1y = llNode->y;
\r
430 switch(llNode->rotation) {
\r
431 case getOrientation(0):
\r
435 case getOrientation(1):
\r
439 case getOrientation(2):
\r
443 case getOrientation(3):
\r
449 ( (spcC1x==spcN1x) && (spcC1y==spcN1y) ) ||
\r
450 ( (spcC1x==spcN2x) && (spcC1y==spcN2y) ) ||
\r
451 ( (spcC2x==spcN2x) && (spcC2y==spcN2y) ) ||
\r
452 ( (spcC2x==spcN1x) && (spcC2y==spcN1y) )
\r
454 if ( (llCurrent->height<=llNode->height+blockHeight+TOLLERANCE) && (llCurrent->height>=llNode->height+blockHeight-TOLLERANCE) ) {
\r
455 llCurrent->falling=0;
\r
456 llCurrent->height=llNode->height+blockHeight; /* if this is missing then small errors build up until the model fails */
\r
457 if ( (llCurrent->height<=tb->highest+TOLLERANCE) && (llCurrent->height>=tb->highest-TOLLERANCE) ) {
\r
458 tb->highest=tb->highest+blockHeight;
\r
463 llNode=llNode->next;
\r
467 /* set location in space */
\r
468 glTranslatef(llCurrent->x,llCurrent->y,-llCurrent->height);
\r
470 glRotatef(llCurrent->rotation, 0.0f, 0.0f, 1.0f);
\r
471 if ((tb->followMode==0) && (llCurrent->next==NULL)) {
\r
472 tb->blockNodeFollow = llCurrent;
\r
475 llCurrent = llCurrent->next;
\r
477 glCallList(tb->block);
\r
478 glPopMatrix(); /* restore state */
\r
480 if (mi->fps_p) do_fps (mi);
\r
483 if (tb->highest>(5*maxFalling)) { drawCarpet=False; }
\r
484 glXSwapBuffers(dpy, window);
\r
489 /* camera is in follow mode, work out where we should be looking */
\r
490 static void followBlock(ModeInfo *mi) {
\r
491 GLfloat xLen,yLen,cx,cy,rangle,xTarget,yTarget;
\r
492 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
\r
494 if ((tb->blockNodeFollow!=NULL) && (tb->followMode==1)){
\r
496 if (tb->highest>tb->eyeLine) { tb->eyeLine=tb->eyeLine + ((tb->highest-tb->eyeLine)/100); }
\r
497 /*tb->blockNodeFollow->color=1; only noticable if you set the colors to 1 */
\r
499 if (tb->blockNodeFollow->height > tb->eyeZ) { tb->eyeZ=tb->eyeZ + ((tb->blockNodeFollow->height - tb->eyeZ)/100); }
\r
500 if (tb->blockNodeFollow->height < tb->eyeZ) { tb->eyeZ=tb->eyeZ - ((tb->eyeZ - tb->blockNodeFollow->height)/100); }
\r
503 /* when the scene is rotated we need to know where the block is in the 2 dimensional coordinates of the carpet area
\r
504 (see http://www.jumpstation.co.uk/rotation/)
\r
507 if (tb->followRadius==0) {
\r
508 xLen = tb->blockNodeFollow->x-cx;
\r
509 yLen = tb->blockNodeFollow->y-cy;
\r
510 tb->followRadius=sqrt( (xLen*xLen) + (yLen*yLen) );
\r
511 tb->followAngle = (180/M_PI) * asin(xLen/tb->followRadius);
\r
512 tb->followAngle = quadrantCorrection(tb->followAngle,(int)cx,(int)cy,(int)tb->blockNodeFollow->x,(int)tb->blockNodeFollow->y);
\r
514 rangle = (tb->followAngle+tb->rotation) * M_PI /180;
\r
515 xTarget = cos(rangle) * tb->followRadius + cx;
\r
516 yTarget = sin(rangle) * tb->followRadius + cy;
\r
517 if (tb->followAngle>360) { tb->followAngle=tb->followAngle-360; }
\r
519 if (xTarget < tb->eyeX) { tb->eyeX=tb->eyeX - ((tb->eyeX - xTarget)/100); }
\r
520 if (xTarget > tb->eyeX) { tb->eyeX=tb->eyeX + ((xTarget - tb->eyeX)/100); }
\r
522 if (yTarget < tb->eyeY) { tb->eyeY=tb->eyeY - ((tb->eyeY - yTarget)/100); }
\r
523 if (yTarget > tb->eyeY) { tb->eyeY=tb->eyeY + ((yTarget - tb->eyeY)/100); }
\r
525 tb->eyeX = xTarget;
\r
526 tb->eyeY = yTarget;
\r
527 ***************************************************************************
\r
529 if (!tb->blockNodeFollow->falling) {
\r
531 /*tb->blockNodeFollow->color=2; only noticable if you set the colors to 1 */
\r
532 tb->followRadius=0;
\r
535 gluLookAt(camX, camY, camZ-tb->eyeLine, tb->eyeX, tb->eyeY, -tb->eyeZ,-1.0,0.0,0.0);
\r
538 /* each quater of the circle has to be adjusted for */
\r
539 static double quadrantCorrection(double angle,int cx,int cy,int x,int y) {
\r
540 if ((x>=cx) && (y>=cy)) {
\r
541 angle = angle + (90-(angle-90) * 2);
\r
542 } else if ((x>=cx) && (y<=cy)) {
\r
543 angle = angle + 90;
\r
544 } else if ((x<=cx) && (y<=cy)) {
\r
545 angle = angle + 90;
\r
546 } else if ((x<=cx) && (y>=cy)) {
\r
547 angle = angle + (90-(angle-90) * 2);
\r
552 /* if random chance then create a new falling block */
\r
553 static void generateNewBlock(ModeInfo *mi) {
\r
554 NODE *llCurrent, *llTail;
\r
555 GLfloat startOffx, startOffy;
\r
556 int endOffx, endOffy;
\r
557 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
\r
558 if ( ((random() % spawn) == 1) && (tb->highestFalling<getHeight((tb->plusheight-blockHeight)+tb->highest)) ) {
\r
563 tb->numFallingBlocks++;
\r
564 llTail = tb->blockNodeRoot;
\r
565 if (llTail == NULL) {
\r
566 if ((llCurrent = ((NODE*) malloc(sizeof(NODE)))) == NULL) { fprintf(stderr, "%s: out of memory.\n", progname); }
\r
567 llTail = llCurrent;
\r
568 tb->blockNodeRoot = llCurrent;
\r
570 if (tb->numFallingBlocks>=maxFalling) {
\r
572 llCurrent=llTail->next;
\r
573 tb->blockNodeRoot=llCurrent->next;
\r
575 if ((llCurrent = ((NODE*) malloc(sizeof(NODE)))) == NULL) { fprintf(stderr, "%s: out of memory..\n", progname); }
\r
577 while (llTail->next != NULL) { llTail = llTail->next; } /* find last item in list */
\r
579 llCurrent->falling=1;
\r
580 llCurrent->rotation=getOrientation(random() % 4);
\r
581 if (llCurrent->rotation==getOrientation(0)) {
\r
586 } else if (llCurrent->rotation==getOrientation(1)) {
\r
591 } else if (llCurrent->rotation==getOrientation(2)) {
\r
596 } else if (llCurrent->rotation==getOrientation(3)) {
\r
603 llCurrent->x=(startOffx-(tb->carpetLength/2)) + getLocation(random() % ((tb->carpetLength/2)+endOffx) );
\r
604 llCurrent->y=(startOffy-(tb->carpetLength/2)) + getLocation(random() % ((tb->carpetLength/2)+endOffy) );
\r
605 llCurrent->color=(random() % maxColors);
\r
606 llCurrent->height=getHeight(tb->plusheight+tb->highest);
\r
607 if (tb->numFallingBlocks>=maxFalling) {
\r
608 tb->numFallingBlocks--;
\r
609 tb->numFallingBlocks--;
\r
611 llTail->next = llCurrent;
\r
612 llTail = llCurrent;
\r
613 llTail->next = NULL;
\r
618 /* called at init this creates the 'carpet' display list item */
\r
619 static void buildCarpet(ModeInfo *mi) {
\r
622 int wire = MI_IS_WIREFRAME(mi);
\r
623 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
\r
624 GLUquadricObj *quadratic;
\r
629 tb->carpet=glGenLists(1); /* only one */
\r
630 glNewList(tb->carpet,GL_COMPILE);
\r
631 glPushMatrix(); /* save state */
\r
633 y=tb->carpetLength;
\r
634 if (wire) { glColor3fv(color); }
\r
635 else { glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); }
\r
636 /* draw carpet plane */
\r
637 glBegin( wire ? GL_LINE_LOOP : GL_QUADS );
\r
639 glNormal3f( 0, 0, -1 );
\r
640 glVertex3f(0.0,0.0,0.0);
\r
641 glVertex3f(x,0.0,0.0);
\r
642 glVertex3f(x,y,0.0);
\r
643 glVertex3f(0.0,y,0.0);
\r
644 if (wire) { glEnd(); }
\r
646 /* add edge pieces */
\r
648 glNormal3f( 0, -1, 0 );
\r
649 glVertex3f(0.0,0.0,0.0);
\r
650 glVertex3f(x,0.0,0.0);
\r
651 glVertex3f(x,0,singleThick);
\r
652 glVertex3f(0.0,0,singleThick);
\r
654 glNormal3f( -1, 0, 0 );
\r
655 glVertex3f(0.0,0.0,0.0);
\r
656 glVertex3f(0,y,0.0);
\r
657 glVertex3f(0,y,singleThick);
\r
658 glVertex3f(0.0,0,singleThick);
\r
660 glNormal3f( 1, 0, 0 );
\r
661 glVertex3f(x,0.0,0.0);
\r
662 glVertex3f(x,y,0.0);
\r
663 glVertex3f(x,y,singleThick);
\r
664 glVertex3f(x,0,singleThick);
\r
666 glNormal3f( 0, 1, 0 );
\r
667 glVertex3f(0,y,0.0);
\r
668 glVertex3f(x,y,0.0);
\r
669 glVertex3f(x,y,singleThick);
\r
670 glVertex3f(0,y,singleThick);
\r
675 quadratic=gluNewQuadric(); /* Create A Pointer To The Quadric Object */
\r
676 gluQuadricNormals(quadratic, GLU_SMOOTH); /* Create Smooth Normals */
\r
677 gluQuadricTexture(quadratic, GL_TRUE); /* Create Texture Coords */
\r
678 glTranslatef(0.5f,0.5f,-.25); /* move to the cylinder center */
\r
679 for (c=0;c<x;c++) {
\r
680 glPushMatrix(); /* save state */
\r
681 for (i=0;i<y;i++) {
\r
682 gluCylinder(quadratic, cylSize, cylSize, 0.25f, resolution, resolution); /* quad, radius(bottom, radius(top), height, subdivisions (around Z), subdevisions (along Z) */
\r
683 glRotatef(180, 0.0f, 1.0f, 0.0f); /* they are upside down */
\r
684 gluDisk(quadratic, 0.0f, cylSize, resolution, resolution ); /* inner size (cd hole), outer size (radius), subdivisions radial, subdivisions circular */
\r
685 glRotatef(180, 0.0f, 1.0f, 0.0f); /* recover */
\r
686 glTranslatef(0.0f,1.0f,0.0f); /* move to the next cylinder center (backward) */
\r
688 glPopMatrix(); /* save state */
\r
689 glTranslatef(1.0f,0.0f,0.0f); /* reset */
\r
692 glPopMatrix(); /* restore state */
\r
696 /* using the verticies arrays builds the plane, now with normals */
\r
697 static void polygonPlane(int wire, int a, int b, int c , int d, int i)
\r
699 GLfloat topBlockNormals[5][3] = { {0,0,-1}, {0,1,0}, {1,0,0}, {0,0,1}, {0,-1,0} };
\r
700 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} };
\r
701 glBegin( wire ? GL_LINE_LOOP : GL_POLYGON);
\r
702 glNormal3fv(topBlockNormals[i] );
\r
703 glVertex3fv(topBlockVertices[a]);
\r
704 glVertex3fv(topBlockVertices[b]);
\r
705 glVertex3fv(topBlockVertices[c]);
\r
706 glVertex3fv(topBlockVertices[d]);
\r
710 /* called at init this creates the 'block' display list item */
\r
711 /* the spheres came about originaly as quick way to test the directional lighting/normals */
\r
712 static void buildBlock(ModeInfo *mi) {
\r
714 int wire = MI_IS_WIREFRAME(mi);
\r
715 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
\r
716 GLUquadricObj *quadratic;
\r
717 tb->block=glGenLists(1); /* only one */
\r
718 glNewList(tb->block,GL_COMPILE);
\r
719 glPushMatrix(); /* save state */
\r
720 glRotatef(90, 0.0f, 1.0f, 0.0f);
\r
722 polygonPlane(wire, 0,3,2,1,0);
\r
723 polygonPlane(wire, 2,3,7,6,1);
\r
724 polygonPlane(wire, 1,2,6,5,2);
\r
725 polygonPlane(wire, 4,5,6,7,3);
\r
726 polygonPlane(wire, 0,1,5,4,4);
\r
729 /* draw 8 cylinders each with a disk cap */
\r
730 quadratic=gluNewQuadric(); /* Create A Pointer To The Quadric Object */
\r
731 gluQuadricNormals(quadratic, GLU_SMOOTH); /* Create Smooth Normals */
\r
732 glRotatef(90, 0.0f, 1.0f, 0.0f); /* 'aim' the pointer ready for the cylinder */
\r
733 glTranslatef(0.5f,0.5f,0.99f); /* move to the cylinder center */
\r
734 for (c=0;c<2;c++) {
\r
735 for (i=0;i<4;i++) {
\r
736 gluCylinder(quadratic, cylSize, cylSize, 0.25f, resolution, resolution); /* quad, radius(bottom, radius(top), height, subdivisions (around Z), subdevisions (along Z) */
\r
737 glTranslatef(0.0f,0.0f,0.25f); /* move to the cylinder cap */
\r
738 gluDisk(quadratic, 0.0f, cylSize, resolution, resolution ); /* inner size (cd hole), outer size (radius), subdivisions radial, subdivisions circular */
\r
739 glTranslatef(0.0f,0.0f,-0.25f); /* move back from the cylinder cap */
\r
741 glTranslatef(0.0f,-1.0f,0.0f); /* move to the next cylinder center (forward) */
\r
743 glTranslatef(0.0f,1.0f,0.0f); /* move to the next cylinder center (backward) */
\r
746 glTranslatef(-1.0f,1.0f,0.0f); /* move to the cylinder center */
\r
749 /* 3 cylinders on the underside */
\r
750 glTranslatef(1.5f,-2.5f,-1.5f); /* move to the center, under the top of the brick */
\r
751 for (c=0;c<3;c++) {
\r
752 gluCylinder(quadratic, uddSize, uddSize, 1.5f, resolution, resolution); /* quad, radius(bottom, radius(top), height, subdivisions (around Z), subdevisions (along Z) */
\r
753 glTranslatef(0.0f,-1.0f,0.0f); /* move to the center */
\r
756 glPopMatrix(); /* restore state */
\r
761 rip off of the builBlock() function creating the GL compilied pointer "block" but only creates two spheres.
\r
762 spheres are created with unit_sphere from spheres.h to allow wire frame
\r
764 static void buildBlobBlock(ModeInfo *mi) {
\r
765 int wire = MI_IS_WIREFRAME(mi);
\r
766 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
\r
767 tb->block=glGenLists(1); /* only one */
\r
768 glNewList(tb->block,GL_COMPILE);
\r
770 glScalef(1.4,1.4,1.4);
\r
771 unit_sphere (resolution/2,resolution, wire);
\r
773 glTranslatef(0.0f,-2.0f,0.0f);
\r
774 glScalef(1.4,1.4,1.4);
\r
775 unit_sphere (resolution/2,resolution, wire);
\r
780 /* handle input events or not if daemon running the show */
\r
782 topBlock_handle_event (ModeInfo *mi, XEvent *event) {
\r
783 topBlockSTATE *tb = &tbs[MI_SCREEN(mi)];
\r
784 if (event->xany.type == KeyPress) {
\r
787 XLookupString (&event->xkey, &c, 1, &keysym, 0);
\r
789 tb->eyeX=tb->eyeX+1;
\r
791 } else if (c == 'z') {
\r
792 tb->eyeX=tb->eyeX-1;
\r
794 } else if (c == 's') {
\r
795 tb->eyeY=tb->eyeY+1;
\r
797 } else if (c == 'x') {
\r
798 tb->eyeY=tb->eyeY-1;
\r
800 } else if (c == 'd') {
\r
801 tb->eyeZ=tb->eyeZ+1;
\r
803 } else if (c == 'c') {
\r
804 tb->eyeZ=tb->eyeZ-1;
\r
806 } else if (c == 'f') {
\r
809 } else if (c == 'v') {
\r
812 } else if (c == 'g') {
\r
815 } else if (c == 'b') {
\r
818 } else if (c == 'h') {
\r
821 } else if (c == 'n') {
\r
824 } else if (c == 'r') {
\r
832 /* this is tha main change for v5 compatability and acompanying ENTRYPOINTS */
\r
833 XSCREENSAVER_MODULE_2 ("topBlock", topblock, topBlock)
\r
835 #endif /* USE_GL */
\r