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