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