From http://www.jwz.org/xscreensaver/xscreensaver-5.33.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                "*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       XCharStruct e;
1116       int w, h;
1117       texture_string_metrics (ci->font, c->text, &e, 0, 0);
1118       w = e.width;
1119       h = e.ascent + e.descent;
1120
1121       glPushMatrix();
1122       glTranslatef (0, 0, 0.1);
1123       glRotatef (90, 0, 0, 1);
1124       glScalef (s, s, s);
1125       glTranslatef (-w/2, 0, 0);
1126       glColor4fv (texfg);
1127       print_texture_string (ci->font, c->text);
1128       glPopMatrix();
1129     }
1130
1131     glDisable(GL_TEXTURE_2D);
1132     glDisable(GL_BLEND);
1133     d = (h*2-0.1) / c->pins;
1134     d*=2;
1135     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
1136     glMaterialfv(GL_FRONT, GL_SPECULAR, lspec);
1137     glMaterialfv(GL_FRONT, GL_SHININESS, &lshine);
1138     for (z = 0 ; z < c->pins/2 ; z++) {
1139       polys += ICLeg(w, -h + z*d + d/2, 0, 0);
1140     }
1141     for (z = 0 ; z < c->pins/2 ; z++) {
1142       polys += ICLeg(-w, -h + z*d + d/2, 0, 1);
1143     }
1144     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col2);
1145     glTranslatef(-w+0.3, h-0.3, 0.1);
1146     glRotatef(90, 0, 1, 0);
1147     polys += circle(ci, 0.1, 7, 0);
1148     glPopMatrix();
1149     return polys;
1150 }
1151
1152 static int DrawDisp(Circuit *ci, Disp *d)
1153 {
1154   int polys = 0;
1155   GLfloat col[] = {0.8, 0.8, 0.8, 1.0}; /* body colour */
1156   GLfloat front[] = {0.2, 0.2, 0.2, 1.0}; /* front colour */
1157   GLfloat on[] = {0.9, 0, 0, 1}; /* 'on' segment */
1158   GLfloat off[] = {0.3, 0, 0, 1}; /* 'off' segment */
1159   int i, j, k;
1160   GLfloat x, y; /* for the pins */
1161   GLfloat spec[] = {0.6, 0.6, 0.6, 0};
1162   GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
1163   GLfloat shine = 40;
1164   static const GLfloat vdata_h[6][2] = {
1165     {0, 0},
1166     {0.1, 0.1},
1167     {0.9, 0.1},
1168     {1, 0},
1169     {0.9, -0.1},
1170     {0.1, -0.1}
1171   };
1172   static const GLfloat vdata_v[6][2] = {
1173     {0.27, 0},
1174     {0.35, -0.1},
1175     {0.2, -0.9},
1176     {0.1, -1},
1177     {0, -0.9},
1178     {0.15, -0.15}
1179   };
1180
1181   static const GLfloat seg_start[7][2] = {
1182     {0.55, 2.26},
1183     {1.35, 2.26},
1184     {1.2, 1.27},
1185     {0.25, 0.25},
1186     {0.06, 1.25},
1187     {0.25, 2.25},
1188     {0.39, 1.24}
1189   };
1190
1191   static const int nums[10][7] = {
1192     {1, 1, 1, 1, 1, 1, 0}, /* 0 */
1193     {0, 1, 1, 0, 0, 0, 0}, /* 1 */
1194     {1, 1, 0, 1, 1, 0, 1}, /* 2 */
1195     {1, 1, 1, 1, 0, 0, 1}, /* 3 */
1196     {0, 1, 1, 0, 0, 1, 1}, /* 4 */
1197     {1, 0, 1, 1, 0, 1, 1}, /* 5 */
1198     {1, 0, 1, 1, 1, 1, 1}, /* 6 */
1199     {1, 1, 1, 0, 0, 0, 0}, /* 7 */
1200     {1, 1, 1, 1, 1, 1, 1}, /* 8 */
1201     {1, 1, 1, 0, 0, 1, 1}  /* 9 */
1202   };
1203
1204    glTranslatef(-0.9, -1.8, 0);
1205    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1206    polys += Rect(0, 0, -0.01, 1.8, 2.6, 0.7);
1207    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, front);
1208    glBegin(GL_QUADS);
1209      glVertex2f(-0.05, -0.05);
1210      glVertex2f(-0.05, 2.65);
1211      glVertex2f(1.85, 2.65);
1212      glVertex2f(1.85, -0.05);
1213      polys++;
1214    glEnd();
1215    glDisable(GL_LIGHTING); /* lit segments dont need light */
1216    if (!seven && (random() % 30) == 19) { /* randomly change value */
1217      d->value = random() % 10;
1218    }
1219    for (j = 0 ; j < 7 ; j++) { /* draw the segments */
1220      GLfloat xx[6], yy[6];
1221      if (nums[d->value][j])
1222        glColor3fv(on);
1223      else
1224        glColor3fv(off);
1225      for (k = 0 ; k < 6 ; k++) {
1226        if (j == 0 || j == 3 || j == 6) {
1227          xx[k] = seg_start[j][0] + vdata_h[k][0];
1228          yy[k] = seg_start[j][1] + vdata_h[k][1];
1229        } else {
1230          xx[k] = seg_start[j][0] + vdata_v[k][0];
1231          yy[k] = seg_start[j][1] + vdata_v[k][1];
1232        }
1233      }
1234      glBegin(GL_POLYGON);
1235      for(i = 0 ; i < 6 ; i++) {
1236        glVertex3f(xx[i], yy[i], 0.01);
1237      }
1238      polys++;
1239      glEnd();
1240    }
1241    glColor3fv(on);
1242    glPointSize(4);
1243    glBegin(GL_POINTS);
1244     glVertex3f(1.5, 0.2, 0.01);
1245     polys++;
1246    glEnd();
1247    glEnable(GL_LIGHTING);
1248    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
1249    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1250    glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
1251    for (x = 0.35 ; x <= 1.5 ; x+= 1.15) {
1252      for ( y = 0.2 ; y <= 2.4 ; y += 0.3) {
1253        polys += ICLeg(x, y, -0.7, 1);
1254      }
1255    }
1256    return polys;
1257 }
1258
1259 static int HoledRectangle(Circuit *ci, 
1260                            GLfloat w, GLfloat h, GLfloat d, GLfloat radius,
1261                            int p)
1262 {
1263   int polys = 0;
1264   int step, a;
1265   GLfloat x1, y1, x2, y2;
1266   GLfloat yr, yr1, xr, xr1, side, side1;
1267   GLfloat nx, ny;
1268
1269   step = 360 / p;
1270   x1 = radius; y1 = 0;
1271   xr1 = w/2; yr1 = 0;
1272   side = w/2;
1273   side1 = h/2;
1274   glBegin(GL_QUADS);
1275   for (a = 0 ; a <= 360 ; a+= step) {
1276     y2=radius*(float)ci->sin_table[(int)a];
1277     x2=radius*(float)ci->cos_table[(int)a];
1278
1279     if (a < 45 || a > 315) {
1280       xr = side;
1281       yr = side1 * ci->tan_table[a];
1282       nx = 1; ny = 0;
1283     } else if (a <= 135 || a >= 225) {
1284       xr = side/ci->tan_table[a];
1285       if (a >= 225) {
1286        yr = -side1;
1287        xr = 0 - xr;
1288        nx = 0; ny = -1;
1289       } else {
1290        yr = side1;
1291        nx = 0; ny = 1;
1292      }
1293     } else {
1294       xr = -side;
1295       yr = -side1 * ci->tan_table[a];
1296       nx = -1; ny = 0;
1297     }
1298
1299       glNormal3f(-x1, -y1, 0); /* cylinder */
1300       glVertex3f(x1,y1,0);
1301       glVertex3f(x1,y1,-d);
1302       glVertex3f(x2,y2,-d);
1303       glVertex3f(x2,y2,0);
1304       polys++;
1305
1306       glNormal3f(0, 0, 1); /* front face */
1307       glVertex3f(x1,y1,0);
1308       glVertex3f(xr1, yr1, 0);
1309       glVertex3f(xr, yr, 0);
1310       glVertex3f(x2, y2, 0);
1311       polys++;
1312
1313       glNormal3f(nx, ny, 0); /* side */
1314       glVertex3f(xr, yr, 0);
1315       glVertex3f(xr, yr, -d);
1316       glVertex3f(xr1, yr1, -d);
1317       glVertex3f(xr1, yr1, 0);
1318       polys++;
1319
1320       glNormal3f(0, 0, -1); /* back */
1321       glVertex3f(xr, yr, -d);
1322       glVertex3f(x2, y2, -d);
1323       glVertex3f(x1, y1, -d);
1324       glVertex3f(xr1, yr1, -d);
1325       polys++;
1326
1327     x1=x2;
1328     y1=y2;
1329     xr1 = xr; yr1 = yr;
1330   }
1331   glEnd();
1332   return polys;
1333 }
1334
1335 static int DrawTransistor(Circuit *ci, Transistor *t)
1336 {
1337   int polys = 0;
1338   GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
1339   GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
1340   GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
1341   GLfloat shin = 30;
1342
1343   glPushMatrix();
1344   glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1345   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col);
1346   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1347   if (t->type == 1) { /* TO-92 style */
1348     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1349     glRotatef(90, 0, 1, 0);
1350     glRotatef(90, 0, 0, 1);
1351     polys += createCylinder(ci, 1.0, 0.4, 1, 1);
1352     polys += Rect(0, -0.2, 0.4, 1, 0.2, 0.8);
1353 /* Draw the markings */
1354
1355     {
1356       GLfloat texfg[] = {0.7, 0.7, 0.7, 1.0};
1357       GLfloat s = 0.015;
1358       XCharStruct e;
1359       int w, h;
1360       texture_string_metrics (ci->font, t->text, &e, 0, 0);
1361       w = e.width;
1362       h = e.ascent + e.descent;
1363       glPushMatrix();
1364       glRotatef (90, 1, 0, 0);
1365       glTranslatef (0.5, -0.05, 0.21);
1366       glScalef (s, s, s);
1367       glTranslatef (-w/2, 0, 0);
1368       glColor4fv (texfg);
1369       print_texture_string (ci->font, t->text);
1370       glPopMatrix();
1371     }
1372
1373     glDisable(GL_TEXTURE_2D);
1374     glDisable(GL_BLEND);
1375     glDepthMask(GL_TRUE);
1376     glTranslatef(-2, 0, -0.2);
1377     polys += wire(ci, 2);
1378     glTranslatef(0, 0, 0.2);
1379     polys += wire(ci, 2);
1380     glTranslatef(0, 0, 0.2);
1381     polys += wire(ci, 2);
1382   } else if (t->type == 0) { /* TO-220 Style */
1383     polys += Rect(0, 0, 0, 1.5, 1.5, 0.5);
1384     {
1385       GLfloat texfg[] = {0.7, 0.7, 0.7, 1.0};
1386       GLfloat s = 0.015;
1387       XCharStruct e;
1388       int w, h;
1389       texture_string_metrics (ci->font, t->text, &e, 0, 0);
1390       w = e.width;
1391       h = e.ascent + e.descent;
1392       glPushMatrix();
1393       glTranslatef (0.75, 0.75, 0.01);
1394       glScalef (s, s, s);
1395       glTranslatef (-w/2, 0, 0);
1396       glColor4fv (texfg);
1397       print_texture_string (ci->font, t->text);
1398       glPopMatrix();
1399     }
1400     glDisable(GL_TEXTURE_2D);
1401     glDisable(GL_BLEND);
1402     glDepthMask(GL_TRUE);
1403     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1404     glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1405     glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1406     polys += Rect(0, 0, -0.5, 1.5, 1.5, 0.30);
1407     if (!glIsEnabled(GL_NORMALIZE)) glEnable(GL_NORMALIZE);
1408     glTranslatef(0.75, 1.875, -0.55);
1409     polys += HoledRectangle(ci, 1.5, 0.75, 0.25, 0.2, 8);
1410     glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
1411     glTranslatef(-0.375, -1.875, 0);
1412     glRotatef(90, 0, 0, -1);
1413     polys += wire(ci, 2);
1414     glTranslatef(0, 0.375, 0);
1415     polys += wire(ci, 2);
1416     glTranslatef(0, 0.375, 0);
1417     polys += wire(ci, 2);
1418   } else {              /* SMC transistor */
1419 /* Draw the body */
1420     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1421     glTranslatef(-0.5, -0.25, 0.1);
1422     polys += Rect(0, 0, 0, 1, 0.5, 0.2);
1423 /* Draw the markings */
1424     glEnable(GL_TEXTURE_2D);
1425     glEnable(GL_BLEND);
1426     glDepthMask(GL_FALSE);
1427     glBegin (GL_QUADS);
1428      glNormal3f(0, 0, 1);
1429      glTexCoord2f(0, 1);
1430      glVertex3f(0.2, 0, 0.01);
1431      glTexCoord2f(1, 1);
1432      glVertex3f(0.8, 0, 0.01);
1433      glTexCoord2f(1, 0);
1434      glVertex3f(0.8, 0.5, 0.01);
1435      glTexCoord2f(0, 0);
1436      glVertex3f(0.2, 0.5, 0.01);
1437      polys++;
1438     glEnd();
1439     glDisable(GL_TEXTURE_2D);
1440     glDisable(GL_BLEND);
1441     glDepthMask(GL_TRUE);
1442 /* Now draw the legs */
1443     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1444     glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1445     glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1446     polys += Rect(0.25, -0.1, -0.05, 0.1, 0.1, 0.2);
1447     polys += Rect(0.75, -0.1, -0.05, 0.1, 0.1, 0.2);
1448     polys += Rect(0.5, 0.5, -0.05, 0.1, 0.1, 0.2);
1449     polys += Rect(0.25, -0.2, -0.2, 0.1, 0.15, 0.1);
1450     polys += Rect(0.75, -0.2, -0.2, 0.1, 0.15, 0.1);
1451     polys += Rect(0.5, 0.5, -0.2, 0.1, 0.15, 0.1);
1452   }
1453   glPopMatrix();
1454   return polys;
1455 }
1456
1457 static Component * NewComponent(ModeInfo *mi)
1458 {
1459   Circuit *ci = &circuit[MI_SCREEN(mi)];
1460   Component *c;
1461   float rnd;
1462
1463   c = malloc(sizeof(Component));
1464   c->angle = RAND_RANGE(0,360);
1465   rnd = f_rand();
1466   if (rnd < 0.25) { /* come from the top */
1467      c->y = ci->YMAX/2;
1468      c->x = RAND_RANGE(0, ci->XMAX) - ci->XMAX/2;
1469      if (c->x > 0)
1470        c->dx = 0 - RAND_RANGE(0.5, 2);
1471      else 
1472        c->dx = RAND_RANGE(0.5, 2);
1473      c->dy = 0 - RAND_RANGE(0.5, 2);
1474   } else if (rnd < 0.5) { /* come from the bottom */
1475      c->y = 0 - ci->YMAX/2;
1476      c->x = RAND_RANGE(0, ci->XMAX) - ci->XMAX/2;
1477      if (c->x > 0)
1478        c->dx = 0 - RAND_RANGE(0.5, 2);
1479      else 
1480        c->dx = RAND_RANGE(0.5, 2);
1481      c->dy = RAND_RANGE(0.5, 2);
1482   } else if (rnd < 0.75) { /* come from the left */
1483      c->x = 0 - ci->XMAX/2;
1484      c->y = RAND_RANGE(0, ci->YMAX) - ci->YMAX/2;
1485      c->dx = RAND_RANGE(0.5, 2);
1486      if (c->y > 0)
1487        c->dy = 0 - RAND_RANGE(0.5, 2);
1488      else 
1489        c->dy = RAND_RANGE(0.5, 2);
1490   } else { /* come from the right */
1491      c->x = ci->XMAX/2;
1492      c->y = RAND_RANGE(0, ci->YMAX) - ci->YMAX/2;
1493      c->dx =  0 - RAND_RANGE(0.5, 2);
1494      if (c->y > 0)
1495        c->dy = 0 - RAND_RANGE(0.5, 2);
1496      else 
1497        c->dy = RAND_RANGE(0.5, 2);
1498   }
1499   c->z = RAND_RANGE(0, 7) - 9;
1500   c->rotx = f_rand();
1501   c->roty = f_rand();
1502   c->rotz = f_rand();
1503   c->drot = f_rand() * 3;
1504   c->rdeg = 0;
1505   c->dz = f_rand()*2 - 1;
1506   c->norm = 0;
1507   c->alpha = 0; /* explicitly set to 1 later */
1508   rnd = random() % 11;
1509   if (rnd < 1) {
1510     c->c = NewResistor();
1511     c->type = 0;
1512     if (f_rand() < 0.4)
1513       c->norm = 1; /* some resistors shine */
1514   } else if (rnd < 2) {
1515     c->c = NewDiode();
1516     if (f_rand() < 0.4)
1517       c->norm = 1; /* some diodes shine */
1518     c->type = 1;
1519   } else if (rnd < 3) {
1520     c->c = NewTransistor(mi);
1521     c->norm = 1;
1522     c->type = 2;
1523   } else if (rnd < 4) {
1524     c->c = NewCapacitor(ci);
1525     c->norm = 1;
1526     c->type = 4;
1527   } else if (rnd < 5) {
1528     c->c = NewIC(mi);
1529     c->type = 5;
1530     c->norm = 1;
1531   } else if (rnd < 6) {
1532     c->c = NewLED(ci);
1533     c->type = 3;
1534     c->norm = 1;
1535     c->alpha = 1;
1536   } else if (rnd < 7) {
1537     c->c = NewFuse(ci);
1538     c->norm = 1;
1539     c->type = 7;
1540     c->alpha = 1;
1541   } else if (rnd < 8) {
1542     c->c = NewRCA(ci);
1543     c->norm = 1;
1544     c->type = 8;
1545   } else if (rnd < 9) {
1546     c->c = NewThreeFive(ci);
1547     c->norm = 1;
1548     c->type = 9;
1549   } else if (rnd < 10) {
1550     c->c = NewSwitch(ci);
1551     c->norm = 1;
1552     c->type = 10;
1553   } else {
1554     c->c = NewDisp(ci);
1555     c->type = 6;
1556   }
1557   return c;
1558 }
1559
1560 static Transistor *NewTransistor(ModeInfo *mi)
1561 {
1562   Transistor *t;
1563
1564   t = malloc(sizeof(Transistor));
1565   t->type = (random() % 3);
1566   if (t->type == 0) {
1567     t->text = transistortypes[random() % countof(transistortypes)];
1568   } else if (t->type == 2) {
1569     t->text = smctypes[random() % countof(smctypes)];
1570   } else if (t->type == 1) {
1571     t->text = to92types[random() % countof(to92types)];
1572   }
1573   return t;
1574 }
1575
1576 static Capacitor *NewCapacitor(Circuit *ci)
1577 {
1578   Capacitor *c;
1579
1580   c = malloc(sizeof(Capacitor));
1581   c->type = (f_rand() < 0.5);
1582   if (!c->type) {
1583     c->length = RAND_RANGE(0.5, 1);
1584     c->width = RAND_RANGE(0.5, 1);
1585   } else {
1586     c->width = RAND_RANGE(0.3, 1);
1587   }
1588   return c;
1589 }
1590
1591 /* 7 segment display */
1592
1593 static Disp *NewDisp(Circuit *ci)
1594 {
1595   Disp *d;
1596
1597   d = malloc(sizeof(Disp));
1598   if (seven)
1599     d->value = 7;
1600   else
1601     d->value = RAND_RANGE(0, 10);
1602   return d;
1603 }
1604
1605
1606 static IC *NewIC(ModeInfo *mi)
1607 {
1608   IC *c;
1609   int pins;
1610   const char *val;
1611   int types[countof(ictypes)], i, n = 0;
1612
1613   c = malloc(sizeof(IC));
1614   c->type = 0;
1615   switch((int)RAND_RANGE(0,4)) {
1616     case 0:
1617       pins = 8;
1618       break;
1619     case 1:
1620       pins = 14;
1621       break;
1622     case 2:
1623       pins = 16;
1624       break;
1625     case 3:
1626     default:
1627       pins = 24;
1628       break;
1629   }
1630   for (i = 0 ; i < countof(ictypes) ; i++) {
1631     if (ictypes[i].pins == pins) {
1632        types[n] = i;
1633        n++;
1634     }
1635   }
1636
1637   if (n > countof(types)) abort();
1638   val = ictypes[types[random() % n]].val;
1639   sprintf(c->text, "%s\n%02d%02d", val,
1640           (int)RAND_RANGE(80, 100), (int)RAND_RANGE(1,53));
1641   c->pins = pins;
1642   return c;
1643 }
1644
1645 static LED *NewLED(Circuit *ci)
1646 {
1647   LED *l;
1648   float r;
1649
1650   l = malloc(sizeof(LED));
1651   r = f_rand();
1652   l->light = 0;
1653   if (!ci->light && (f_rand() < 0.4)) {
1654      ci->light = 1;
1655      l->light = 1;
1656   }
1657   if (r < 0.2) {
1658     l->r = 0.9; l->g = 0; l->b = 0;
1659   } else if (r < 0.4) {
1660     l->r = 0.3; l->g = 0.9; l->b = 0;
1661   } else if (r < 0.6) {
1662     l->r = 0.8; l->g = 0.9; l->b = 0;
1663   } else if (r < 0.8) {
1664     l->r = 0.0; l->g = 0.2; l->b = 0.8;
1665   } else {
1666     l->r = 0.9, l->g = 0.55, l->b = 0;
1667   }
1668   return l;
1669 }
1670
1671 static Fuse *NewFuse(Circuit *ci)
1672 {
1673   Fuse *f;
1674
1675   f = malloc(sizeof(Fuse));
1676   return f;
1677 }
1678
1679 static RCA *NewRCA(Circuit *ci)
1680 {
1681   RCA *r;
1682
1683   r = malloc(sizeof(RCA));
1684   r->col = (random() % 10 < 5);
1685   return r;
1686 }
1687
1688 static ThreeFive *NewThreeFive(Circuit *ci)
1689 {
1690   ThreeFive *r;
1691
1692   r = malloc(sizeof(ThreeFive));
1693   return r;
1694 }
1695
1696 static Switch *NewSwitch(Circuit *ci)
1697 {
1698   Switch *s;
1699
1700   s = malloc(sizeof(Switch));
1701   s->position = 0;
1702   return s;
1703 }
1704
1705 static Diode *NewDiode(void)
1706 {
1707   Band *b;
1708   Diode *ret;
1709
1710   ret = malloc(sizeof(Diode));
1711   b = malloc(sizeof(Band));
1712   b->pos = 0.8;
1713   b->len = 0.1;
1714   if (f_rand() < 0.5) {
1715     b->r = 1;
1716     b->g = 1;
1717     b->b = 1;
1718     ret->r = 0.7; ret->g = 0.1 ; ret->b = 0.1;
1719   } else {
1720     b->r = 1;
1721     b->g = 1;
1722     b->b = 1;
1723     ret->r = 0.2; ret->g = 0.2 ; ret->b = 0.2;
1724   }
1725   ret->band = b;
1726   return ret;
1727 }
1728
1729
1730 static Resistor  * NewResistor(void)
1731 {
1732   int v, m, t; /* value, multiplier, tolerance */
1733   Resistor *ret;
1734
1735   v = RAND(9);
1736   m = RAND(5);
1737   t = (RAND(10) < 5) ? 10 : 11; 
1738   ret = malloc(sizeof(Resistor));
1739
1740   if (seven) {
1741     ret->b[0] = ret->b[1] = ret->b[2] = 7;
1742   } else {
1743     ret->b[0] = values[v][0];
1744     ret->b[1] = values[v][1];
1745     ret->b[2] = m;
1746   }
1747   ret->b[3] = t;
1748
1749   return ret;
1750 }
1751
1752 static void makebandlist(Circuit *ci)
1753 {
1754   int i;
1755   GLfloat col[] = {0,0,0,0};
1756   GLfloat spec[] = {0.8,0.8,0.8,0};
1757   GLfloat shine = 40;
1758
1759    for (i = 0 ; i < 12 ; i++) {
1760      ci->band_list[i] = glGenLists(1);
1761      glNewList(ci->band_list[i], GL_COMPILE);
1762      col[0] = colorcodes[i][0];
1763      col[1] = colorcodes[i][1];
1764      col[2] = colorcodes[i][2];
1765      glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
1766      glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
1767      glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
1768      ci->band_list_polys[i] = createCylinder(ci, 0.1, 0.42, 0, 0);
1769      glEndList();
1770   }
1771 }
1772   
1773
1774 static int bandedCylinder(Circuit *ci, 
1775                            float radius, float l, 
1776                            GLfloat r, GLfloat g, GLfloat bl, 
1777                            Band **b, int nbands)
1778 {
1779   int polys = 0;
1780   int n; /* band number */
1781   GLfloat col[] = {0,0,0,0};
1782
1783    col[0] = r; col[1] = g; col[2] = bl;
1784    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1785    polys += createCylinder(ci, l, radius, 1, 0); /* body */
1786    for (n = 0 ; n < nbands ; n++) {
1787      glPushMatrix();
1788      glTranslatef(b[n]->pos*l, 0, 0);
1789      col[0] = b[n]->r; col[1] = b[n]->g; col[2] = b[n]->b;
1790      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1791      polys += createCylinder(ci, b[n]->len*l, radius*1.05, 0, 0); /* band */
1792      glPopMatrix();
1793    }
1794    return polys;
1795 }
1796
1797 static int drawgrid(Circuit *ci)
1798 {
1799   int polys = 0;
1800   GLfloat x, y;
1801   GLfloat col3[] = {0, 0.8, 0};
1802
1803   if (!ci->draw_s) {
1804      if (f_rand() < ((rotatespeed > 0) ? 0.05 : 0.01)) {
1805        ci->draw_sdir = RAND_RANGE(0, 4);
1806        ci->draw_ds = RAND_RANGE(0.4, 0.8);
1807        switch (ci->draw_sdir) {
1808           case 0:
1809            ci->draw_sx = -ci->XMAX/2;
1810            ci->draw_sy = ((int)RAND_RANGE(0, ci->YMAX/2))*2 - ci->YMAX/2;
1811            break;
1812           case 1:
1813            ci->draw_sx = ci->XMAX/2;
1814            ci->draw_sy = ((int)RAND_RANGE(0, ci->YMAX/2))*2 - ci->YMAX/2;
1815            break;
1816           case 2:
1817            ci->draw_sy = ci->YMAX/2;
1818            ci->draw_sx = ((int)RAND_RANGE(0, ci->XMAX/2))*2 - ci->XMAX/2;
1819            break;
1820           case 3:
1821            ci->draw_sy = -ci->YMAX/2;
1822            ci->draw_sx = ((int)RAND_RANGE(0, ci->XMAX/2))*2 - ci->XMAX/2;
1823            break;
1824         }
1825         ci->draw_s = 1;
1826       }
1827   } else if (rotatespeed <= 0) {
1828     if (ci->grid_col[1] < 0.25) {
1829       ci->grid_col[1] += 0.025; ci->grid_col[2] += 0.005;
1830       ci->grid_col2[1] += 0.015 ; ci->grid_col2[2] += 0.005;
1831     }
1832   }
1833
1834   glDisable(GL_LIGHTING);
1835   if (ci->draw_s) {
1836     glColor3fv(col3);
1837     glPushMatrix();
1838     glTranslatef(ci->draw_sx, ci->draw_sy, -10);
1839     polys += sphere(ci, 0.1, 10, 10, 0, 10, 0, 10);
1840     if (ci->draw_sdir == 0) 
1841       glTranslatef(-ci->draw_ds, 0, 0);
1842     if (ci->draw_sdir == 1) 
1843       glTranslatef(ci->draw_ds, 0, 0);
1844     if (ci->draw_sdir == 2) 
1845       glTranslatef(0, ci->draw_ds, 0);
1846     if (ci->draw_sdir == 3) 
1847       glTranslatef(0, -ci->draw_ds, 0);
1848     polys += sphere(ci, 0.05, 10, 10, 0, 10, 0, 10);
1849     glPopMatrix();
1850     if (ci->draw_sdir == 0) {
1851        ci->draw_sx += ci->draw_ds;
1852        if (ci->draw_sx > ci->XMAX/2)
1853          ci->draw_s = 0;
1854     }
1855     if (ci->draw_sdir == 1) {
1856        ci->draw_sx -= ci->draw_ds;
1857        if (ci->draw_sx < -ci->XMAX/2)
1858          ci->draw_s = 0;
1859     }
1860     if (ci->draw_sdir == 2) {
1861        ci->draw_sy -= ci->draw_ds;
1862        if (ci->draw_sy < ci->YMAX/2)
1863          ci->draw_s = 0;
1864     }
1865     if (ci->draw_sdir == 3) {
1866        ci->draw_sy += ci->draw_ds;
1867        if (ci->draw_sy > ci->YMAX/2)
1868          ci->draw_s = 0;
1869     }
1870   } else if (rotatespeed <= 0) {
1871     if (ci->grid_col[1] > 0) {
1872       ci->grid_col[1] -= 0.0025; ci->grid_col[2] -= 0.0005;
1873       ci->grid_col2[1] -= 0.0015 ; ci->grid_col2[2] -= 0.0005;
1874     }
1875   }
1876   for (x = -ci->XMAX/2 ; x <= ci->XMAX/2 ; x+= 2) {
1877     glColor3fv(ci->grid_col);
1878     glBegin(GL_LINES);
1879      glVertex3f(x, ci->YMAX/2, -10);
1880      glVertex3f(x, -ci->YMAX/2, -10);
1881      glColor3fv(ci->grid_col2);
1882      glVertex3f(x-0.02, ci->YMAX/2, -10);
1883      glVertex3f(x-0.02, -ci->YMAX/2, -10);
1884      glVertex3f(x+0.02, ci->YMAX/2, -10);
1885      glVertex3f(x+0.02, -ci->YMAX/2, -10);
1886     glEnd();
1887   }
1888   for (y = -ci->YMAX/2 ; y <= ci->YMAX/2 ; y+= 2) {
1889     glColor3fv(ci->grid_col);
1890     glBegin(GL_LINES);
1891      glVertex3f(-ci->XMAX/2, y, -10);
1892      glVertex3f(ci->XMAX/2, y, -10);
1893      glColor3fv(ci->grid_col2);
1894      glVertex3f(-ci->XMAX/2, y-0.02, -10);
1895      glVertex3f(ci->XMAX/2, y-0.02, -10);
1896      glVertex3f(-ci->XMAX/2, y+0.02, -10);
1897      glVertex3f(ci->XMAX/2, y+0.02, -10);
1898     glEnd();
1899   }
1900   glEnable(GL_LIGHTING);
1901   return polys;
1902 }
1903
1904 static void display(ModeInfo *mi)
1905 {
1906   Circuit *ci = &circuit[MI_SCREEN(mi)];
1907   GLfloat light_sp[] = {0.8, 0.8, 0.8, 1.0};
1908   GLfloat black[] = {0, 0, 0, 1.0};
1909   int j;
1910
1911   mi->polygon_count = 0;
1912
1913   if (ci->display_i == 0) {
1914     for (ci->display_i = 0 ; ci->display_i < maxparts ; ci->display_i++) {
1915       ci->components[ci->display_i] = NULL;
1916     }
1917   } 
1918   glEnable(GL_LIGHTING);
1919   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
1920   glLoadIdentity();
1921   /* glRotatef(current_device_rotation(), 0, 0, 1); */
1922   gluLookAt(ci->viewer[0], ci->viewer[1], ci->viewer[2], 
1923             0.0, 0.0, 0.0, 
1924             0.0, 1.0, 0.0);
1925   glPushMatrix();
1926   glRotatef(ci->rotate_angle, 0, 0, 1);
1927   ci->rotate_angle += 0.01 * (float)rotatespeed;
1928   if (ci->rotate_angle >= 360) ci->rotate_angle = 0;
1929
1930   glLightfv(GL_LIGHT0, GL_POSITION, ci->lightpos);
1931   glLightfv(GL_LIGHT0, GL_SPECULAR, light_sp);
1932   glLightfv(GL_LIGHT0, GL_DIFFUSE, light_sp);
1933   glLighti(GL_LIGHT0, GL_CONSTANT_ATTENUATION, (GLfloat)1); 
1934   glLighti(GL_LIGHT0, GL_LINEAR_ATTENUATION, (GLfloat)0.5); 
1935   glLighti(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, (GLfloat)0); 
1936   mi->polygon_count += drawgrid(ci);
1937   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light_sp);
1938   if (f_rand() < 0.05) {
1939     for (j = 0 ; j < maxparts ; j++) {
1940       if (ci->components[j] == NULL) {
1941         ci->components[j] = NewComponent(mi);
1942         j = maxparts;
1943       }
1944     }
1945     reorder(&ci->components[0]);
1946   }
1947   for (j = 0 ; j < maxparts ; j++) {
1948      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, black);
1949      glMaterialfv(GL_FRONT, GL_EMISSION, black);
1950      glMaterialfv(GL_FRONT, GL_SPECULAR, black);
1951      if (ci->components[j] != NULL) {
1952        if (DrawComponent(ci, ci->components[j], &mi->polygon_count)) {
1953         free(ci->components[j]); ci->components[j] = NULL;
1954        }
1955      }
1956   }
1957   glPopMatrix();
1958   glFlush();
1959 }
1960
1961 /* ensure transparent components are at the end */
1962 static void reorder(Component *c[])
1963 {
1964   int i, j, k;
1965   Component *c1[MAX_COMPONENTS];
1966   Component *c2[MAX_COMPONENTS];
1967
1968   j = 0;
1969   for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
1970     c1[i] = NULL;
1971     c2[i] = NULL;
1972   }
1973   for (i = 0 ; i < maxparts ; i++) {
1974     if (c[i] == NULL) continue;
1975     if (c[i]->alpha) { /* transparent parts go to c1 */
1976       c1[j] = c[i];
1977       j++;
1978     } else { /* opaque parts go to c2 */
1979       c2[i] = c[i];
1980     }
1981   }
1982   for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
1983     c[i] = NULL;
1984   }
1985   k = 0;
1986   for (i = 0 ; i < maxparts ; i++) { /* insert opaque part */
1987     if (c2[i] != NULL) {
1988       c[k] = c2[i];
1989       k++;
1990     }
1991   }
1992   for (i = 0 ; i < j ; i++) { /* insert transparent parts */
1993     c[k] = c1[i];
1994     k++;
1995   }
1996 }
1997
1998 ENTRYPOINT void reshape_circuit(ModeInfo *mi, int width, int height)
1999 {
2000  Circuit *ci = &circuit[MI_SCREEN(mi)];
2001  GLfloat h = (GLfloat) height / (GLfloat) width;
2002  glViewport(0,0,(GLint)width, (GLint) height);
2003  glMatrixMode(GL_PROJECTION);
2004  glLoadIdentity();
2005  glFrustum(-1.0,1.0,-h,h,1.5,35.0);
2006  glMatrixMode(GL_MODELVIEW);
2007  ci->win_h = height; 
2008  ci->win_w = width;
2009  ci->YMAX = ci->XMAX * h;
2010 }
2011
2012
2013 ENTRYPOINT void init_circuit(ModeInfo *mi)
2014 {
2015 int screen = MI_SCREEN(mi);
2016 Circuit *ci;
2017
2018  if (circuit == NULL) {
2019    if ((circuit = (Circuit *) calloc(MI_NUM_SCREENS(mi),
2020                                         sizeof(Circuit))) == NULL)
2021           return;
2022  }
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 ENTRYPOINT void release_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