http://ftp.nluug.nl/pub/os/Linux/distr/pardusrepo/sources/xscreensaver-5.02.tar.gz
[xscreensaver] / hacks / glx / circuit.c
1 /*
2  * circuit - Random electronic components floating around
3  *
4  * version 1.4
5  *
6  * Since version 1.1: added to-220 transistor, added fuse
7  * Since version 1.2: random display digits, LED improvements (flickering)
8  * Since version 1.3: ICs look better, font textures, improved normals to
9  *                    eliminate segmenting on curved surfaces, speedups
10  * Since version 1.4: Added RCA connector, 3.5mm connector, slide switch,
11  *                    surface mount, to-92 markings. Fixed ~5min crash.
12  *                    Better LED illumination. Other minor changes.
13  *
14  * Copyright (C) 2001,2002 Ben Buxton (bb@cactii.net)
15  *
16  * Permission to use, copy, modify, distribute, and sell this software and its
17  * documentation for any purpose is hereby granted without fee, provided that
18  * the above copyright notice appear in all copies and that both that
19  * copyright notice and this permission notice appear in supporting
20  * documentation.  No representations are made about the suitability of this
21  * software for any purpose.  It is provided "as is" without express or
22  * implied warranty.
23  */
24
25 /* Written over a few days in a (successful) bid to learn GL coding 
26  *
27  * -seven option is dedicated to all the Slarkeners
28  *
29  * try "-rotate -rotate-speed 0"
30  *
31  * This hack uses lookup tables for sin, cos and tan - it can do a lot
32  */
33
34 #ifdef STANDALONE
35 #define DEFAULTS        "*delay:   20000 \n" \
36                         "*showFPS: False \n"
37
38 # define refresh_circuit 0
39 # define circuit_handle_event 0
40 # include "xlockmore.h"                         /* from the xscreensaver distribution */
41 #else  /* !STANDALONE */
42 # include "xlock.h"                                     /* from the xlockmore distribution */
43 #endif /* !STANDALONE */
44
45 #define DEF_SPIN        "True"
46 #define DEF_SEVEN       "False"
47 #define DEF_PARTS       "10"
48
49 /* lifted from lament.c */
50 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
51 #define RANDSIGN() ((random() & 1) ? 1 : -1)
52
53
54 #ifdef USE_GL
55
56 #include "font-ximage.h"
57
58 #undef countof
59 #define countof(x) (sizeof((x))/sizeof((*x)))
60
61 static int maxparts;
62 static char *font;
63 static int rotatespeed;
64 static int spin;
65 static int rotate;
66 static int uselight;
67 static int seven;
68
69 #undef countof
70 #define countof(x) (sizeof((x))/sizeof((*x)))
71
72 static XrmOptionDescRec opts[] = {
73   {"-parts", ".circuit.parts", XrmoptionSepArg, "10" },
74   {"-font", ".circuit.font", XrmoptionSepArg, "fixed" },
75   {"-rotate-speed", ".circuit.rotatespeed", XrmoptionSepArg, "1" },
76   {"+spin", ".circuit.spin", XrmoptionNoArg, "false" },
77   {"-spin", ".circuit.spin", XrmoptionNoArg, "true" },
78   {"+light", ".circuit.light", XrmoptionNoArg, "false" },
79   {"-light", ".circuit.light", XrmoptionNoArg, "true" },
80   {"+seven", ".circuit.seven", XrmoptionNoArg, "false" },
81   {"-seven", ".circuit.seven", XrmoptionNoArg, "true" },
82   {"+rotate", ".circuit.rotate", XrmoptionNoArg, "false" },
83   {"-rotate", ".circuit.rotate", XrmoptionNoArg, "true" },
84 };
85
86 static argtype vars[] = {
87   {&maxparts, "parts", "Parts", DEF_PARTS, t_Int},
88   {&font, "font", "Font", "fixed", t_String},
89   {&rotatespeed, "rotatespeed", "Rotatespeed", "1", t_Int},
90   {&spin, "spin", "Spin", DEF_SPIN, t_Bool},
91   {&rotate, "rotate", "Rotate", "False", t_Bool},
92   {&uselight, "light", "Light", "True", t_Bool},
93   {&seven, "seven", "Seven", DEF_SEVEN, t_Bool},
94 };
95
96 ENTRYPOINT ModeSpecOpt circuit_opts = {countof(opts), opts, countof(vars), vars, NULL};
97
98 #ifdef USE_MODULES
99 ModStruct   circuit_description =
100 {"circuit", "init_circuit", "draw_circuit", "release_circuit",
101  "draw_circuit", "init_circuit", NULL, &circuit_opts,
102  1000, 1, 2, 1, 4, 1.0, "",
103  "Flying electronic components", 0, NULL};
104
105 #endif
106
107 #define MAX_COMPONENTS 31
108 #define MOVE_MULT 0.02
109
110 static float f_rand(void)
111 {
112    return ((float)RAND(10000)/(float)10000);
113 }
114
115 #define RAND_RANGE(min, max) ((min) + (max - min) * f_rand())
116
117 /* used for allocating font textures */
118 typedef struct {
119   int num; /* index number */
120   int w;   /* width */
121   int h;   /* height */
122 } TexNum;
123
124 /* Represents a band on a resistor/diode/etc */
125 typedef struct {
126   float pos;     /* relative position from start/previous band */
127   GLfloat r, g, b; /* colour of the band */
128   float len;     /* length as a fraction of total length */
129 } Band;
130
131 typedef struct {
132   Band *b1, *b2, *b3, *b4; /* bands */
133   int b[4];
134 } Resistor;
135
136 typedef struct {
137   Band *band;
138   GLfloat r, g, b; /* body colour */
139 } Diode;
140
141 static const char * const transistortypes[] = {
142   "TIP2955",
143   "TIP32C",
144   "LM 350T",
145   "IRF730",
146   "ULN2577",
147   "7805T",
148   "7912T",
149   "TIP120",
150   "2N6401",
151   "BD239",
152   "2SC1590",
153   "MRF485",
154   "SC141D"
155 };
156
157 static const char * const to92types[] = {
158   "C\n548",
159   "C\n848",
160   "74\nL05",
161   "C\n858",
162   "BC\n212L",
163   "BC\n640",
164   "BC\n337",
165   "BC\n338",
166   "S817",
167   "78\nL12",
168   "TL\n431",
169   "LM\n35DZ",
170 };
171
172 static const char * const smctypes[] = {
173   "1M-",
174   "1K",
175   "1F",
176   "B10",
177   "S14",
178   "Q3",
179   "4A"
180 };
181
182 typedef struct {
183   int type; /* package type. 0 = to-92, 1 = to-220 */
184   GLfloat tw, th; /* texture dimensions */
185   GLuint tnum; /* texture binding */
186 } Transistor;
187
188 typedef struct {
189   GLfloat r,g,b; /* LED colour */
190   int light; /* are we the light source? */
191 } LED;
192
193 typedef struct {
194   int type; /* 0 = electro, 1 = ceramic */
195   float width; /* width of an electro/ceramic */
196   float length; /* length of an electro */
197 } Capacitor;
198
199 /* 3.5 mm plug */
200 typedef struct {
201   int blah;
202 } ThreeFive;
203
204 /* slide switch */
205 typedef struct {
206   int position;
207 } Switch;
208
209 typedef struct {
210   int pins;
211   const char *val;
212 } ICTypes;
213
214 static const ICTypes ictypes[] = {
215   {8, "NE 555"},
216   {8, "LM 386N"},
217   {8, "ADC0831"},
218   {8, "LM 383T"},
219   {8, "TL071"},
220   {8, "LM 311"},
221   {8, "LM393"},
222   {8, "LM 3909"},
223
224   {14, "LM 380N"},
225   {14, "NE 556"},
226   {14, "TL074"},
227   {14, "LM324"},
228   {14, "LM339"},
229   {14, "MC1488"},
230   {14, "MC1489"},
231   {14, "LM1877-9"},
232   {14, "4011"},
233   {14, "4017"},
234   {14, "4013"},
235   {14, "4024"},
236   {14, "4066"},
237
238   {16, "4076"},
239   {16, "4049"},
240   {16, "4094"},
241   {16, "4043"},
242   {16, "4510"},
243   {16, "4511"},
244   {16, "4035"},
245   {16, "RS232"},
246   {16, "MC1800"},
247   {16, "ULN2081"},
248   {16, "UDN2953"},
249
250   {24, "ISD1416P"},
251   {24, "4515"},
252   {24, "TMS6264L"},
253   {24, "MC146818"}
254 };
255
256 typedef struct {
257   int type; /* 0 = DIL, 1 = flat square */
258   int pins; 
259   float tw, th; /* texture dimensions for markings */
260   int tnum; /* texture number */
261 } IC;
262
263 /* 7 segment display */
264
265 typedef struct {
266   int value; /* displayed number */
267 } Disp;
268
269 typedef struct {
270   GLfloat l, w;
271 } Fuse;
272
273 typedef struct {
274   GLfloat l, w;
275   int col;
276 } RCA;
277
278 typedef struct {
279   GLfloat x, y, z; /* current co-ordinates */
280   GLfloat dx, dy, dz; /* current direction */
281   GLfloat rotx, roty, rotz; /* rotation vector */
282   GLfloat drot; /* rotation velocity (degrees per frame) */
283   int norm; /* Normalize this component (for shine) */
284   int rdeg; /* current rotation degrees */
285   int angle; /* angle about the z axis */
286   int alpha; /* 0 if not a transparent component */
287   int type;  /* 0 = resistor, 1 = diode, 2 = transistor, 3 = LED, 4 = cap, 5=IC,
288                 6 = 7 seg disp */
289   void * c; /* pointer to the component */
290 } Component;
291
292 /* standard colour codes */
293
294 static const GLfloat colorcodes [12][3] = {
295   {0.0,0.0,0.0},    /* black  0 */
296   {0.49,0.25,0.08}, /* brown  1 */
297   {1.0,0.0,0.0},    /* red    2 */
298   {1.0,0.5,0.0},    /* orange 3 */
299   {1.0,1.0,0.0},    /* yellow 4 */
300   {0.0,1.0,0.0},    /* green  5 */
301   {0.0,0.5,1.0},    /* blue   6 */
302   {0.7,0.2,1.0},    /* violet 7 */
303   {0.5,0.5,0.5},    /* grey   8 */
304   {1.0,1.0,1.0},    /* white  9 */
305   {0.66,0.56,0.2},    /* gold  10 */
306   {0.8,0.8,0.8},    /* silver 11 */
307 };
308
309 /* base values for components - we can multiply by 0 - 1M */
310 static const int values [9][2] = {
311   {1,0},
312   {2,2},
313   {3,3},
314   {4,7},
315   {5,6},
316   {6,8},
317   {7,5},
318   {8,2},
319   {9,1}
320 };
321
322 typedef struct {
323   GLXContext *glx_context;
324   Window window;
325
326   int XMAX, YMAX;
327   int win_w, win_h;
328
329   /* one lucky led gets to be a light source , unless -no-light*/
330   int light;
331   int lighton;
332
333   /* stores refs to textures */
334   int s_refs[50];
335
336   GLfloat viewer[3];
337   GLfloat lightpos[4];
338
339   float sin_table[720];
340   float cos_table[720];
341   float tan_table[720];
342
343   Component *components[MAX_COMPONENTS];
344   int band_list[12];
345
346   GLfloat grid_col[3], grid_col2[3];
347
348   int display_i;
349   GLfloat rotate_angle;
350
351   char *font_strings[50]; /* max of 40 textures */
352   int font_w[50], font_h[50];
353   int font_init;
354
355   GLfloat draw_sx, draw_sy; /* bright spot co-ords */
356   int draw_sdir; /* 0 = left-right, 1 = right-left, 2 = up->dn, 3 = dn->up */
357   int draw_s; /* if spot is enabled */
358   float draw_ds; /* speed of spot */
359
360 } Circuit;
361
362 static Circuit *circuit = NULL;
363
364
365 static void DrawResistor(Circuit *, Resistor *);
366 static void DrawDiode(Circuit *, Diode *);
367 static void DrawTransistor(Circuit *, Transistor *);
368 static void DrawLED(Circuit *, LED *);
369 static void DrawIC(Circuit *, IC *);
370 static void DrawCapacitor(Circuit *, Capacitor *);
371 static void DrawDisp(Circuit *, Disp *);
372 static void DrawFuse(Circuit *, Fuse *);
373 static void DrawRCA(Circuit *, RCA *);
374 static void DrawThreeFive(Circuit *, ThreeFive *);
375 static void DrawSwitch(Circuit *, Switch *);
376
377 static void freetexture(Circuit *, GLuint);
378 static void reorder(Component *[]);
379 static void circle(Circuit *, float, int,int);
380 static void bandedCylinder(Circuit *, 
381                            float, float , GLfloat, GLfloat , GLfloat,  
382                            Band **, int);
383 static TexNum *fonttexturealloc(ModeInfo *, const char *, float *, float *);
384 static void Rect(GLfloat , GLfloat , GLfloat, GLfloat , GLfloat ,GLfloat);
385 static void ICLeg(GLfloat, GLfloat, GLfloat, int);
386 static void HoledRectangle(Circuit *ci, 
387                            GLfloat, GLfloat, GLfloat, GLfloat, int);
388 static Resistor *NewResistor(void);
389 static Diode *NewDiode(void);
390 static Transistor *NewTransistor(ModeInfo *);
391 static LED * NewLED(Circuit *);
392 static Capacitor *NewCapacitor(Circuit *);
393 static IC* NewIC(ModeInfo *);
394 static Disp* NewDisp(Circuit *);
395 static Fuse *NewFuse(Circuit *);
396 static RCA *NewRCA(Circuit *);
397 static ThreeFive *NewThreeFive(Circuit *);
398 static Switch *NewSwitch(Circuit *);
399
400 /* we use trig tables to speed things up - 200 calls to sin()
401  in one frame can be a bit harsh..
402 */
403
404 static void make_tables(Circuit *ci) 
405 {
406 int i;
407 float f;
408
409   f = 360 / (M_PI * 2);
410   for (i = 0 ; i < 720 ; i++) {
411     ci->sin_table[i] = sin(i/f);
412   }
413   for (i = 0 ; i < 720 ; i++) {
414     ci->cos_table[i] = cos(i/f);
415   }
416   for (i = 0 ; i < 720 ; i++) {
417     ci->tan_table[i] = tan(i/f);
418   }
419 }
420
421
422 static void createCylinder (Circuit *ci,
423                             float length, float radius, int endcaps, int half) 
424 {
425   int a; /* current angle around cylinder */
426   int angle, norm;
427   float z1, y1, z2, y2,ex;
428   int step;
429   int nsegs;
430
431   glPushMatrix();
432   nsegs = radius*MAX(ci->win_w, ci->win_h)/20;
433   nsegs = MAX(nsegs, 4);
434   if (nsegs % 2)
435      nsegs += 1;
436   angle = (half) ? (180 - 90/nsegs) : 374;
437   step = angle/nsegs;
438   z1 = radius; y1 = 0;
439   glBegin(GL_QUADS);
440   for (a = 0 ; a <= angle ; a+= angle/nsegs) {
441     y2=radius*(float)ci->sin_table[(int)a];
442     z2=radius*(float)ci->cos_table[(int)a];
443       glNormal3f(0, y1, z1);
444       glVertex3f(0,y1,z1);
445       glVertex3f(length,y1,z1);
446       glNormal3f(0, y2, z2);
447       glVertex3f(length,y2,z2);
448       glVertex3f(0,y2,z2);
449     z1=z2;
450     y1=y2;
451   }
452   glEnd();
453   if (half) {
454     glBegin(GL_POLYGON);
455       glNormal3f(0, 1, 0);
456       glVertex3f(0, 0, radius);
457       glVertex3f(length, 0, radius);
458       glVertex3f(length, 0, 0 - radius);
459       glVertex3f(0, 0, 0 - radius);
460     glEnd();
461   }
462   if (endcaps) {
463     for(ex = 0 ; ex <= length ; ex += length) {
464       z1 = radius; y1 = 0;
465       norm = (ex == length) ? 1 : -1;
466       glBegin(GL_TRIANGLES);
467       glNormal3f(norm, 0, 0);
468       for (a = 0 ; a <= angle ; a+= angle/nsegs) {
469         y2=radius*(float)ci->sin_table[(int)a];
470         z2=radius*(float)ci->cos_table[(int)a];
471           glVertex3f(ex,0, 0);
472           glVertex3f(ex,y1,z1);
473           glVertex3f(ex,y2,z2);
474         z1=z2;
475         y1=y2;
476       }
477       glEnd();
478     }
479   }
480   glPopMatrix();
481 }
482
483 static void circle(Circuit *ci, float radius, int segments, int half)
484 {
485   float x1 = 0, x2 = 0;
486   float y1 = 0, y2 = 0;
487   int i, t, s;
488
489   if (half) {
490     t = 270; s = 90;
491     x1 = radius, y1 = 0;
492   } else {
493     t = 360, s = 0;
494   }
495   glBegin(GL_TRIANGLES);
496   glNormal3f(1, 0, 0);
497   for(i=s;i<=t;i+=10)
498   {
499     float angle=i;
500     x2=radius*(float)ci->cos_table[(int)angle];
501     y2=radius*(float)ci->sin_table[(int)angle];
502     glVertex3f(0,0,0);
503     glVertex3f(0,y1,x1);
504     glVertex3f(0,y2,x2);
505     x1=x2;
506     y1=y2;
507   }
508   glEnd();
509 }
510
511 static void wire(Circuit *ci, float len)
512 {
513   GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
514   GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
515   GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
516   GLfloat shin = 30;
517   int n;
518
519   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
520   glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
521   glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
522   n = glIsEnabled(GL_NORMALIZE);
523   if (!n) glEnable(GL_NORMALIZE);
524   createCylinder(ci, len, 0.05, 1, 0);
525   if (!n) glDisable(GL_NORMALIZE);
526   glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
527 }
528
529 #if 0
530 static void ring(GLfloat inner, GLfloat outer, int nsegs)
531 {
532   GLfloat z1, z2, y1, y2;
533   GLfloat Z1, Z2, Y1, Y2;
534   int i;
535
536   z1 = inner; y1 = 0;
537   Z1 = outer; Y1 = 0;
538   glBegin(GL_QUADS);
539   glNormal3f(1, 0, 0);
540   for(i=0; i <=360 ; i+= 360/nsegs)
541   {
542     float angle=i;
543     z2=inner*(float)ci->sin_table[(int)angle];
544     y2=inner*(float)ci->cos_table[(int)angle];
545     Z2=outer*(float)ci->sin_table[(int)angle];
546     Y2=outer*(float)ci->cos_table[(int)angle];
547     glVertex3f(0, Y1, Z1);
548     glVertex3f(0, y1, z1);
549     glVertex3f(0, y2, z2);
550     glVertex3f(0, Y2, Z2);
551     z1=z2;
552     y1=y2;
553     Z1=Z2;
554     Y1=Y2;
555   }
556   glEnd();
557 }
558 #endif
559
560 static void sphere(Circuit *ci, GLfloat r, float stacks, float slices,
561              int startstack, int endstack, int startslice,
562              int endslice)
563 {
564   GLfloat d, d1, dr, dr1, Dr, Dr1, D, D1, z1, z2, y1, y2, Y1, Z1, Y2, Z2;
565   int a, a1, b, b1, c0, c1;
566   GLfloat step, sstep;
567
568   step = 180/stacks;
569   sstep = 360/slices;
570   a1 = startstack * step;
571   b1 = startslice * sstep;
572   y1 = z1 = Y1 = Z1 = 0;
573   c0 = (endslice / slices) * 360;
574   c1 = (endstack/stacks)*180;
575   glBegin(GL_QUADS);
576   for (a = startstack * step ; a <= c1 ; a+= step) {
577     d=ci->sin_table[a];
578     d1=ci->sin_table[a1];
579     D=ci->cos_table[a];
580     D1=ci->cos_table[a1];
581     dr = d * r;
582     dr1 = d1 * r;
583     Dr = D * r;
584     Dr1 = D1 * r;
585     for (b = b1 ; b <= c0 ; b+= sstep) {
586       y2=dr*ci->sin_table[b];
587       z2=dr*ci->cos_table[b];
588       Y2=dr1*ci->sin_table[b];
589       Z2=dr1*ci->cos_table[b];
590         glNormal3f(Dr, y1, z1);
591         glVertex3f(Dr,y1,z1);
592         glNormal3f(Dr, y2, z2);
593         glVertex3f(Dr,y2,z2);
594         glNormal3f(Dr1, Y2, Z2);
595         glVertex3f(Dr1,Y2,Z2);
596         glNormal3f(Dr1, Y1, Z1);
597         glVertex3f(Dr1,Y1,Z1);
598       z1=z2;
599       y1=y2;
600       Z1=Z2;
601       Y1=Y2;
602     }
603     a1 = a;
604   }
605   glEnd();
606 }
607
608 static int DrawComponent(Circuit *ci, Component *c)
609 {
610   int ret = 0; /* return 1 if component is freed */
611
612    glPushMatrix();
613    glTranslatef(c->x, c->y, c->z);
614      if (c->angle > 0) {
615         glRotatef(c->angle, c->rotx, c->roty, c->rotz);
616      }
617    if (spin) {
618      glRotatef(c->rdeg, c->rotx, c->roty, c->rotz);
619      c->rdeg += c->drot;
620    }
621
622    if (c->norm)
623      glEnable(GL_NORMALIZE);
624    else
625      glDisable(GL_NORMALIZE);
626
627  /* call object draw routine here */
628    if (c->type == 0) {
629      DrawResistor(ci, c->c);
630    } else if (c->type == 1) {
631      DrawDiode(ci, c->c);
632    } else if (c->type == 2) {
633      DrawTransistor(ci, c->c);
634    } else if (c->type == 3) {
635      if (((LED *)c->c)->light && ci->light) {
636        GLfloat lp[] = {0.1, 0, 0, 1};
637        glEnable(GL_LIGHT1);
638        glLightfv(GL_LIGHT1, GL_POSITION, lp);
639      }
640      DrawLED(ci, c->c);
641    } else if (c->type == 4) {
642      DrawCapacitor(ci, c->c);
643    } else if (c->type == 5) {
644      DrawIC(ci, c->c);
645    } else if (c->type == 6) {
646      DrawDisp(ci, c->c);
647    } else if (c->type == 7) {
648      DrawFuse(ci, c->c);
649    } else if (c->type == 8) {
650      DrawRCA(ci, c->c);
651    } else if (c->type == 9) {
652      DrawThreeFive(ci, c->c);
653    } else if (c->type == 10) {
654      DrawSwitch(ci, c->c);
655    }
656    c->x += c->dx * MOVE_MULT;
657    c->y += c->dy * MOVE_MULT;
658    if (c->x > ci->XMAX/2 || c->x < 0 - ci->XMAX/2 ||
659        c->y > ci->YMAX/2 || c->y < 0 - ci->YMAX/2) {
660         if (c->type == 3 && ((LED *)c->c)->light && ci->light) {
661           glDisable(GL_LIGHT1);
662           ci->light = 0; ci->lighton = 0;
663         }
664         if (c->type == 5) {
665           if (((IC *)c->c)->tnum)
666             freetexture(ci, ((IC *)c->c)->tnum);
667         }
668         if (c->type == 2) {
669           if (((Transistor *)c->c)->tnum)
670             freetexture(ci, ((Transistor *)c->c)->tnum);
671         }
672         if (c->type == 1)
673           free(((Diode *)c->c)->band); /* remember to free diode band */
674         free(c->c);
675         ret = 1;
676    }
677
678    glPopMatrix();
679    glDisable(GL_NORMALIZE);
680    return ret;
681 }
682
683 /* draw a resistor */
684
685 static void DrawResistor(Circuit *ci, Resistor *r)
686 {
687   int i;
688   GLfloat col[] = {0.74, 0.62, 0.46, 1.0};
689   GLfloat spec[] = {0.8, 0.8, 0.8, 1.0};
690   GLfloat shine = 30;
691
692    glTranslatef(-4, 0, 0);
693    wire(ci, 3);
694    glTranslatef(3, 0, 0);
695    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
696    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
697    glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
698    createCylinder(ci, 1.8, 0.4, 1, 0);
699    glPushMatrix();
700    for (i = 0 ; i < 4 ; i++) {
701      glTranslatef(0.35, 0, 0);
702      glCallList(ci->band_list[r->b[i]]);
703    }
704    glPopMatrix();
705    glTranslatef(1.8, 0, 0);
706    wire(ci, 3);
707 }
708
709 static void DrawRCA(Circuit *ci, RCA *rca)
710 {
711   GLfloat col[] = {0.6, 0.6, 0.6, 1.0}; /* metal */
712   GLfloat red[] = {1.0, 0.0, 0.0, 1.0}; /* red */
713   GLfloat white[] = {1.0, 1.0, 1.0, 1.0}; /* white */
714   GLfloat spec[] = {1, 1, 1, 1}; /* glass */
715
716    glPushMatrix();
717    glTranslatef(0.3, 0, 0);
718    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
719    glMateriali(GL_FRONT, GL_SHININESS, 40);
720    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
721    createCylinder(ci, 0.7, 0.45, 0, 0);
722    glTranslatef(0.4, 0, 0);
723    createCylinder(ci, 0.9, 0.15, 1, 0);
724    glTranslatef(-1.9, 0, 0);
725    glMateriali(GL_FRONT, GL_SHININESS, 20);
726    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, rca->col ? white : red);
727    createCylinder(ci, 1.5, 0.6, 1, 0);
728    glTranslatef(-0.9, 0, 0);
729    createCylinder(ci, 0.9, 0.25, 0, 0);
730    glTranslatef(0.1, 0, 0);
731    createCylinder(ci, 0.2, 0.3, 0, 0);
732    glTranslatef(0.3, 0, 0);
733    createCylinder(ci, 0.2, 0.3, 1, 0);
734    glTranslatef(0.3, 0, 0);
735    createCylinder(ci, 0.2, 0.3, 1, 0);
736    glPopMatrix();
737 }
738
739 static void DrawSwitch(Circuit *ci, Switch *f)
740 {
741   GLfloat col[] = {0.6, 0.6, 0.6, 0}; /* metal */
742   GLfloat dark[] = {0.1, 0.1, 0.1, 1.0}; /* dark */
743   GLfloat brown[] = {0.69, 0.32, 0, 1.0}; /* brown */
744   GLfloat spec[] = {0.9, 0.9, 0.9, 1}; /* shiny */
745
746    glPushMatrix();
747    glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
748    glMaterialfv(GL_FRONT, GL_AMBIENT, dark);
749    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
750    glMateriali(GL_FRONT, GL_SHININESS, 90);
751    Rect(-0.25, 0, 0, 1.5, 0.5, 0.75);
752 /* Rect(-0.5, 0.5, 0, 2, 0.1, 0.75); */
753    glPushMatrix();
754    glRotatef(90, 1, 0, 0);
755    glTranslatef(-0.5, -0.4, -0.4);
756    HoledRectangle(ci, 0.5, 0.75, 0.1, 0.15, 8);
757    glTranslatef(2, 0, 0);
758    HoledRectangle(ci, 0.5, 0.75, 0.1, 0.15, 8);
759    glPopMatrix();
760    Rect(0.1, -0.4, -0.25, 0.1, 0.4, 0.05);
761    Rect(0.5, -0.4, -0.25, 0.1, 0.4, 0.05);
762    Rect(0.9, -0.4, -0.25, 0.1, 0.4, 0.05);
763    Rect(0.1, -0.4, -0.5, 0.1, 0.4, 0.05);
764    Rect(0.5, -0.4, -0.5, 0.1, 0.4, 0.05);
765    Rect(0.9, -0.4, -0.5, 0.1, 0.4, 0.05);
766    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, dark);
767    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
768    Rect(0, 0.5, -0.1, 1, 0.05, 0.5);
769    Rect(0, 0.6, -0.1, 0.5, 0.6, 0.5);
770    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, brown);
771    Rect(-0.2, -0.01, -0.1, 1.4, 0.1, 0.55);
772    glPopMatrix();
773 }
774
775
776 static void DrawFuse(Circuit *ci, Fuse *f)
777 {
778   GLfloat col[] = {0.5, 0.5, 0.5, 1.0}; /* endcaps */
779   GLfloat glass[] = {0.4, 0.4, 0.4, 0.3}; /* glass */
780   GLfloat spec[] = {1, 1, 1, 1}; /* glass */
781
782    glPushMatrix();
783    glTranslatef(-1.8, 0, 0);
784    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
785    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
786    glMateriali(GL_FRONT, GL_SHININESS, 40);
787    createCylinder(ci, 0.8, 0.45, 1, 0);
788    glTranslatef(0.8, 0, 0);
789    glEnable(GL_BLEND);
790    glDepthMask(GL_FALSE);
791    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, glass);
792    glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 40);
793    createCylinder(ci, 2, 0.4, 0, 0);
794    createCylinder(ci, 2, 0.3, 0, 0);
795    glDisable(GL_BLEND);
796    glDepthMask(GL_TRUE);
797    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
798    glMateriali(GL_FRONT, GL_SHININESS, 40);
799    glBegin(GL_LINES);
800    glVertex3f(0, 0, 0);
801    glVertex3f(2, 0. ,0);
802    glEnd();
803    glTranslatef(2, 0, 0);
804    createCylinder(ci, 0.8, 0.45, 1, 0);
805    glPopMatrix();
806 }
807
808
809 static void DrawCapacitor(Circuit *ci, Capacitor *c)
810 {
811   GLfloat col[] = {0, 0, 0, 0};
812   GLfloat spec[] = {0.8, 0.8, 0.8, 0};
813   GLfloat brown[] = {0.84, 0.5, 0};
814   GLfloat shine = 40;
815
816   glPushMatrix();
817   if (c->type) {
818     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, brown);
819     sphere(ci, c->width, 15, 15, 0, 4 ,0, 15);
820     glTranslatef(1.35*c->width, 0, 0);
821     sphere(ci, c->width, 15, 15, 11, 15, 0, 15);
822     glRotatef(90, 0, 0, 1);
823     glTranslatef(0, 0.7*c->width, 0.3*c->width);
824     wire(ci, 3*c->width);
825     glTranslatef(0, 0, -0.6*c->width);
826     wire(ci, 3*c->width);
827   } else {
828     glTranslatef(0-c->length*2, 0, 0);
829     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
830     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
831     glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
832     glBegin(GL_POLYGON);
833      glVertex3f(0, 0.82*c->width, -0.1);
834      glVertex3f(3*c->length, 0.82*c->width, -0.1);
835      glVertex3f(3*c->length, 0.82*c->width, 0.1);
836      glVertex3f(0, 0.82*c->width, 0.1);
837     glEnd();
838     col[0] = 0.0;
839     col[1] = 0.2;
840     col[2] = 0.9;
841     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
842     glEnable(GL_POLYGON_OFFSET_FILL);
843     glPolygonOffset(1.0, 1.0);
844     createCylinder(ci, 3.0*c->length, 0.8*c->width, 1, 0);
845     glDisable(GL_POLYGON_OFFSET_FILL);
846     col[0] = 0.7;
847     col[1] = 0.7;
848     col[2] = 0.7;
849     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
850     circle(ci, 0.6*c->width, 30, 0);
851     col[0] = 0;
852     col[1] = 0;
853     col[2] = 0;
854     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
855     glTranslatef(3.0*c->length, 0.0, 0);
856     circle(ci, 0.6*c->width, 30, 0);
857     glTranslatef(0, 0.4*c->width, 0);
858     wire(ci, 3*c->length);
859     glTranslatef(0.0, -0.8*c->width, 0);
860     wire(ci, 3.3*c->length);
861   }
862   glPopMatrix();
863 }
864
865 static void DrawLED(Circuit *ci, LED *l)
866 {
867   GLfloat col[] = {0, 0, 0, 0.6};
868   GLfloat black[] = {0, 0, 0, 0.6};
869
870   col[0] = l->r; col[1] = l->g; col[2] = l->b;
871   if (l->light && ci->light) {
872     GLfloat dir[] = {-1, 0, 0};
873     glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, dir);
874     if (!ci->lighton) {
875       glLightfv(GL_LIGHT1, GL_SPECULAR, col);
876       glLightfv(GL_LIGHT1, GL_AMBIENT, black);
877       col[0] /= 1.5; col[1] /= 1.5; col[2] /= 1.5;
878       glLightfv(GL_LIGHT1, GL_DIFFUSE, col);
879       glLighti(GL_LIGHT1, GL_SPOT_CUTOFF, (GLint) 90);
880       glLighti(GL_LIGHT1, GL_CONSTANT_ATTENUATION, (GLfloat)1); 
881       glLighti(GL_LIGHT1, GL_LINEAR_ATTENUATION, (GLfloat)0); 
882       glLighti(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, (GLfloat)0); 
883       glLighti(GL_LIGHT1, GL_SPOT_EXPONENT, (GLint) 20);
884       ci->lighton = 1;
885     }
886   }
887   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
888   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
889   /* no transparency when LED is lit */
890   if (!l->light) { 
891     glEnable(GL_BLEND);
892     glDepthMask(GL_FALSE);
893     glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
894   }
895   glTranslatef(-0.9, 0, 0);
896   createCylinder(ci, 1.2, 0.3, 0, 0);
897   if (l->light && ci->light) {
898     glDisable(GL_LIGHTING);
899     glColor3fv(col);
900   }
901   sphere(ci, 0.3, 7, 7, 3, 7, 0, 7);
902   if (l->light && ci->light) {
903     glEnable(GL_LIGHTING);
904   } else {
905     glDepthMask(GL_TRUE);
906     glDisable(GL_BLEND);
907   }
908
909   glTranslatef(1.2, 0, 0);
910   createCylinder(ci, 0.1, 0.38, 1, 0);
911   glTranslatef(-0.3, 0.15, 0);
912   wire(ci, 3);
913   glTranslatef(0, -0.3, 0);
914   wire(ci, 3.3);
915   if (random() % 50 == 25) {
916     if (l->light) {
917       l->light = 0; ci->light = 0; ci->lighton = 0;
918       glDisable(GL_LIGHT1);
919     } else if (!ci->light) {
920       l->light = 1; 
921       ci->light = 1;
922     }
923   }
924 }
925
926
927 static void DrawThreeFive(Circuit *ci, ThreeFive *d)
928 {
929   GLfloat shine = 40;
930   GLfloat const dark[] = {0.3, 0.3, 0.3, 0};
931   GLfloat const light[] = {0.6, 0.6, 0.6, 0};
932   GLfloat const cream[] = {0.8, 0.8, 0.6, 0};
933   GLfloat const spec[] = {0.7, 0.7, 0.7, 0};
934
935    glPushMatrix();
936    glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
937    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cream);
938    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
939    
940    glTranslatef(-2.0, 0, 0);
941    createCylinder(ci, 0.7, 0.2, 0, 0);
942    glTranslatef(0.7, 0, 0);
943    createCylinder(ci, 1.3, 0.4, 1, 0);
944    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light);
945    glTranslatef(1.3, 0, 0);
946    createCylinder(ci, 1.3, 0.2, 0, 0);
947    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, dark);
948    glTranslatef(0.65, 0, 0);
949    createCylinder(ci, 0.15, 0.21, 0, 0);
950    glTranslatef(0.3, 0, 0);
951    createCylinder(ci, 0.15, 0.21, 0, 0);
952    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light);
953    glTranslatef(0.4, 0, 0);
954    sphere(ci, 0.23, 7, 7, 0, 5, 0, 7);
955
956    glPopMatrix();
957 }
958
959 static void DrawDiode(Circuit *ci, Diode *d)
960 {
961   GLfloat shine = 40;
962   GLfloat col[] = {0.3, 0.3, 0.3, 0};
963   GLfloat spec[] = {0.7, 0.7, 0.7, 0};
964
965    glPushMatrix();
966    glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
967    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
968    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
969    glTranslatef(-4, 0, 0);
970    wire(ci, 3);
971    glTranslatef(3, 0, 0);
972    bandedCylinder(ci, 0.3, 1.5, d->r, d->g, d->b, &(d->band), 1);
973    glTranslatef(1.5, 0, 0);
974    wire(ci, 3);
975    glPopMatrix();
976 }
977
978 static void Rect(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h,
979             GLfloat t)
980 {
981   GLfloat yh;
982   GLfloat xw;
983   GLfloat zt;
984
985   yh = y+h; xw = x+w; zt = z - t;
986
987   glBegin(GL_QUADS); /* front */
988     glNormal3f(0, 0, 1);
989     glVertex3f(x, y, z);
990     glVertex3f(x, yh, z);
991     glVertex3f(xw, yh, z);
992     glVertex3f(xw, y, z);
993   /* back */
994     glNormal3f(0, 0, -1);
995     glVertex3f(x, y, zt);
996     glVertex3f(x, yh, zt);
997     glVertex3f(xw, yh, zt);
998     glVertex3f(xw, y, zt);
999   /* top */
1000     glNormal3f(0, 1, 0);
1001     glVertex3f(x, yh, z);
1002     glVertex3f(x, yh, zt);
1003     glVertex3f(xw, yh, zt);
1004     glVertex3f(xw, yh, z);
1005   /* bottom */
1006     glNormal3f(0, -1, 0);
1007     glVertex3f(x, y, z);
1008     glVertex3f(x, y, zt);
1009     glVertex3f(xw, y, zt);
1010     glVertex3f(xw, y, z);
1011   /* left */
1012     glNormal3f(-1, 0, 0);
1013     glVertex3f(x, y, z);
1014     glVertex3f(x, y, zt);
1015     glVertex3f(x, yh, zt);
1016     glVertex3f(x, yh, z);
1017   /* right */
1018     glNormal3f(1, 0, 0);
1019     glVertex3f(xw, y, z);
1020     glVertex3f(xw, y, zt);
1021     glVertex3f(xw, yh, zt);
1022     glVertex3f(xw, yh, z);
1023   glEnd();
1024 }
1025
1026 /* IC pins */
1027
1028 static void ICLeg(GLfloat x, GLfloat y, GLfloat z, int dir)
1029 {
1030   if (dir) {
1031     Rect(x-0.1, y, z, 0.1, 0.1, 0.02);
1032     Rect(x-0.1, y, z, 0.02, 0.1, 0.1);
1033     Rect(x-0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
1034   } else {
1035     Rect(x, y, z, 0.1, 0.1, 0.02);
1036     Rect(x+0.8*0.1, y, z, 0.02, 0.1, 0.1);
1037     Rect(x+0.8*0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
1038   }
1039
1040 }
1041
1042
1043 static void DrawIC(Circuit *ci, IC *c)
1044 {
1045   GLfloat w, h, d;
1046   int z;
1047   GLfloat col[] = {0.1, 0.1, 0.1, 0};
1048   GLfloat col2[] = {0.2, 0.2, 0.2, 0};
1049   GLfloat spec[] = {0.6, 0.6, 0.6, 0};
1050   GLfloat shine = 40;
1051   GLfloat lspec[] = {0.6, 0.6, 0.6, 0};
1052   GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
1053   GLfloat lshine = 40;
1054   float mult, th, size;
1055
1056   glPushMatrix();
1057   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1058   glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1059   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1060   glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
1061   switch(c->pins) {
1062     case 8:
1063       w = 1.0; h = 1.5;
1064       break;
1065     case 14:
1066       w = 1.0; h = 3;
1067       break;
1068     case 16:
1069       w = 1.0; h = 3;
1070       break;
1071     case 24:
1072     default:
1073       w = 1.5; h = 3.5;
1074       break;
1075   }
1076   w = w/2; h = h/2;
1077     glEnable(GL_POLYGON_OFFSET_FILL);
1078     glPolygonOffset(1.0, 1.0);
1079     glBegin(GL_QUADS);
1080       glNormal3f(0, 0, 1);
1081       glVertex3f(w, h, 0.1);
1082       glVertex3f(w, -h, 0.1);
1083       glVertex3f(-w, -h, 0.1);
1084       glVertex3f(-w, h, 0.1);
1085       glNormal3f(0, 0, -1);
1086       glVertex3f(w, h, -0.1);
1087       glVertex3f(w, -h, -0.1);
1088       glVertex3f(-w, -h, -0.1);
1089       glVertex3f(-w, h, -0.1);
1090       glNormal3f(1, 0, 0);
1091       glVertex3f(w, h, -0.1);
1092       glVertex3f(w, -h, -0.1);
1093       glVertex3f(w, -h, 0.1);
1094       glVertex3f(w, h, 0.1);
1095       glNormal3f(0, -1, 0);
1096       glVertex3f(w, -h, -0.1);
1097       glVertex3f(w, -h, 0.1);
1098       glVertex3f(-w, -h, 0.1);
1099       glVertex3f(-w, -h, -0.1);
1100       glNormal3f(-1, 0, 0);
1101       glVertex3f(-w, h, -0.1);
1102       glVertex3f(-w, h, 0.1);
1103       glVertex3f(-w, -h, 0.1);
1104       glVertex3f(-w, -h, -0.1);
1105       glNormal3f(0, -1, 0);
1106       glVertex3f(-w, h, -0.1);
1107       glVertex3f(w, h, -0.1);
1108       glVertex3f(w, h, 0.1);
1109       glVertex3f(-w, h, 0.1);
1110     glEnd();
1111     glDisable(GL_POLYGON_OFFSET_FILL);
1112     if (c->tnum) glBindTexture(GL_TEXTURE_2D, c->tnum);
1113     glEnable(GL_TEXTURE_2D);
1114     glEnable(GL_BLEND);
1115     if (c->pins == 8)
1116       size = 0.4;
1117     else
1118       size = 0.6;
1119     th = size*2/3;
1120     mult = size*c->tw / c->th;
1121     mult /= 2;
1122     glBegin(GL_QUADS); /* text markings */
1123      glNormal3f(0, 0, 1);
1124      glTexCoord2f(0, 1);
1125      glVertex3f(th, mult, 0.1);
1126      glTexCoord2f(1, 1);
1127      glVertex3f(th, -mult, 0.1);
1128      glTexCoord2f(1, 0);
1129      glVertex3f(-th, -mult, 0.1);
1130      glTexCoord2f(0, 0);
1131      glVertex3f(-th, mult, 0.1);
1132     glEnd();
1133     glDisable(GL_TEXTURE_2D);
1134     glDisable(GL_BLEND);
1135     d = (h*2-0.1) / c->pins;
1136     d*=2;
1137     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
1138     glMaterialfv(GL_FRONT, GL_SPECULAR, lspec);
1139     glMaterialfv(GL_FRONT, GL_SHININESS, &lshine);
1140     for (z = 0 ; z < c->pins/2 ; z++) {
1141       ICLeg(w, -h + z*d + d/2, 0, 0);
1142     }
1143     for (z = 0 ; z < c->pins/2 ; z++) {
1144       ICLeg(-w, -h + z*d + d/2, 0, 1);
1145     }
1146     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col2);
1147     glTranslatef(-w+0.3, h-0.3, 0.1);
1148     glRotatef(90, 0, 1, 0);
1149     circle(ci, 0.1, 7, 0);
1150     glPopMatrix();
1151 }
1152
1153 static void DrawDisp(Circuit *ci, Disp *d)
1154 {
1155   GLfloat col[] = {0.8, 0.8, 0.8, 1.0}; /* body colour */
1156   GLfloat front[] = {0.2, 0.2, 0.2, 1.0}; /* front colour */
1157   GLfloat on[] = {0.9, 0, 0, 1}; /* 'on' segment */
1158   GLfloat off[] = {0.3, 0, 0, 1}; /* 'off' segment */
1159   int i, j, k;
1160   GLfloat x, y; /* for the pins */
1161   GLfloat spec[] = {0.6, 0.6, 0.6, 0};
1162   GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
1163   GLfloat shine = 40;
1164   static const GLfloat vdata_h[6][2] = {
1165     {0, 0},
1166     {0.1, 0.1},
1167     {0.9, 0.1},
1168     {1, 0},
1169     {0.9, -0.1},
1170     {0.1, -0.1}
1171   };
1172   static const GLfloat vdata_v[6][2] = {
1173     {0.27, 0},
1174     {0.35, -0.1},
1175     {0.2, -0.9},
1176     {0.1, -1},
1177     {0, -0.9},
1178     {0.15, -0.15}
1179   };
1180
1181   static const GLfloat seg_start[7][2] = {
1182     {0.55, 2.26},
1183     {1.35, 2.26},
1184     {1.2, 1.27},
1185     {0.25, 0.25},
1186     {0.06, 1.25},
1187     {0.25, 2.25},
1188     {0.39, 1.24}
1189   };
1190
1191   static const int nums[10][7] = {
1192     {1, 1, 1, 1, 1, 1, 0}, /* 0 */
1193     {0, 1, 1, 0, 0, 0, 0}, /* 1 */
1194     {1, 1, 0, 1, 1, 0, 1}, /* 2 */
1195     {1, 1, 1, 1, 0, 0, 1}, /* 3 */
1196     {0, 1, 1, 0, 0, 1, 1}, /* 4 */
1197     {1, 0, 1, 1, 0, 1, 1}, /* 5 */
1198     {1, 0, 1, 1, 1, 1, 1}, /* 6 */
1199     {1, 1, 1, 0, 0, 0, 0}, /* 7 */
1200     {1, 1, 1, 1, 1, 1, 1}, /* 8 */
1201     {1, 1, 1, 0, 0, 1, 1}  /* 9 */
1202   };
1203
1204    glTranslatef(-0.9, -1.8, 0);
1205    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1206    Rect(0, 0, -0.01, 1.8, 2.6, 0.7);
1207    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, front);
1208    glBegin(GL_QUADS);
1209      glVertex2f(-0.05, -0.05);
1210      glVertex2f(-0.05, 2.65);
1211      glVertex2f(1.85, 2.65);
1212      glVertex2f(1.85, -0.05);
1213    glEnd();
1214    glDisable(GL_LIGHTING); /* lit segments dont need light */
1215    if (!seven && (random() % 30) == 19) { /* randomly change value */
1216      d->value = random() % 10;
1217    }
1218    for (j = 0 ; j < 7 ; j++) { /* draw the segments */
1219      GLfloat xx[6], yy[6];
1220      if (nums[d->value][j])
1221        glColor3fv(on);
1222      else
1223        glColor3fv(off);
1224      for (k = 0 ; k < 6 ; k++) {
1225        if (j == 0 || j == 3 || j == 6) {
1226          xx[k] = seg_start[j][0] + vdata_h[k][0];
1227          yy[k] = seg_start[j][1] + vdata_h[k][1];
1228        } else {
1229          xx[k] = seg_start[j][0] + vdata_v[k][0];
1230          yy[k] = seg_start[j][1] + vdata_v[k][1];
1231        }
1232      }
1233      glBegin(GL_POLYGON);
1234      for(i = 0 ; i < 6 ; i++) {
1235        glVertex3f(xx[i], yy[i], 0.01);
1236      }
1237      glEnd();
1238    }
1239    glColor3fv(on);
1240    glPointSize(4);
1241    glBegin(GL_POINTS);
1242     glVertex3f(1.5, 0.2, 0.01);
1243    glEnd();
1244    glEnable(GL_LIGHTING);
1245    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
1246    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1247    glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
1248    for (x = 0.35 ; x <= 1.5 ; x+= 1.15) {
1249      for ( y = 0.2 ; y <= 2.4 ; y += 0.3) {
1250        ICLeg(x, y, -0.7, 1);
1251      }
1252    }
1253 }
1254
1255 static void HoledRectangle(Circuit *ci, 
1256                            GLfloat w, GLfloat h, GLfloat d, GLfloat radius,
1257                            int p)
1258 {
1259   int step, a;
1260   GLfloat x1, y1, x2, y2;
1261   GLfloat yr, yr1, xr, xr1, side, side1;
1262   GLfloat nx, ny;
1263
1264   step = 360 / p;
1265   x1 = radius; y1 = 0;
1266   xr1 = w/2; yr1 = 0;
1267   side = w/2;
1268   side1 = h/2;
1269   glBegin(GL_QUADS);
1270   for (a = 0 ; a <= 360 ; a+= step) {
1271     y2=radius*(float)ci->sin_table[(int)a];
1272     x2=radius*(float)ci->cos_table[(int)a];
1273
1274     if (a < 45 || a > 315) {
1275       xr = side;
1276       yr = side1 * ci->tan_table[a];
1277       nx = 1; ny = 0;
1278     } else if (a <= 135 || a >= 225) {
1279       xr = side/ci->tan_table[a];
1280       if (a >= 225) {
1281        yr = -side1;
1282        xr = 0 - xr;
1283        nx = 0; ny = -1;
1284       } else {
1285        yr = side1;
1286        nx = 0; ny = 1;
1287      }
1288     } else {
1289       xr = -side;
1290       yr = -side1 * ci->tan_table[a];
1291       nx = -1; ny = 0;
1292     }
1293
1294       glNormal3f(-x1, -y1, 0); /* cylinder */
1295       glVertex3f(x1,y1,0);
1296       glVertex3f(x1,y1,-d);
1297       glVertex3f(x2,y2,-d);
1298       glVertex3f(x2,y2,0);
1299
1300       glNormal3f(0, 0, 1); /* front face */
1301       glVertex3f(x1,y1,0);
1302       glVertex3f(xr1, yr1, 0);
1303       glVertex3f(xr, yr, 0);
1304       glVertex3f(x2, y2, 0);
1305
1306       glNormal3f(nx, ny, 0); /* side */
1307       glVertex3f(xr, yr, 0);
1308       glVertex3f(xr, yr, -d);
1309       glVertex3f(xr1, yr1, -d);
1310       glVertex3f(xr1, yr1, 0);
1311
1312       glNormal3f(0, 0, -1); /* back */
1313       glVertex3f(xr, yr, -d);
1314       glVertex3f(x2, y2, -d);
1315       glVertex3f(x1, y1, -d);
1316       glVertex3f(xr1, yr1, -d);
1317
1318     x1=x2;
1319     y1=y2;
1320     xr1 = xr; yr1 = yr;
1321   }
1322   glEnd();
1323 }
1324
1325 static void DrawTransistor(Circuit *ci, Transistor *t)
1326 {
1327   GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
1328   GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
1329   GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
1330   GLfloat shin = 30;
1331
1332   glPushMatrix();
1333   glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1334   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col);
1335   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1336   if (t->type == 1) { /* TO-92 style */
1337     float mult, y1, y2;
1338     mult = 1.5*t->th/t->tw;
1339     y1 = 0.2+mult/2;
1340     y2 = 0.8-mult/2;
1341     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1342     glRotatef(90, 0, 1, 0);
1343     glRotatef(90, 0, 0, 1);
1344     createCylinder(ci, 1.0, 0.4, 1, 1);
1345     Rect(0, -0.2, 0.4, 1, 0.2, 0.8);
1346 /* Draw the markings */
1347     glEnable(GL_TEXTURE_2D);
1348     if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
1349     glEnable(GL_BLEND);
1350     glDepthMask(GL_FALSE);
1351     glBegin (GL_QUADS);
1352      glNormal3f(0, 0, 1);
1353      glTexCoord2f(0, 1);
1354      glVertex3f(y1, -0.21, 0.3);
1355      glTexCoord2f(1, 1);
1356      glVertex3f(y1, -0.21, -0.3);
1357      glTexCoord2f(1, 0);
1358      glVertex3f(y2, -0.21, -0.3);
1359      glTexCoord2f(0, 0);
1360      glVertex3f(y2, -0.21, 0.3);
1361     glEnd();
1362     glDisable(GL_TEXTURE_2D);
1363     glDisable(GL_BLEND);
1364     glDepthMask(GL_TRUE);
1365     glTranslatef(-2, 0, -0.2);
1366     wire(ci, 2);
1367     glTranslatef(0, 0, 0.2);
1368     wire(ci, 2);
1369     glTranslatef(0, 0, 0.2);
1370     wire(ci, 2);
1371   } else if (t->type == 0) { /* TO-220 Style */
1372     float mult, y1, y2;
1373     mult = 1.5*t->th/t->tw;
1374     y1 = 0.75+mult/2;
1375     y2 = 0.75-mult/2;
1376     Rect(0, 0, 0, 1.5, 1.5, 0.5);
1377     glEnable(GL_TEXTURE_2D);
1378     if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
1379     glEnable(GL_BLEND);
1380     glDepthMask(GL_FALSE);
1381     glBegin (GL_QUADS);
1382      glNormal3f(0, 0, 1);
1383      glTexCoord2f(0, 1);
1384      glVertex3f(0, y1, 0.01);
1385      glTexCoord2f(1, 1);
1386      glVertex3f(1.5, y1, 0.01);
1387      glTexCoord2f(1, 0);
1388      glVertex3f(1.5, y2, 0.01);
1389      glTexCoord2f(0, 0);
1390      glVertex3f(0, y2, 0.01);
1391     glEnd();
1392     glDisable(GL_TEXTURE_2D);
1393     glDisable(GL_BLEND);
1394     glDepthMask(GL_TRUE);
1395     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1396     glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1397     glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1398     Rect(0, 0, -0.5, 1.5, 1.5, 0.30);
1399     if (!glIsEnabled(GL_NORMALIZE)) glEnable(GL_NORMALIZE);
1400     glTranslatef(0.75, 1.875, -0.55);
1401     HoledRectangle(ci, 1.5, 0.75, 0.25, 0.2, 8);
1402     glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
1403     glTranslatef(-0.375, -1.875, 0);
1404     glRotatef(90, 0, 0, -1);
1405     wire(ci, 2);
1406     glTranslatef(0, 0.375, 0);
1407     wire(ci, 2);
1408     glTranslatef(0, 0.375, 0);
1409     wire(ci, 2);
1410   } else {              /* SMC transistor */
1411 /* Draw the body */
1412     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1413     glTranslatef(-0.5, -0.25, 0.1);
1414     Rect(0, 0, 0, 1, 0.5, 0.2);
1415 /* Draw the markings */
1416     glEnable(GL_TEXTURE_2D);
1417     if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
1418     glEnable(GL_BLEND);
1419     glDepthMask(GL_FALSE);
1420     glBegin (GL_QUADS);
1421      glNormal3f(0, 0, 1);
1422      glTexCoord2f(0, 1);
1423      glVertex3f(0.2, 0, 0.01);
1424      glTexCoord2f(1, 1);
1425      glVertex3f(0.8, 0, 0.01);
1426      glTexCoord2f(1, 0);
1427      glVertex3f(0.8, 0.5, 0.01);
1428      glTexCoord2f(0, 0);
1429      glVertex3f(0.2, 0.5, 0.01);
1430     glEnd();
1431     glDisable(GL_TEXTURE_2D);
1432     glDisable(GL_BLEND);
1433     glDepthMask(GL_TRUE);
1434 /* Now draw the legs */
1435     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1436     glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1437     glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1438     Rect(0.25, -0.1, -0.05, 0.1, 0.1, 0.2);
1439     Rect(0.75, -0.1, -0.05, 0.1, 0.1, 0.2);
1440     Rect(0.5, 0.5, -0.05, 0.1, 0.1, 0.2);
1441     Rect(0.25, -0.2, -0.2, 0.1, 0.15, 0.1);
1442     Rect(0.75, -0.2, -0.2, 0.1, 0.15, 0.1);
1443     Rect(0.5, 0.5, -0.2, 0.1, 0.15, 0.1);
1444   }
1445   glPopMatrix();
1446 }
1447
1448 static Component * NewComponent(ModeInfo *mi)
1449 {
1450   Circuit *ci = &circuit[MI_SCREEN(mi)];
1451   Component *c;
1452   float rnd;
1453
1454   c = malloc(sizeof(Component));
1455   c->angle = RAND_RANGE(0,360);
1456   rnd = f_rand();
1457   if (rnd < 0.25) { /* come from the top */
1458      c->y = ci->YMAX/2;
1459      c->x = RAND_RANGE(0, ci->XMAX) - ci->XMAX/2;
1460      if (c->x > 0)
1461        c->dx = 0 - RAND_RANGE(0.5, 2);
1462      else 
1463        c->dx = RAND_RANGE(0.5, 2);
1464      c->dy = 0 - RAND_RANGE(0.5, 2);
1465   } else if (rnd < 0.5) { /* come from the bottom */
1466      c->y = 0 - ci->YMAX/2;
1467      c->x = RAND_RANGE(0, ci->XMAX) - ci->XMAX/2;
1468      if (c->x > 0)
1469        c->dx = 0 - RAND_RANGE(0.5, 2);
1470      else 
1471        c->dx = RAND_RANGE(0.5, 2);
1472      c->dy = RAND_RANGE(0.5, 2);
1473   } else if (rnd < 0.75) { /* come from the left */
1474      c->x = 0 - ci->XMAX/2;
1475      c->y = RAND_RANGE(0, ci->YMAX) - ci->YMAX/2;
1476      c->dx = RAND_RANGE(0.5, 2);
1477      if (c->y > 0)
1478        c->dy = 0 - RAND_RANGE(0.5, 2);
1479      else 
1480        c->dy = RAND_RANGE(0.5, 2);
1481   } else { /* come from the right */
1482      c->x = ci->XMAX/2;
1483      c->y = RAND_RANGE(0, ci->YMAX) - ci->YMAX/2;
1484      c->dx =  0 - RAND_RANGE(0.5, 2);
1485      if (c->y > 0)
1486        c->dy = 0 - RAND_RANGE(0.5, 2);
1487      else 
1488        c->dy = RAND_RANGE(0.5, 2);
1489   }
1490   c->z = RAND_RANGE(0, 7) - 9;
1491   c->rotx = f_rand();
1492   c->roty = f_rand();
1493   c->rotz = f_rand();
1494   c->drot = f_rand() * 3;
1495   c->rdeg = 0;
1496   c->dz = f_rand()*2 - 1;
1497   c->norm = 0;
1498   c->alpha = 0; /* explicitly set to 1 later */
1499   rnd = random() % 11;
1500   if (rnd < 1) {
1501     c->c = NewResistor();
1502     c->type = 0;
1503     if (f_rand() < 0.4)
1504       c->norm = 1; /* some resistors shine */
1505   } else if (rnd < 2) {
1506     c->c = NewDiode();
1507     if (f_rand() < 0.4)
1508       c->norm = 1; /* some diodes shine */
1509     c->type = 1;
1510   } else if (rnd < 3) {
1511     c->c = NewTransistor(mi);
1512     c->norm = 1;
1513     c->type = 2;
1514   } else if (rnd < 4) {
1515     c->c = NewCapacitor(ci);
1516     c->norm = 1;
1517     c->type = 4;
1518   } else if (rnd < 5) {
1519     c->c = NewIC(mi);
1520     c->type = 5;
1521     c->norm = 1;
1522   } else if (rnd < 6) {
1523     c->c = NewLED(ci);
1524     c->type = 3;
1525     c->norm = 1;
1526     c->alpha = 1;
1527   } else if (rnd < 7) {
1528     c->c = NewFuse(ci);
1529     c->norm = 1;
1530     c->type = 7;
1531     c->alpha = 1;
1532   } else if (rnd < 8) {
1533     c->c = NewRCA(ci);
1534     c->norm = 1;
1535     c->type = 8;
1536   } else if (rnd < 9) {
1537     c->c = NewThreeFive(ci);
1538     c->norm = 1;
1539     c->type = 9;
1540   } else if (rnd < 10) {
1541     c->c = NewSwitch(ci);
1542     c->norm = 1;
1543     c->type = 10;
1544   } else {
1545     c->c = NewDisp(ci);
1546     c->type = 6;
1547   }
1548   return c;
1549 }
1550
1551 static Transistor *NewTransistor(ModeInfo *mi)
1552 {
1553   Transistor *t;
1554   float texfg[] = {0.7, 0.7, 0.7, 1.0};
1555   float texbg[] = {0.3, 0.3, 0.3, 0.1};
1556   TexNum *tn;
1557   const char *val;
1558
1559   t = malloc(sizeof(Transistor));
1560   t->type = (random() % 3);
1561   if (t->type == 0) {
1562     val = transistortypes[random() % countof(transistortypes)];
1563     tn = fonttexturealloc(mi, val, texfg, texbg);
1564     if (tn == NULL) {
1565       fprintf(stderr, "Error getting a texture for a string!\n");
1566       t->tnum = 0;
1567     } else {
1568       t->tnum = tn->num;
1569       t->tw = tn->w; t->th = tn->h;
1570       free(tn);
1571     }
1572   } else if (t->type == 2) {
1573     val = smctypes[random() % countof(smctypes)];
1574     tn = fonttexturealloc(mi, val, texfg, texbg);
1575     if (tn == NULL) {
1576       fprintf(stderr, "Error getting a texture for a string!\n");
1577       t->tnum = 0;
1578     } else {
1579       t->tnum = tn->num;
1580       t->tw = tn->w; t->th = tn->h;
1581       free(tn);
1582     }
1583   } else if (t->type == 1) {
1584     val = to92types[random() % countof(to92types)];
1585     tn = fonttexturealloc(mi, val, texfg, texbg);
1586     if (tn == NULL) {
1587       fprintf(stderr, "Error getting a texture for a string!\n");
1588       t->tnum = 0;
1589     } else {
1590       t->tnum = tn->num;
1591       t->tw = tn->w; t->th = tn->h;
1592       free(tn);
1593     }
1594   }
1595
1596   return t;
1597 }
1598
1599 static Capacitor *NewCapacitor(Circuit *ci)
1600 {
1601   Capacitor *c;
1602
1603   c = malloc(sizeof(Capacitor));
1604   c->type = (f_rand() < 0.5);
1605   if (!c->type) {
1606     c->length = RAND_RANGE(0.5, 1);
1607     c->width = RAND_RANGE(0.5, 1);
1608   } else {
1609     c->width = RAND_RANGE(0.3, 1);
1610   }
1611   return c;
1612 }
1613
1614 /* 7 segment display */
1615
1616 static Disp *NewDisp(Circuit *ci)
1617 {
1618   Disp *d;
1619
1620   d = malloc(sizeof(Disp));
1621   if (seven)
1622     d->value = 7;
1623   else
1624     d->value = RAND_RANGE(0, 10);
1625   return d;
1626 }
1627
1628
1629 static IC *NewIC(ModeInfo *mi)
1630 {
1631   IC *c;
1632   int pins;
1633   TexNum *tn;
1634   float texfg[] = {0.7, 0.7, 0.7, 1.0};
1635   float texbg[] = {0.1, 0.1, 0.1, 0};
1636   const char *val;
1637   char *str;
1638   int types[countof(ictypes)], i, n = 0;
1639
1640   c = malloc(sizeof(IC));
1641   c->type = 0;
1642   switch((int)RAND_RANGE(0,4)) {
1643     case 0:
1644       pins = 8;
1645       break;
1646     case 1:
1647       pins = 14;
1648       break;
1649     case 2:
1650       pins = 16;
1651       break;
1652     case 3:
1653     default:
1654       pins = 24;
1655       break;
1656   }
1657   for (i = 0 ; i < countof(ictypes) ; i++) {
1658     if (ictypes[i].pins == pins) {
1659        types[n] = i;
1660        n++;
1661     }
1662   }
1663
1664   if (n > countof(types)) abort();
1665   val = ictypes[types[random() % n]].val;
1666   str = malloc(strlen(val) + 1 + 4 + 1); /* add space for production date */
1667   sprintf(str, "%s\n%02d%02d", val, (int)RAND_RANGE(80, 100), (int)RAND_RANGE(1,53));
1668   tn = fonttexturealloc(mi, str, texfg, texbg);
1669   free(str);
1670   if (tn == NULL) {
1671     fprintf(stderr, "Error allocating font texture for '%s'\n", val);
1672     c->tnum = 0;
1673   } else {
1674     c->tw = tn->w; c->th = tn->h;
1675     c->tnum = tn->num;
1676     free(tn);
1677   }
1678   c->pins = pins;
1679   return c;
1680 }
1681
1682 static LED *NewLED(Circuit *ci)
1683 {
1684   LED *l;
1685   float r;
1686
1687   l = malloc(sizeof(LED));
1688   r = f_rand();
1689   l->light = 0;
1690   if (!ci->light && (f_rand() < 0.4)) {
1691      ci->light = 1;
1692      l->light = 1;
1693   }
1694   if (r < 0.2) {
1695     l->r = 0.9; l->g = 0; l->b = 0;
1696   } else if (r < 0.4) {
1697     l->r = 0.3; l->g = 0.9; l->b = 0;
1698   } else if (r < 0.6) {
1699     l->r = 0.8; l->g = 0.9; l->b = 0;
1700   } else if (r < 0.8) {
1701     l->r = 0.0; l->g = 0.2; l->b = 0.8;
1702   } else {
1703     l->r = 0.9, l->g = 0.55, l->b = 0;
1704   }
1705   return l;
1706 }
1707
1708 static Fuse *NewFuse(Circuit *ci)
1709 {
1710   Fuse *f;
1711
1712   f = malloc(sizeof(Fuse));
1713   return f;
1714 }
1715
1716 static RCA *NewRCA(Circuit *ci)
1717 {
1718   RCA *r;
1719
1720   r = malloc(sizeof(RCA));
1721   r->col = (random() % 10 < 5);
1722   return r;
1723 }
1724
1725 static ThreeFive *NewThreeFive(Circuit *ci)
1726 {
1727   ThreeFive *r;
1728
1729   r = malloc(sizeof(ThreeFive));
1730   return r;
1731 }
1732
1733 static Switch *NewSwitch(Circuit *ci)
1734 {
1735   Switch *s;
1736
1737   s = malloc(sizeof(Switch));
1738   s->position = 0;
1739   return s;
1740 }
1741
1742 static Diode *NewDiode(void)
1743 {
1744   Band *b;
1745   Diode *ret;
1746
1747   ret = malloc(sizeof(Diode));
1748   b = malloc(sizeof(Band));
1749   b->pos = 0.8;
1750   b->len = 0.1;
1751   if (f_rand() < 0.5) {
1752     b->r = 1;
1753     b->g = 1;
1754     b->b = 1;
1755     ret->r = 0.7; ret->g = 0.1 ; ret->b = 0.1;
1756   } else {
1757     b->r = 1;
1758     b->g = 1;
1759     b->b = 1;
1760     ret->r = 0.2; ret->g = 0.2 ; ret->b = 0.2;
1761   }
1762   ret->band = b;
1763   return ret;
1764 }
1765
1766
1767 static Resistor  * NewResistor(void)
1768 {
1769   int v, m, t; /* value, multiplier, tolerance */
1770   Resistor *ret;
1771
1772   v = RAND(9);
1773   m = RAND(5);
1774   t = (RAND(10) < 5) ? 10 : 11; 
1775   ret = malloc(sizeof(Resistor));
1776
1777   if (seven) {
1778     ret->b[0] = ret->b[1] = ret->b[2] = 7;
1779   } else {
1780     ret->b[0] = values[v][0];
1781     ret->b[1] = values[v][1];
1782     ret->b[2] = m;
1783   }
1784   ret->b[3] = t;
1785
1786   return ret;
1787 }
1788
1789 static void makebandlist(Circuit *ci)
1790 {
1791   int i;
1792   GLfloat col[] = {0,0,0,0};
1793   GLfloat spec[] = {0.8,0.8,0.8,0};
1794   GLfloat shine = 40;
1795
1796    for (i = 0 ; i < 12 ; i++) {
1797      ci->band_list[i] = glGenLists(i);
1798      glNewList(ci->band_list[i], GL_COMPILE);
1799      col[0] = colorcodes[i][0];
1800      col[1] = colorcodes[i][1];
1801      col[2] = colorcodes[i][2];
1802      glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
1803      glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
1804      glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
1805      createCylinder(ci, 0.1, 0.42, 0, 0);
1806      glEndList();
1807   }
1808 }
1809   
1810
1811 static void bandedCylinder(Circuit *ci, 
1812                            float radius, float l, 
1813                            GLfloat r, GLfloat g, GLfloat bl, 
1814                            Band **b, int nbands)
1815 {
1816   int n; /* band number */
1817   int p = 0; /* prev number + 1; */
1818   GLfloat col[] = {0,0,0,0};
1819
1820    col[0] = r; col[1] = g; col[2] = bl;
1821    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1822    createCylinder(ci, l, radius, 1, 0); /* body */
1823    for (n = 0 ; n < nbands ; n++) {
1824      glPushMatrix();
1825      glTranslatef(b[n]->pos*l, 0, 0);
1826      col[0] = b[n]->r; col[1] = b[n]->g; col[2] = b[n]->b;
1827      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1828      createCylinder(ci, b[n]->len*l, radius*1.05, 0, 0); /* band */
1829      glPopMatrix();
1830      p = n+1;
1831    }
1832 }
1833
1834 static void drawgrid(Circuit *ci)
1835 {
1836   GLfloat x, y;
1837   GLfloat col3[] = {0, 0.8, 0};
1838
1839   if (!ci->draw_s) {
1840      if (f_rand() < ((rotate) ? 0.05 : 0.01)) {
1841        ci->draw_sdir = RAND_RANGE(0, 4);
1842        ci->draw_ds = RAND_RANGE(0.4, 0.8);
1843        switch (ci->draw_sdir) {
1844           case 0:
1845            ci->draw_sx = -ci->XMAX/2;
1846            ci->draw_sy = ((int)RAND_RANGE(0, ci->YMAX/2))*2 - ci->YMAX/2;
1847            break;
1848           case 1:
1849            ci->draw_sx = ci->XMAX/2;
1850            ci->draw_sy = ((int)RAND_RANGE(0, ci->YMAX/2))*2 - ci->YMAX/2;
1851            break;
1852           case 2:
1853            ci->draw_sy = ci->YMAX/2;
1854            ci->draw_sx = ((int)RAND_RANGE(0, ci->XMAX/2))*2 - ci->XMAX/2;
1855            break;
1856           case 3:
1857            ci->draw_sy = -ci->YMAX/2;
1858            ci->draw_sx = ((int)RAND_RANGE(0, ci->XMAX/2))*2 - ci->XMAX/2;
1859            break;
1860         }
1861         ci->draw_s = 1;
1862       }
1863   } else if (!rotate) {
1864     if (ci->grid_col[1] < 0.25) {
1865       ci->grid_col[1] += 0.025; ci->grid_col[2] += 0.005;
1866       ci->grid_col2[1] += 0.015 ; ci->grid_col2[2] += 0.005;
1867     }
1868   }
1869
1870   glDisable(GL_LIGHTING);
1871   if (ci->draw_s) {
1872     glColor3fv(col3);
1873     glPushMatrix();
1874     glTranslatef(ci->draw_sx, ci->draw_sy, -10);
1875     sphere(ci, 0.1, 10, 10, 0, 10, 0, 10);
1876     if (ci->draw_sdir == 0) 
1877       glTranslatef(-ci->draw_ds, 0, 0);
1878     if (ci->draw_sdir == 1) 
1879       glTranslatef(ci->draw_ds, 0, 0);
1880     if (ci->draw_sdir == 2) 
1881       glTranslatef(0, ci->draw_ds, 0);
1882     if (ci->draw_sdir == 3) 
1883       glTranslatef(0, -ci->draw_ds, 0);
1884     sphere(ci, 0.05, 10, 10, 0, 10, 0, 10);
1885     glPopMatrix();
1886     if (ci->draw_sdir == 0) {
1887        ci->draw_sx += ci->draw_ds;
1888        if (ci->draw_sx > ci->XMAX/2)
1889          ci->draw_s = 0;
1890     }
1891     if (ci->draw_sdir == 1) {
1892        ci->draw_sx -= ci->draw_ds;
1893        if (ci->draw_sx < -ci->XMAX/2)
1894          ci->draw_s = 0;
1895     }
1896     if (ci->draw_sdir == 2) {
1897        ci->draw_sy -= ci->draw_ds;
1898        if (ci->draw_sy < ci->YMAX/2)
1899          ci->draw_s = 0;
1900     }
1901     if (ci->draw_sdir == 3) {
1902        ci->draw_sy += ci->draw_ds;
1903        if (ci->draw_sy > ci->YMAX/2)
1904          ci->draw_s = 0;
1905     }
1906   } else if (!rotate) {
1907     if (ci->grid_col[1] > 0) {
1908       ci->grid_col[1] -= 0.0025; ci->grid_col[2] -= 0.0005;
1909       ci->grid_col2[1] -= 0.0015 ; ci->grid_col2[2] -= 0.0005;
1910     }
1911   }
1912   for (x = -ci->XMAX/2 ; x <= ci->XMAX/2 ; x+= 2) {
1913     glColor3fv(ci->grid_col);
1914     glBegin(GL_LINES);
1915      glVertex3f(x, ci->YMAX/2, -10);
1916      glVertex3f(x, -ci->YMAX/2, -10);
1917      glColor3fv(ci->grid_col2);
1918      glVertex3f(x-0.02, ci->YMAX/2, -10);
1919      glVertex3f(x-0.02, -ci->YMAX/2, -10);
1920      glVertex3f(x+0.02, ci->YMAX/2, -10);
1921      glVertex3f(x+0.02, -ci->YMAX/2, -10);
1922     glEnd();
1923   }
1924   for (y = -ci->YMAX/2 ; y <= ci->YMAX/2 ; y+= 2) {
1925     glColor3fv(ci->grid_col);
1926     glBegin(GL_LINES);
1927      glVertex3f(-ci->XMAX/2, y, -10);
1928      glVertex3f(ci->XMAX/2, y, -10);
1929      glColor3fv(ci->grid_col2);
1930      glVertex3f(-ci->XMAX/2, y-0.02, -10);
1931      glVertex3f(ci->XMAX/2, y-0.02, -10);
1932      glVertex3f(-ci->XMAX/2, y+0.02, -10);
1933      glVertex3f(ci->XMAX/2, y+0.02, -10);
1934     glEnd();
1935   }
1936   glEnable(GL_LIGHTING);
1937 }
1938
1939 static void display(ModeInfo *mi)
1940 {
1941   Circuit *ci = &circuit[MI_SCREEN(mi)];
1942   GLfloat light_sp[] = {0.8, 0.8, 0.8, 1.0};
1943   GLfloat black[] = {0, 0, 0, 1.0};
1944   int j;
1945
1946   if (ci->display_i == 0) {
1947     for (ci->display_i = 0 ; ci->display_i < maxparts ; ci->display_i++) {
1948       ci->components[ci->display_i] = NULL;
1949     }
1950   } 
1951   glEnable(GL_LIGHTING);
1952   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
1953   glLoadIdentity();
1954   gluLookAt(ci->viewer[0], ci->viewer[1], ci->viewer[2], 
1955             0.0, 0.0, 0.0, 
1956             0.0, 1.0, 0.0);
1957   glPushMatrix();
1958   if (rotate) {
1959      glRotatef(ci->rotate_angle, 0, 0, 1);
1960      ci->rotate_angle += 0.01 * (float)rotatespeed;
1961      if (ci->rotate_angle >= 360) ci->rotate_angle = 0;
1962   }
1963   glLightfv(GL_LIGHT0, GL_POSITION, ci->lightpos);
1964   glLightfv(GL_LIGHT0, GL_SPECULAR, light_sp);
1965   glLightfv(GL_LIGHT0, GL_DIFFUSE, light_sp);
1966   glLighti(GL_LIGHT0, GL_CONSTANT_ATTENUATION, (GLfloat)1); 
1967   glLighti(GL_LIGHT0, GL_LINEAR_ATTENUATION, (GLfloat)0.5); 
1968   glLighti(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, (GLfloat)0); 
1969   drawgrid(ci);
1970   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light_sp);
1971   if (f_rand() < 0.05) {
1972     for (j = 0 ; j < maxparts ; j++) {
1973       if (ci->components[j] == NULL) {
1974         ci->components[j] = NewComponent(mi);
1975         j = maxparts;
1976       }
1977     }
1978     reorder(&ci->components[0]);
1979   }
1980   for (j = 0 ; j < maxparts ; j++) {
1981      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, black);
1982      glMaterialfv(GL_FRONT, GL_EMISSION, black);
1983      glMaterialfv(GL_FRONT, GL_SPECULAR, black);
1984      if (ci->components[j] != NULL) {
1985        if (DrawComponent(ci, ci->components[j])) {
1986         free(ci->components[j]); ci->components[j] = NULL;
1987        }
1988      }
1989   }
1990   glPopMatrix();
1991   glFlush();
1992 }
1993
1994 static void freetexture (Circuit *ci, GLuint texture) 
1995 {
1996   ci->s_refs[texture]--;
1997   if (ci->s_refs[texture] < 1) {
1998     glDeleteTextures(1, &texture);
1999   }
2000 }
2001
2002 static TexNum * fonttexturealloc (ModeInfo *mi,
2003                                   const char *str, float *fg, float *bg)
2004 {
2005   Circuit *ci = &circuit[MI_SCREEN(mi)];
2006   int i, status;
2007   XImage *ximage;
2008   char *c;
2009   TexNum *t;
2010
2011   if (ci->font_init == 0) {
2012     for (i = 0 ; i < 50 ; i++) {
2013       ci->font_strings[i] = NULL;
2014       ci->s_refs[i] = 0;
2015       ci->font_w[i] = 0; ci->font_h[i] = 0;
2016     }
2017     ci->font_init++;
2018   }
2019   for (i = 0 ; i < 50 ; i++) {
2020     if (!ci->s_refs[i] && ci->font_strings[i]) {
2021       free (ci->font_strings[i]);
2022       ci->font_strings[i] = NULL;
2023     }
2024     if (ci->font_strings[i] && !strcmp(str, ci->font_strings[i])) { /* if one matches */
2025       t = malloc(sizeof(TexNum));
2026       t->w = ci->font_w[i]; t->h = ci->font_h[i];
2027       t->num = i;
2028       ci->s_refs[i]++;
2029       return t;
2030     }
2031   }
2032
2033   /* at this point we need to make the new texture */
2034   ximage = text_to_ximage (mi->xgwa.screen,
2035                            mi->xgwa.visual,
2036                            font, str,
2037                            fg, bg);
2038   for (i = 0 ; ci->font_strings[i] != NULL ; i++) { /* set i to the next unused value */
2039      if (i > 49) {
2040         fprintf(stderr, "Texture cache full!\n");
2041         free(ximage->data);
2042         ximage->data = 0;
2043         XFree (ximage);
2044         return NULL;
2045      }
2046   }
2047
2048   glBindTexture(GL_TEXTURE_2D, i);
2049   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2050   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2051   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2052
2053   clear_gl_error();
2054   status = gluBuild2DMipmaps(GL_TEXTURE_2D, 4, ximage->width, ximage->height,
2055                              GL_RGBA, GL_UNSIGNED_BYTE, ximage->data);
2056   if (status)
2057     {
2058       const char *s = (char *) gluErrorString (status);
2059       fprintf (stderr, "%s: error mipmapping %dx%d texture: %s\n",
2060                progname, ximage->width, ximage->height,
2061                (s ? s : "(unknown)"));
2062       exit (1);
2063     }
2064   check_gl_error("mipmapping");
2065
2066   t = malloc(sizeof(TexNum));
2067   t->w = ximage->width;
2068   t->h = ximage->height;
2069   ci->font_w[i] = t->w; ci->font_h[i] = t->h;
2070   free(ximage->data);
2071   ximage->data = 0;
2072   XFree (ximage);
2073   c = malloc(strlen(str)+1);
2074   strncpy(c, str, strlen(str)+1);
2075   ci->font_strings[i] = c;
2076   ci->s_refs[i]++;
2077   t->num = i;
2078   return t;
2079 }
2080
2081 /* ensure transparent components are at the end */
2082 static void reorder(Component *c[])
2083 {
2084   int i, j, k;
2085   Component *c1[MAX_COMPONENTS];
2086   Component *c2[MAX_COMPONENTS];
2087
2088   j = 0;
2089   for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
2090     c1[i] = NULL;
2091     c2[i] = NULL;
2092   }
2093   for (i = 0 ; i < maxparts ; i++) {
2094     if (c[i] == NULL) continue;
2095     if (c[i]->alpha) { /* transparent parts go to c1 */
2096       c1[j] = c[i];
2097       j++;
2098     } else { /* opaque parts go to c2 */
2099       c2[i] = c[i];
2100     }
2101   }
2102   for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
2103     c[i] = NULL;
2104   }
2105   k = 0;
2106   for (i = 0 ; i < maxparts ; i++) { /* insert opaque part */
2107     if (c2[i] != NULL) {
2108       c[k] = c2[i];
2109       k++;
2110     }
2111   }
2112   for (i = 0 ; i < j ; i++) { /* insert transparent parts */
2113     c[k] = c1[i];
2114     k++;
2115   }
2116 }
2117
2118 ENTRYPOINT void reshape_circuit(ModeInfo *mi, int width, int height)
2119 {
2120  Circuit *ci = &circuit[MI_SCREEN(mi)];
2121  GLfloat h = (GLfloat) height / (GLfloat) width;
2122  glViewport(0,0,(GLint)width, (GLint) height);
2123  glMatrixMode(GL_PROJECTION);
2124  glLoadIdentity();
2125  glFrustum(-1.0,1.0,-h,h,1.5,35.0);
2126  glMatrixMode(GL_MODELVIEW);
2127  ci->win_h = height; 
2128  ci->win_w = width;
2129  ci->YMAX = ci->XMAX * h;
2130 }
2131
2132
2133 ENTRYPOINT void init_circuit(ModeInfo *mi)
2134 {
2135 int screen = MI_SCREEN(mi);
2136 Circuit *ci;
2137
2138  if (circuit == NULL) {
2139    if ((circuit = (Circuit *) calloc(MI_NUM_SCREENS(mi),
2140                                         sizeof(Circuit))) == NULL)
2141           return;
2142  }
2143  ci = &circuit[screen];
2144  ci->window = MI_WINDOW(mi);
2145
2146  ci->XMAX = ci->YMAX = 30;
2147  ci->viewer[2] = 14;
2148  ci->lightpos[0] = 7;
2149  ci->lightpos[1] = 7;
2150  ci->lightpos[2] = 15;
2151  ci->lightpos[3] = 1;
2152
2153  ci->grid_col[1] = 0.25;
2154  ci->grid_col[2] = 0.05;
2155  ci->grid_col2[1] = 0.125;
2156  ci->grid_col2[2] = 0.05;
2157
2158  if (maxparts >= MAX_COMPONENTS)
2159    maxparts = MAX_COMPONENTS-1;
2160
2161  if ((ci->glx_context = init_GL(mi)) != NULL) {
2162       reshape_circuit(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
2163  } else {
2164      MI_CLEARWINDOW(mi);
2165  }
2166  if (uselight == 0)
2167     ci->light = 1;
2168  glClearColor(0.0,0.0,0.0,0.0);
2169  glShadeModel(GL_SMOOTH);
2170  glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
2171  glEnable(GL_DEPTH_TEST);
2172  glEnable(GL_LIGHTING);
2173  glEnable(GL_LIGHT0);
2174  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2175  make_tables(ci);
2176  makebandlist(ci);
2177  
2178 }
2179
2180 ENTRYPOINT void draw_circuit(ModeInfo *mi)
2181 {
2182   Circuit *ci = &circuit[MI_SCREEN(mi)];
2183   Window w = MI_WINDOW(mi);
2184   Display *disp = MI_DISPLAY(mi);
2185
2186   if (!ci->glx_context)
2187       return;
2188
2189  glXMakeCurrent(disp, w, *(ci->glx_context));
2190
2191   display(mi);
2192
2193   if(mi->fps_p) do_fps(mi);
2194   glFinish(); 
2195   glXSwapBuffers(disp, w);
2196 }
2197
2198 ENTRYPOINT void release_circuit(ModeInfo *mi)
2199 {
2200   if (circuit != NULL) {
2201    (void) free((void *) circuit);
2202    circuit = NULL;
2203   }
2204   FreeAllGL(mi);
2205 }
2206
2207 XSCREENSAVER_MODULE ("Circuit", circuit)
2208
2209 #endif