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