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