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