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