da3be7709efc75e882a47dec68a44f35a51b5d9e
[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 nsegs;
427
428   glPushMatrix();
429   nsegs = radius*MAX(ci->win_w, ci->win_h)/20;
430   nsegs = MAX(nsegs, 4);
431   if (nsegs % 2)
432      nsegs += 1;
433   angle = (half) ? (180 - 90/nsegs) : 374;
434   z1 = radius; y1 = 0;
435   glBegin(GL_QUADS);
436   for (a = 0 ; a <= angle ; a+= angle/nsegs) {
437     y2=radius*(float)ci->sin_table[(int)a];
438     z2=radius*(float)ci->cos_table[(int)a];
439       glNormal3f(0, y1, z1);
440       glVertex3f(0,y1,z1);
441       glVertex3f(length,y1,z1);
442       glNormal3f(0, y2, z2);
443       glVertex3f(length,y2,z2);
444       glVertex3f(0,y2,z2);
445       polys++;
446     z1=z2;
447     y1=y2;
448   }
449   glEnd();
450   if (half) {
451     glBegin(GL_POLYGON);
452       glNormal3f(0, 1, 0);
453       glVertex3f(0, 0, radius);
454       glVertex3f(length, 0, radius);
455       glVertex3f(length, 0, 0 - radius);
456       glVertex3f(0, 0, 0 - radius);
457       polys++;
458     glEnd();
459   }
460   if (endcaps) {
461     for(ex = 0 ; ex <= length ; ex += length) {
462       z1 = radius; y1 = 0;
463       norm = (ex == length) ? 1 : -1;
464       glBegin(GL_TRIANGLES);
465       glNormal3f(norm, 0, 0);
466       for (a = 0 ; a <= angle ; a+= angle/nsegs) {
467         y2=radius*(float)ci->sin_table[(int)a];
468         z2=radius*(float)ci->cos_table[(int)a];
469           glVertex3f(ex,0, 0);
470           glVertex3f(ex,y1,z1);
471           glVertex3f(ex,y2,z2);
472           polys++;
473         z1=z2;
474         y1=y2;
475       }
476       glEnd();
477     }
478   }
479   glPopMatrix();
480   return polys;
481 }
482
483 static int circle(Circuit *ci, float radius, int segments, int half)
484 {
485   int polys = 0;
486   float x1 = 0, x2 = 0;
487   float y1 = 0, y2 = 0;
488   int i, t, s;
489
490   if (half) {
491     t = 270; s = 90;
492     x1 = radius, y1 = 0;
493   } else {
494     t = 360, s = 0;
495   }
496   glBegin(GL_TRIANGLES);
497   glNormal3f(1, 0, 0);
498   for(i=s;i<=t;i+=10)
499   {
500     float angle=i;
501     x2=radius*(float)ci->cos_table[(int)angle];
502     y2=radius*(float)ci->sin_table[(int)angle];
503     glVertex3f(0,0,0);
504     glVertex3f(0,y1,x1);
505     glVertex3f(0,y2,x2);
506     polys++;
507     x1=x2;
508     y1=y2;
509   }
510   glEnd();
511   return polys;
512 }
513
514 static int wire(Circuit *ci, float len)
515 {
516   int polys = 0;
517   GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
518   GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
519   GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
520   GLfloat shin = 30;
521   int n;
522
523   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
524   glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
525   glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
526   n = glIsEnabled(GL_NORMALIZE);
527   if (!n) glEnable(GL_NORMALIZE);
528   polys += createCylinder(ci, len, 0.05, 1, 0);
529   if (!n) glDisable(GL_NORMALIZE);
530   glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
531   return polys;
532 }
533
534 #if 0
535 static int ring(GLfloat inner, GLfloat outer, int nsegs)
536 {
537   int polys = 0;
538   GLfloat z1, z2, y1, y2;
539   GLfloat Z1, Z2, Y1, Y2;
540   int i;
541
542   z1 = inner; y1 = 0;
543   Z1 = outer; Y1 = 0;
544   glBegin(GL_QUADS);
545   glNormal3f(1, 0, 0);
546   for(i=0; i <=360 ; i+= 360/nsegs)
547   {
548     float angle=i;
549     z2=inner*(float)ci->sin_table[(int)angle];
550     y2=inner*(float)ci->cos_table[(int)angle];
551     Z2=outer*(float)ci->sin_table[(int)angle];
552     Y2=outer*(float)ci->cos_table[(int)angle];
553     glVertex3f(0, Y1, Z1);
554     glVertex3f(0, y1, z1);
555     glVertex3f(0, y2, z2);
556     glVertex3f(0, Y2, Z2);
557     polys++;
558     z1=z2;
559     y1=y2;
560     Z1=Z2;
561     Y1=Y2;
562   }
563   glEnd();
564   return polys;
565 }
566 #endif
567
568 static int sphere(Circuit *ci, GLfloat r, float stacks, float slices,
569              int startstack, int endstack, int startslice,
570              int endslice)
571 {
572   int polys = 0;
573   GLfloat d, d1, dr, dr1, Dr, Dr1, D, D1, z1, z2, y1, y2, Y1, Z1, Y2, Z2;
574   int a, a1, b, b1, c0, c1;
575   GLfloat step, sstep;
576
577   step = 180/stacks;
578   sstep = 360/slices;
579   a1 = startstack * step;
580   b1 = startslice * sstep;
581   y1 = z1 = Y1 = Z1 = 0;
582   c0 = (endslice / slices) * 360;
583   c1 = (endstack/stacks)*180;
584   glBegin(GL_QUADS);
585   for (a = startstack * step ; a <= c1 ; a+= step) {
586     d=ci->sin_table[a];
587     d1=ci->sin_table[a1];
588     D=ci->cos_table[a];
589     D1=ci->cos_table[a1];
590     dr = d * r;
591     dr1 = d1 * r;
592     Dr = D * r;
593     Dr1 = D1 * r;
594     for (b = b1 ; b <= c0 ; b+= sstep) {
595       y2=dr*ci->sin_table[b];
596       z2=dr*ci->cos_table[b];
597       Y2=dr1*ci->sin_table[b];
598       Z2=dr1*ci->cos_table[b];
599         glNormal3f(Dr, y1, z1);
600         glVertex3f(Dr,y1,z1);
601         glNormal3f(Dr, y2, z2);
602         glVertex3f(Dr,y2,z2);
603         glNormal3f(Dr1, Y2, Z2);
604         glVertex3f(Dr1,Y2,Z2);
605         glNormal3f(Dr1, Y1, Z1);
606         glVertex3f(Dr1,Y1,Z1);
607         polys++;
608       z1=z2;
609       y1=y2;
610       Z1=Z2;
611       Y1=Y2;
612     }
613     a1 = a;
614   }
615   glEnd();
616   return polys;
617 }
618
619 static int DrawComponent(Circuit *ci, Component *c, unsigned long *polysP)
620 {
621   int polys = *polysP;
622   int ret = 0; /* return 1 if component is freed */
623
624    glPushMatrix();
625    glTranslatef(c->x, c->y, c->z);
626      if (c->angle > 0) {
627         glRotatef(c->angle, c->rotx, c->roty, c->rotz);
628      }
629    if (spin) {
630      glRotatef(c->rdeg, c->rotx, c->roty, c->rotz);
631      c->rdeg += c->drot;
632    }
633
634    if (c->norm)
635      glEnable(GL_NORMALIZE);
636    else
637      glDisable(GL_NORMALIZE);
638
639  /* call object draw routine here */
640    if (c->type == 0) {
641      polys += DrawResistor(ci, c->c);
642    } else if (c->type == 1) {
643      polys += DrawDiode(ci, c->c);
644    } else if (c->type == 2) {
645      polys += DrawTransistor(ci, c->c);
646    } else if (c->type == 3) {
647      if (((LED *)c->c)->light && ci->light) {
648        GLfloat lp[] = {0.1, 0, 0, 1};
649        glEnable(GL_LIGHT1);
650        glLightfv(GL_LIGHT1, GL_POSITION, lp);
651      }
652      polys += DrawLED(ci, c->c);
653    } else if (c->type == 4) {
654      polys += DrawCapacitor(ci, c->c);
655    } else if (c->type == 5) {
656      polys += DrawIC(ci, c->c);
657    } else if (c->type == 6) {
658      polys += DrawDisp(ci, c->c);
659    } else if (c->type == 7) {
660      polys += DrawFuse(ci, c->c);
661    } else if (c->type == 8) {
662      polys += DrawRCA(ci, c->c);
663    } else if (c->type == 9) {
664      polys += DrawThreeFive(ci, c->c);
665    } else if (c->type == 10) {
666      polys += DrawSwitch(ci, c->c);
667    }
668    c->x += c->dx * MOVE_MULT;
669    c->y += c->dy * MOVE_MULT;
670    if (c->x > ci->XMAX/2 || c->x < 0 - ci->XMAX/2 ||
671        c->y > ci->YMAX/2 || c->y < 0 - ci->YMAX/2) {
672         if (c->type == 3 && ((LED *)c->c)->light && ci->light) {
673           glDisable(GL_LIGHT1);
674           ci->light = 0; ci->lighton = 0;
675         }
676         if (c->type == 5) {
677           if (((IC *)c->c)->tnum)
678             freetexture(ci, ((IC *)c->c)->tnum);
679         }
680         if (c->type == 2) {
681           if (((Transistor *)c->c)->tnum)
682             freetexture(ci, ((Transistor *)c->c)->tnum);
683         }
684         if (c->type == 1)
685           free(((Diode *)c->c)->band); /* remember to free diode band */
686         free(c->c);
687         ret = 1;
688    }
689
690    glPopMatrix();
691    glDisable(GL_NORMALIZE);
692    *polysP = polys;
693    return ret;
694 }
695
696 /* draw a resistor */
697
698 static int DrawResistor(Circuit *ci, Resistor *r)
699 {
700   int polys = 0;
701   int i;
702   GLfloat col[] = {0.74, 0.62, 0.46, 1.0};
703   GLfloat spec[] = {0.8, 0.8, 0.8, 1.0};
704   GLfloat shine = 30;
705
706    glTranslatef(-4, 0, 0);
707    polys += wire(ci, 3);
708    glTranslatef(3, 0, 0);
709    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
710    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
711    glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
712    polys += createCylinder(ci, 1.8, 0.4, 1, 0);
713    glPushMatrix();
714    for (i = 0 ; i < 4 ; i++) {
715      glTranslatef(0.35, 0, 0);
716      glCallList(ci->band_list[r->b[i]]);
717      polys += ci->band_list_polys[r->b[i]];
718    }
719    glPopMatrix();
720    glTranslatef(1.8, 0, 0);
721    polys += wire(ci, 3);
722    return polys;
723 }
724
725 static int DrawRCA(Circuit *ci, RCA *rca)
726 {
727   int polys = 0;
728   GLfloat col[] = {0.6, 0.6, 0.6, 1.0}; /* metal */
729   GLfloat red[] = {1.0, 0.0, 0.0, 1.0}; /* red */
730   GLfloat white[] = {1.0, 1.0, 1.0, 1.0}; /* white */
731   GLfloat spec[] = {1, 1, 1, 1}; /* glass */
732
733    glPushMatrix();
734    glTranslatef(0.3, 0, 0);
735    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
736    glMateriali(GL_FRONT, GL_SHININESS, 40);
737    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
738    polys += createCylinder(ci, 0.7, 0.45, 0, 0);
739    glTranslatef(0.4, 0, 0);
740    polys += createCylinder(ci, 0.9, 0.15, 1, 0);
741    glTranslatef(-1.9, 0, 0);
742    glMateriali(GL_FRONT, GL_SHININESS, 20);
743    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, rca->col ? white : red);
744    polys += createCylinder(ci, 1.5, 0.6, 1, 0);
745    glTranslatef(-0.9, 0, 0);
746    polys += createCylinder(ci, 0.9, 0.25, 0, 0);
747    glTranslatef(0.1, 0, 0);
748    polys += createCylinder(ci, 0.2, 0.3, 0, 0);
749    glTranslatef(0.3, 0, 0);
750    polys += createCylinder(ci, 0.2, 0.3, 1, 0);
751    glTranslatef(0.3, 0, 0);
752    polys += createCylinder(ci, 0.2, 0.3, 1, 0);
753    glPopMatrix();
754    return polys;
755 }
756
757 static int DrawSwitch(Circuit *ci, Switch *f)
758 {
759   int polys = 0;
760   GLfloat col[] = {0.6, 0.6, 0.6, 0}; /* metal */
761   GLfloat dark[] = {0.1, 0.1, 0.1, 1.0}; /* dark */
762   GLfloat brown[] = {0.69, 0.32, 0, 1.0}; /* brown */
763   GLfloat spec[] = {0.9, 0.9, 0.9, 1}; /* shiny */
764
765    glPushMatrix();
766    glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
767    glMaterialfv(GL_FRONT, GL_AMBIENT, dark);
768    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
769    glMateriali(GL_FRONT, GL_SHININESS, 90);
770    polys += Rect(-0.25, 0, 0, 1.5, 0.5, 0.75);
771 /* polys += Rect(-0.5, 0.5, 0, 2, 0.1, 0.75); */
772    glPushMatrix();
773    glRotatef(90, 1, 0, 0);
774    glTranslatef(-0.5, -0.4, -0.4);
775    polys += HoledRectangle(ci, 0.5, 0.75, 0.1, 0.15, 8);
776    glTranslatef(2, 0, 0);
777    polys += HoledRectangle(ci, 0.5, 0.75, 0.1, 0.15, 8);
778    glPopMatrix();
779    polys += Rect(0.1, -0.4, -0.25, 0.1, 0.4, 0.05);
780    polys += Rect(0.5, -0.4, -0.25, 0.1, 0.4, 0.05);
781    polys += Rect(0.9, -0.4, -0.25, 0.1, 0.4, 0.05);
782    polys += Rect(0.1, -0.4, -0.5, 0.1, 0.4, 0.05);
783    polys += Rect(0.5, -0.4, -0.5, 0.1, 0.4, 0.05);
784    polys += Rect(0.9, -0.4, -0.5, 0.1, 0.4, 0.05);
785    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, dark);
786    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
787    polys += Rect(0, 0.5, -0.1, 1, 0.05, 0.5);
788    polys += Rect(0, 0.6, -0.1, 0.5, 0.6, 0.5);
789    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, brown);
790    polys += Rect(-0.2, -0.01, -0.1, 1.4, 0.1, 0.55);
791    glPopMatrix();
792    return polys;
793 }
794
795
796 static int DrawFuse(Circuit *ci, Fuse *f)
797 {
798   int polys = 0;
799   GLfloat col[] = {0.5, 0.5, 0.5, 1.0}; /* endcaps */
800   GLfloat glass[] = {0.4, 0.4, 0.4, 0.3}; /* glass */
801   GLfloat spec[] = {1, 1, 1, 1}; /* glass */
802
803    glPushMatrix();
804    glTranslatef(-1.8, 0, 0);
805    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
806    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
807    glMateriali(GL_FRONT, GL_SHININESS, 40);
808    polys += createCylinder(ci, 0.8, 0.45, 1, 0);
809    glTranslatef(0.8, 0, 0);
810    glEnable(GL_BLEND);
811    glDepthMask(GL_FALSE);
812    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, glass);
813    glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 40);
814    polys += createCylinder(ci, 2, 0.4, 0, 0);
815    polys += createCylinder(ci, 2, 0.3, 0, 0);
816    glDisable(GL_BLEND);
817    glDepthMask(GL_TRUE);
818    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
819    glMateriali(GL_FRONT, GL_SHININESS, 40);
820    glBegin(GL_LINES);
821    glVertex3f(0, 0, 0);
822    glVertex3f(2, 0. ,0);
823    glEnd();
824    glTranslatef(2, 0, 0);
825    polys += createCylinder(ci, 0.8, 0.45, 1, 0);
826    glPopMatrix();
827    return polys;
828 }
829
830
831 static int DrawCapacitor(Circuit *ci, Capacitor *c)
832 {
833   int polys = 0;
834   GLfloat col[] = {0, 0, 0, 0};
835   GLfloat spec[] = {0.8, 0.8, 0.8, 0};
836   GLfloat brown[] = {0.84, 0.5, 0};
837   GLfloat shine = 40;
838
839   glPushMatrix();
840   if (c->type) {
841     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, brown);
842     polys += sphere(ci, c->width, 15, 15, 0, 4 ,0, 15);
843     glTranslatef(1.35*c->width, 0, 0);
844     polys += sphere(ci, c->width, 15, 15, 11, 15, 0, 15);
845     glRotatef(90, 0, 0, 1);
846     glTranslatef(0, 0.7*c->width, 0.3*c->width);
847     polys += wire(ci, 3*c->width);
848     glTranslatef(0, 0, -0.6*c->width);
849     polys += wire(ci, 3*c->width);
850   } else {
851     glTranslatef(0-c->length*2, 0, 0);
852     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
853     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
854     glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
855     glBegin(GL_POLYGON);
856      glVertex3f(0, 0.82*c->width, -0.1);
857      glVertex3f(3*c->length, 0.82*c->width, -0.1);
858      glVertex3f(3*c->length, 0.82*c->width, 0.1);
859      glVertex3f(0, 0.82*c->width, 0.1);
860     glEnd();
861     col[0] = 0.0;
862     col[1] = 0.2;
863     col[2] = 0.9;
864     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
865     glEnable(GL_POLYGON_OFFSET_FILL);
866     glPolygonOffset(1.0, 1.0);
867     polys += createCylinder(ci, 3.0*c->length, 0.8*c->width, 1, 0);
868     glDisable(GL_POLYGON_OFFSET_FILL);
869     col[0] = 0.7;
870     col[1] = 0.7;
871     col[2] = 0.7;
872     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
873     polys += circle(ci, 0.6*c->width, 30, 0);
874     col[0] = 0;
875     col[1] = 0;
876     col[2] = 0;
877     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
878     glTranslatef(3.0*c->length, 0.0, 0);
879     polys += circle(ci, 0.6*c->width, 30, 0);
880     glTranslatef(0, 0.4*c->width, 0);
881     polys += wire(ci, 3*c->length);
882     glTranslatef(0.0, -0.8*c->width, 0);
883     polys += wire(ci, 3.3*c->length);
884   }
885   glPopMatrix();
886   return polys;
887 }
888
889 static int DrawLED(Circuit *ci, LED *l)
890 {
891   int polys = 0;
892   GLfloat col[] = {0, 0, 0, 0.6};
893   GLfloat black[] = {0, 0, 0, 0.6};
894
895   col[0] = l->r; col[1] = l->g; col[2] = l->b;
896   if (l->light && ci->light) {
897     GLfloat dir[] = {-1, 0, 0};
898     glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, dir);
899     if (!ci->lighton) {
900       glLightfv(GL_LIGHT1, GL_SPECULAR, col);
901       glLightfv(GL_LIGHT1, GL_AMBIENT, black);
902       col[0] /= 1.5; col[1] /= 1.5; col[2] /= 1.5;
903       glLightfv(GL_LIGHT1, GL_DIFFUSE, col);
904       glLighti(GL_LIGHT1, GL_SPOT_CUTOFF, (GLint) 90);
905       glLighti(GL_LIGHT1, GL_CONSTANT_ATTENUATION, (GLfloat)1); 
906       glLighti(GL_LIGHT1, GL_LINEAR_ATTENUATION, (GLfloat)0); 
907       glLighti(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, (GLfloat)0); 
908       glLighti(GL_LIGHT1, GL_SPOT_EXPONENT, (GLint) 20);
909       ci->lighton = 1;
910     }
911   }
912   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
913   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
914   /* no transparency when LED is lit */
915   if (!l->light) { 
916     glEnable(GL_BLEND);
917     glDepthMask(GL_FALSE);
918     glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
919   }
920   glTranslatef(-0.9, 0, 0);
921   polys += createCylinder(ci, 1.2, 0.3, 0, 0);
922   if (l->light && ci->light) {
923     glDisable(GL_LIGHTING);
924     glColor3fv(col);
925   }
926   polys += sphere(ci, 0.3, 7, 7, 3, 7, 0, 7);
927   if (l->light && ci->light) {
928     glEnable(GL_LIGHTING);
929   } else {
930     glDepthMask(GL_TRUE);
931     glDisable(GL_BLEND);
932   }
933
934   glTranslatef(1.2, 0, 0);
935   polys += createCylinder(ci, 0.1, 0.38, 1, 0);
936   glTranslatef(-0.3, 0.15, 0);
937   polys += wire(ci, 3);
938   glTranslatef(0, -0.3, 0);
939   polys += wire(ci, 3.3);
940   if (random() % 50 == 25) {
941     if (l->light) {
942       l->light = 0; ci->light = 0; ci->lighton = 0;
943       glDisable(GL_LIGHT1);
944     } else if (!ci->light) {
945       l->light = 1; 
946       ci->light = 1;
947     }
948   }
949   return polys;
950 }
951
952
953 static int DrawThreeFive(Circuit *ci, ThreeFive *d)
954 {
955   int polys = 0;
956   GLfloat shine = 40;
957   GLfloat const dark[] = {0.3, 0.3, 0.3, 0};
958   GLfloat const light[] = {0.6, 0.6, 0.6, 0};
959   GLfloat const cream[] = {0.8, 0.8, 0.6, 0};
960   GLfloat const spec[] = {0.7, 0.7, 0.7, 0};
961
962    glPushMatrix();
963    glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
964    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cream);
965    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
966    
967    glTranslatef(-2.0, 0, 0);
968    polys += createCylinder(ci, 0.7, 0.2, 0, 0);
969    glTranslatef(0.7, 0, 0);
970    polys += createCylinder(ci, 1.3, 0.4, 1, 0);
971    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light);
972    glTranslatef(1.3, 0, 0);
973    polys += createCylinder(ci, 1.3, 0.2, 0, 0);
974    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, dark);
975    glTranslatef(0.65, 0, 0);
976    polys += createCylinder(ci, 0.15, 0.21, 0, 0);
977    glTranslatef(0.3, 0, 0);
978    polys += createCylinder(ci, 0.15, 0.21, 0, 0);
979    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light);
980    glTranslatef(0.4, 0, 0);
981    polys += sphere(ci, 0.23, 7, 7, 0, 5, 0, 7);
982
983    glPopMatrix();
984    return polys;
985 }
986
987 static int DrawDiode(Circuit *ci, Diode *d)
988 {
989   int polys = 0;
990   GLfloat shine = 40;
991   GLfloat col[] = {0.3, 0.3, 0.3, 0};
992   GLfloat spec[] = {0.7, 0.7, 0.7, 0};
993
994    glPushMatrix();
995    glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
996    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
997    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
998    glTranslatef(-4, 0, 0);
999    polys += wire(ci, 3);
1000    glTranslatef(3, 0, 0);
1001    polys += bandedCylinder(ci, 0.3, 1.5, d->r, d->g, d->b, &(d->band), 1);
1002    glTranslatef(1.5, 0, 0);
1003    polys += wire(ci, 3);
1004    glPopMatrix();
1005    return polys;
1006 }
1007
1008 static int Rect(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h,
1009             GLfloat t)
1010 {
1011   int polys = 0;
1012   GLfloat yh;
1013   GLfloat xw;
1014   GLfloat zt;
1015
1016   yh = y+h; xw = x+w; zt = z - t;
1017
1018   glBegin(GL_QUADS); /* front */
1019     glNormal3f(0, 0, 1);
1020     glVertex3f(x, y, z);
1021     glVertex3f(x, yh, z);
1022     glVertex3f(xw, yh, z);
1023     glVertex3f(xw, y, z);
1024     polys++;
1025   /* back */
1026     glNormal3f(0, 0, -1);
1027     glVertex3f(x, y, zt);
1028     glVertex3f(x, yh, zt);
1029     glVertex3f(xw, yh, zt);
1030     glVertex3f(xw, y, zt);
1031     polys++;
1032   /* top */
1033     glNormal3f(0, 1, 0);
1034     glVertex3f(x, yh, z);
1035     glVertex3f(x, yh, zt);
1036     glVertex3f(xw, yh, zt);
1037     glVertex3f(xw, yh, z);
1038     polys++;
1039   /* bottom */
1040     glNormal3f(0, -1, 0);
1041     glVertex3f(x, y, z);
1042     glVertex3f(x, y, zt);
1043     glVertex3f(xw, y, zt);
1044     glVertex3f(xw, y, z);
1045     polys++;
1046   /* left */
1047     glNormal3f(-1, 0, 0);
1048     glVertex3f(x, y, z);
1049     glVertex3f(x, y, zt);
1050     glVertex3f(x, yh, zt);
1051     glVertex3f(x, yh, z);
1052     polys++;
1053   /* right */
1054     glNormal3f(1, 0, 0);
1055     glVertex3f(xw, y, z);
1056     glVertex3f(xw, y, zt);
1057     glVertex3f(xw, yh, zt);
1058     glVertex3f(xw, yh, z);
1059     polys++;
1060   glEnd();
1061   return polys;
1062 }
1063
1064 /* IC pins */
1065
1066 static int ICLeg(GLfloat x, GLfloat y, GLfloat z, int dir)
1067 {
1068   int polys = 0;
1069   if (dir) {
1070     polys += Rect(x-0.1, y, z, 0.1, 0.1, 0.02);
1071     polys += Rect(x-0.1, y, z, 0.02, 0.1, 0.1);
1072     polys += Rect(x-0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
1073   } else {
1074     polys += Rect(x, y, z, 0.1, 0.1, 0.02);
1075     polys += Rect(x+0.8*0.1, y, z, 0.02, 0.1, 0.1);
1076     polys += Rect(x+0.8*0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
1077   }
1078   return polys;
1079 }
1080
1081
1082 static int DrawIC(Circuit *ci, IC *c)
1083 {
1084   int polys = 0;
1085   GLfloat w, h, d;
1086   int z;
1087   GLfloat col[] = {0.1, 0.1, 0.1, 0};
1088   GLfloat col2[] = {0.2, 0.2, 0.2, 0};
1089   GLfloat spec[] = {0.6, 0.6, 0.6, 0};
1090   GLfloat shine = 40;
1091   GLfloat lspec[] = {0.6, 0.6, 0.6, 0};
1092   GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
1093   GLfloat lshine = 40;
1094   float mult, th, size;
1095
1096   glPushMatrix();
1097   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1098   glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1099   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1100   glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
1101   switch(c->pins) {
1102     case 8:
1103       w = 1.0; h = 1.5;
1104       break;
1105     case 14:
1106       w = 1.0; h = 3;
1107       break;
1108     case 16:
1109       w = 1.0; h = 3;
1110       break;
1111     case 24:
1112     default:
1113       w = 1.5; h = 3.5;
1114       break;
1115   }
1116   w = w/2; h = h/2;
1117     glEnable(GL_POLYGON_OFFSET_FILL);
1118     glPolygonOffset(1.0, 1.0);
1119     glBegin(GL_QUADS);
1120       glNormal3f(0, 0, 1);
1121       glVertex3f(w, h, 0.1);
1122       glVertex3f(w, -h, 0.1);
1123       glVertex3f(-w, -h, 0.1);
1124       glVertex3f(-w, h, 0.1);
1125       polys++;
1126       glNormal3f(0, 0, -1);
1127       glVertex3f(w, h, -0.1);
1128       glVertex3f(w, -h, -0.1);
1129       glVertex3f(-w, -h, -0.1);
1130       glVertex3f(-w, h, -0.1);
1131       polys++;
1132       glNormal3f(1, 0, 0);
1133       glVertex3f(w, h, -0.1);
1134       glVertex3f(w, -h, -0.1);
1135       glVertex3f(w, -h, 0.1);
1136       glVertex3f(w, h, 0.1);
1137       polys++;
1138       glNormal3f(0, -1, 0);
1139       glVertex3f(w, -h, -0.1);
1140       glVertex3f(w, -h, 0.1);
1141       glVertex3f(-w, -h, 0.1);
1142       glVertex3f(-w, -h, -0.1);
1143       polys++;
1144       glNormal3f(-1, 0, 0);
1145       glVertex3f(-w, h, -0.1);
1146       glVertex3f(-w, h, 0.1);
1147       glVertex3f(-w, -h, 0.1);
1148       glVertex3f(-w, -h, -0.1);
1149       polys++;
1150       glNormal3f(0, -1, 0);
1151       glVertex3f(-w, h, -0.1);
1152       glVertex3f(w, h, -0.1);
1153       glVertex3f(w, h, 0.1);
1154       glVertex3f(-w, h, 0.1);
1155       polys++;
1156     glEnd();
1157     glDisable(GL_POLYGON_OFFSET_FILL);
1158     if (c->tnum) glBindTexture(GL_TEXTURE_2D, c->tnum);
1159     glEnable(GL_TEXTURE_2D);
1160     glEnable(GL_BLEND);
1161     if (c->pins == 8)
1162       size = 0.4;
1163     else
1164       size = 0.6;
1165     th = size*2/3;
1166     mult = size*c->tw / c->th;
1167     mult /= 2;
1168     glBegin(GL_QUADS); /* text markings */
1169      glNormal3f(0, 0, 1);
1170      glTexCoord2f(0, 1);
1171      glVertex3f(th, mult, 0.1);
1172      glTexCoord2f(1, 1);
1173      glVertex3f(th, -mult, 0.1);
1174      glTexCoord2f(1, 0);
1175      glVertex3f(-th, -mult, 0.1);
1176      glTexCoord2f(0, 0);
1177      glVertex3f(-th, mult, 0.1);
1178       polys++;
1179     glEnd();
1180     glDisable(GL_TEXTURE_2D);
1181     glDisable(GL_BLEND);
1182     d = (h*2-0.1) / c->pins;
1183     d*=2;
1184     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
1185     glMaterialfv(GL_FRONT, GL_SPECULAR, lspec);
1186     glMaterialfv(GL_FRONT, GL_SHININESS, &lshine);
1187     for (z = 0 ; z < c->pins/2 ; z++) {
1188       polys += ICLeg(w, -h + z*d + d/2, 0, 0);
1189     }
1190     for (z = 0 ; z < c->pins/2 ; z++) {
1191       polys += ICLeg(-w, -h + z*d + d/2, 0, 1);
1192     }
1193     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col2);
1194     glTranslatef(-w+0.3, h-0.3, 0.1);
1195     glRotatef(90, 0, 1, 0);
1196     polys += circle(ci, 0.1, 7, 0);
1197     glPopMatrix();
1198     return polys;
1199 }
1200
1201 static int DrawDisp(Circuit *ci, Disp *d)
1202 {
1203   int polys = 0;
1204   GLfloat col[] = {0.8, 0.8, 0.8, 1.0}; /* body colour */
1205   GLfloat front[] = {0.2, 0.2, 0.2, 1.0}; /* front colour */
1206   GLfloat on[] = {0.9, 0, 0, 1}; /* 'on' segment */
1207   GLfloat off[] = {0.3, 0, 0, 1}; /* 'off' segment */
1208   int i, j, k;
1209   GLfloat x, y; /* for the pins */
1210   GLfloat spec[] = {0.6, 0.6, 0.6, 0};
1211   GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
1212   GLfloat shine = 40;
1213   static const GLfloat vdata_h[6][2] = {
1214     {0, 0},
1215     {0.1, 0.1},
1216     {0.9, 0.1},
1217     {1, 0},
1218     {0.9, -0.1},
1219     {0.1, -0.1}
1220   };
1221   static const GLfloat vdata_v[6][2] = {
1222     {0.27, 0},
1223     {0.35, -0.1},
1224     {0.2, -0.9},
1225     {0.1, -1},
1226     {0, -0.9},
1227     {0.15, -0.15}
1228   };
1229
1230   static const GLfloat seg_start[7][2] = {
1231     {0.55, 2.26},
1232     {1.35, 2.26},
1233     {1.2, 1.27},
1234     {0.25, 0.25},
1235     {0.06, 1.25},
1236     {0.25, 2.25},
1237     {0.39, 1.24}
1238   };
1239
1240   static const int nums[10][7] = {
1241     {1, 1, 1, 1, 1, 1, 0}, /* 0 */
1242     {0, 1, 1, 0, 0, 0, 0}, /* 1 */
1243     {1, 1, 0, 1, 1, 0, 1}, /* 2 */
1244     {1, 1, 1, 1, 0, 0, 1}, /* 3 */
1245     {0, 1, 1, 0, 0, 1, 1}, /* 4 */
1246     {1, 0, 1, 1, 0, 1, 1}, /* 5 */
1247     {1, 0, 1, 1, 1, 1, 1}, /* 6 */
1248     {1, 1, 1, 0, 0, 0, 0}, /* 7 */
1249     {1, 1, 1, 1, 1, 1, 1}, /* 8 */
1250     {1, 1, 1, 0, 0, 1, 1}  /* 9 */
1251   };
1252
1253    glTranslatef(-0.9, -1.8, 0);
1254    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1255    polys += Rect(0, 0, -0.01, 1.8, 2.6, 0.7);
1256    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, front);
1257    glBegin(GL_QUADS);
1258      glVertex2f(-0.05, -0.05);
1259      glVertex2f(-0.05, 2.65);
1260      glVertex2f(1.85, 2.65);
1261      glVertex2f(1.85, -0.05);
1262      polys++;
1263    glEnd();
1264    glDisable(GL_LIGHTING); /* lit segments dont need light */
1265    if (!seven && (random() % 30) == 19) { /* randomly change value */
1266      d->value = random() % 10;
1267    }
1268    for (j = 0 ; j < 7 ; j++) { /* draw the segments */
1269      GLfloat xx[6], yy[6];
1270      if (nums[d->value][j])
1271        glColor3fv(on);
1272      else
1273        glColor3fv(off);
1274      for (k = 0 ; k < 6 ; k++) {
1275        if (j == 0 || j == 3 || j == 6) {
1276          xx[k] = seg_start[j][0] + vdata_h[k][0];
1277          yy[k] = seg_start[j][1] + vdata_h[k][1];
1278        } else {
1279          xx[k] = seg_start[j][0] + vdata_v[k][0];
1280          yy[k] = seg_start[j][1] + vdata_v[k][1];
1281        }
1282      }
1283      glBegin(GL_POLYGON);
1284      for(i = 0 ; i < 6 ; i++) {
1285        glVertex3f(xx[i], yy[i], 0.01);
1286      }
1287      polys++;
1288      glEnd();
1289    }
1290    glColor3fv(on);
1291    glPointSize(4);
1292    glBegin(GL_POINTS);
1293     glVertex3f(1.5, 0.2, 0.01);
1294     polys++;
1295    glEnd();
1296    glEnable(GL_LIGHTING);
1297    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
1298    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1299    glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
1300    for (x = 0.35 ; x <= 1.5 ; x+= 1.15) {
1301      for ( y = 0.2 ; y <= 2.4 ; y += 0.3) {
1302        polys += ICLeg(x, y, -0.7, 1);
1303      }
1304    }
1305    return polys;
1306 }
1307
1308 static int HoledRectangle(Circuit *ci, 
1309                            GLfloat w, GLfloat h, GLfloat d, GLfloat radius,
1310                            int p)
1311 {
1312   int polys = 0;
1313   int step, a;
1314   GLfloat x1, y1, x2, y2;
1315   GLfloat yr, yr1, xr, xr1, side, side1;
1316   GLfloat nx, ny;
1317
1318   step = 360 / p;
1319   x1 = radius; y1 = 0;
1320   xr1 = w/2; yr1 = 0;
1321   side = w/2;
1322   side1 = h/2;
1323   glBegin(GL_QUADS);
1324   for (a = 0 ; a <= 360 ; a+= step) {
1325     y2=radius*(float)ci->sin_table[(int)a];
1326     x2=radius*(float)ci->cos_table[(int)a];
1327
1328     if (a < 45 || a > 315) {
1329       xr = side;
1330       yr = side1 * ci->tan_table[a];
1331       nx = 1; ny = 0;
1332     } else if (a <= 135 || a >= 225) {
1333       xr = side/ci->tan_table[a];
1334       if (a >= 225) {
1335        yr = -side1;
1336        xr = 0 - xr;
1337        nx = 0; ny = -1;
1338       } else {
1339        yr = side1;
1340        nx = 0; ny = 1;
1341      }
1342     } else {
1343       xr = -side;
1344       yr = -side1 * ci->tan_table[a];
1345       nx = -1; ny = 0;
1346     }
1347
1348       glNormal3f(-x1, -y1, 0); /* cylinder */
1349       glVertex3f(x1,y1,0);
1350       glVertex3f(x1,y1,-d);
1351       glVertex3f(x2,y2,-d);
1352       glVertex3f(x2,y2,0);
1353       polys++;
1354
1355       glNormal3f(0, 0, 1); /* front face */
1356       glVertex3f(x1,y1,0);
1357       glVertex3f(xr1, yr1, 0);
1358       glVertex3f(xr, yr, 0);
1359       glVertex3f(x2, y2, 0);
1360       polys++;
1361
1362       glNormal3f(nx, ny, 0); /* side */
1363       glVertex3f(xr, yr, 0);
1364       glVertex3f(xr, yr, -d);
1365       glVertex3f(xr1, yr1, -d);
1366       glVertex3f(xr1, yr1, 0);
1367       polys++;
1368
1369       glNormal3f(0, 0, -1); /* back */
1370       glVertex3f(xr, yr, -d);
1371       glVertex3f(x2, y2, -d);
1372       glVertex3f(x1, y1, -d);
1373       glVertex3f(xr1, yr1, -d);
1374       polys++;
1375
1376     x1=x2;
1377     y1=y2;
1378     xr1 = xr; yr1 = yr;
1379   }
1380   glEnd();
1381   return polys;
1382 }
1383
1384 static int DrawTransistor(Circuit *ci, Transistor *t)
1385 {
1386   int polys = 0;
1387   GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
1388   GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
1389   GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
1390   GLfloat shin = 30;
1391
1392   glPushMatrix();
1393   glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1394   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col);
1395   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1396   if (t->type == 1) { /* TO-92 style */
1397     float mult, y1, y2;
1398     mult = 1.5*t->th/t->tw;
1399     y1 = 0.2+mult/2;
1400     y2 = 0.8-mult/2;
1401     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1402     glRotatef(90, 0, 1, 0);
1403     glRotatef(90, 0, 0, 1);
1404     polys += createCylinder(ci, 1.0, 0.4, 1, 1);
1405     polys += Rect(0, -0.2, 0.4, 1, 0.2, 0.8);
1406 /* Draw the markings */
1407     glEnable(GL_TEXTURE_2D);
1408     if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
1409     glEnable(GL_BLEND);
1410     glDepthMask(GL_FALSE);
1411     glBegin (GL_QUADS);
1412      glNormal3f(0, 0, 1);
1413      glTexCoord2f(0, 1);
1414      glVertex3f(y1, -0.21, 0.3);
1415      glTexCoord2f(1, 1);
1416      glVertex3f(y1, -0.21, -0.3);
1417      glTexCoord2f(1, 0);
1418      glVertex3f(y2, -0.21, -0.3);
1419      glTexCoord2f(0, 0);
1420      glVertex3f(y2, -0.21, 0.3);
1421      polys++;
1422     glEnd();
1423     glDisable(GL_TEXTURE_2D);
1424     glDisable(GL_BLEND);
1425     glDepthMask(GL_TRUE);
1426     glTranslatef(-2, 0, -0.2);
1427     polys += wire(ci, 2);
1428     glTranslatef(0, 0, 0.2);
1429     polys += wire(ci, 2);
1430     glTranslatef(0, 0, 0.2);
1431     polys += wire(ci, 2);
1432   } else if (t->type == 0) { /* TO-220 Style */
1433     float mult, y1, y2;
1434     mult = 1.5*t->th/t->tw;
1435     y1 = 0.75+mult/2;
1436     y2 = 0.75-mult/2;
1437     polys += Rect(0, 0, 0, 1.5, 1.5, 0.5);
1438     glEnable(GL_TEXTURE_2D);
1439     if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
1440     glEnable(GL_BLEND);
1441     glDepthMask(GL_FALSE);
1442     glBegin (GL_QUADS);
1443      glNormal3f(0, 0, 1);
1444      glTexCoord2f(0, 1);
1445      glVertex3f(0, y1, 0.01);
1446      glTexCoord2f(1, 1);
1447      glVertex3f(1.5, y1, 0.01);
1448      glTexCoord2f(1, 0);
1449      glVertex3f(1.5, y2, 0.01);
1450      glTexCoord2f(0, 0);
1451      glVertex3f(0, y2, 0.01);
1452     glEnd();
1453     glDisable(GL_TEXTURE_2D);
1454     glDisable(GL_BLEND);
1455     glDepthMask(GL_TRUE);
1456     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1457     glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1458     glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1459     polys += Rect(0, 0, -0.5, 1.5, 1.5, 0.30);
1460     if (!glIsEnabled(GL_NORMALIZE)) glEnable(GL_NORMALIZE);
1461     glTranslatef(0.75, 1.875, -0.55);
1462     polys += HoledRectangle(ci, 1.5, 0.75, 0.25, 0.2, 8);
1463     glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
1464     glTranslatef(-0.375, -1.875, 0);
1465     glRotatef(90, 0, 0, -1);
1466     polys += wire(ci, 2);
1467     glTranslatef(0, 0.375, 0);
1468     polys += wire(ci, 2);
1469     glTranslatef(0, 0.375, 0);
1470     polys += wire(ci, 2);
1471   } else {              /* SMC transistor */
1472 /* Draw the body */
1473     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1474     glTranslatef(-0.5, -0.25, 0.1);
1475     polys += Rect(0, 0, 0, 1, 0.5, 0.2);
1476 /* Draw the markings */
1477     glEnable(GL_TEXTURE_2D);
1478     if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
1479     glEnable(GL_BLEND);
1480     glDepthMask(GL_FALSE);
1481     glBegin (GL_QUADS);
1482      glNormal3f(0, 0, 1);
1483      glTexCoord2f(0, 1);
1484      glVertex3f(0.2, 0, 0.01);
1485      glTexCoord2f(1, 1);
1486      glVertex3f(0.8, 0, 0.01);
1487      glTexCoord2f(1, 0);
1488      glVertex3f(0.8, 0.5, 0.01);
1489      glTexCoord2f(0, 0);
1490      glVertex3f(0.2, 0.5, 0.01);
1491      polys++;
1492     glEnd();
1493     glDisable(GL_TEXTURE_2D);
1494     glDisable(GL_BLEND);
1495     glDepthMask(GL_TRUE);
1496 /* Now draw the legs */
1497     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1498     glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1499     glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1500     polys += Rect(0.25, -0.1, -0.05, 0.1, 0.1, 0.2);
1501     polys += Rect(0.75, -0.1, -0.05, 0.1, 0.1, 0.2);
1502     polys += Rect(0.5, 0.5, -0.05, 0.1, 0.1, 0.2);
1503     polys += Rect(0.25, -0.2, -0.2, 0.1, 0.15, 0.1);
1504     polys += Rect(0.75, -0.2, -0.2, 0.1, 0.15, 0.1);
1505     polys += Rect(0.5, 0.5, -0.2, 0.1, 0.15, 0.1);
1506   }
1507   glPopMatrix();
1508   return polys;
1509 }
1510
1511 static Component * NewComponent(ModeInfo *mi)
1512 {
1513   Circuit *ci = &circuit[MI_SCREEN(mi)];
1514   Component *c;
1515   float rnd;
1516
1517   c = malloc(sizeof(Component));
1518   c->angle = RAND_RANGE(0,360);
1519   rnd = f_rand();
1520   if (rnd < 0.25) { /* come from the top */
1521      c->y = ci->YMAX/2;
1522      c->x = RAND_RANGE(0, ci->XMAX) - ci->XMAX/2;
1523      if (c->x > 0)
1524        c->dx = 0 - RAND_RANGE(0.5, 2);
1525      else 
1526        c->dx = RAND_RANGE(0.5, 2);
1527      c->dy = 0 - RAND_RANGE(0.5, 2);
1528   } else if (rnd < 0.5) { /* come from the bottom */
1529      c->y = 0 - ci->YMAX/2;
1530      c->x = RAND_RANGE(0, ci->XMAX) - ci->XMAX/2;
1531      if (c->x > 0)
1532        c->dx = 0 - RAND_RANGE(0.5, 2);
1533      else 
1534        c->dx = RAND_RANGE(0.5, 2);
1535      c->dy = RAND_RANGE(0.5, 2);
1536   } else if (rnd < 0.75) { /* come from the left */
1537      c->x = 0 - ci->XMAX/2;
1538      c->y = RAND_RANGE(0, ci->YMAX) - ci->YMAX/2;
1539      c->dx = RAND_RANGE(0.5, 2);
1540      if (c->y > 0)
1541        c->dy = 0 - RAND_RANGE(0.5, 2);
1542      else 
1543        c->dy = RAND_RANGE(0.5, 2);
1544   } else { /* come from the right */
1545      c->x = ci->XMAX/2;
1546      c->y = RAND_RANGE(0, ci->YMAX) - ci->YMAX/2;
1547      c->dx =  0 - RAND_RANGE(0.5, 2);
1548      if (c->y > 0)
1549        c->dy = 0 - RAND_RANGE(0.5, 2);
1550      else 
1551        c->dy = RAND_RANGE(0.5, 2);
1552   }
1553   c->z = RAND_RANGE(0, 7) - 9;
1554   c->rotx = f_rand();
1555   c->roty = f_rand();
1556   c->rotz = f_rand();
1557   c->drot = f_rand() * 3;
1558   c->rdeg = 0;
1559   c->dz = f_rand()*2 - 1;
1560   c->norm = 0;
1561   c->alpha = 0; /* explicitly set to 1 later */
1562   rnd = random() % 11;
1563   if (rnd < 1) {
1564     c->c = NewResistor();
1565     c->type = 0;
1566     if (f_rand() < 0.4)
1567       c->norm = 1; /* some resistors shine */
1568   } else if (rnd < 2) {
1569     c->c = NewDiode();
1570     if (f_rand() < 0.4)
1571       c->norm = 1; /* some diodes shine */
1572     c->type = 1;
1573   } else if (rnd < 3) {
1574     c->c = NewTransistor(mi);
1575     c->norm = 1;
1576     c->type = 2;
1577   } else if (rnd < 4) {
1578     c->c = NewCapacitor(ci);
1579     c->norm = 1;
1580     c->type = 4;
1581   } else if (rnd < 5) {
1582     c->c = NewIC(mi);
1583     c->type = 5;
1584     c->norm = 1;
1585   } else if (rnd < 6) {
1586     c->c = NewLED(ci);
1587     c->type = 3;
1588     c->norm = 1;
1589     c->alpha = 1;
1590   } else if (rnd < 7) {
1591     c->c = NewFuse(ci);
1592     c->norm = 1;
1593     c->type = 7;
1594     c->alpha = 1;
1595   } else if (rnd < 8) {
1596     c->c = NewRCA(ci);
1597     c->norm = 1;
1598     c->type = 8;
1599   } else if (rnd < 9) {
1600     c->c = NewThreeFive(ci);
1601     c->norm = 1;
1602     c->type = 9;
1603   } else if (rnd < 10) {
1604     c->c = NewSwitch(ci);
1605     c->norm = 1;
1606     c->type = 10;
1607   } else {
1608     c->c = NewDisp(ci);
1609     c->type = 6;
1610   }
1611   return c;
1612 }
1613
1614 static Transistor *NewTransistor(ModeInfo *mi)
1615 {
1616   Transistor *t;
1617   float texfg[] = {0.7, 0.7, 0.7, 1.0};
1618   float texbg[] = {0.3, 0.3, 0.3, 0.1};
1619   TexNum *tn;
1620   const char *val;
1621
1622   t = malloc(sizeof(Transistor));
1623   t->type = (random() % 3);
1624   if (t->type == 0) {
1625     val = transistortypes[random() % countof(transistortypes)];
1626     tn = fonttexturealloc(mi, val, texfg, texbg);
1627     if (tn == NULL) {
1628       fprintf(stderr, "Error getting a texture for a string!\n");
1629       t->tnum = 0;
1630     } else {
1631       t->tnum = tn->num;
1632       t->tw = tn->w; t->th = tn->h;
1633       free(tn);
1634     }
1635   } else if (t->type == 2) {
1636     val = smctypes[random() % countof(smctypes)];
1637     tn = fonttexturealloc(mi, val, texfg, texbg);
1638     if (tn == NULL) {
1639       fprintf(stderr, "Error getting a texture for a string!\n");
1640       t->tnum = 0;
1641     } else {
1642       t->tnum = tn->num;
1643       t->tw = tn->w; t->th = tn->h;
1644       free(tn);
1645     }
1646   } else if (t->type == 1) {
1647     val = to92types[random() % countof(to92types)];
1648     tn = fonttexturealloc(mi, val, texfg, texbg);
1649     if (tn == NULL) {
1650       fprintf(stderr, "Error getting a texture for a string!\n");
1651       t->tnum = 0;
1652     } else {
1653       t->tnum = tn->num;
1654       t->tw = tn->w; t->th = tn->h;
1655       free(tn);
1656     }
1657   }
1658
1659   return t;
1660 }
1661
1662 static Capacitor *NewCapacitor(Circuit *ci)
1663 {
1664   Capacitor *c;
1665
1666   c = malloc(sizeof(Capacitor));
1667   c->type = (f_rand() < 0.5);
1668   if (!c->type) {
1669     c->length = RAND_RANGE(0.5, 1);
1670     c->width = RAND_RANGE(0.5, 1);
1671   } else {
1672     c->width = RAND_RANGE(0.3, 1);
1673   }
1674   return c;
1675 }
1676
1677 /* 7 segment display */
1678
1679 static Disp *NewDisp(Circuit *ci)
1680 {
1681   Disp *d;
1682
1683   d = malloc(sizeof(Disp));
1684   if (seven)
1685     d->value = 7;
1686   else
1687     d->value = RAND_RANGE(0, 10);
1688   return d;
1689 }
1690
1691
1692 static IC *NewIC(ModeInfo *mi)
1693 {
1694   IC *c;
1695   int pins;
1696   TexNum *tn;
1697   float texfg[] = {0.7, 0.7, 0.7, 1.0};
1698   float texbg[] = {0.1, 0.1, 0.1, 0};
1699   const char *val;
1700   char *str;
1701   int types[countof(ictypes)], i, n = 0;
1702
1703   c = malloc(sizeof(IC));
1704   c->type = 0;
1705   switch((int)RAND_RANGE(0,4)) {
1706     case 0:
1707       pins = 8;
1708       break;
1709     case 1:
1710       pins = 14;
1711       break;
1712     case 2:
1713       pins = 16;
1714       break;
1715     case 3:
1716     default:
1717       pins = 24;
1718       break;
1719   }
1720   for (i = 0 ; i < countof(ictypes) ; i++) {
1721     if (ictypes[i].pins == pins) {
1722        types[n] = i;
1723        n++;
1724     }
1725   }
1726
1727   if (n > countof(types)) abort();
1728   val = ictypes[types[random() % n]].val;
1729   str = malloc(strlen(val) + 1 + 4 + 1); /* add space for production date */
1730   sprintf(str, "%s\n%02d%02d", val, (int)RAND_RANGE(80, 100), (int)RAND_RANGE(1,53));
1731   tn = fonttexturealloc(mi, str, texfg, texbg);
1732   free(str);
1733   if (tn == NULL) {
1734     fprintf(stderr, "Error allocating font texture for '%s'\n", val);
1735     c->tnum = 0;
1736   } else {
1737     c->tw = tn->w; c->th = tn->h;
1738     c->tnum = tn->num;
1739     free(tn);
1740   }
1741   c->pins = pins;
1742   return c;
1743 }
1744
1745 static LED *NewLED(Circuit *ci)
1746 {
1747   LED *l;
1748   float r;
1749
1750   l = malloc(sizeof(LED));
1751   r = f_rand();
1752   l->light = 0;
1753   if (!ci->light && (f_rand() < 0.4)) {
1754      ci->light = 1;
1755      l->light = 1;
1756   }
1757   if (r < 0.2) {
1758     l->r = 0.9; l->g = 0; l->b = 0;
1759   } else if (r < 0.4) {
1760     l->r = 0.3; l->g = 0.9; l->b = 0;
1761   } else if (r < 0.6) {
1762     l->r = 0.8; l->g = 0.9; l->b = 0;
1763   } else if (r < 0.8) {
1764     l->r = 0.0; l->g = 0.2; l->b = 0.8;
1765   } else {
1766     l->r = 0.9, l->g = 0.55, l->b = 0;
1767   }
1768   return l;
1769 }
1770
1771 static Fuse *NewFuse(Circuit *ci)
1772 {
1773   Fuse *f;
1774
1775   f = malloc(sizeof(Fuse));
1776   return f;
1777 }
1778
1779 static RCA *NewRCA(Circuit *ci)
1780 {
1781   RCA *r;
1782
1783   r = malloc(sizeof(RCA));
1784   r->col = (random() % 10 < 5);
1785   return r;
1786 }
1787
1788 static ThreeFive *NewThreeFive(Circuit *ci)
1789 {
1790   ThreeFive *r;
1791
1792   r = malloc(sizeof(ThreeFive));
1793   return r;
1794 }
1795
1796 static Switch *NewSwitch(Circuit *ci)
1797 {
1798   Switch *s;
1799
1800   s = malloc(sizeof(Switch));
1801   s->position = 0;
1802   return s;
1803 }
1804
1805 static Diode *NewDiode(void)
1806 {
1807   Band *b;
1808   Diode *ret;
1809
1810   ret = malloc(sizeof(Diode));
1811   b = malloc(sizeof(Band));
1812   b->pos = 0.8;
1813   b->len = 0.1;
1814   if (f_rand() < 0.5) {
1815     b->r = 1;
1816     b->g = 1;
1817     b->b = 1;
1818     ret->r = 0.7; ret->g = 0.1 ; ret->b = 0.1;
1819   } else {
1820     b->r = 1;
1821     b->g = 1;
1822     b->b = 1;
1823     ret->r = 0.2; ret->g = 0.2 ; ret->b = 0.2;
1824   }
1825   ret->band = b;
1826   return ret;
1827 }
1828
1829
1830 static Resistor  * NewResistor(void)
1831 {
1832   int v, m, t; /* value, multiplier, tolerance */
1833   Resistor *ret;
1834
1835   v = RAND(9);
1836   m = RAND(5);
1837   t = (RAND(10) < 5) ? 10 : 11; 
1838   ret = malloc(sizeof(Resistor));
1839
1840   if (seven) {
1841     ret->b[0] = ret->b[1] = ret->b[2] = 7;
1842   } else {
1843     ret->b[0] = values[v][0];
1844     ret->b[1] = values[v][1];
1845     ret->b[2] = m;
1846   }
1847   ret->b[3] = t;
1848
1849   return ret;
1850 }
1851
1852 static void makebandlist(Circuit *ci)
1853 {
1854   int i;
1855   GLfloat col[] = {0,0,0,0};
1856   GLfloat spec[] = {0.8,0.8,0.8,0};
1857   GLfloat shine = 40;
1858
1859    for (i = 0 ; i < 12 ; i++) {
1860      ci->band_list[i] = glGenLists(1);
1861      glNewList(ci->band_list[i], GL_COMPILE);
1862      col[0] = colorcodes[i][0];
1863      col[1] = colorcodes[i][1];
1864      col[2] = colorcodes[i][2];
1865      glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
1866      glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
1867      glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
1868      ci->band_list_polys[i] = createCylinder(ci, 0.1, 0.42, 0, 0);
1869      glEndList();
1870   }
1871 }
1872   
1873
1874 static int bandedCylinder(Circuit *ci, 
1875                            float radius, float l, 
1876                            GLfloat r, GLfloat g, GLfloat bl, 
1877                            Band **b, int nbands)
1878 {
1879   int polys = 0;
1880   int n; /* band number */
1881   GLfloat col[] = {0,0,0,0};
1882
1883    col[0] = r; col[1] = g; col[2] = bl;
1884    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1885    polys += createCylinder(ci, l, radius, 1, 0); /* body */
1886    for (n = 0 ; n < nbands ; n++) {
1887      glPushMatrix();
1888      glTranslatef(b[n]->pos*l, 0, 0);
1889      col[0] = b[n]->r; col[1] = b[n]->g; col[2] = b[n]->b;
1890      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1891      polys += createCylinder(ci, b[n]->len*l, radius*1.05, 0, 0); /* band */
1892      glPopMatrix();
1893    }
1894    return polys;
1895 }
1896
1897 static int drawgrid(Circuit *ci)
1898 {
1899   int polys = 0;
1900   GLfloat x, y;
1901   GLfloat col3[] = {0, 0.8, 0};
1902
1903   if (!ci->draw_s) {
1904      if (f_rand() < ((rotatespeed > 0) ? 0.05 : 0.01)) {
1905        ci->draw_sdir = RAND_RANGE(0, 4);
1906        ci->draw_ds = RAND_RANGE(0.4, 0.8);
1907        switch (ci->draw_sdir) {
1908           case 0:
1909            ci->draw_sx = -ci->XMAX/2;
1910            ci->draw_sy = ((int)RAND_RANGE(0, ci->YMAX/2))*2 - ci->YMAX/2;
1911            break;
1912           case 1:
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 2:
1917            ci->draw_sy = ci->YMAX/2;
1918            ci->draw_sx = ((int)RAND_RANGE(0, ci->XMAX/2))*2 - ci->XMAX/2;
1919            break;
1920           case 3:
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         }
1925         ci->draw_s = 1;
1926       }
1927   } else if (rotatespeed <= 0) {
1928     if (ci->grid_col[1] < 0.25) {
1929       ci->grid_col[1] += 0.025; ci->grid_col[2] += 0.005;
1930       ci->grid_col2[1] += 0.015 ; ci->grid_col2[2] += 0.005;
1931     }
1932   }
1933
1934   glDisable(GL_LIGHTING);
1935   if (ci->draw_s) {
1936     glColor3fv(col3);
1937     glPushMatrix();
1938     glTranslatef(ci->draw_sx, ci->draw_sy, -10);
1939     polys += sphere(ci, 0.1, 10, 10, 0, 10, 0, 10);
1940     if (ci->draw_sdir == 0) 
1941       glTranslatef(-ci->draw_ds, 0, 0);
1942     if (ci->draw_sdir == 1) 
1943       glTranslatef(ci->draw_ds, 0, 0);
1944     if (ci->draw_sdir == 2) 
1945       glTranslatef(0, ci->draw_ds, 0);
1946     if (ci->draw_sdir == 3) 
1947       glTranslatef(0, -ci->draw_ds, 0);
1948     polys += sphere(ci, 0.05, 10, 10, 0, 10, 0, 10);
1949     glPopMatrix();
1950     if (ci->draw_sdir == 0) {
1951        ci->draw_sx += ci->draw_ds;
1952        if (ci->draw_sx > ci->XMAX/2)
1953          ci->draw_s = 0;
1954     }
1955     if (ci->draw_sdir == 1) {
1956        ci->draw_sx -= ci->draw_ds;
1957        if (ci->draw_sx < -ci->XMAX/2)
1958          ci->draw_s = 0;
1959     }
1960     if (ci->draw_sdir == 2) {
1961        ci->draw_sy -= ci->draw_ds;
1962        if (ci->draw_sy < ci->YMAX/2)
1963          ci->draw_s = 0;
1964     }
1965     if (ci->draw_sdir == 3) {
1966        ci->draw_sy += ci->draw_ds;
1967        if (ci->draw_sy > ci->YMAX/2)
1968          ci->draw_s = 0;
1969     }
1970   } else if (rotatespeed <= 0) {
1971     if (ci->grid_col[1] > 0) {
1972       ci->grid_col[1] -= 0.0025; ci->grid_col[2] -= 0.0005;
1973       ci->grid_col2[1] -= 0.0015 ; ci->grid_col2[2] -= 0.0005;
1974     }
1975   }
1976   for (x = -ci->XMAX/2 ; x <= ci->XMAX/2 ; x+= 2) {
1977     glColor3fv(ci->grid_col);
1978     glBegin(GL_LINES);
1979      glVertex3f(x, ci->YMAX/2, -10);
1980      glVertex3f(x, -ci->YMAX/2, -10);
1981      glColor3fv(ci->grid_col2);
1982      glVertex3f(x-0.02, ci->YMAX/2, -10);
1983      glVertex3f(x-0.02, -ci->YMAX/2, -10);
1984      glVertex3f(x+0.02, ci->YMAX/2, -10);
1985      glVertex3f(x+0.02, -ci->YMAX/2, -10);
1986     glEnd();
1987   }
1988   for (y = -ci->YMAX/2 ; y <= ci->YMAX/2 ; y+= 2) {
1989     glColor3fv(ci->grid_col);
1990     glBegin(GL_LINES);
1991      glVertex3f(-ci->XMAX/2, y, -10);
1992      glVertex3f(ci->XMAX/2, y, -10);
1993      glColor3fv(ci->grid_col2);
1994      glVertex3f(-ci->XMAX/2, y-0.02, -10);
1995      glVertex3f(ci->XMAX/2, y-0.02, -10);
1996      glVertex3f(-ci->XMAX/2, y+0.02, -10);
1997      glVertex3f(ci->XMAX/2, y+0.02, -10);
1998     glEnd();
1999   }
2000   glEnable(GL_LIGHTING);
2001   return polys;
2002 }
2003
2004 static void display(ModeInfo *mi)
2005 {
2006   Circuit *ci = &circuit[MI_SCREEN(mi)];
2007   GLfloat light_sp[] = {0.8, 0.8, 0.8, 1.0};
2008   GLfloat black[] = {0, 0, 0, 1.0};
2009   int j;
2010
2011   mi->polygon_count = 0;
2012
2013   if (ci->display_i == 0) {
2014     for (ci->display_i = 0 ; ci->display_i < maxparts ; ci->display_i++) {
2015       ci->components[ci->display_i] = NULL;
2016     }
2017   } 
2018   glEnable(GL_LIGHTING);
2019   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
2020   glLoadIdentity();
2021   gluLookAt(ci->viewer[0], ci->viewer[1], ci->viewer[2], 
2022             0.0, 0.0, 0.0, 
2023             0.0, 1.0, 0.0);
2024   glPushMatrix();
2025   glRotatef(ci->rotate_angle, 0, 0, 1);
2026   ci->rotate_angle += 0.01 * (float)rotatespeed;
2027   if (ci->rotate_angle >= 360) ci->rotate_angle = 0;
2028
2029   glLightfv(GL_LIGHT0, GL_POSITION, ci->lightpos);
2030   glLightfv(GL_LIGHT0, GL_SPECULAR, light_sp);
2031   glLightfv(GL_LIGHT0, GL_DIFFUSE, light_sp);
2032   glLighti(GL_LIGHT0, GL_CONSTANT_ATTENUATION, (GLfloat)1); 
2033   glLighti(GL_LIGHT0, GL_LINEAR_ATTENUATION, (GLfloat)0.5); 
2034   glLighti(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, (GLfloat)0); 
2035   mi->polygon_count += drawgrid(ci);
2036   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light_sp);
2037   if (f_rand() < 0.05) {
2038     for (j = 0 ; j < maxparts ; j++) {
2039       if (ci->components[j] == NULL) {
2040         ci->components[j] = NewComponent(mi);
2041         j = maxparts;
2042       }
2043     }
2044     reorder(&ci->components[0]);
2045   }
2046   for (j = 0 ; j < maxparts ; j++) {
2047      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, black);
2048      glMaterialfv(GL_FRONT, GL_EMISSION, black);
2049      glMaterialfv(GL_FRONT, GL_SPECULAR, black);
2050      if (ci->components[j] != NULL) {
2051        if (DrawComponent(ci, ci->components[j], &mi->polygon_count)) {
2052         free(ci->components[j]); ci->components[j] = NULL;
2053        }
2054      }
2055   }
2056   glPopMatrix();
2057   glFlush();
2058 }
2059
2060 static void freetexture (Circuit *ci, GLuint texture) 
2061 {
2062   ci->s_refs[texture]--;
2063   if (ci->s_refs[texture] < 1) {
2064     glDeleteTextures(1, &texture);
2065   }
2066 }
2067
2068 static TexNum * fonttexturealloc (ModeInfo *mi,
2069                                   const char *str, float *fg, float *bg)
2070 {
2071   Circuit *ci = &circuit[MI_SCREEN(mi)];
2072   int i, status;
2073   XImage *ximage;
2074   char *c;
2075   TexNum *t;
2076
2077   if (ci->font_init == 0) {
2078     for (i = 0 ; i < 50 ; i++) {
2079       ci->font_strings[i] = NULL;
2080       ci->s_refs[i] = 0;
2081       ci->font_w[i] = 0; ci->font_h[i] = 0;
2082     }
2083     ci->font_init++;
2084   }
2085   for (i = 0 ; i < 50 ; i++) {
2086     if (!ci->s_refs[i] && ci->font_strings[i]) {
2087       free (ci->font_strings[i]);
2088       ci->font_strings[i] = NULL;
2089     }
2090     if (ci->font_strings[i] && !strcmp(str, ci->font_strings[i])) { /* if one matches */
2091       t = malloc(sizeof(TexNum));
2092       t->w = ci->font_w[i]; t->h = ci->font_h[i];
2093       t->num = i;
2094       ci->s_refs[i]++;
2095       return t;
2096     }
2097   }
2098
2099   /* at this point we need to make the new texture */
2100   ximage = text_to_ximage (mi->xgwa.screen,
2101                            mi->xgwa.visual,
2102                            font, str,
2103                            fg, bg);
2104   for (i = 0 ; ci->font_strings[i] != NULL ; i++) { /* set i to the next unused value */
2105      if (i > 49) {
2106         fprintf(stderr, "Texture cache full!\n");
2107         free(ximage->data);
2108         ximage->data = 0;
2109         XFree (ximage);
2110         return NULL;
2111      }
2112   }
2113
2114   glBindTexture(GL_TEXTURE_2D, i);
2115   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2116   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2117   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2118
2119   clear_gl_error();
2120   status = gluBuild2DMipmaps(GL_TEXTURE_2D, 4, ximage->width, ximage->height,
2121                              GL_RGBA, GL_UNSIGNED_BYTE, ximage->data);
2122   if (status)
2123     {
2124       const char *s = (char *) gluErrorString (status);
2125       fprintf (stderr, "%s: error mipmapping %dx%d texture: %s\n",
2126                progname, ximage->width, ximage->height,
2127                (s ? s : "(unknown)"));
2128       exit (1);
2129     }
2130   check_gl_error("mipmapping");
2131
2132   t = malloc(sizeof(TexNum));
2133   t->w = ximage->width;
2134   t->h = ximage->height;
2135   ci->font_w[i] = t->w; ci->font_h[i] = t->h;
2136   free(ximage->data);
2137   ximage->data = 0;
2138   XFree (ximage);
2139   c = malloc(strlen(str)+1);
2140   strncpy(c, str, strlen(str)+1);
2141   ci->font_strings[i] = c;
2142   ci->s_refs[i]++;
2143   t->num = i;
2144   return t;
2145 }
2146
2147 /* ensure transparent components are at the end */
2148 static void reorder(Component *c[])
2149 {
2150   int i, j, k;
2151   Component *c1[MAX_COMPONENTS];
2152   Component *c2[MAX_COMPONENTS];
2153
2154   j = 0;
2155   for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
2156     c1[i] = NULL;
2157     c2[i] = NULL;
2158   }
2159   for (i = 0 ; i < maxparts ; i++) {
2160     if (c[i] == NULL) continue;
2161     if (c[i]->alpha) { /* transparent parts go to c1 */
2162       c1[j] = c[i];
2163       j++;
2164     } else { /* opaque parts go to c2 */
2165       c2[i] = c[i];
2166     }
2167   }
2168   for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
2169     c[i] = NULL;
2170   }
2171   k = 0;
2172   for (i = 0 ; i < maxparts ; i++) { /* insert opaque part */
2173     if (c2[i] != NULL) {
2174       c[k] = c2[i];
2175       k++;
2176     }
2177   }
2178   for (i = 0 ; i < j ; i++) { /* insert transparent parts */
2179     c[k] = c1[i];
2180     k++;
2181   }
2182 }
2183
2184 ENTRYPOINT void reshape_circuit(ModeInfo *mi, int width, int height)
2185 {
2186  Circuit *ci = &circuit[MI_SCREEN(mi)];
2187  GLfloat h = (GLfloat) height / (GLfloat) width;
2188  glViewport(0,0,(GLint)width, (GLint) height);
2189  glMatrixMode(GL_PROJECTION);
2190  glLoadIdentity();
2191  glFrustum(-1.0,1.0,-h,h,1.5,35.0);
2192  glMatrixMode(GL_MODELVIEW);
2193  ci->win_h = height; 
2194  ci->win_w = width;
2195  ci->YMAX = ci->XMAX * h;
2196 }
2197
2198
2199 ENTRYPOINT void init_circuit(ModeInfo *mi)
2200 {
2201 int screen = MI_SCREEN(mi);
2202 Circuit *ci;
2203
2204  if (circuit == NULL) {
2205    if ((circuit = (Circuit *) calloc(MI_NUM_SCREENS(mi),
2206                                         sizeof(Circuit))) == NULL)
2207           return;
2208  }
2209  ci = &circuit[screen];
2210  ci->window = MI_WINDOW(mi);
2211
2212  ci->XMAX = ci->YMAX = 30;
2213  ci->viewer[2] = 14;
2214  ci->lightpos[0] = 7;
2215  ci->lightpos[1] = 7;
2216  ci->lightpos[2] = 15;
2217  ci->lightpos[3] = 1;
2218
2219  ci->grid_col[1] = 0.25;
2220  ci->grid_col[2] = 0.05;
2221  ci->grid_col2[1] = 0.125;
2222  ci->grid_col2[2] = 0.05;
2223
2224  if (maxparts >= MAX_COMPONENTS)
2225    maxparts = MAX_COMPONENTS-1;
2226
2227  if ((ci->glx_context = init_GL(mi)) != NULL) {
2228       reshape_circuit(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
2229  } else {
2230      MI_CLEARWINDOW(mi);
2231  }
2232  if (uselight == 0)
2233     ci->light = 1;
2234  glShadeModel(GL_SMOOTH);
2235  glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
2236  glEnable(GL_DEPTH_TEST);
2237  glEnable(GL_LIGHTING);
2238  glEnable(GL_LIGHT0);
2239  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2240  make_tables(ci);
2241  makebandlist(ci);
2242  
2243 }
2244
2245 ENTRYPOINT void draw_circuit(ModeInfo *mi)
2246 {
2247   Circuit *ci = &circuit[MI_SCREEN(mi)];
2248   Window w = MI_WINDOW(mi);
2249   Display *disp = MI_DISPLAY(mi);
2250
2251   if (!ci->glx_context)
2252       return;
2253
2254  glXMakeCurrent(disp, w, *(ci->glx_context));
2255
2256   display(mi);
2257
2258   if(mi->fps_p) do_fps(mi);
2259   glFinish(); 
2260   glXSwapBuffers(disp, w);
2261 }
2262
2263 ENTRYPOINT void release_circuit(ModeInfo *mi)
2264 {
2265   if (circuit != NULL) {
2266    (void) free((void *) circuit);
2267    circuit = NULL;
2268   }
2269   FreeAllGL(mi);
2270 }
2271
2272 XSCREENSAVER_MODULE ("Circuit", circuit)
2273
2274 #endif