http://packetstormsecurity.org/UNIX/admin/xscreensaver-3.34.tar.gz
[xscreensaver] / hacks / glx / circuit.c
1 /*
2  * circuit - Random electronic components floating around
3  *
4  * version 1.3
5  *
6  * Since version 1.1: added to-220 transistor, added fuse
7  * Since version 1.2: random display digits, LED improvements (flickering)
8  *
9  * Copyright (C) 2001 Ben Buxton (bb@cactii.net)
10  *
11  * Permission to use, copy, modify, distribute, and sell this software and its
12  * documentation for any purpose is hereby granted without fee, provided that
13  * the above copyright notice appear in all copies and that both that
14  * copyright notice and this permission notice appear in supporting
15  * documentation.  No representations are made about the suitability of this
16  * software for any purpose.  It is provided "as is" without express or
17  * implied warranty.
18  */
19
20 /* Written over a few days in a (successful) bid to learn GL coding 
21  *
22  * -seven option is dedicated to all the Slarkeners
23  *
24  * try "-rotate -rotate-speed 0"
25  *
26  * This hack uses lookup tables for sin, cos and tan - it can do a lot
27  */
28
29
30 #include <X11/Intrinsic.h>
31
32 #ifdef STANDALONE
33 # define PROGCLASS                                      "Circuit"
34 # define HACK_INIT                                      init_circuit
35 # define HACK_DRAW                                      draw_circuit
36 # define HACK_RESHAPE                           reshape_circuit
37 # define circuit_opts                                     xlockmore_opts
38 /* insert defaults here */
39
40 #define DEF_SPIN        "True"
41 #define DEF_SEVEN       "False"
42 #define DEF_PARTS       "10"
43
44
45 #define DEFAULTS        "*parts:      " DEF_PARTS " \n" \
46                         "*spin:       " DEF_SPIN   "\n" \
47                         "*delay:       20000       \n" \
48                         "*showFPS:       False       \n" \
49                         "*seven:      " DEF_SEVEN  "\n" \
50                         "*light:      True  \n" \
51                         "*rotate:      False\n" \
52                         "*rotatespeed:      1\n" \
53
54 # include "xlockmore.h"                         /* from the xscreensaver distribution */
55 #else  /* !STANDALONE */
56 # include "xlock.h"                                     /* from the xlockmore distribution */
57 #endif /* !STANDALONE */
58
59 /* lifted from lament.c */
60 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
61 #define RANDSIGN() ((random() & 1) ? 1 : -1)
62
63
64 #ifdef USE_GL
65
66 #include <GL/glu.h>
67
68
69 static int maxparts;
70 static int spin;
71 static int seven;
72 static int rotate;
73 static int rotatespeed;
74 static int uselight;
75 int def_parts = 10;
76
77 #undef countof
78 #define countof(x) (sizeof((x))/sizeof((*x)))
79
80 static XrmOptionDescRec opts[] = {
81   {"-parts", ".circuit.parts", XrmoptionSepArg, "10" },
82   {"-rotate-speed", ".circuit.rotatespeed", XrmoptionSepArg, "1" },
83   {"+spin", ".circuit.spin", XrmoptionNoArg, (caddr_t) "false" },
84   {"-spin", ".circuit.spin", XrmoptionNoArg, (caddr_t) "true" },
85   {"+light", ".circuit.light", XrmoptionNoArg, (caddr_t) "false" },
86   {"-light", ".circuit.light", XrmoptionNoArg, (caddr_t) "true" },
87   {"+seven", ".circuit.seven", XrmoptionNoArg, (caddr_t) "false" },
88   {"-seven", ".circuit.seven", XrmoptionNoArg, (caddr_t) "true" },
89   {"+rotate", ".circuit.rotate", XrmoptionNoArg, (caddr_t) "false" },
90   {"-rotate", ".circuit.rotate", XrmoptionNoArg, (caddr_t) "true" },
91 };
92
93 static argtype vars[] = {
94   {(caddr_t *) &maxparts, "parts", "Parts", DEF_PARTS, t_Int},
95   {(caddr_t *) &rotatespeed, "rotatespeed", "Rotatespeed", "1", t_Int},
96   {(caddr_t *) &spin, "spin", "Spin", DEF_SPIN, t_Bool},
97   {(caddr_t *) &rotate, "rotate", "Rotate", "False", t_Bool},
98   {(caddr_t *) &uselight, "light", "Light", "True", t_Bool},
99   {(caddr_t *) &seven, "seven", "Seven", DEF_SEVEN, t_Bool},
100 };
101
102 ModeSpecOpt circuit_opts = {countof(opts), opts, countof(vars), vars, NULL};
103
104 #ifdef USE_MODULES
105 ModStruct   circuit_description =
106 {"circuit", "init_circuit", "draw_circuit", "release_circuit",
107  "draw_circuit", "init_circuit", NULL, &circuit_opts,
108  1000, 1, 2, 1, 4, 1.0, "",
109  "Flying electronic components", 0, NULL};
110
111 #endif
112
113
114 typedef struct {
115   GLXContext *glx_context;
116   Window window;
117 } Circuit;
118
119 static Circuit *circuit = NULL;
120
121 #include <math.h>
122 #include <sys/time.h>
123 #include <stdio.h>
124 #include <stdlib.h>
125
126 #ifndef M_PI
127 #define M_PI 3.14159265
128 #endif
129
130 /* window width, height */
131 int win_w, win_h;
132
133 /* width and height of viewport */
134
135 #define XMAX 30
136 #define YMAX 30
137
138 #define MAX_COMPONENTS 30
139
140 #define MOVE_MULT 0.05
141
142 static float f_rand(void) {
143    return ((float)RAND(10000)/(float)10000);
144 }
145
146 #define RAND_RANGE(min, max) ((min) + (max - min) * f_rand())
147
148 /* one lucky led gets to be a light source , unless -no-light*/
149 int light = 0;
150 int lighton = 0;
151
152 static GLfloat viewer[] = {0.0, 0.0, 14.0};
153 static GLfloat lightpos[] = {7.0, 7.0, 15, 1.0};
154
155 float sin_table[720];
156 float cos_table[720];
157 float tan_table[720];
158
159
160 /* Represents a band on a resistor/diode/etc */
161 typedef struct {
162   float pos;     /* relative position from start/previous band */
163   GLfloat r, g, b; /* colour of the band */
164   float len;     /* length as a fraction of total length */
165 } Band;
166
167 typedef struct {
168   Band *b1, *b2, *b3, *b4; /* bands */
169   int b[4];
170 } Resistor;
171
172 typedef struct {
173   Band *band;
174   GLfloat r, g, b; /* body colour */
175 } Diode;
176
177 typedef struct {
178   int type; /* package type. 0 = to-92, 1 = to-220 */
179 } Transistor;
180
181 typedef struct {
182   GLfloat r,g,b; /* LED colour */
183   int light; /* are we the light source? */
184 } LED;
185
186 typedef struct {
187   int type; /* 0 = electro, 1 = ceramic */
188   float width; /* width of an electro/ceramic */
189   float length; /* length of an electro */
190 } Capacitor;
191
192 typedef struct {
193   int type; /* 0 = DIL, 1 = flat square */
194   int pins; 
195 } IC;
196
197 /* 7 segment display */
198
199 typedef struct {
200   int value; /* displayed number */
201 } Disp;
202
203 typedef struct {
204   GLfloat l, w;
205 } Fuse;
206
207 typedef struct {
208   GLfloat x, y, z; /* current co-ordinates */
209   GLfloat dx, dy, dz; /* current direction */
210   GLfloat rotx, roty, rotz; /* rotation vector */
211   GLfloat drot; /* rotation velocity (degrees per frame) */
212   int norm; /* Normalize this component (for shine) */
213   int rdeg; /* current rotation degrees */
214   int angle; /* angle about the z axis */
215   int alpha; /* 0 if not a transparent component */
216   int type;  /* 0 = resistor, 1 = diode, 2 = transistor, 3 = LED, 4 = cap, 5=IC,
217                 6 = 7 seg disp */
218   void * c; /* pointer to the component */
219 } Component;
220
221 static int band_list[12];
222   
223 /* standard colour codes */
224
225 static GLfloat colorcodes [12][3] = {
226   {0.0,0.0,0.0},    /* black  0 */
227   {0.49,0.25,0.08}, /* brown  1 */
228   {1.0,0.0,0.0},    /* red    2 */
229   {1.0,0.5,0.0},    /* orange 3 */
230   {1.0,1.0,0.0},    /* yellow 4 */
231   {0.0,1.0,0.0},    /* green  5 */
232   {0.0,0.5,1.0},    /* blue   6 */
233   {0.7,0.2,1.0},    /* violet 7 */
234   {0.5,0.5,0.5},    /* grey   8 */
235   {1.0,1.0,1.0},    /* white  9 */
236   {0.66,0.56,0.2},    /* gold  10 */
237   {0.8,0.8,0.8},    /* silver 11 */
238 };
239
240 /* base values for components - we can multiply by 0 - 1M */
241 static int values [9][2] = {
242   {1,0},
243   {2,2},
244   {3,3},
245   {4,7},
246   {5,6},
247   {6,8},
248   {7,5},
249   {8,2},
250   {9,1}
251 };
252
253 void DrawResistor(Resistor *);
254 void DrawDiode(Diode *);
255 void DrawTransistor(Transistor *);
256 void DrawLED(LED *);
257 void DrawIC(IC *);
258 void DrawCapacitor(Capacitor *);
259 void DrawDisp(Disp *);
260 void DrawFuse(Fuse *);
261
262 void reorder(Component *[]);
263 void circle(float, int,int);
264 void bandedCylinder(float, float , GLfloat, GLfloat , GLfloat,  Band **, int);
265 Resistor *NewResistor(void);
266 Diode *NewDiode(void);
267 Transistor *NewTransistor(void);
268 LED * NewLED(void);
269 Capacitor *NewCapacitor(void);
270 IC* NewIC(void);
271 Disp* NewDisp(void);
272 Fuse *NewFuse(void);
273
274 /* we use trig tables to speed things up - 200 calls to sin()
275  in one frame can be a bit harsh..
276 */
277
278 void make_tables(void) {
279 int i;
280 float f;
281
282   f = 360 / (M_PI * 2);
283   for (i = 0 ; i < 720 ; i++) {
284     sin_table[i] = sin(i/f);
285   }
286   for (i = 0 ; i < 720 ; i++) {
287     cos_table[i] = cos(i/f);
288   }
289   for (i = 0 ; i < 720 ; i++) {
290     tan_table[i] = tan(i/f);
291   }
292 }
293
294
295 void createCylinder (float length, float radius, int endcaps, int half) {
296 int a; /* current angle around cylinder */
297 int angle, norm;
298 float z1, y1, z2, y2, ex;
299 int nsegs;
300
301   glPushMatrix();
302   nsegs = radius*MAX(win_w, win_h)/10;
303   nsegs = MAX(nsegs, 6);
304   if (nsegs % 2)
305      nsegs += 1;
306   angle = (half) ? (180 - 90/nsegs) : 374;
307   z1 = radius; y1 = 0;
308   glBegin(GL_QUADS);
309   for (a = 0 ; a <= angle ; a+= angle/nsegs) {
310     y2=radius*(float)sin_table[(int)a];
311     z2=radius*(float)cos_table[(int)a];
312       glNormal3f(0, y1, z1);
313       glVertex3f(0,y1,z1);
314       glVertex3f(length,y1,z1);
315       glVertex3f(length,y2,z2);
316       glVertex3f(0,y2,z2);
317     z1=z2;
318     y1=y2;
319   }
320   glEnd();
321   if (half) {
322     glBegin(GL_POLYGON);
323       glNormal3f(0, 1, 0);
324       glVertex3f(0, 0, radius);
325       glVertex3f(length, 0, radius);
326       glVertex3f(length, 0, 0 - radius);
327       glVertex3f(0, 0, 0 - radius);
328     glEnd();
329   }
330   if (endcaps) {
331     for(ex = 0 ; ex <= length ; ex += length) {
332       z1 = radius; y1 = 0;
333       norm = (ex == length) ? 1 : -1;
334       for (a = 0 ; a <= angle ; a+= angle/nsegs) {
335         y2=radius*(float)sin_table[(int)a];
336         z2=radius*(float)cos_table[(int)a];
337         glBegin(GL_TRIANGLES);
338           glNormal3f(norm, 0, 0);
339           glVertex3f(ex,0, 0);
340           glVertex3f(ex,y1,z1);
341           glVertex3f(ex,y2,z2);
342         glEnd();
343         z1=z2;
344         y1=y2;
345       }
346     }
347   }
348   glPopMatrix();
349 }
350
351 void circle(float radius, int segments, int half) {
352 float x1 = 0, x2 = 0;
353 float y1 = 0, y2 = 0;
354 int i, t, s;
355
356   if (half) {
357     t = 270; s = 90;
358     x1 = radius, y1 = 0;
359   } else {
360     t = 360, s = 0;
361   }
362   glBegin(GL_TRIANGLES);
363   glNormal3f(1, 0, 0);
364   for(i=s;i<=t;i+=10)
365   {
366     float angle=i;
367     x2=radius*(float)cos_table[(int)angle];
368     y2=radius*(float)sin_table[(int)angle];
369     glVertex3f(0,0,0);
370     glVertex3f(0,y1,x1);
371     glVertex3f(0,y2,x2);
372     x1=x2;
373     y1=y2;
374   }
375   glEnd();
376 }
377
378 void wire(float len) {
379 static GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
380 static GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
381 static GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
382 GLfloat shin = 30;
383 int n;
384
385   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
386   glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
387   glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
388   n = glIsEnabled(GL_NORMALIZE);
389   if (!n) glEnable(GL_NORMALIZE);
390   createCylinder(len, 0.05, 1, 0);
391   if (!n) glDisable(GL_NORMALIZE);
392   glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
393 }
394
395 void ring(GLfloat inner, GLfloat outer, int nsegs) {
396 GLfloat z1, z2, y1, y2;
397 GLfloat Z1, Z2, Y1, Y2;
398 int i;
399
400   z1 = inner; y1 = 0;
401   Z1 = outer; Y1 = 0;
402   glBegin(GL_QUADS);
403   glNormal3f(1, 0, 0);
404   for(i=0; i <=360 ; i+= 360/nsegs)
405   {
406     float angle=i;
407     z2=inner*(float)sin_table[(int)angle];
408     y2=inner*(float)cos_table[(int)angle];
409     Z2=outer*(float)sin_table[(int)angle];
410     Y2=outer*(float)cos_table[(int)angle];
411     glVertex3f(0, Y1, Z1);
412     glVertex3f(0, y1, z1);
413     glVertex3f(0, y2, z2);
414     glVertex3f(0, Y2, Z2);
415     z1=z2;
416     y1=y2;
417     Z1=Z2;
418     Y1=Y2;
419   }
420   glEnd();
421 }
422
423 void sphere(GLfloat r, float stacks, float slices,
424              int startstack, int endstack, int startslice,
425              int endslice) {
426 GLfloat d, d1, dr, dr1, Dr, Dr1, D, D1, z1, z2, y1, y2, Y1, Z1, Y2, Z2;
427 int a, a1, b, b1, c, c1;
428 GLfloat step, sstep;
429
430       step = 180/stacks;
431       sstep = 360/slices;
432       a1 = startstack * step;
433       b1 = startslice * sstep;
434       y1 = z1 = Y1 = Z1 = 0;
435       c = (endslice / slices) * 360;
436       c1 = (endstack/stacks)*180;
437       glBegin(GL_QUADS);
438       for (a = startstack * step ; a <= c1 ; a+= step) {
439         d=sin_table[a];
440         d1=sin_table[a1];
441         D=cos_table[a];
442         D1=cos_table[a1];
443         dr = d * r;
444         dr1 = d1 * r;
445         Dr = D * r;
446         Dr1 = D1 * r;
447         for (b = b1 ; b <= c ; b+= sstep) {
448           y2=dr*sin_table[b];
449           z2=dr*cos_table[b];
450           Y2=dr1*sin_table[b];
451           Z2=dr1*cos_table[b];
452             glNormal3f(D, y1, z1);
453             glVertex3f(Dr,y1,z1);
454             glVertex3f(Dr,y2,z2);
455             glVertex3f(Dr1,Y2,Z2);
456             glVertex3f(Dr1,Y1,Z1);
457           z1=z2;
458           y1=y2;
459           Z1=Z2;
460           Y1=Y2;
461         }
462         a1 = a;
463      }
464      glEnd();
465 }
466
467 int DrawComponent(Component *c) {
468 int ret = 0; /* return 1 if component is freed */
469
470    glPushMatrix();
471    glTranslatef(c->x, c->y, c->z);
472      if (c->angle > 0) {
473         glRotatef(c->angle, 0, 0, 1);
474      }
475    if (spin) {
476      glRotatef(c->rdeg, c->rotx, c->roty, c->rotz);
477      c->rdeg += c->drot;
478    }
479
480    if (c->norm)
481      glEnable(GL_NORMALIZE);
482    else
483      glDisable(GL_NORMALIZE);
484
485  /* call object draw routine here */
486    if (c->type == 0) {
487      DrawResistor(c->c);
488    } else if (c->type == 1) {
489      DrawDiode(c->c);
490    } else if (c->type == 2) {
491      DrawTransistor(c->c);
492    } else if (c->type == 3) {
493      if (((LED *)c->c)->light && light) {
494        GLfloat lp[] = {0.1, 0, 0, 1};
495        glEnable(GL_LIGHT1);
496        glLightfv(GL_LIGHT1, GL_POSITION, lp);
497      }
498      DrawLED(c->c);
499    } else if (c->type == 4) {
500      DrawCapacitor(c->c);
501    } else if (c->type == 5) {
502      DrawIC(c->c);
503    } else if (c->type == 6) {
504      DrawDisp(c->c);
505    } else if (c->type == 7) {
506      DrawFuse(c->c);
507    }
508    c->x += c->dx * MOVE_MULT;
509    c->y += c->dy * MOVE_MULT;
510    if (c->x > XMAX/2 || c->x < 0 - XMAX/2 ||
511        c->y > YMAX/2 || c->y < 0 - YMAX/2) {
512         if (c->type == 3 && ((LED *)c->c)->light && light) {
513           glDisable(GL_LIGHT1);
514           light = 0; lighton = 0;
515         }
516         free(c->c);
517         ret = 1;
518    }
519
520    glPopMatrix();
521    glDisable(GL_NORMALIZE);
522    return ret;
523 }
524 /* draw a resistor */
525
526 void DrawResistor(Resistor *r) {
527 int i;
528 GLfloat col[] = {0.74, 0.62, 0.46, 1.0};
529 GLfloat spec[] = {0.8, 0.8, 0.8, 1.0};
530 GLfloat shine = 30;
531
532    glTranslatef(-4, 0, 0);
533    wire(3);
534    glTranslatef(3, 0, 0);
535    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
536    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
537    glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
538    createCylinder(1.8, 0.4, 1, 0);
539    glPushMatrix();
540    for (i = 0 ; i < 4 ; i++) {
541      glTranslatef(0.35, 0, 0);
542      glCallList(band_list[r->b[i]]);
543    }
544    glPopMatrix();
545    glTranslatef(1.8, 0, 0);
546    wire(3);
547 }
548
549 void DrawFuse(Fuse *f) {
550 static GLfloat col[] = {0.5, 0.5, 0.5, 1.0}; /* endcaps */
551 static GLfloat glass[] = {0.4, 0.4, 0.4, 0.3}; /* glass */
552 static GLfloat spec[] = {1, 1, 1, 1}; /* glass */
553
554    glPushMatrix();
555    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
556    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
557    glMateriali(GL_FRONT, GL_SHININESS, 40);
558    createCylinder(0.8, 0.45, 1, 0);
559    glTranslatef(0.8, 0, 0);
560    glEnable(GL_BLEND);
561    glDepthMask(GL_FALSE);
562    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
563    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, glass);
564    glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 40);
565    createCylinder(2, 0.4, 0, 0);
566    createCylinder(2, 0.3, 0, 0);
567    glDisable(GL_BLEND);
568    glDepthMask(GL_TRUE);
569    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
570    glMateriali(GL_FRONT, GL_SHININESS, 40);
571    glBegin(GL_LINES);
572    glVertex3f(0, 0, 0);
573    glVertex3f(2, 0. ,0);
574    glEnd();
575    glTranslatef(2, 0, 0);
576    createCylinder(0.8, 0.45, 1, 0);
577    glPopMatrix();
578 }
579
580
581 void DrawCapacitor(Capacitor *c) {
582 static GLfloat col[] = {0, 0, 0, 0};
583 static GLfloat spec[] = {0.8, 0.8, 0.8, 0};
584 GLfloat brown[] = {0.84, 0.5, 0};
585 static GLfloat shine = 40;
586
587   glPushMatrix();
588   if (c->type) {
589     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, brown);
590     sphere(c->width, 20, 20, 0, 5 ,0, 20);
591     glTranslatef(1.45*c->width, 0, 0);
592     sphere(c->width, 20, 20, 15, 20, 0, 20);
593     glRotatef(90, 0, 0, 1);
594     glTranslatef(0, 0.7*c->width, 0.3*c->width);
595     wire(3*c->width);
596     glTranslatef(0, 0, -0.6*c->width);
597     wire(3*c->width);
598   } else {
599     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
600     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
601     glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
602     glBegin(GL_POLYGON);
603      glVertex3f(0, 0.82*c->width, -0.1);
604      glVertex3f(3*c->length, 0.82*c->width, -0.1);
605      glVertex3f(3*c->length, 0.82*c->width, 0.1);
606      glVertex3f(0, 0.82*c->width, 0.1);
607     glEnd();
608     col[0] = 0.7;
609     col[1] = 0.7;
610     col[2] = 0.7;
611     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
612     circle(0.6*c->width, 30, 0);
613     col[0] = 0.0;
614     col[1] = 0.2;
615     col[2] = 0.9;
616     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
617     ring(0.6*c->width, 0.8*c->width, 30);
618     glTranslatef(0.01, 0.0, 0);
619     createCylinder(3.0*c->length, 0.8*c->width, 1, 0);
620     col[0] = 0;
621     col[1] = 0;
622     col[2] = 0;
623     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
624     glTranslatef(3.01*c->length, 0.0, 0);
625     circle(0.6*c->width, 30, 0);
626     glTranslatef(0, 0.4*c->width, 0);
627     wire(3*c->length);
628     glTranslatef(0.0, -0.8*c->width, 0);
629     wire(3.3*c->length);
630   }
631   glPopMatrix();
632 }
633
634 void DrawLED(LED *l) {
635 GLfloat col[] = {0, 0, 0, 0.6};
636
637   col[0] = l->r; col[1] = l->g; col[2] = l->b;
638   if (l->light && light) {
639     GLfloat dir[] = {-1, 0, 0};
640     glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, dir);
641     if (!lighton) {
642       glLightfv(GL_LIGHT1, GL_SPECULAR, col);
643       glLightfv(GL_LIGHT1, GL_AMBIENT, col);
644       glLightfv(GL_LIGHT1, GL_DIFFUSE, col);
645       glLighti(GL_LIGHT1, GL_SPOT_CUTOFF, (GLint) 90);
646       glLighti(GL_LIGHT1, GL_CONSTANT_ATTENUATION, (GLfloat)1); 
647       glLighti(GL_LIGHT1, GL_LINEAR_ATTENUATION, (GLfloat)0); 
648       glLighti(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, (GLfloat)0); 
649       glLighti(GL_LIGHT1, GL_SPOT_EXPONENT, (GLint) 20);
650       lighton = 1;
651     }
652   }
653   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
654   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
655   /* no transparency when LED is lit */
656   if (!l->light) { 
657     glEnable(GL_BLEND);
658     glDepthMask(GL_FALSE);
659     glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
660   }
661   createCylinder(1.2, 0.3, 0, 0);
662   if (l->light && light) {
663     glDisable(GL_LIGHTING);
664     glColor3fv(col);
665   }
666   sphere(0.3, 10, 10, 5, 10, 0, 10);
667   if (l->light && light) {
668     glEnable(GL_LIGHTING);
669   } else {
670     glDepthMask(GL_TRUE);
671     glDisable(GL_BLEND);
672   }
673
674   glTranslatef(1.2, 0, 0);
675   createCylinder(0.1, 0.38, 1, 0);
676   glTranslatef(-0.3, 0.15, 0);
677   wire(3);
678   glTranslatef(0, -0.3, 0);
679   wire(3.3);
680   if (random() % 50 == 25) {
681     if (l->light) {
682       l->light = 0; light = 0; lighton = 0;
683       glDisable(GL_LIGHT1);
684     } else if (!light) {
685       l->light = 1; light = 1;
686     }
687   }
688 }
689    
690
691
692 void DrawDiode(Diode *d) {
693 GLfloat shine = 40;
694 GLfloat col[] = {0.3, 0.3, 0.3, 0};
695 GLfloat spec[] = {0.7, 0.7, 0.7, 0};
696
697    glPushMatrix();
698    glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
699    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
700    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
701    glTranslatef(-4, 0, 0);
702    wire(3);
703    glTranslatef(3, 0, 0);
704    bandedCylinder(0.3, 1.5, d->r, d->g, d->b, &(d->band), 1);
705    glTranslatef(1.5, 0, 0);
706    wire(3);
707    glPopMatrix();
708 }
709
710 void Rect(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h,
711             GLfloat t) {
712 GLfloat yh;
713 GLfloat xw;
714 GLfloat zt;
715
716   yh = y+h; xw = x+w; zt = z - t;
717
718   glBegin(GL_QUADS); /* front */
719     glNormal3f(0, 0, 1);
720     glVertex3f(x, y, z);
721     glVertex3f(x, yh, z);
722     glVertex3f(xw, yh, z);
723     glVertex3f(xw, y, z);
724   /* back */
725     glNormal3f(0, 0, -1);
726     glVertex3f(x, y, zt);
727     glVertex3f(x, yh, zt);
728     glVertex3f(xw, yh, zt);
729     glVertex3f(xw, y, zt);
730   /* top */
731     glNormal3f(0, 1, 0);
732     glVertex3f(x, yh, z);
733     glVertex3f(x, yh, zt);
734     glVertex3f(xw, yh, zt);
735     glVertex3f(xw, yh, z);
736   /* bottom */
737     glNormal3f(0, -1, 0);
738     glVertex3f(x, y, z);
739     glVertex3f(x, y, zt);
740     glVertex3f(xw, y, zt);
741     glVertex3f(xw, y, z);
742   /* left */
743     glNormal3f(-1, 0, 0);
744     glVertex3f(x, y, z);
745     glVertex3f(x, y, zt);
746     glVertex3f(x, yh, zt);
747     glVertex3f(x, yh, z);
748   /* right */
749     glNormal3f(1, 0, 0);
750     glVertex3f(xw, y, z);
751     glVertex3f(xw, y, zt);
752     glVertex3f(xw, yh, zt);
753     glVertex3f(xw, yh, z);
754   glEnd();
755 }
756
757 /* IC pins */
758
759 void ICLeg(GLfloat x, GLfloat y, GLfloat z, int dir) {
760
761
762   if (dir) {
763     Rect(x-0.1, y, z, 0.1, 0.1, 0.02);
764     Rect(x-0.1, y, z, 0.02, 0.1, 0.1);
765     Rect(x-0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
766   } else {
767     Rect(x, y, z, 0.1, 0.1, 0.02);
768     Rect(x+0.8*0.1, y, z, 0.02, 0.1, 0.1);
769     Rect(x+0.8*0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
770   }
771
772 }
773
774
775 void DrawIC(IC *c) {
776 GLfloat w, h, d;
777 int z;
778 GLfloat col[] = {0.1, 0.1, 0.1, 0};
779 GLfloat spec[] = {0.6, 0.6, 0.6, 0};
780 GLfloat shine = 40;
781 GLfloat lspec[] = {0.6, 0.6, 0.6, 0};
782 GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
783 GLfloat lshine = 40;
784
785   glPushMatrix();
786   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
787   glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
788   glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
789   switch(c->pins) {
790     case 8:
791       w = 1.0; h = 1.5;
792       break;
793     case 14:
794       w = 1.0; h = 3;
795       break;
796     case 16:
797       w = 1.0; h = 3;
798       break;
799     case 24:
800     default:
801       w = 1.5; h = 3.5;
802       break;
803   }
804   w = w/2; h = h/2;
805     glBegin(GL_QUADS);
806       glNormal3f(0, 0, 1);
807       glVertex3f(w, h, 0.1);
808       glVertex3f(w, -h, 0.1);
809       glVertex3f(-w, -h, 0.1);
810       glVertex3f(-w, h, 0.1);
811       glNormal3f(0, 0, -1);
812       glVertex3f(w, h, -0.1);
813       glVertex3f(w, -h, -0.1);
814       glVertex3f(-w, -h, -0.1);
815       glVertex3f(-w, h, -0.1);
816       glNormal3f(1, 0, 0);
817       glVertex3f(w, h, -0.1);
818       glVertex3f(w, -h, -0.1);
819       glVertex3f(w, -h, 0.1);
820       glVertex3f(w, h, 0.1);
821       glNormal3f(0, -1, 0);
822       glVertex3f(w, -h, -0.1);
823       glVertex3f(w, -h, 0.1);
824       glVertex3f(-w, -h, 0.1);
825       glVertex3f(-w, -h, -0.1);
826       glNormal3f(-1, 0, 0);
827       glVertex3f(-w, h, -0.1);
828       glVertex3f(-w, h, 0.1);
829       glVertex3f(-w, -h, 0.1);
830       glVertex3f(-w, -h, -0.1);
831       glNormal3f(0, -1, 0);
832       glVertex3f(-w, h, -0.1);
833       glVertex3f(w, h, -0.1);
834       glVertex3f(w, h, 0.1);
835       glVertex3f(-w, h, 0.1);
836     glEnd();
837     d = (h*2-0.1) / c->pins;
838     d*=2;
839     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
840     glMaterialfv(GL_FRONT, GL_SPECULAR, lspec);
841     glMaterialfv(GL_FRONT, GL_SHININESS, &lshine);
842     for (z = 0 ; z < c->pins/2 ; z++) {
843       ICLeg(w, -h + z*d + d/2, 0, 0);
844     }
845     for (z = 0 ; z < c->pins/2 ; z++) {
846       ICLeg(-w, -h + z*d + d/2, 0, 1);
847     }
848     glPopMatrix();
849 }
850
851 void DrawDisp(Disp *d) {
852 GLfloat col[] = {0.8, 0.8, 0.8, 1.0}; /* body colour */
853 GLfloat front[] = {0.2, 0.2, 0.2, 1.0}; /* front colour */
854 GLfloat on[] = {0.9, 0, 0, 1}; /* 'on' segment */
855 GLfloat off[] = {0.3, 0, 0, 1}; /* 'off' segment */
856 int i, j, k;
857 GLfloat x, y; /* for the pins */
858 GLfloat spec[] = {0.6, 0.6, 0.6, 0};
859 GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
860 GLfloat shine = 40;
861 static GLfloat vdata_h[6][2] = 
862 {
863   {0, 0},
864   {0.1, 0.1},
865   {0.9, 0.1},
866   {1, 0},
867   {0.9, -0.1},
868   {0.1, -0.1}
869 };
870 static GLfloat vdata_v[6][2] =
871 {
872   {0.27, 0},
873   {0.35, -0.1},
874   {0.2, -0.9},
875   {0.1, -1},
876   {0, -0.9},
877   {0.15, -0.15}
878 };
879
880 static GLfloat seg_start[7][2] = 
881 {
882
883   {0.55, 2.26},
884   {1.35, 2.26},
885   {1.2, 1.27},
886   {0.25, 0.25},
887   {0.06, 1.25},
888   {0.25, 2.25},
889   {0.39, 1.24}
890 };
891
892 static int nums[10][7] =
893 {
894   {1, 1, 1, 1, 1, 1, 0}, /* 0 */
895   {0, 1, 1, 0, 0, 0, 0}, /* 1 */
896   {1, 1, 0, 1, 1, 0, 1}, /* 2 */
897   {1, 1, 1, 1, 0, 0, 1}, /* 3 */
898   {0, 1, 1, 0, 0, 1, 1}, /* 4 */
899   {1, 0, 1, 1, 0, 1, 1}, /* 5 */
900   {1, 0, 1, 1, 1, 1, 1}, /* 6 */
901   {1, 1, 1, 0, 0, 0, 0}, /* 7 */
902   {1, 1, 1, 1, 1, 1, 1}, /* 8 */
903   {1, 1, 1, 0, 0, 1, 1}  /* 9 */
904 };
905   
906    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
907    Rect(0, 0, -0.01, 1.8, 2.6, 0.7);
908    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, front);
909    glBegin(GL_QUADS);
910      glVertex2f(-0.05, -0.05);
911      glVertex2f(-0.05, 2.65);
912      glVertex2f(1.85, 2.65);
913      glVertex2f(1.85, -0.05);
914    glEnd();
915    glDisable(GL_LIGHTING); /* lit segments dont need light */
916    if (!seven && (random() % 30) == 19) { /* randomly change value */
917      d->value = random() % 10;
918    }
919    for (j = 0 ; j < 7 ; j++) { /* draw the segments */
920      GLfloat xx[6], yy[6];
921      if (nums[d->value][j])
922        glColor3fv(on);
923      else
924        glColor3fv(off);
925      for (k = 0 ; k < 6 ; k++) {
926        if (j == 0 || j == 3 || j == 6) {
927          xx[k] = seg_start[j][0] + vdata_h[k][0];
928          yy[k] = seg_start[j][1] + vdata_h[k][1];
929        } else {
930          xx[k] = seg_start[j][0] + vdata_v[k][0];
931          yy[k] = seg_start[j][1] + vdata_v[k][1];
932        }
933      }
934      glBegin(GL_POLYGON);
935      for(i = 0 ; i < 6 ; i++) {
936        glVertex3f(xx[i], yy[i], 0.01);
937      }
938      glEnd();
939    }
940    glColor3fv(on);
941    glPointSize(4);
942    glBegin(GL_POINTS);
943     glVertex3f(1.5, 0.2, 0.01);
944    glEnd();
945    glEnable(GL_LIGHTING);
946    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
947    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
948    glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
949    for (x = 0.35 ; x <= 1.5 ; x+= 1.15) {
950      for ( y = 0.2 ; y <= 2.4 ; y += 0.3) {
951        ICLeg(x, y, -0.7, 1);
952      }
953    }
954 }
955
956 void HoledRectangle(GLfloat w, GLfloat h, GLfloat d, GLfloat radius, int p) {
957 int step, a;
958 GLfloat x1, y1, x2, y2;
959 GLfloat yr, yr1, xr, xr1, side, side1;
960 GLfloat nx, ny;
961
962   step = 360 / p;
963   x1 = radius; y1 = 0;
964   xr1 = w/2; yr1 = 0;
965   side = w/2;
966   side1 = h/2;
967   glBegin(GL_QUADS);
968   for (a = 0 ; a <= 360 ; a+= step) {
969     y2=radius*(float)sin_table[(int)a];
970     x2=radius*(float)cos_table[(int)a];
971
972     if (a < 45 || a > 315) {
973       xr = side;
974       yr = side1 * tan_table[a];
975       nx = 1; ny = 0;
976     } else if (a <= 135 || a >= 225) {
977       xr = side/tan_table[a];
978       if (a >= 225) {
979        yr = -side1;
980        xr = 0 - xr;
981        nx = 0; ny = -1;
982       } else {
983        yr = side1;
984        nx = 0; ny = 1;
985      }
986     } else {
987       xr = -side;
988       yr = -side1 * tan_table[a];
989       nx = -1; ny = 0;
990     }
991
992       glNormal3f(-x1, -y1, 0); /* cylinder */
993       glVertex3f(x1,y1,0);
994       glVertex3f(x1,y1,-d);
995       glVertex3f(x2,y2,-d);
996       glVertex3f(x2,y2,0);
997
998       glNormal3f(0, 0, 1); /* front face */
999       glVertex3f(x1,y1,0);
1000       glVertex3f(xr1, yr1, 0);
1001       glVertex3f(xr, yr, 0);
1002       glVertex3f(x2, y2, 0);
1003
1004       glNormal3f(nx, ny, 0); /* side */
1005       glVertex3f(xr, yr, 0);
1006       glVertex3f(xr, yr, -d);
1007       glVertex3f(xr1, yr1, -d);
1008       glVertex3f(xr1, yr1, 0);
1009
1010       glNormal3f(0, 0, -1); /* back */
1011       glVertex3f(xr, yr, -d);
1012       glVertex3f(x2, y2, -d);
1013       glVertex3f(x1, y1, -d);
1014       glVertex3f(xr1, yr1, -d);
1015
1016     x1=x2;
1017     y1=y2;
1018     xr1 = xr; yr1 = yr;
1019   }
1020   glEnd();
1021 }
1022
1023 void DrawTransistor(Transistor *t) {
1024 static GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
1025 static GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
1026 static GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
1027 GLfloat shin = 30;
1028
1029   glPushMatrix();
1030   glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1031   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col);
1032   if (t->type == 1) {
1033     glRotatef(90, 0, 1, 0);
1034     glRotatef(90, 0, 0, 1);
1035     createCylinder(1.0, 0.4, 1, 1);
1036     Rect(0, -0.2, 0.4, 1, 0.2, 0.8);
1037     glTranslatef(-2, 0, -0.2);
1038     wire(2);
1039     glTranslatef(0, 0, 0.2);
1040     wire(2);
1041     glTranslatef(0, 0, 0.2);
1042     wire(2);
1043   } else {
1044     Rect(0, 0, 0, 1.5, 1.5, 0.75);
1045     glTranslatef(0.75, 1.875, -0.5);
1046     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1047     glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1048     glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1049     if (glIsEnabled(GL_NORMALIZE)) glEnable(GL_NORMALIZE);
1050     HoledRectangle(1.5, 0.75, 0.25, 0.2, 8);
1051     glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
1052     glTranslatef(-0.375, -1.875, 0);
1053     glRotatef(90, 0, 0, -1);
1054     wire(2);
1055     glTranslatef(0, 0.375, 0);
1056     wire(2);
1057     glTranslatef(0, 0.375, 0);
1058     wire(2);
1059   }
1060   glPopMatrix();
1061 }
1062
1063 Component * NewComponent(void) {
1064 Component *c;
1065 float rnd;
1066
1067   c = malloc(sizeof(Component));
1068   c->angle = RAND_RANGE(0,360);
1069   rnd = f_rand();
1070   if (rnd < 0.25) { /* come from the top */
1071      c->y = YMAX/2;
1072      c->x = RAND_RANGE(0, XMAX) - XMAX/2;
1073      if (c->x > 0)
1074        c->dx = 0 - RAND_RANGE(0.5, 2);
1075      else 
1076        c->dx = RAND_RANGE(0.5, 2);
1077      c->dy = 0 - RAND_RANGE(0.5, 2);
1078   } else if (rnd < 0.5) { /* come from the bottom */
1079      c->y = 0 - YMAX/2;
1080      c->x = RAND_RANGE(0, XMAX) - XMAX/2;
1081      if (c->x > 0)
1082        c->dx = 0 - RAND_RANGE(0.5, 2);
1083      else 
1084        c->dx = RAND_RANGE(0.5, 2);
1085      c->dy = RAND_RANGE(0.5, 2);
1086   } else if (rnd < 0.75) { /* come from the left */
1087      c->x = 0 - XMAX/2;
1088      c->y = RAND_RANGE(0, YMAX) - YMAX/2;
1089      c->dx = RAND_RANGE(0.5, 2);
1090      if (c->y > 0)
1091        c->dy = 0 - RAND_RANGE(0.5, 2);
1092      else 
1093        c->dy = RAND_RANGE(0.5, 2);
1094   } else { /* come from the right */
1095      c->x = XMAX/2;
1096      c->y = RAND_RANGE(0, YMAX) - YMAX/2;
1097      c->dx =  0 - RAND_RANGE(0.5, 2);
1098      if (c->y > 0)
1099        c->dy = 0 - RAND_RANGE(0.5, 2);
1100      else 
1101        c->dy = RAND_RANGE(0.5, 2);
1102   }
1103   c->z = RAND_RANGE(0, 7) - 9;
1104   c->rotx = f_rand();
1105   c->roty = f_rand();
1106   c->rotz = f_rand();
1107   c->drot = f_rand() * 7;
1108   c->rdeg = 0;
1109   c->dz = f_rand()*2 - 1;
1110   c->norm = 0;
1111   c->alpha = 0; /* explicitly set to 1 later */
1112   rnd = f_rand();
1113   if (rnd < 0.1) {
1114     c->c = NewResistor();
1115     c->type = 0;
1116     if (f_rand() < 0.4)
1117       c->norm = 1; /* some resistors shine */
1118   } else if (rnd < 0.2) {
1119     c->c = NewDiode();
1120     if (f_rand() < 0.4)
1121       c->norm = 1; /* some diodes shine */
1122     c->type = 1;
1123   } else if (rnd < 0.3) {
1124     c->c = NewTransistor();
1125     c->norm = 1;
1126     c->type = 2;
1127   } else if (rnd < 0.4) {
1128     c->c = NewCapacitor();
1129     if (f_rand() < 0.4)
1130       c->norm = 1; /* some capacitors shine */
1131     c->type = 4;
1132   } else if (rnd < 0.6) {
1133     c->c = NewIC();
1134     c->type = 5;
1135   } else if (rnd < 0.7) {
1136     c->c = NewLED();
1137     c->type = 3;
1138     c->norm = 1;
1139     c->alpha = 1;
1140   } else if (rnd < 0.8) {
1141     c->c = NewFuse();
1142     c->norm = 1;
1143     c->type = 7;
1144     c->alpha = 1;
1145   } else {
1146     c->c = NewDisp();
1147     c->type = 6;
1148   }
1149   return c;
1150 }
1151
1152 Transistor *NewTransistor(void) {
1153 Transistor *t;
1154
1155   t = malloc(sizeof(Transistor));
1156   t->type = (f_rand() < 0.5);
1157   return t;
1158 }
1159
1160 Capacitor *NewCapacitor(void) {
1161 Capacitor *c;
1162
1163   c = malloc(sizeof(Capacitor));
1164   c->type = (f_rand() < 0.5);
1165   if (!c->type) {
1166     c->length = RAND_RANGE(0.5, 1);
1167     c->width = RAND_RANGE(0.5, 1);
1168   } else {
1169     c->width = RAND_RANGE(1, 2);
1170   }
1171   return c;
1172 }
1173
1174 /* 7 segment display */
1175
1176 Disp *NewDisp(void) {
1177 Disp *d;
1178
1179   d = malloc(sizeof(Disp));
1180   if (seven)
1181     d->value = 7;
1182   else
1183     d->value = RAND_RANGE(0, 10);
1184   return d;
1185 }
1186
1187
1188 IC *NewIC(void) {
1189 IC *c;
1190 int pins;
1191
1192   c = malloc(sizeof(IC));
1193   c->type = 0;
1194   switch((int)RAND_RANGE(0,4)) {
1195     case 0:
1196       pins = 8;
1197       break;
1198     case 1:
1199       pins = 14;
1200       break;
1201     case 2:
1202       pins = 16;
1203       break;
1204     case 3:
1205     default:
1206       pins = 24;
1207       break;
1208   }
1209   c->pins = pins;
1210   return c;
1211 }
1212
1213 LED *NewLED(void) {
1214 LED *l;
1215 float r;
1216
1217   l = malloc(sizeof(LED));
1218   r = f_rand();
1219   l->light = 0;
1220   if (!light && (f_rand() < 0.4)) {
1221      light = 1;
1222      l->light = 1;
1223   }
1224   if (r < 0.2) {
1225     l->r = 0.9; l->g = 0; l->b = 0;
1226   } else if (r < 0.4) {
1227     l->r = 0.3; l->g = 0.9; l->b = 0;
1228   } else if (r < 0.6) {
1229     l->r = 0.8; l->g = 0.9; l->b = 0;
1230   } else if (r < 0.8) {
1231     l->r = 0.0; l->g = 0.2; l->b = 0.8;
1232   } else {
1233     l->r = 0.9, l->g = 0.55, l->b = 0;
1234   }
1235   return l;
1236 }
1237
1238 Fuse *NewFuse(void) {
1239 Fuse *f;
1240
1241   f = malloc(sizeof(Fuse));
1242   return f;
1243 }
1244
1245 Diode *NewDiode(void) {
1246 Band *b;
1247 Diode *ret;
1248
1249   ret = malloc(sizeof(Diode));
1250   b = malloc(sizeof(Band));
1251   b->pos = 0.8;
1252   b->len = 0.1;
1253   if (f_rand() < 0.5) {
1254     b->r = 1;
1255     b->g = 1;
1256     b->b = 1;
1257     ret->r = 0.7; ret->g = 0.1 ; ret->b = 0.1;
1258   } else {
1259     b->r = 1;
1260     b->g = 1;
1261     b->b = 1;
1262     ret->r = 0.2; ret->g = 0.2 ; ret->b = 0.2;
1263   }
1264   ret->band = b;
1265   return ret;
1266 }
1267
1268
1269 Resistor  * NewResistor(void) {
1270 int v, m, t; /* value, multiplier, tolerance */
1271 Resistor *ret;
1272
1273   v = RAND(9);
1274   m = RAND(5);
1275   t = (RAND(10) < 5) ? 10 : 11; 
1276   ret = malloc(sizeof(Resistor));
1277
1278   if (seven) {
1279     ret->b[0] = ret->b[1] = ret->b[2] = 7;
1280   } else {
1281     ret->b[0] = values[v][0];
1282     ret->b[1] = values[v][1];
1283     ret->b[2] = m;
1284   }
1285   ret->b[3] = t;
1286
1287   return ret;
1288 }
1289
1290 void makebandlist(void) {
1291 int i;
1292 GLfloat col[] = {0,0,0,0};
1293 GLfloat spec[] = {0.8,0.8,0.8,0};
1294 GLfloat shine = 40;
1295
1296    for (i = 0 ; i < 12 ; i++) {
1297      band_list[i] = glGenLists(i);
1298      glNewList(band_list[i], GL_COMPILE);
1299      col[0] = colorcodes[i][0];
1300      col[1] = colorcodes[i][1];
1301      col[2] = colorcodes[i][2];
1302      glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
1303      glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
1304      glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
1305      createCylinder(0.1, 0.42, 0, 0);
1306      glEndList();
1307   }
1308 }
1309   
1310
1311 void bandedCylinder(float radius, float l, GLfloat r, GLfloat g, GLfloat bl, 
1312                         Band **b, int nbands) {
1313 int n; /* band number */
1314 int p = 0; /* prev number + 1; */
1315 GLfloat col[] = {0,0,0,0};
1316
1317    col[0] = r; col[1] = g; col[2] = bl;
1318    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1319    createCylinder(l, radius, 1, 0); /* body */
1320    for (n = 0 ; n < nbands ; n++) {
1321      glPushMatrix();
1322      glTranslatef(b[n]->pos*l, 0, 0);
1323      col[0] = b[n]->r; col[1] = b[n]->g; col[2] = b[n]->b;
1324      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1325      createCylinder(b[n]->len*l, radius*1.05, 0, 0); /* band */
1326      glPopMatrix();
1327      p = n+1;
1328    }
1329 }
1330
1331 void drawgrid(void) {
1332 GLfloat x, y;
1333 static GLfloat col[] = {0, 0.25, 0.05};
1334 static GLfloat col2[] = {0, 0.125, 0.05};
1335 GLfloat col3[] = {0, 0.8, 0};
1336 static GLfloat sx, sy; /* bright spot co-ords */
1337 static int sdir; /* 0 = left-right, 1 = right-left, 2 = up->dn, 3 = dn->up */
1338 static int s = 0; /* if spot is enabled */
1339 static float ds; /* speed of spot */
1340
1341   if (!s) {
1342      if (f_rand() < ((rotate) ? 0.05 : 0.01)) {
1343        sdir = RAND_RANGE(0, 4);
1344        ds = RAND_RANGE(0.4, 0.8);
1345        switch (sdir) {
1346           case 0:
1347            sx = -XMAX/2;
1348            sy = ((int)RAND_RANGE(0, YMAX/2))*2 - YMAX/2;
1349            break;
1350           case 1:
1351            sx = XMAX/2;
1352            sy = ((int)RAND_RANGE(0, YMAX/2))*2 - YMAX/2;
1353            break;
1354           case 2:
1355            sy = YMAX/2;
1356            sx = ((int)RAND_RANGE(0, XMAX/2))*2 - XMAX/2;
1357            break;
1358           case 3:
1359            sy = -YMAX/2;
1360            sx = ((int)RAND_RANGE(0, XMAX/2))*2 - XMAX/2;
1361            break;
1362         }
1363         s = 1;
1364       }
1365   } else if (!rotate) {
1366     if (col[1] < 0.25) {
1367       col[1] += 0.025; col[2] += 0.005;
1368       col2[1] += 0.015 ; col2[2] += 0.005;
1369     }
1370   }
1371
1372   glDisable(GL_LIGHTING);
1373   if (s) {
1374     glColor3fv(col3);
1375     glPushMatrix();
1376     glTranslatef(sx, sy, -10);
1377     sphere(0.1, 10, 10, 0, 10, 0, 10);
1378     if (sdir == 0) 
1379       glTranslatef(-ds, 0, 0);
1380     if (sdir == 1) 
1381       glTranslatef(ds, 0, 0);
1382     if (sdir == 2) 
1383       glTranslatef(0, ds, 0);
1384     if (sdir == 3) 
1385       glTranslatef(0, -ds, 0);
1386     sphere(0.05, 10, 10, 0, 10, 0, 10);
1387     glPopMatrix();
1388     if (sdir == 0) {
1389        sx += ds;
1390        if (sx > XMAX/2)
1391          s = 0;
1392     }
1393     if (sdir == 1) {
1394        sx -= ds;
1395        if (sx < -XMAX/2)
1396          s = 0;
1397     }
1398     if (sdir == 2) {
1399        sy -= ds;
1400        if (sy < YMAX/2)
1401          s = 0;
1402     }
1403     if (sdir == 3) {
1404        sy += ds;
1405        if (sy > YMAX/2)
1406          s = 0;
1407     }
1408   } else if (!rotate) {
1409     if (col[1] > 0) {
1410       col[1] -= 0.0025; col[2] -= 0.0005;
1411       col2[1] -= 0.0015 ; col2[2] -= 0.0005;
1412     }
1413   }
1414   for (x = -XMAX/2 ; x <= XMAX/2 ; x+= 2) {
1415     glColor3fv(col);
1416     glBegin(GL_LINES);
1417      glVertex3f(x, YMAX/2, -10);
1418      glVertex3f(x, -YMAX/2, -10);
1419      glColor3fv(col2);
1420      glVertex3f(x-0.02, YMAX/2, -10);
1421      glVertex3f(x-0.02, -YMAX/2, -10);
1422      glVertex3f(x+0.02, YMAX/2, -10);
1423      glVertex3f(x+0.02, -YMAX/2, -10);
1424     glEnd();
1425   }
1426   for (y = -YMAX/2 ; y <= YMAX/2 ; y+= 2) {
1427     glColor3fv(col);
1428     glBegin(GL_LINES);
1429      glVertex3f(-XMAX/2, y, -10);
1430      glVertex3f(XMAX/2, y, -10);
1431      glColor3fv(col2);
1432      glVertex3f(-XMAX/2, y-0.02, -10);
1433      glVertex3f(XMAX/2, y-0.02, -10);
1434      glVertex3f(-XMAX/2, y+0.02, -10);
1435      glVertex3f(XMAX/2, y+0.02, -10);
1436     glEnd();
1437   }
1438   glEnable(GL_LIGHTING);
1439 }
1440
1441 void display(void) {
1442 static Component *c[MAX_COMPONENTS];
1443 static int i = 0;
1444 GLfloat light_sp[] = {0.8, 0.8, 0.8, 1.0};
1445 GLfloat black[] = {0, 0, 0, 1.0};
1446 static GLfloat rotate_angle = 0; /*  when 'rotate' is enabled */
1447 int j;
1448
1449   if (i == 0) {
1450     for (i = 0 ; i < maxparts ; i++) {
1451       c[i] = NULL;
1452     }
1453   } 
1454   glEnable(GL_LIGHTING);
1455   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
1456   glLoadIdentity();
1457   gluLookAt(viewer[0], viewer[1], viewer[2], 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
1458   glPushMatrix();
1459   if (rotate) {
1460      glRotatef(rotate_angle, 0, 0, 1);
1461      rotate_angle += 0.01 * (float)rotatespeed;
1462      if (rotate_angle >= 360) rotate_angle = 0;
1463   }
1464   glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
1465   glLightfv(GL_LIGHT0, GL_SPECULAR, light_sp);
1466   glLightfv(GL_LIGHT0, GL_DIFFUSE, light_sp);
1467   glLighti(GL_LIGHT0, GL_CONSTANT_ATTENUATION, (GLfloat)1); 
1468   glLighti(GL_LIGHT0, GL_LINEAR_ATTENUATION, (GLfloat)0.5); 
1469   glLighti(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, (GLfloat)0); 
1470   drawgrid();
1471   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light_sp);
1472   if (f_rand() < 0.05) {
1473     for (j = 0 ; j < maxparts ; j++) {
1474       if (c[j] == NULL) {
1475         c[j] = NewComponent();
1476         j = maxparts;
1477       }
1478     }
1479     reorder(&c[0]);
1480   }
1481   for (j = 0 ; j < maxparts ; j++) {
1482      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, black);
1483      glMaterialfv(GL_FRONT, GL_EMISSION, black);
1484      glMaterialfv(GL_FRONT, GL_SPECULAR, black);
1485      if (c[j] != NULL) {
1486        if (DrawComponent(c[j])) {
1487         free(c[j]); c[j] = NULL;
1488        }
1489      }
1490   }
1491   glPopMatrix();
1492   glFlush();
1493 }
1494
1495 /* ensure transparent components are at the end */
1496 void reorder(Component *c[]) {
1497 int i, j, k;
1498 Component *c1[MAX_COMPONENTS];
1499 Component *c2[MAX_COMPONENTS];
1500
1501   j = 0;
1502   for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
1503     c1[i] = NULL;
1504     c2[i] = NULL;
1505   }
1506   for (i = 0 ; i < maxparts ; i++) {
1507     if (c[i] == NULL) continue;
1508     if (c[i]->alpha) { /* transparent parts go to c1 */
1509       c1[j] = c[i];
1510       j++;
1511     } else { /* opaque parts go to c2 */
1512       c2[i] = c[i];
1513     }
1514   }
1515   for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
1516     c[i] = NULL;
1517   }
1518   k = 0;
1519   for (i = 0 ; i < maxparts ; i++) { /* insert opaque part */
1520     if (c2[i] != NULL) {
1521       c[k] = c2[i];
1522       k++;
1523     }
1524   }
1525   for (i = 0 ; i < j ; i++) { /* insert transparent parts */
1526     c[k] = c1[i];
1527     k++;
1528   }
1529 }
1530
1531 void reshape_circuit(ModeInfo *mi, int width, int height)
1532 {
1533
1534  glViewport(0,0,(GLint)width, (GLint) height);
1535  glMatrixMode(GL_PROJECTION);
1536  glLoadIdentity();
1537  glFrustum(-1.0,1.0,-1.0,1.0,1.5,35.0);
1538  glMatrixMode(GL_MODELVIEW);
1539  win_h = height; win_w = width;
1540 }
1541
1542
1543 void init_circuit(ModeInfo *mi)
1544 {
1545 int screen = MI_SCREEN(mi);
1546 Circuit *c;
1547
1548  if (circuit == NULL) {
1549    if ((circuit = (Circuit *) calloc(MI_NUM_SCREENS(mi),
1550                                         sizeof(Circuit))) == NULL)
1551           return;
1552  }
1553  c = &circuit[screen];
1554  c->window = MI_WINDOW(mi);
1555
1556
1557  if ((c->glx_context = init_GL(mi)) != NULL) {
1558       reshape_circuit(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1559  } else {
1560      MI_CLEARWINDOW(mi);
1561  }
1562  if (uselight == 0)
1563     light = 1;
1564  glClearColor(0.0,0.0,0.0,0.0);
1565  glShadeModel(GL_SMOOTH);
1566  glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
1567  glEnable(GL_DEPTH_TEST);
1568  glEnable(GL_LIGHTING);
1569  glEnable(GL_LIGHT0);
1570  make_tables();
1571  makebandlist();
1572  
1573 }
1574
1575 void draw_circuit(ModeInfo *mi) {
1576 Circuit *c = &circuit[MI_SCREEN(mi)];
1577 Window w = MI_WINDOW(mi);
1578 Display *disp = MI_DISPLAY(mi);
1579
1580   if (!c->glx_context)
1581       return;
1582
1583  glXMakeCurrent(disp, w, *(c->glx_context));
1584
1585   display();
1586
1587   if(mi->fps_p) do_fps(mi);
1588   glFinish(); 
1589   glXSwapBuffers(disp, w);
1590 }
1591
1592 void release_circuit(ModeInfo *mi) {
1593
1594   if (circuit != NULL) {
1595    (void) free((void *) circuit);
1596    circuit = NULL;
1597   }
1598   FreeAllGL(MI);
1599 }
1600
1601 #endif