2 * circuit - Random electronic components floating around
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.
14 * Copyright (C) 2001,2002 Ben Buxton (bb@cactii.net)
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
25 /* Written over a few days in a (successful) bid to learn GL coding
27 * -seven option is dedicated to all the Slarkeners
29 * try "-rotate -rotate-speed 0"
31 * This hack uses lookup tables for sin, cos and tan - it can do a lot
35 #include <X11/Intrinsic.h>
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 */
45 #define DEF_SPIN "True"
46 #define DEF_SEVEN "False"
47 #define DEF_PARTS "10"
49 #define DEFAULTS "*delay: 20000 \n" \
52 # include "xlockmore.h" /* from the xscreensaver distribution */
53 #else /* !STANDALONE */
54 # include "xlock.h" /* from the xlockmore distribution */
55 #endif /* !STANDALONE */
57 /* lifted from lament.c */
58 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
59 #define RANDSIGN() ((random() & 1) ? 1 : -1)
65 #include "font-ximage.h"
68 #define countof(x) (sizeof((x))/sizeof((*x)))
74 static int rotatespeed;
80 #define countof(x) (sizeof((x))/sizeof((*x)))
82 static XrmOptionDescRec opts[] = {
83 {"-parts", ".circuit.parts", XrmoptionSepArg, "10" },
84 {"-font", ".circuit.font", XrmoptionSepArg, "fixed" },
85 {"-rotate-speed", ".circuit.rotatespeed", XrmoptionSepArg, "1" },
86 {"+spin", ".circuit.spin", XrmoptionNoArg, "false" },
87 {"-spin", ".circuit.spin", XrmoptionNoArg, "true" },
88 {"+light", ".circuit.light", XrmoptionNoArg, "false" },
89 {"-light", ".circuit.light", XrmoptionNoArg, "true" },
90 {"+seven", ".circuit.seven", XrmoptionNoArg, "false" },
91 {"-seven", ".circuit.seven", XrmoptionNoArg, "true" },
92 {"+rotate", ".circuit.rotate", XrmoptionNoArg, "false" },
93 {"-rotate", ".circuit.rotate", XrmoptionNoArg, "true" },
96 static argtype vars[] = {
97 {&maxparts, "parts", "Parts", DEF_PARTS, t_Int},
98 {&font, "font", "Font", "fixed", t_String},
99 {&rotatespeed, "rotatespeed", "Rotatespeed", "1", t_Int},
100 {&spin, "spin", "Spin", DEF_SPIN, t_Bool},
101 {&rotate, "rotate", "Rotate", "False", t_Bool},
102 {&uselight, "light", "Light", "True", t_Bool},
103 {&seven, "seven", "Seven", DEF_SEVEN, t_Bool},
106 ModeSpecOpt circuit_opts = {countof(opts), opts, countof(vars), vars, NULL};
109 ModStruct circuit_description =
110 {"circuit", "init_circuit", "draw_circuit", "release_circuit",
111 "draw_circuit", "init_circuit", NULL, &circuit_opts,
112 1000, 1, 2, 1, 4, 1.0, "",
113 "Flying electronic components", 0, NULL};
119 GLXContext *glx_context;
123 static Circuit *circuit = NULL;
126 #include <sys/time.h>
131 #define M_PI 3.14159265
134 /* window width, height */
137 /* width and height of viewport */
140 static int YMAX = 30;
142 #define MAX_COMPONENTS 30
144 #define MOVE_MULT 0.02
146 static float f_rand(void) {
147 return ((float)RAND(10000)/(float)10000);
150 #define RAND_RANGE(min, max) ((min) + (max - min) * f_rand())
152 /* one lucky led gets to be a light source , unless -no-light*/
156 /* stores refs to textures */
157 static int s_refs[50];
159 static GLfloat viewer[] = {0.0, 0.0, 14.0};
160 static GLfloat lightpos[] = {7.0, 7.0, 15, 1.0};
162 float sin_table[720];
163 float cos_table[720];
164 float tan_table[720];
168 /* used for allocating font textures */
170 int num; /* index number */
175 /* Represents a band on a resistor/diode/etc */
177 float pos; /* relative position from start/previous band */
178 GLfloat r, g, b; /* colour of the band */
179 float len; /* length as a fraction of total length */
183 Band *b1, *b2, *b3, *b4; /* bands */
189 GLfloat r, g, b; /* body colour */
192 static const char * transistortypes[] = {
208 static const char * to92types[] = {
223 static const char * smctypes[] = {
234 int type; /* package type. 0 = to-92, 1 = to-220 */
235 GLfloat tw, th; /* texture dimensions */
236 GLuint tnum; /* texture binding */
240 GLfloat r,g,b; /* LED colour */
241 int light; /* are we the light source? */
245 int type; /* 0 = electro, 1 = ceramic */
246 float width; /* width of an electro/ceramic */
247 float length; /* length of an electro */
265 static const ICTypes ictypes[] = {
308 int type; /* 0 = DIL, 1 = flat square */
310 float tw, th; /* texture dimensions for markings */
311 int tnum; /* texture number */
314 /* 7 segment display */
317 int value; /* displayed number */
330 GLfloat x, y, z; /* current co-ordinates */
331 GLfloat dx, dy, dz; /* current direction */
332 GLfloat rotx, roty, rotz; /* rotation vector */
333 GLfloat drot; /* rotation velocity (degrees per frame) */
334 int norm; /* Normalize this component (for shine) */
335 int rdeg; /* current rotation degrees */
336 int angle; /* angle about the z axis */
337 int alpha; /* 0 if not a transparent component */
338 int type; /* 0 = resistor, 1 = diode, 2 = transistor, 3 = LED, 4 = cap, 5=IC,
340 void * c; /* pointer to the component */
343 static int band_list[12];
345 /* standard colour codes */
347 static GLfloat colorcodes [12][3] = {
348 {0.0,0.0,0.0}, /* black 0 */
349 {0.49,0.25,0.08}, /* brown 1 */
350 {1.0,0.0,0.0}, /* red 2 */
351 {1.0,0.5,0.0}, /* orange 3 */
352 {1.0,1.0,0.0}, /* yellow 4 */
353 {0.0,1.0,0.0}, /* green 5 */
354 {0.0,0.5,1.0}, /* blue 6 */
355 {0.7,0.2,1.0}, /* violet 7 */
356 {0.5,0.5,0.5}, /* grey 8 */
357 {1.0,1.0,1.0}, /* white 9 */
358 {0.66,0.56,0.2}, /* gold 10 */
359 {0.8,0.8,0.8}, /* silver 11 */
362 /* base values for components - we can multiply by 0 - 1M */
363 static int values [9][2] = {
375 void DrawResistor(Resistor *);
376 void DrawDiode(Diode *);
377 void DrawTransistor(Transistor *);
380 void DrawCapacitor(Capacitor *);
381 void DrawDisp(Disp *);
382 void DrawFuse(Fuse *);
384 void DrawThreeFive(ThreeFive *);
385 void DrawSwitch(Switch *);
387 void freetexture(GLuint);
388 void reorder(Component *[]);
389 void circle(float, int,int);
390 void bandedCylinder(float, float , GLfloat, GLfloat , GLfloat, Band **, int);
391 TexNum *fonttexturealloc(const char *, float *, float *);
392 void Rect(GLfloat , GLfloat , GLfloat, GLfloat , GLfloat ,GLfloat);
393 void ICLeg(GLfloat, GLfloat, GLfloat, int);
394 void HoledRectangle(GLfloat, GLfloat, GLfloat, GLfloat, int);
395 Resistor *NewResistor(void);
396 Diode *NewDiode(void);
397 Transistor *NewTransistor(void);
399 Capacitor *NewCapacitor(void);
404 ThreeFive *NewThreeFive(void);
405 Switch *NewSwitch(void);
407 /* we use trig tables to speed things up - 200 calls to sin()
408 in one frame can be a bit harsh..
411 void make_tables(void) {
415 f = 360 / (M_PI * 2);
416 for (i = 0 ; i < 720 ; i++) {
417 sin_table[i] = sin(i/f);
419 for (i = 0 ; i < 720 ; i++) {
420 cos_table[i] = cos(i/f);
422 for (i = 0 ; i < 720 ; i++) {
423 tan_table[i] = tan(i/f);
428 void createCylinder (float length, float radius, int endcaps, int half)
430 int a; /* current angle around cylinder */
432 float z1, y1, z2, y2,ex;
437 nsegs = radius*MAX(win_w, win_h)/20;
438 nsegs = MAX(nsegs, 4);
441 angle = (half) ? (180 - 90/nsegs) : 374;
445 for (a = 0 ; a <= angle ; a+= angle/nsegs) {
446 y2=radius*(float)sin_table[(int)a];
447 z2=radius*(float)cos_table[(int)a];
448 glNormal3f(0, y1, z1);
450 glVertex3f(length,y1,z1);
451 glNormal3f(0, y2, z2);
452 glVertex3f(length,y2,z2);
461 glVertex3f(0, 0, radius);
462 glVertex3f(length, 0, radius);
463 glVertex3f(length, 0, 0 - radius);
464 glVertex3f(0, 0, 0 - radius);
468 for(ex = 0 ; ex <= length ; ex += length) {
470 norm = (ex == length) ? 1 : -1;
471 glBegin(GL_TRIANGLES);
472 glNormal3f(norm, 0, 0);
473 for (a = 0 ; a <= angle ; a+= angle/nsegs) {
474 y2=radius*(float)sin_table[(int)a];
475 z2=radius*(float)cos_table[(int)a];
477 glVertex3f(ex,y1,z1);
478 glVertex3f(ex,y2,z2);
488 void circle(float radius, int segments, int half)
490 float x1 = 0, x2 = 0;
491 float y1 = 0, y2 = 0;
500 glBegin(GL_TRIANGLES);
505 x2=radius*(float)cos_table[(int)angle];
506 y2=radius*(float)sin_table[(int)angle];
518 static GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
519 static GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
520 static GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
524 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
525 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
526 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
527 n = glIsEnabled(GL_NORMALIZE);
528 if (!n) glEnable(GL_NORMALIZE);
529 createCylinder(len, 0.05, 1, 0);
530 if (!n) glDisable(GL_NORMALIZE);
531 glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
534 void ring(GLfloat inner, GLfloat outer, int nsegs)
536 GLfloat z1, z2, y1, y2;
537 GLfloat Z1, Z2, Y1, Y2;
544 for(i=0; i <=360 ; i+= 360/nsegs)
547 z2=inner*(float)sin_table[(int)angle];
548 y2=inner*(float)cos_table[(int)angle];
549 Z2=outer*(float)sin_table[(int)angle];
550 Y2=outer*(float)cos_table[(int)angle];
551 glVertex3f(0, Y1, Z1);
552 glVertex3f(0, y1, z1);
553 glVertex3f(0, y2, z2);
554 glVertex3f(0, Y2, Z2);
563 void sphere(GLfloat r, float stacks, float slices,
564 int startstack, int endstack, int startslice,
567 GLfloat d, d1, dr, dr1, Dr, Dr1, D, D1, z1, z2, y1, y2, Y1, Z1, Y2, Z2;
568 int a, a1, b, b1, c, c1;
573 a1 = startstack * step;
574 b1 = startslice * sstep;
575 y1 = z1 = Y1 = Z1 = 0;
576 c = (endslice / slices) * 360;
577 c1 = (endstack/stacks)*180;
579 for (a = startstack * step ; a <= c1 ; a+= step) {
588 for (b = b1 ; b <= c ; b+= sstep) {
593 glNormal3f(Dr, y1, z1);
594 glVertex3f(Dr,y1,z1);
595 glNormal3f(Dr, y2, z2);
596 glVertex3f(Dr,y2,z2);
597 glNormal3f(Dr1, Y2, Z2);
598 glVertex3f(Dr1,Y2,Z2);
599 glNormal3f(Dr1, Y1, Z1);
600 glVertex3f(Dr1,Y1,Z1);
611 int DrawComponent(Component *c)
613 int ret = 0; /* return 1 if component is freed */
616 glTranslatef(c->x, c->y, c->z);
618 glRotatef(c->angle, c->rotx, c->roty, c->rotz);
621 glRotatef(c->rdeg, c->rotx, c->roty, c->rotz);
626 glEnable(GL_NORMALIZE);
628 glDisable(GL_NORMALIZE);
630 /* call object draw routine here */
633 } else if (c->type == 1) {
635 } else if (c->type == 2) {
636 DrawTransistor(c->c);
637 } else if (c->type == 3) {
638 if (((LED *)c->c)->light && light) {
639 GLfloat lp[] = {0.1, 0, 0, 1};
641 glLightfv(GL_LIGHT1, GL_POSITION, lp);
644 } else if (c->type == 4) {
646 } else if (c->type == 5) {
648 } else if (c->type == 6) {
650 } else if (c->type == 7) {
652 } else if (c->type == 8) {
654 } else if (c->type == 9) {
656 } else if (c->type == 10) {
659 c->x += c->dx * MOVE_MULT;
660 c->y += c->dy * MOVE_MULT;
661 if (c->x > XMAX/2 || c->x < 0 - XMAX/2 ||
662 c->y > YMAX/2 || c->y < 0 - YMAX/2) {
663 if (c->type == 3 && ((LED *)c->c)->light && light) {
664 glDisable(GL_LIGHT1);
665 light = 0; lighton = 0;
668 if (((IC *)c->c)->tnum)
669 freetexture(((IC *)c->c)->tnum);
672 if (((Transistor *)c->c)->tnum)
673 freetexture(((Transistor *)c->c)->tnum);
676 free(((Diode *)c->c)->band); /* remember to free diode band */
682 glDisable(GL_NORMALIZE);
686 /* draw a resistor */
688 void DrawResistor(Resistor *r)
691 GLfloat col[] = {0.74, 0.62, 0.46, 1.0};
692 GLfloat spec[] = {0.8, 0.8, 0.8, 1.0};
695 glTranslatef(-4, 0, 0);
697 glTranslatef(3, 0, 0);
698 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
699 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
700 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
701 createCylinder(1.8, 0.4, 1, 0);
703 for (i = 0 ; i < 4 ; i++) {
704 glTranslatef(0.35, 0, 0);
705 glCallList(band_list[r->b[i]]);
708 glTranslatef(1.8, 0, 0);
712 void DrawRCA(RCA *rca)
714 static GLfloat col[] = {0.6, 0.6, 0.6, 1.0}; /* metal */
715 static GLfloat red[] = {1.0, 0.0, 0.0, 1.0}; /* red */
716 static GLfloat white[] = {1.0, 1.0, 1.0, 1.0}; /* white */
717 static GLfloat spec[] = {1, 1, 1, 1}; /* glass */
720 glTranslatef(0.3, 0, 0);
721 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
722 glMateriali(GL_FRONT, GL_SHININESS, 40);
723 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
724 createCylinder(0.7, 0.45, 0, 0);
725 glTranslatef(0.4, 0, 0);
726 createCylinder(0.9, 0.15, 1, 0);
727 glTranslatef(-1.9, 0, 0);
728 glMateriali(GL_FRONT, GL_SHININESS, 20);
729 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, rca->col ? white : red);
730 createCylinder(1.5, 0.6, 1, 0);
731 glTranslatef(-0.9, 0, 0);
732 createCylinder(0.9, 0.25, 0, 0);
733 glTranslatef(0.1, 0, 0);
734 createCylinder(0.2, 0.3, 0, 0);
735 glTranslatef(0.3, 0, 0);
736 createCylinder(0.2, 0.3, 1, 0);
737 glTranslatef(0.3, 0, 0);
738 createCylinder(0.2, 0.3, 1, 0);
742 void DrawSwitch(Switch *f)
744 static GLfloat col[] = {0.6, 0.6, 0.6, 0}; /* metal */
745 static GLfloat dark[] = {0.1, 0.1, 0.1, 1.0}; /* dark */
746 static GLfloat brown[] = {0.69, 0.32, 0, 1.0}; /* brown */
747 static GLfloat spec[] = {0.9, 0.9, 0.9, 1}; /* shiny */
750 glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
751 glMaterialfv(GL_FRONT, GL_AMBIENT, dark);
752 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
753 glMateriali(GL_FRONT, GL_SHININESS, 90);
754 Rect(-0.25, 0, 0, 1.5, 0.5, 0.75);
755 /* Rect(-0.5, 0.5, 0, 2, 0.1, 0.75); */
757 glRotatef(90, 1, 0, 0);
758 glTranslatef(-0.5, -0.4, -0.4);
759 HoledRectangle(0.5, 0.75, 0.1, 0.15, 8);
760 glTranslatef(2, 0, 0);
761 HoledRectangle(0.5, 0.75, 0.1, 0.15, 8);
763 Rect(0.1, -0.4, -0.25, 0.1, 0.4, 0.05);
764 Rect(0.5, -0.4, -0.25, 0.1, 0.4, 0.05);
765 Rect(0.9, -0.4, -0.25, 0.1, 0.4, 0.05);
766 Rect(0.1, -0.4, -0.5, 0.1, 0.4, 0.05);
767 Rect(0.5, -0.4, -0.5, 0.1, 0.4, 0.05);
768 Rect(0.9, -0.4, -0.5, 0.1, 0.4, 0.05);
769 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, dark);
770 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
771 Rect(0, 0.5, -0.1, 1, 0.05, 0.5);
772 Rect(0, 0.6, -0.1, 0.5, 0.6, 0.5);
773 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, brown);
774 Rect(-0.2, -0.01, -0.1, 1.4, 0.1, 0.55);
779 void DrawFuse(Fuse *f)
781 static GLfloat col[] = {0.5, 0.5, 0.5, 1.0}; /* endcaps */
782 static GLfloat glass[] = {0.4, 0.4, 0.4, 0.3}; /* glass */
783 static GLfloat spec[] = {1, 1, 1, 1}; /* glass */
786 glTranslatef(-1.8, 0, 0);
787 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
788 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
789 glMateriali(GL_FRONT, GL_SHININESS, 40);
790 createCylinder(0.8, 0.45, 1, 0);
791 glTranslatef(0.8, 0, 0);
793 glDepthMask(GL_FALSE);
794 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, glass);
795 glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 40);
796 createCylinder(2, 0.4, 0, 0);
797 createCylinder(2, 0.3, 0, 0);
799 glDepthMask(GL_TRUE);
800 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
801 glMateriali(GL_FRONT, GL_SHININESS, 40);
804 glVertex3f(2, 0. ,0);
806 glTranslatef(2, 0, 0);
807 createCylinder(0.8, 0.45, 1, 0);
812 void DrawCapacitor(Capacitor *c)
814 static GLfloat col[] = {0, 0, 0, 0};
815 static GLfloat spec[] = {0.8, 0.8, 0.8, 0};
816 GLfloat brown[] = {0.84, 0.5, 0};
817 static GLfloat shine = 40;
821 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, brown);
822 sphere(c->width, 15, 15, 0, 4 ,0, 15);
823 glTranslatef(1.35*c->width, 0, 0);
824 sphere(c->width, 15, 15, 11, 15, 0, 15);
825 glRotatef(90, 0, 0, 1);
826 glTranslatef(0, 0.7*c->width, 0.3*c->width);
828 glTranslatef(0, 0, -0.6*c->width);
831 glTranslatef(0-c->length*2, 0, 0);
832 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
833 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
834 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
836 glVertex3f(0, 0.82*c->width, -0.1);
837 glVertex3f(3*c->length, 0.82*c->width, -0.1);
838 glVertex3f(3*c->length, 0.82*c->width, 0.1);
839 glVertex3f(0, 0.82*c->width, 0.1);
844 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
845 glEnable(GL_POLYGON_OFFSET_FILL);
846 glPolygonOffset(1.0, 1.0);
847 createCylinder(3.0*c->length, 0.8*c->width, 1, 0);
848 glDisable(GL_POLYGON_OFFSET_FILL);
852 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
853 circle(0.6*c->width, 30, 0);
857 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
858 glTranslatef(3.0*c->length, 0.0, 0);
859 circle(0.6*c->width, 30, 0);
860 glTranslatef(0, 0.4*c->width, 0);
862 glTranslatef(0.0, -0.8*c->width, 0);
870 GLfloat col[] = {0, 0, 0, 0.6};
871 GLfloat black[] = {0, 0, 0, 0.6};
873 col[0] = l->r; col[1] = l->g; col[2] = l->b;
874 if (l->light && light) {
875 GLfloat dir[] = {-1, 0, 0};
876 glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, dir);
878 glLightfv(GL_LIGHT1, GL_SPECULAR, col);
879 glLightfv(GL_LIGHT1, GL_AMBIENT, black);
880 col[0] /= 1.5; col[1] /= 1.5; col[2] /= 1.5;
881 glLightfv(GL_LIGHT1, GL_DIFFUSE, col);
882 glLighti(GL_LIGHT1, GL_SPOT_CUTOFF, (GLint) 90);
883 glLighti(GL_LIGHT1, GL_CONSTANT_ATTENUATION, (GLfloat)1);
884 glLighti(GL_LIGHT1, GL_LINEAR_ATTENUATION, (GLfloat)0);
885 glLighti(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, (GLfloat)0);
886 glLighti(GL_LIGHT1, GL_SPOT_EXPONENT, (GLint) 20);
890 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
891 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
892 /* no transparency when LED is lit */
895 glDepthMask(GL_FALSE);
896 glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
898 glTranslatef(-0.9, 0, 0);
899 createCylinder(1.2, 0.3, 0, 0);
900 if (l->light && light) {
901 glDisable(GL_LIGHTING);
904 sphere(0.3, 7, 7, 3, 7, 0, 7);
905 if (l->light && light) {
906 glEnable(GL_LIGHTING);
908 glDepthMask(GL_TRUE);
912 glTranslatef(1.2, 0, 0);
913 createCylinder(0.1, 0.38, 1, 0);
914 glTranslatef(-0.3, 0.15, 0);
916 glTranslatef(0, -0.3, 0);
918 if (random() % 50 == 25) {
920 l->light = 0; light = 0; lighton = 0;
921 glDisable(GL_LIGHT1);
923 l->light = 1; light = 1;
929 void DrawThreeFive(ThreeFive *d)
932 GLfloat dark[] = {0.3, 0.3, 0.3, 0};
933 GLfloat light[] = {0.6, 0.6, 0.6, 0};
934 GLfloat cream[] = {0.8, 0.8, 0.6, 0};
935 GLfloat spec[] = {0.7, 0.7, 0.7, 0};
938 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
939 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cream);
940 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
942 glTranslatef(-2.0, 0, 0);
943 createCylinder(0.7, 0.2, 0, 0);
944 glTranslatef(0.7, 0, 0);
945 createCylinder(1.3, 0.4, 1, 0);
946 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light);
947 glTranslatef(1.3, 0, 0);
948 createCylinder(1.3, 0.2, 0, 0);
949 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, dark);
950 glTranslatef(0.65, 0, 0);
951 createCylinder(0.15, 0.21, 0, 0);
952 glTranslatef(0.3, 0, 0);
953 createCylinder(0.15, 0.21, 0, 0);
954 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light);
955 glTranslatef(0.4, 0, 0);
956 sphere(0.23, 7, 7, 0, 5, 0, 7);
961 void DrawDiode(Diode *d)
964 GLfloat col[] = {0.3, 0.3, 0.3, 0};
965 GLfloat spec[] = {0.7, 0.7, 0.7, 0};
968 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
969 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
970 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
971 glTranslatef(-4, 0, 0);
973 glTranslatef(3, 0, 0);
974 bandedCylinder(0.3, 1.5, d->r, d->g, d->b, &(d->band), 1);
975 glTranslatef(1.5, 0, 0);
980 void Rect(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h,
987 yh = y+h; xw = x+w; zt = z - t;
989 glBegin(GL_QUADS); /* front */
992 glVertex3f(x, yh, z);
993 glVertex3f(xw, yh, z);
994 glVertex3f(xw, y, z);
996 glNormal3f(0, 0, -1);
997 glVertex3f(x, y, zt);
998 glVertex3f(x, yh, zt);
999 glVertex3f(xw, yh, zt);
1000 glVertex3f(xw, y, zt);
1002 glNormal3f(0, 1, 0);
1003 glVertex3f(x, yh, z);
1004 glVertex3f(x, yh, zt);
1005 glVertex3f(xw, yh, zt);
1006 glVertex3f(xw, yh, z);
1008 glNormal3f(0, -1, 0);
1009 glVertex3f(x, y, z);
1010 glVertex3f(x, y, zt);
1011 glVertex3f(xw, y, zt);
1012 glVertex3f(xw, y, z);
1014 glNormal3f(-1, 0, 0);
1015 glVertex3f(x, y, z);
1016 glVertex3f(x, y, zt);
1017 glVertex3f(x, yh, zt);
1018 glVertex3f(x, yh, z);
1020 glNormal3f(1, 0, 0);
1021 glVertex3f(xw, y, z);
1022 glVertex3f(xw, y, zt);
1023 glVertex3f(xw, yh, zt);
1024 glVertex3f(xw, yh, z);
1030 void ICLeg(GLfloat x, GLfloat y, GLfloat z, int dir)
1033 Rect(x-0.1, y, z, 0.1, 0.1, 0.02);
1034 Rect(x-0.1, y, z, 0.02, 0.1, 0.1);
1035 Rect(x-0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
1037 Rect(x, y, z, 0.1, 0.1, 0.02);
1038 Rect(x+0.8*0.1, y, z, 0.02, 0.1, 0.1);
1039 Rect(x+0.8*0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
1049 GLfloat col[] = {0.1, 0.1, 0.1, 0};
1050 GLfloat col2[] = {0.2, 0.2, 0.2, 0};
1051 GLfloat spec[] = {0.6, 0.6, 0.6, 0};
1053 GLfloat lspec[] = {0.6, 0.6, 0.6, 0};
1054 GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
1055 GLfloat lshine = 40;
1056 float mult, th, size;
1059 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1060 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1061 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1062 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
1079 glEnable(GL_POLYGON_OFFSET_FILL);
1080 glPolygonOffset(1.0, 1.0);
1082 glNormal3f(0, 0, 1);
1083 glVertex3f(w, h, 0.1);
1084 glVertex3f(w, -h, 0.1);
1085 glVertex3f(-w, -h, 0.1);
1086 glVertex3f(-w, h, 0.1);
1087 glNormal3f(0, 0, -1);
1088 glVertex3f(w, h, -0.1);
1089 glVertex3f(w, -h, -0.1);
1090 glVertex3f(-w, -h, -0.1);
1091 glVertex3f(-w, h, -0.1);
1092 glNormal3f(1, 0, 0);
1093 glVertex3f(w, h, -0.1);
1094 glVertex3f(w, -h, -0.1);
1095 glVertex3f(w, -h, 0.1);
1096 glVertex3f(w, h, 0.1);
1097 glNormal3f(0, -1, 0);
1098 glVertex3f(w, -h, -0.1);
1099 glVertex3f(w, -h, 0.1);
1100 glVertex3f(-w, -h, 0.1);
1101 glVertex3f(-w, -h, -0.1);
1102 glNormal3f(-1, 0, 0);
1103 glVertex3f(-w, h, -0.1);
1104 glVertex3f(-w, h, 0.1);
1105 glVertex3f(-w, -h, 0.1);
1106 glVertex3f(-w, -h, -0.1);
1107 glNormal3f(0, -1, 0);
1108 glVertex3f(-w, h, -0.1);
1109 glVertex3f(w, h, -0.1);
1110 glVertex3f(w, h, 0.1);
1111 glVertex3f(-w, h, 0.1);
1113 glDisable(GL_POLYGON_OFFSET_FILL);
1114 if (c->tnum) glBindTexture(GL_TEXTURE_2D, c->tnum);
1115 glEnable(GL_TEXTURE_2D);
1122 mult = size*c->tw / c->th;
1124 glBegin(GL_QUADS); /* text markings */
1125 glNormal3f(0, 0, 1);
1127 glVertex3f(th, mult, 0.1);
1129 glVertex3f(th, -mult, 0.1);
1131 glVertex3f(-th, -mult, 0.1);
1133 glVertex3f(-th, mult, 0.1);
1135 glDisable(GL_TEXTURE_2D);
1136 glDisable(GL_BLEND);
1137 d = (h*2-0.1) / c->pins;
1139 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
1140 glMaterialfv(GL_FRONT, GL_SPECULAR, lspec);
1141 glMaterialfv(GL_FRONT, GL_SHININESS, &lshine);
1142 for (z = 0 ; z < c->pins/2 ; z++) {
1143 ICLeg(w, -h + z*d + d/2, 0, 0);
1145 for (z = 0 ; z < c->pins/2 ; z++) {
1146 ICLeg(-w, -h + z*d + d/2, 0, 1);
1148 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col2);
1149 glTranslatef(-w+0.3, h-0.3, 0.1);
1150 glRotatef(90, 0, 1, 0);
1155 void DrawDisp(Disp *d)
1157 GLfloat col[] = {0.8, 0.8, 0.8, 1.0}; /* body colour */
1158 GLfloat front[] = {0.2, 0.2, 0.2, 1.0}; /* front colour */
1159 GLfloat on[] = {0.9, 0, 0, 1}; /* 'on' segment */
1160 GLfloat off[] = {0.3, 0, 0, 1}; /* 'off' segment */
1162 GLfloat x, y; /* for the pins */
1163 GLfloat spec[] = {0.6, 0.6, 0.6, 0};
1164 GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
1166 static GLfloat vdata_h[6][2] = {
1174 static GLfloat vdata_v[6][2] = {
1183 static GLfloat seg_start[7][2] = {
1193 static int nums[10][7] = {
1194 {1, 1, 1, 1, 1, 1, 0}, /* 0 */
1195 {0, 1, 1, 0, 0, 0, 0}, /* 1 */
1196 {1, 1, 0, 1, 1, 0, 1}, /* 2 */
1197 {1, 1, 1, 1, 0, 0, 1}, /* 3 */
1198 {0, 1, 1, 0, 0, 1, 1}, /* 4 */
1199 {1, 0, 1, 1, 0, 1, 1}, /* 5 */
1200 {1, 0, 1, 1, 1, 1, 1}, /* 6 */
1201 {1, 1, 1, 0, 0, 0, 0}, /* 7 */
1202 {1, 1, 1, 1, 1, 1, 1}, /* 8 */
1203 {1, 1, 1, 0, 0, 1, 1} /* 9 */
1206 glTranslatef(-0.9, -1.8, 0);
1207 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1208 Rect(0, 0, -0.01, 1.8, 2.6, 0.7);
1209 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, front);
1211 glVertex2f(-0.05, -0.05);
1212 glVertex2f(-0.05, 2.65);
1213 glVertex2f(1.85, 2.65);
1214 glVertex2f(1.85, -0.05);
1216 glDisable(GL_LIGHTING); /* lit segments dont need light */
1217 if (!seven && (random() % 30) == 19) { /* randomly change value */
1218 d->value = random() % 10;
1220 for (j = 0 ; j < 7 ; j++) { /* draw the segments */
1221 GLfloat xx[6], yy[6];
1222 if (nums[d->value][j])
1226 for (k = 0 ; k < 6 ; k++) {
1227 if (j == 0 || j == 3 || j == 6) {
1228 xx[k] = seg_start[j][0] + vdata_h[k][0];
1229 yy[k] = seg_start[j][1] + vdata_h[k][1];
1231 xx[k] = seg_start[j][0] + vdata_v[k][0];
1232 yy[k] = seg_start[j][1] + vdata_v[k][1];
1235 glBegin(GL_POLYGON);
1236 for(i = 0 ; i < 6 ; i++) {
1237 glVertex3f(xx[i], yy[i], 0.01);
1244 glVertex3f(1.5, 0.2, 0.01);
1246 glEnable(GL_LIGHTING);
1247 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
1248 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1249 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
1250 for (x = 0.35 ; x <= 1.5 ; x+= 1.15) {
1251 for ( y = 0.2 ; y <= 2.4 ; y += 0.3) {
1252 ICLeg(x, y, -0.7, 1);
1257 void HoledRectangle(GLfloat w, GLfloat h, GLfloat d, GLfloat radius, int p)
1260 GLfloat x1, y1, x2, y2;
1261 GLfloat yr, yr1, xr, xr1, side, side1;
1265 x1 = radius; y1 = 0;
1270 for (a = 0 ; a <= 360 ; a+= step) {
1271 y2=radius*(float)sin_table[(int)a];
1272 x2=radius*(float)cos_table[(int)a];
1274 if (a < 45 || a > 315) {
1276 yr = side1 * tan_table[a];
1278 } else if (a <= 135 || a >= 225) {
1279 xr = side/tan_table[a];
1290 yr = -side1 * tan_table[a];
1294 glNormal3f(-x1, -y1, 0); /* cylinder */
1295 glVertex3f(x1,y1,0);
1296 glVertex3f(x1,y1,-d);
1297 glVertex3f(x2,y2,-d);
1298 glVertex3f(x2,y2,0);
1300 glNormal3f(0, 0, 1); /* front face */
1301 glVertex3f(x1,y1,0);
1302 glVertex3f(xr1, yr1, 0);
1303 glVertex3f(xr, yr, 0);
1304 glVertex3f(x2, y2, 0);
1306 glNormal3f(nx, ny, 0); /* side */
1307 glVertex3f(xr, yr, 0);
1308 glVertex3f(xr, yr, -d);
1309 glVertex3f(xr1, yr1, -d);
1310 glVertex3f(xr1, yr1, 0);
1312 glNormal3f(0, 0, -1); /* back */
1313 glVertex3f(xr, yr, -d);
1314 glVertex3f(x2, y2, -d);
1315 glVertex3f(x1, y1, -d);
1316 glVertex3f(xr1, yr1, -d);
1325 void DrawTransistor(Transistor *t)
1327 static GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
1328 static GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
1329 static GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
1333 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1334 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col);
1335 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1336 if (t->type == 1) { /* TO-92 style */
1338 mult = 1.5*t->th/t->tw;
1341 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1342 glRotatef(90, 0, 1, 0);
1343 glRotatef(90, 0, 0, 1);
1344 createCylinder(1.0, 0.4, 1, 1);
1345 Rect(0, -0.2, 0.4, 1, 0.2, 0.8);
1346 /* Draw the markings */
1347 glEnable(GL_TEXTURE_2D);
1348 if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
1350 glDepthMask(GL_FALSE);
1352 glNormal3f(0, 0, 1);
1354 glVertex3f(y1, -0.21, 0.3);
1356 glVertex3f(y1, -0.21, -0.3);
1358 glVertex3f(y2, -0.21, -0.3);
1360 glVertex3f(y2, -0.21, 0.3);
1362 glDisable(GL_TEXTURE_2D);
1363 glDisable(GL_BLEND);
1364 glDepthMask(GL_TRUE);
1365 glTranslatef(-2, 0, -0.2);
1367 glTranslatef(0, 0, 0.2);
1369 glTranslatef(0, 0, 0.2);
1371 } else if (t->type == 0) { /* TO-220 Style */
1373 mult = 1.5*t->th/t->tw;
1376 Rect(0, 0, 0, 1.5, 1.5, 0.5);
1377 glEnable(GL_TEXTURE_2D);
1378 if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
1380 glDepthMask(GL_FALSE);
1382 glNormal3f(0, 0, 1);
1384 glVertex3f(0, y1, 0.01);
1386 glVertex3f(1.5, y1, 0.01);
1388 glVertex3f(1.5, y2, 0.01);
1390 glVertex3f(0, y2, 0.01);
1392 glDisable(GL_TEXTURE_2D);
1393 glDisable(GL_BLEND);
1394 glDepthMask(GL_TRUE);
1395 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1396 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1397 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1398 Rect(0, 0, -0.5, 1.5, 1.5, 0.30);
1399 if (!glIsEnabled(GL_NORMALIZE)) glEnable(GL_NORMALIZE);
1400 glTranslatef(0.75, 1.875, -0.55);
1401 HoledRectangle(1.5, 0.75, 0.25, 0.2, 8);
1402 glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
1403 glTranslatef(-0.375, -1.875, 0);
1404 glRotatef(90, 0, 0, -1);
1406 glTranslatef(0, 0.375, 0);
1408 glTranslatef(0, 0.375, 0);
1410 } else { /* SMC transistor */
1412 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1413 glTranslatef(-0.5, -0.25, 0.1);
1414 Rect(0, 0, 0, 1, 0.5, 0.2);
1415 /* Draw the markings */
1416 glEnable(GL_TEXTURE_2D);
1417 if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
1419 glDepthMask(GL_FALSE);
1421 glNormal3f(0, 0, 1);
1423 glVertex3f(0.2, 0, 0.01);
1425 glVertex3f(0.8, 0, 0.01);
1427 glVertex3f(0.8, 0.5, 0.01);
1429 glVertex3f(0.2, 0.5, 0.01);
1431 glDisable(GL_TEXTURE_2D);
1432 glDisable(GL_BLEND);
1433 glDepthMask(GL_TRUE);
1434 /* Now draw the legs */
1435 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1436 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1437 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1438 Rect(0.25, -0.1, -0.05, 0.1, 0.1, 0.2);
1439 Rect(0.75, -0.1, -0.05, 0.1, 0.1, 0.2);
1440 Rect(0.5, 0.5, -0.05, 0.1, 0.1, 0.2);
1441 Rect(0.25, -0.2, -0.2, 0.1, 0.15, 0.1);
1442 Rect(0.75, -0.2, -0.2, 0.1, 0.15, 0.1);
1443 Rect(0.5, 0.5, -0.2, 0.1, 0.15, 0.1);
1448 Component * NewComponent(void)
1453 c = malloc(sizeof(Component));
1454 c->angle = RAND_RANGE(0,360);
1456 if (rnd < 0.25) { /* come from the top */
1458 c->x = RAND_RANGE(0, XMAX) - XMAX/2;
1460 c->dx = 0 - RAND_RANGE(0.5, 2);
1462 c->dx = RAND_RANGE(0.5, 2);
1463 c->dy = 0 - RAND_RANGE(0.5, 2);
1464 } else if (rnd < 0.5) { /* come from the bottom */
1466 c->x = RAND_RANGE(0, XMAX) - XMAX/2;
1468 c->dx = 0 - RAND_RANGE(0.5, 2);
1470 c->dx = RAND_RANGE(0.5, 2);
1471 c->dy = RAND_RANGE(0.5, 2);
1472 } else if (rnd < 0.75) { /* come from the left */
1474 c->y = RAND_RANGE(0, YMAX) - YMAX/2;
1475 c->dx = RAND_RANGE(0.5, 2);
1477 c->dy = 0 - RAND_RANGE(0.5, 2);
1479 c->dy = RAND_RANGE(0.5, 2);
1480 } else { /* come from the right */
1482 c->y = RAND_RANGE(0, YMAX) - YMAX/2;
1483 c->dx = 0 - RAND_RANGE(0.5, 2);
1485 c->dy = 0 - RAND_RANGE(0.5, 2);
1487 c->dy = RAND_RANGE(0.5, 2);
1489 c->z = RAND_RANGE(0, 7) - 9;
1493 c->drot = f_rand() * 3;
1495 c->dz = f_rand()*2 - 1;
1497 c->alpha = 0; /* explicitly set to 1 later */
1498 rnd = random() % 11;
1500 c->c = NewResistor();
1503 c->norm = 1; /* some resistors shine */
1504 } else if (rnd < 2) {
1507 c->norm = 1; /* some diodes shine */
1509 } else if (rnd < 3) {
1510 c->c = NewTransistor();
1513 } else if (rnd < 4) {
1514 c->c = NewCapacitor();
1517 } else if (rnd < 5) {
1521 } else if (rnd < 6) {
1526 } else if (rnd < 7) {
1531 } else if (rnd < 8) {
1535 } else if (rnd < 9) {
1536 c->c = NewThreeFive();
1539 } else if (rnd < 10) {
1550 Transistor *NewTransistor(void)
1553 float texfg[] = {0.7, 0.7, 0.7, 1.0};
1554 float texbg[] = {0.3, 0.3, 0.3, 0.1};
1558 t = malloc(sizeof(Transistor));
1559 t->type = (random() % 3);
1561 val = transistortypes[random() % countof(transistortypes)];
1562 tn = fonttexturealloc(val, texfg, texbg);
1564 fprintf(stderr, "Error getting a texture for a string!\n");
1568 t->tw = tn->w; t->th = tn->h;
1571 } else if (t->type == 2) {
1572 val = smctypes[random() % countof(smctypes)];
1573 tn = fonttexturealloc(val, texfg, texbg);
1575 fprintf(stderr, "Error getting a texture for a string!\n");
1579 t->tw = tn->w; t->th = tn->h;
1582 } else if (t->type == 1) {
1583 val = to92types[random() % countof(to92types)];
1584 tn = fonttexturealloc(val, texfg, texbg);
1586 fprintf(stderr, "Error getting a texture for a string!\n");
1590 t->tw = tn->w; t->th = tn->h;
1598 Capacitor *NewCapacitor(void)
1602 c = malloc(sizeof(Capacitor));
1603 c->type = (f_rand() < 0.5);
1605 c->length = RAND_RANGE(0.5, 1);
1606 c->width = RAND_RANGE(0.5, 1);
1608 c->width = RAND_RANGE(0.3, 1);
1613 /* 7 segment display */
1619 d = malloc(sizeof(Disp));
1623 d->value = RAND_RANGE(0, 10);
1633 float texfg[] = {0.7, 0.7, 0.7, 1.0};
1634 float texbg[] = {0.1, 0.1, 0.1, 0};
1637 int types[countof(ictypes)], i, n = 0;
1639 c = malloc(sizeof(IC));
1641 switch((int)RAND_RANGE(0,4)) {
1656 for (i = 0 ; i < countof(ictypes) ; i++) {
1657 if (ictypes[i].pins == pins) {
1663 if (n > countof(types)) abort();
1664 val = ictypes[types[random() % n]].val;
1665 str = malloc(strlen(val) + 1 + 4 + 1); /* add space for production date */
1666 sprintf(str, "%s\n%02d%02d", val, (int)RAND_RANGE(80, 100), (int)RAND_RANGE(1,53));
1667 tn = fonttexturealloc(str, texfg, texbg);
1670 fprintf(stderr, "Error allocating font texture for '%s'\n", val);
1673 c->tw = tn->w; c->th = tn->h;
1686 l = malloc(sizeof(LED));
1689 if (!light && (f_rand() < 0.4)) {
1694 l->r = 0.9; l->g = 0; l->b = 0;
1695 } else if (r < 0.4) {
1696 l->r = 0.3; l->g = 0.9; l->b = 0;
1697 } else if (r < 0.6) {
1698 l->r = 0.8; l->g = 0.9; l->b = 0;
1699 } else if (r < 0.8) {
1700 l->r = 0.0; l->g = 0.2; l->b = 0.8;
1702 l->r = 0.9, l->g = 0.55, l->b = 0;
1711 f = malloc(sizeof(Fuse));
1719 r = malloc(sizeof(RCA));
1720 r->col = (random() % 10 < 5);
1724 ThreeFive *NewThreeFive(void)
1728 r = malloc(sizeof(ThreeFive));
1732 Switch *NewSwitch(void)
1736 s = malloc(sizeof(Switch));
1741 Diode *NewDiode(void)
1746 ret = malloc(sizeof(Diode));
1747 b = malloc(sizeof(Band));
1750 if (f_rand() < 0.5) {
1754 ret->r = 0.7; ret->g = 0.1 ; ret->b = 0.1;
1759 ret->r = 0.2; ret->g = 0.2 ; ret->b = 0.2;
1766 Resistor * NewResistor(void)
1768 int v, m, t; /* value, multiplier, tolerance */
1773 t = (RAND(10) < 5) ? 10 : 11;
1774 ret = malloc(sizeof(Resistor));
1777 ret->b[0] = ret->b[1] = ret->b[2] = 7;
1779 ret->b[0] = values[v][0];
1780 ret->b[1] = values[v][1];
1788 void makebandlist(void)
1791 GLfloat col[] = {0,0,0,0};
1792 GLfloat spec[] = {0.8,0.8,0.8,0};
1795 for (i = 0 ; i < 12 ; i++) {
1796 band_list[i] = glGenLists(i);
1797 glNewList(band_list[i], GL_COMPILE);
1798 col[0] = colorcodes[i][0];
1799 col[1] = colorcodes[i][1];
1800 col[2] = colorcodes[i][2];
1801 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
1802 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
1803 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
1804 createCylinder(0.1, 0.42, 0, 0);
1810 void bandedCylinder(float radius, float l, GLfloat r, GLfloat g, GLfloat bl,
1811 Band **b, int nbands)
1813 int n; /* band number */
1814 int p = 0; /* prev number + 1; */
1815 GLfloat col[] = {0,0,0,0};
1817 col[0] = r; col[1] = g; col[2] = bl;
1818 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1819 createCylinder(l, radius, 1, 0); /* body */
1820 for (n = 0 ; n < nbands ; n++) {
1822 glTranslatef(b[n]->pos*l, 0, 0);
1823 col[0] = b[n]->r; col[1] = b[n]->g; col[2] = b[n]->b;
1824 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1825 createCylinder(b[n]->len*l, radius*1.05, 0, 0); /* band */
1834 static GLfloat col[] = {0, 0.25, 0.05};
1835 static GLfloat col2[] = {0, 0.125, 0.05};
1836 GLfloat col3[] = {0, 0.8, 0};
1837 static GLfloat sx, sy; /* bright spot co-ords */
1838 static int sdir; /* 0 = left-right, 1 = right-left, 2 = up->dn, 3 = dn->up */
1839 static int s = 0; /* if spot is enabled */
1840 static float ds; /* speed of spot */
1843 if (f_rand() < ((rotate) ? 0.05 : 0.01)) {
1844 sdir = RAND_RANGE(0, 4);
1845 ds = RAND_RANGE(0.4, 0.8);
1849 sy = ((int)RAND_RANGE(0, YMAX/2))*2 - YMAX/2;
1853 sy = ((int)RAND_RANGE(0, YMAX/2))*2 - YMAX/2;
1857 sx = ((int)RAND_RANGE(0, XMAX/2))*2 - XMAX/2;
1861 sx = ((int)RAND_RANGE(0, XMAX/2))*2 - XMAX/2;
1866 } else if (!rotate) {
1867 if (col[1] < 0.25) {
1868 col[1] += 0.025; col[2] += 0.005;
1869 col2[1] += 0.015 ; col2[2] += 0.005;
1873 glDisable(GL_LIGHTING);
1877 glTranslatef(sx, sy, -10);
1878 sphere(0.1, 10, 10, 0, 10, 0, 10);
1880 glTranslatef(-ds, 0, 0);
1882 glTranslatef(ds, 0, 0);
1884 glTranslatef(0, ds, 0);
1886 glTranslatef(0, -ds, 0);
1887 sphere(0.05, 10, 10, 0, 10, 0, 10);
1909 } else if (!rotate) {
1911 col[1] -= 0.0025; col[2] -= 0.0005;
1912 col2[1] -= 0.0015 ; col2[2] -= 0.0005;
1915 for (x = -XMAX/2 ; x <= XMAX/2 ; x+= 2) {
1918 glVertex3f(x, YMAX/2, -10);
1919 glVertex3f(x, -YMAX/2, -10);
1921 glVertex3f(x-0.02, YMAX/2, -10);
1922 glVertex3f(x-0.02, -YMAX/2, -10);
1923 glVertex3f(x+0.02, YMAX/2, -10);
1924 glVertex3f(x+0.02, -YMAX/2, -10);
1927 for (y = -YMAX/2 ; y <= YMAX/2 ; y+= 2) {
1930 glVertex3f(-XMAX/2, y, -10);
1931 glVertex3f(XMAX/2, y, -10);
1933 glVertex3f(-XMAX/2, y-0.02, -10);
1934 glVertex3f(XMAX/2, y-0.02, -10);
1935 glVertex3f(-XMAX/2, y+0.02, -10);
1936 glVertex3f(XMAX/2, y+0.02, -10);
1939 glEnable(GL_LIGHTING);
1944 static Component *c[MAX_COMPONENTS];
1946 GLfloat light_sp[] = {0.8, 0.8, 0.8, 1.0};
1947 GLfloat black[] = {0, 0, 0, 1.0};
1948 static GLfloat rotate_angle = 0; /* when 'rotate' is enabled */
1952 for (i = 0 ; i < maxparts ; i++) {
1956 glEnable(GL_LIGHTING);
1957 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
1959 gluLookAt(viewer[0], viewer[1], viewer[2], 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
1962 glRotatef(rotate_angle, 0, 0, 1);
1963 rotate_angle += 0.01 * (float)rotatespeed;
1964 if (rotate_angle >= 360) rotate_angle = 0;
1966 glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
1967 glLightfv(GL_LIGHT0, GL_SPECULAR, light_sp);
1968 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_sp);
1969 glLighti(GL_LIGHT0, GL_CONSTANT_ATTENUATION, (GLfloat)1);
1970 glLighti(GL_LIGHT0, GL_LINEAR_ATTENUATION, (GLfloat)0.5);
1971 glLighti(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, (GLfloat)0);
1973 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light_sp);
1974 if (f_rand() < 0.05) {
1975 for (j = 0 ; j < maxparts ; j++) {
1977 c[j] = NewComponent();
1983 for (j = 0 ; j < maxparts ; j++) {
1984 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, black);
1985 glMaterialfv(GL_FRONT, GL_EMISSION, black);
1986 glMaterialfv(GL_FRONT, GL_SPECULAR, black);
1988 if (DrawComponent(c[j])) {
1989 free(c[j]); c[j] = NULL;
1997 void freetexture (GLuint texture) {
1999 if (s_refs[texture] < 1) {
2000 glDeleteTextures(1, &texture);
2004 TexNum * fonttexturealloc (const char *str, float *fg, float *bg)
2006 static char *strings[50]; /* max of 40 textures */
2007 static int w[50], h[50];
2015 for (i = 0 ; i < 50 ; i++) {
2022 for (i = 0 ; i < 50 ; i++) {
2023 if (!s_refs[i] && strings[i]) {
2027 if (strings[i] && !strcmp(str, strings[i])) { /* if one matches */
2028 t = malloc(sizeof(TexNum));
2029 t->w = w[i]; t->h = h[i];
2035 /* at this point we need to make the new texture */
2036 ximage = text_to_ximage (modeinfo->xgwa.screen,
2037 modeinfo->xgwa.visual,
2040 for (i = 0 ; strings[i] != NULL ; i++) { /* set i to the next unused value */
2042 fprintf(stderr, "Texture cache full!\n");
2049 glBindTexture(GL_TEXTURE_2D, i);
2050 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2051 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2052 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2055 status = gluBuild2DMipmaps(GL_TEXTURE_2D, 4, ximage->width, ximage->height,
2056 GL_RGBA, GL_UNSIGNED_BYTE, ximage->data);
2059 const char *s = (char *) gluErrorString (status);
2060 fprintf (stderr, "%s: error mipmapping %dx%d texture: %s\n",
2061 progname, ximage->width, ximage->height,
2062 (s ? s : "(unknown)"));
2065 check_gl_error("mipmapping");
2067 t = malloc(sizeof(TexNum));
2068 t->w = ximage->width;
2069 t->h = ximage->height;
2070 w[i] = t->w; h[i] = t->h;
2074 c = malloc(strlen(str)+1);
2075 strncpy(c, str, strlen(str)+1);
2082 /* ensure transparent components are at the end */
2083 void reorder(Component *c[])
2086 Component *c1[MAX_COMPONENTS];
2087 Component *c2[MAX_COMPONENTS];
2090 for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
2094 for (i = 0 ; i < maxparts ; i++) {
2095 if (c[i] == NULL) continue;
2096 if (c[i]->alpha) { /* transparent parts go to c1 */
2099 } else { /* opaque parts go to c2 */
2103 for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
2107 for (i = 0 ; i < maxparts ; i++) { /* insert opaque part */
2108 if (c2[i] != NULL) {
2113 for (i = 0 ; i < j ; i++) { /* insert transparent parts */
2119 void reshape_circuit(ModeInfo *mi, int width, int height)
2121 GLfloat h = (GLfloat) height / (GLfloat) width;
2122 glViewport(0,0,(GLint)width, (GLint) height);
2123 glMatrixMode(GL_PROJECTION);
2125 glFrustum(-1.0,1.0,-h,h,1.5,35.0);
2126 glMatrixMode(GL_MODELVIEW);
2127 win_h = height; win_w = width;
2132 void init_circuit(ModeInfo *mi)
2134 int screen = MI_SCREEN(mi);
2137 if (circuit == NULL) {
2138 if ((circuit = (Circuit *) calloc(MI_NUM_SCREENS(mi),
2139 sizeof(Circuit))) == NULL)
2142 c = &circuit[screen];
2143 c->window = MI_WINDOW(mi);
2146 if ((c->glx_context = init_GL(mi)) != NULL) {
2147 reshape_circuit(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
2153 glClearColor(0.0,0.0,0.0,0.0);
2154 glShadeModel(GL_SMOOTH);
2155 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
2156 glEnable(GL_DEPTH_TEST);
2157 glEnable(GL_LIGHTING);
2158 glEnable(GL_LIGHT0);
2159 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2165 void draw_circuit(ModeInfo *mi)
2167 Circuit *c = &circuit[MI_SCREEN(mi)];
2168 Window w = MI_WINDOW(mi);
2169 Display *disp = MI_DISPLAY(mi);
2171 if (!c->glx_context)
2175 glXMakeCurrent(disp, w, *(c->glx_context));
2179 if(mi->fps_p) do_fps(mi);
2181 glXSwapBuffers(disp, w);
2184 void release_circuit(ModeInfo *mi)
2186 if (circuit != NULL) {
2187 (void) free((void *) circuit);