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