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"
50 #define DEFAULTS "*parts: " DEF_PARTS " \n" \
51 "*spin: " DEF_SPIN "\n" \
53 "*showFPS: False \n" \
54 "*seven: " DEF_SEVEN "\n" \
60 # include "xlockmore.h" /* from the xscreensaver distribution */
61 #else /* !STANDALONE */
62 # include "xlock.h" /* from the xlockmore distribution */
63 #endif /* !STANDALONE */
65 /* lifted from lament.c */
66 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
67 #define RANDSIGN() ((random() & 1) ? 1 : -1)
73 #include "font-ximage.h"
76 #define countof(x) (sizeof((x))/sizeof((*x)))
82 static int rotatespeed;
88 #define countof(x) (sizeof((x))/sizeof((*x)))
90 static XrmOptionDescRec opts[] = {
91 {"-parts", ".circuit.parts", XrmoptionSepArg, "10" },
92 {"-font", ".circuit.font", XrmoptionSepArg, "fixed" },
93 {"-rotate-speed", ".circuit.rotatespeed", XrmoptionSepArg, "1" },
94 {"+spin", ".circuit.spin", XrmoptionNoArg, "false" },
95 {"-spin", ".circuit.spin", XrmoptionNoArg, "true" },
96 {"+light", ".circuit.light", XrmoptionNoArg, "false" },
97 {"-light", ".circuit.light", XrmoptionNoArg, "true" },
98 {"+seven", ".circuit.seven", XrmoptionNoArg, "false" },
99 {"-seven", ".circuit.seven", XrmoptionNoArg, "true" },
100 {"+rotate", ".circuit.rotate", XrmoptionNoArg, "false" },
101 {"-rotate", ".circuit.rotate", XrmoptionNoArg, "true" },
104 static argtype vars[] = {
105 {&maxparts, "parts", "Parts", DEF_PARTS, t_Int},
106 {&font, "font", "Font", "fixed", t_String},
107 {&rotatespeed, "rotatespeed", "Rotatespeed", "1", t_Int},
108 {&spin, "spin", "Spin", DEF_SPIN, t_Bool},
109 {&rotate, "rotate", "Rotate", "False", t_Bool},
110 {&uselight, "light", "Light", "True", t_Bool},
111 {&seven, "seven", "Seven", DEF_SEVEN, t_Bool},
114 ModeSpecOpt circuit_opts = {countof(opts), opts, countof(vars), vars, NULL};
117 ModStruct circuit_description =
118 {"circuit", "init_circuit", "draw_circuit", "release_circuit",
119 "draw_circuit", "init_circuit", NULL, &circuit_opts,
120 1000, 1, 2, 1, 4, 1.0, "",
121 "Flying electronic components", 0, NULL};
127 GLXContext *glx_context;
131 static Circuit *circuit = NULL;
134 #include <sys/time.h>
139 #define M_PI 3.14159265
142 /* window width, height */
145 /* width and height of viewport */
148 static int YMAX = 30;
150 #define MAX_COMPONENTS 30
152 #define MOVE_MULT 0.02
154 static float f_rand(void) {
155 return ((float)RAND(10000)/(float)10000);
158 #define RAND_RANGE(min, max) ((min) + (max - min) * f_rand())
160 /* one lucky led gets to be a light source , unless -no-light*/
164 /* stores refs to textures */
165 static int s_refs[50];
167 static GLfloat viewer[] = {0.0, 0.0, 14.0};
168 static GLfloat lightpos[] = {7.0, 7.0, 15, 1.0};
170 float sin_table[720];
171 float cos_table[720];
172 float tan_table[720];
176 /* used for allocating font textures */
178 int num; /* index number */
183 /* Represents a band on a resistor/diode/etc */
185 float pos; /* relative position from start/previous band */
186 GLfloat r, g, b; /* colour of the band */
187 float len; /* length as a fraction of total length */
191 Band *b1, *b2, *b3, *b4; /* bands */
197 GLfloat r, g, b; /* body colour */
200 static const char * transistortypes[] = {
216 static const char * to92types[] = {
231 static const char * smctypes[] = {
242 int type; /* package type. 0 = to-92, 1 = to-220 */
243 GLfloat tw, th; /* texture dimensions */
244 GLuint tnum; /* texture binding */
248 GLfloat r,g,b; /* LED colour */
249 int light; /* are we the light source? */
253 int type; /* 0 = electro, 1 = ceramic */
254 float width; /* width of an electro/ceramic */
255 float length; /* length of an electro */
273 static const ICTypes ictypes[] = {
316 int type; /* 0 = DIL, 1 = flat square */
318 float tw, th; /* texture dimensions for markings */
319 int tnum; /* texture number */
322 /* 7 segment display */
325 int value; /* displayed number */
338 GLfloat x, y, z; /* current co-ordinates */
339 GLfloat dx, dy, dz; /* current direction */
340 GLfloat rotx, roty, rotz; /* rotation vector */
341 GLfloat drot; /* rotation velocity (degrees per frame) */
342 int norm; /* Normalize this component (for shine) */
343 int rdeg; /* current rotation degrees */
344 int angle; /* angle about the z axis */
345 int alpha; /* 0 if not a transparent component */
346 int type; /* 0 = resistor, 1 = diode, 2 = transistor, 3 = LED, 4 = cap, 5=IC,
348 void * c; /* pointer to the component */
351 static int band_list[12];
353 /* standard colour codes */
355 static GLfloat colorcodes [12][3] = {
356 {0.0,0.0,0.0}, /* black 0 */
357 {0.49,0.25,0.08}, /* brown 1 */
358 {1.0,0.0,0.0}, /* red 2 */
359 {1.0,0.5,0.0}, /* orange 3 */
360 {1.0,1.0,0.0}, /* yellow 4 */
361 {0.0,1.0,0.0}, /* green 5 */
362 {0.0,0.5,1.0}, /* blue 6 */
363 {0.7,0.2,1.0}, /* violet 7 */
364 {0.5,0.5,0.5}, /* grey 8 */
365 {1.0,1.0,1.0}, /* white 9 */
366 {0.66,0.56,0.2}, /* gold 10 */
367 {0.8,0.8,0.8}, /* silver 11 */
370 /* base values for components - we can multiply by 0 - 1M */
371 static int values [9][2] = {
383 void DrawResistor(Resistor *);
384 void DrawDiode(Diode *);
385 void DrawTransistor(Transistor *);
388 void DrawCapacitor(Capacitor *);
389 void DrawDisp(Disp *);
390 void DrawFuse(Fuse *);
392 void DrawThreeFive(ThreeFive *);
393 void DrawSwitch(Switch *);
395 void freetexture(GLuint);
396 void reorder(Component *[]);
397 void circle(float, int,int);
398 void bandedCylinder(float, float , GLfloat, GLfloat , GLfloat, Band **, int);
399 TexNum *fonttexturealloc(const char *, float *, float *);
400 void Rect(GLfloat , GLfloat , GLfloat, GLfloat , GLfloat ,GLfloat);
401 void ICLeg(GLfloat, GLfloat, GLfloat, int);
402 void HoledRectangle(GLfloat, GLfloat, GLfloat, GLfloat, int);
403 Resistor *NewResistor(void);
404 Diode *NewDiode(void);
405 Transistor *NewTransistor(void);
407 Capacitor *NewCapacitor(void);
412 ThreeFive *NewThreeFive(void);
413 Switch *NewSwitch(void);
415 /* we use trig tables to speed things up - 200 calls to sin()
416 in one frame can be a bit harsh..
419 void make_tables(void) {
423 f = 360 / (M_PI * 2);
424 for (i = 0 ; i < 720 ; i++) {
425 sin_table[i] = sin(i/f);
427 for (i = 0 ; i < 720 ; i++) {
428 cos_table[i] = cos(i/f);
430 for (i = 0 ; i < 720 ; i++) {
431 tan_table[i] = tan(i/f);
436 void createCylinder (float length, float radius, int endcaps, int half)
438 int a; /* current angle around cylinder */
440 float z1, y1, z2, y2,ex;
445 nsegs = radius*MAX(win_w, win_h)/20;
446 nsegs = MAX(nsegs, 4);
449 angle = (half) ? (180 - 90/nsegs) : 374;
453 for (a = 0 ; a <= angle ; a+= angle/nsegs) {
454 y2=radius*(float)sin_table[(int)a];
455 z2=radius*(float)cos_table[(int)a];
456 glNormal3f(0, y1, z1);
458 glVertex3f(length,y1,z1);
459 glNormal3f(0, y2, z2);
460 glVertex3f(length,y2,z2);
469 glVertex3f(0, 0, radius);
470 glVertex3f(length, 0, radius);
471 glVertex3f(length, 0, 0 - radius);
472 glVertex3f(0, 0, 0 - radius);
476 for(ex = 0 ; ex <= length ; ex += length) {
478 norm = (ex == length) ? 1 : -1;
479 glBegin(GL_TRIANGLES);
480 glNormal3f(norm, 0, 0);
481 for (a = 0 ; a <= angle ; a+= angle/nsegs) {
482 y2=radius*(float)sin_table[(int)a];
483 z2=radius*(float)cos_table[(int)a];
485 glVertex3f(ex,y1,z1);
486 glVertex3f(ex,y2,z2);
496 void circle(float radius, int segments, int half)
498 float x1 = 0, x2 = 0;
499 float y1 = 0, y2 = 0;
508 glBegin(GL_TRIANGLES);
513 x2=radius*(float)cos_table[(int)angle];
514 y2=radius*(float)sin_table[(int)angle];
526 static GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
527 static GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
528 static GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
532 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
533 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
534 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
535 n = glIsEnabled(GL_NORMALIZE);
536 if (!n) glEnable(GL_NORMALIZE);
537 createCylinder(len, 0.05, 1, 0);
538 if (!n) glDisable(GL_NORMALIZE);
539 glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
542 void ring(GLfloat inner, GLfloat outer, int nsegs)
544 GLfloat z1, z2, y1, y2;
545 GLfloat Z1, Z2, Y1, Y2;
552 for(i=0; i <=360 ; i+= 360/nsegs)
555 z2=inner*(float)sin_table[(int)angle];
556 y2=inner*(float)cos_table[(int)angle];
557 Z2=outer*(float)sin_table[(int)angle];
558 Y2=outer*(float)cos_table[(int)angle];
559 glVertex3f(0, Y1, Z1);
560 glVertex3f(0, y1, z1);
561 glVertex3f(0, y2, z2);
562 glVertex3f(0, Y2, Z2);
571 void sphere(GLfloat r, float stacks, float slices,
572 int startstack, int endstack, int startslice,
575 GLfloat d, d1, dr, dr1, Dr, Dr1, D, D1, z1, z2, y1, y2, Y1, Z1, Y2, Z2;
576 int a, a1, b, b1, c, c1;
581 a1 = startstack * step;
582 b1 = startslice * sstep;
583 y1 = z1 = Y1 = Z1 = 0;
584 c = (endslice / slices) * 360;
585 c1 = (endstack/stacks)*180;
587 for (a = startstack * step ; a <= c1 ; a+= step) {
596 for (b = b1 ; b <= c ; b+= sstep) {
601 glNormal3f(Dr, y1, z1);
602 glVertex3f(Dr,y1,z1);
603 glNormal3f(Dr, y2, z2);
604 glVertex3f(Dr,y2,z2);
605 glNormal3f(Dr1, Y2, Z2);
606 glVertex3f(Dr1,Y2,Z2);
607 glNormal3f(Dr1, Y1, Z1);
608 glVertex3f(Dr1,Y1,Z1);
619 int DrawComponent(Component *c)
621 int ret = 0; /* return 1 if component is freed */
624 glTranslatef(c->x, c->y, c->z);
626 glRotatef(c->angle, c->rotx, c->roty, c->rotz);
629 glRotatef(c->rdeg, c->rotx, c->roty, c->rotz);
634 glEnable(GL_NORMALIZE);
636 glDisable(GL_NORMALIZE);
638 /* call object draw routine here */
641 } else if (c->type == 1) {
643 } else if (c->type == 2) {
644 DrawTransistor(c->c);
645 } else if (c->type == 3) {
646 if (((LED *)c->c)->light && light) {
647 GLfloat lp[] = {0.1, 0, 0, 1};
649 glLightfv(GL_LIGHT1, GL_POSITION, lp);
652 } else if (c->type == 4) {
654 } else if (c->type == 5) {
656 } else if (c->type == 6) {
658 } else if (c->type == 7) {
660 } else if (c->type == 8) {
662 } else if (c->type == 9) {
664 } else if (c->type == 10) {
667 c->x += c->dx * MOVE_MULT;
668 c->y += c->dy * MOVE_MULT;
669 if (c->x > XMAX/2 || c->x < 0 - XMAX/2 ||
670 c->y > YMAX/2 || c->y < 0 - YMAX/2) {
671 if (c->type == 3 && ((LED *)c->c)->light && light) {
672 glDisable(GL_LIGHT1);
673 light = 0; lighton = 0;
676 if (((IC *)c->c)->tnum)
677 freetexture(((IC *)c->c)->tnum);
680 if (((Transistor *)c->c)->tnum)
681 freetexture(((Transistor *)c->c)->tnum);
684 free(((Diode *)c->c)->band); /* remember to free diode band */
690 glDisable(GL_NORMALIZE);
694 /* draw a resistor */
696 void DrawResistor(Resistor *r)
699 GLfloat col[] = {0.74, 0.62, 0.46, 1.0};
700 GLfloat spec[] = {0.8, 0.8, 0.8, 1.0};
703 glTranslatef(-4, 0, 0);
705 glTranslatef(3, 0, 0);
706 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
707 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
708 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
709 createCylinder(1.8, 0.4, 1, 0);
711 for (i = 0 ; i < 4 ; i++) {
712 glTranslatef(0.35, 0, 0);
713 glCallList(band_list[r->b[i]]);
716 glTranslatef(1.8, 0, 0);
720 void DrawRCA(RCA *rca)
722 static GLfloat col[] = {0.6, 0.6, 0.6, 1.0}; /* metal */
723 static GLfloat red[] = {1.0, 0.0, 0.0, 1.0}; /* red */
724 static GLfloat white[] = {1.0, 1.0, 1.0, 1.0}; /* white */
725 static GLfloat spec[] = {1, 1, 1, 1}; /* glass */
728 glTranslatef(0.3, 0, 0);
729 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
730 glMateriali(GL_FRONT, GL_SHININESS, 40);
731 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
732 createCylinder(0.7, 0.45, 0, 0);
733 glTranslatef(0.4, 0, 0);
734 createCylinder(0.9, 0.15, 1, 0);
735 glTranslatef(-1.9, 0, 0);
736 glMateriali(GL_FRONT, GL_SHININESS, 20);
737 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, rca->col ? white : red);
738 createCylinder(1.5, 0.6, 1, 0);
739 glTranslatef(-0.9, 0, 0);
740 createCylinder(0.9, 0.25, 0, 0);
741 glTranslatef(0.1, 0, 0);
742 createCylinder(0.2, 0.3, 0, 0);
743 glTranslatef(0.3, 0, 0);
744 createCylinder(0.2, 0.3, 1, 0);
745 glTranslatef(0.3, 0, 0);
746 createCylinder(0.2, 0.3, 1, 0);
750 void DrawSwitch(Switch *f)
752 static GLfloat col[] = {0.6, 0.6, 0.6, 0}; /* metal */
753 static GLfloat dark[] = {0.1, 0.1, 0.1, 1.0}; /* dark */
754 static GLfloat brown[] = {0.69, 0.32, 0, 1.0}; /* brown */
755 static GLfloat spec[] = {0.9, 0.9, 0.9, 1}; /* shiny */
758 glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
759 glMaterialfv(GL_FRONT, GL_AMBIENT, dark);
760 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
761 glMateriali(GL_FRONT, GL_SHININESS, 90);
762 Rect(-0.25, 0, 0, 1.5, 0.5, 0.75);
763 /* Rect(-0.5, 0.5, 0, 2, 0.1, 0.75); */
765 glRotatef(90, 1, 0, 0);
766 glTranslatef(-0.5, -0.4, -0.4);
767 HoledRectangle(0.5, 0.75, 0.1, 0.15, 8);
768 glTranslatef(2, 0, 0);
769 HoledRectangle(0.5, 0.75, 0.1, 0.15, 8);
771 Rect(0.1, -0.4, -0.25, 0.1, 0.4, 0.05);
772 Rect(0.5, -0.4, -0.25, 0.1, 0.4, 0.05);
773 Rect(0.9, -0.4, -0.25, 0.1, 0.4, 0.05);
774 Rect(0.1, -0.4, -0.5, 0.1, 0.4, 0.05);
775 Rect(0.5, -0.4, -0.5, 0.1, 0.4, 0.05);
776 Rect(0.9, -0.4, -0.5, 0.1, 0.4, 0.05);
777 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, dark);
778 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
779 Rect(0, 0.5, -0.1, 1, 0.05, 0.5);
780 Rect(0, 0.6, -0.1, 0.5, 0.6, 0.5);
781 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, brown);
782 Rect(-0.2, -0.01, -0.1, 1.4, 0.1, 0.55);
787 void DrawFuse(Fuse *f)
789 static GLfloat col[] = {0.5, 0.5, 0.5, 1.0}; /* endcaps */
790 static GLfloat glass[] = {0.4, 0.4, 0.4, 0.3}; /* glass */
791 static GLfloat spec[] = {1, 1, 1, 1}; /* glass */
794 glTranslatef(-1.8, 0, 0);
795 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
796 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
797 glMateriali(GL_FRONT, GL_SHININESS, 40);
798 createCylinder(0.8, 0.45, 1, 0);
799 glTranslatef(0.8, 0, 0);
801 glDepthMask(GL_FALSE);
802 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, glass);
803 glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 40);
804 createCylinder(2, 0.4, 0, 0);
805 createCylinder(2, 0.3, 0, 0);
807 glDepthMask(GL_TRUE);
808 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
809 glMateriali(GL_FRONT, GL_SHININESS, 40);
812 glVertex3f(2, 0. ,0);
814 glTranslatef(2, 0, 0);
815 createCylinder(0.8, 0.45, 1, 0);
820 void DrawCapacitor(Capacitor *c)
822 static GLfloat col[] = {0, 0, 0, 0};
823 static GLfloat spec[] = {0.8, 0.8, 0.8, 0};
824 GLfloat brown[] = {0.84, 0.5, 0};
825 static GLfloat shine = 40;
829 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, brown);
830 sphere(c->width, 15, 15, 0, 4 ,0, 15);
831 glTranslatef(1.35*c->width, 0, 0);
832 sphere(c->width, 15, 15, 11, 15, 0, 15);
833 glRotatef(90, 0, 0, 1);
834 glTranslatef(0, 0.7*c->width, 0.3*c->width);
836 glTranslatef(0, 0, -0.6*c->width);
839 glTranslatef(0-c->length*2, 0, 0);
840 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
841 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
842 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
844 glVertex3f(0, 0.82*c->width, -0.1);
845 glVertex3f(3*c->length, 0.82*c->width, -0.1);
846 glVertex3f(3*c->length, 0.82*c->width, 0.1);
847 glVertex3f(0, 0.82*c->width, 0.1);
852 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
853 glEnable(GL_POLYGON_OFFSET_FILL);
854 glPolygonOffset(1.0, 1.0);
855 createCylinder(3.0*c->length, 0.8*c->width, 1, 0);
856 glDisable(GL_POLYGON_OFFSET_FILL);
860 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
861 circle(0.6*c->width, 30, 0);
865 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
866 glTranslatef(3.0*c->length, 0.0, 0);
867 circle(0.6*c->width, 30, 0);
868 glTranslatef(0, 0.4*c->width, 0);
870 glTranslatef(0.0, -0.8*c->width, 0);
878 GLfloat col[] = {0, 0, 0, 0.6};
879 GLfloat black[] = {0, 0, 0, 0.6};
881 col[0] = l->r; col[1] = l->g; col[2] = l->b;
882 if (l->light && light) {
883 GLfloat dir[] = {-1, 0, 0};
884 glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, dir);
886 glLightfv(GL_LIGHT1, GL_SPECULAR, col);
887 glLightfv(GL_LIGHT1, GL_AMBIENT, black);
888 col[0] /= 1.5; col[1] /= 1.5; col[2] /= 1.5;
889 glLightfv(GL_LIGHT1, GL_DIFFUSE, col);
890 glLighti(GL_LIGHT1, GL_SPOT_CUTOFF, (GLint) 90);
891 glLighti(GL_LIGHT1, GL_CONSTANT_ATTENUATION, (GLfloat)1);
892 glLighti(GL_LIGHT1, GL_LINEAR_ATTENUATION, (GLfloat)0);
893 glLighti(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, (GLfloat)0);
894 glLighti(GL_LIGHT1, GL_SPOT_EXPONENT, (GLint) 20);
898 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
899 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
900 /* no transparency when LED is lit */
903 glDepthMask(GL_FALSE);
904 glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
906 glTranslatef(-0.9, 0, 0);
907 createCylinder(1.2, 0.3, 0, 0);
908 if (l->light && light) {
909 glDisable(GL_LIGHTING);
912 sphere(0.3, 7, 7, 3, 7, 0, 7);
913 if (l->light && light) {
914 glEnable(GL_LIGHTING);
916 glDepthMask(GL_TRUE);
920 glTranslatef(1.2, 0, 0);
921 createCylinder(0.1, 0.38, 1, 0);
922 glTranslatef(-0.3, 0.15, 0);
924 glTranslatef(0, -0.3, 0);
926 if (random() % 50 == 25) {
928 l->light = 0; light = 0; lighton = 0;
929 glDisable(GL_LIGHT1);
931 l->light = 1; light = 1;
937 void DrawThreeFive(ThreeFive *d)
940 GLfloat dark[] = {0.3, 0.3, 0.3, 0};
941 GLfloat light[] = {0.6, 0.6, 0.6, 0};
942 GLfloat cream[] = {0.8, 0.8, 0.6, 0};
943 GLfloat spec[] = {0.7, 0.7, 0.7, 0};
946 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
947 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cream);
948 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
950 glTranslatef(-2.0, 0, 0);
951 createCylinder(0.7, 0.2, 0, 0);
952 glTranslatef(0.7, 0, 0);
953 createCylinder(1.3, 0.4, 1, 0);
954 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light);
955 glTranslatef(1.3, 0, 0);
956 createCylinder(1.3, 0.2, 0, 0);
957 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, dark);
958 glTranslatef(0.65, 0, 0);
959 createCylinder(0.15, 0.21, 0, 0);
960 glTranslatef(0.3, 0, 0);
961 createCylinder(0.15, 0.21, 0, 0);
962 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light);
963 glTranslatef(0.4, 0, 0);
964 sphere(0.23, 7, 7, 0, 5, 0, 7);
969 void DrawDiode(Diode *d)
972 GLfloat col[] = {0.3, 0.3, 0.3, 0};
973 GLfloat spec[] = {0.7, 0.7, 0.7, 0};
976 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
977 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
978 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
979 glTranslatef(-4, 0, 0);
981 glTranslatef(3, 0, 0);
982 bandedCylinder(0.3, 1.5, d->r, d->g, d->b, &(d->band), 1);
983 glTranslatef(1.5, 0, 0);
988 void Rect(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h,
995 yh = y+h; xw = x+w; zt = z - t;
997 glBegin(GL_QUADS); /* front */
1000 glVertex3f(x, yh, z);
1001 glVertex3f(xw, yh, z);
1002 glVertex3f(xw, y, z);
1004 glNormal3f(0, 0, -1);
1005 glVertex3f(x, y, zt);
1006 glVertex3f(x, yh, zt);
1007 glVertex3f(xw, yh, zt);
1008 glVertex3f(xw, y, zt);
1010 glNormal3f(0, 1, 0);
1011 glVertex3f(x, yh, z);
1012 glVertex3f(x, yh, zt);
1013 glVertex3f(xw, yh, zt);
1014 glVertex3f(xw, yh, z);
1016 glNormal3f(0, -1, 0);
1017 glVertex3f(x, y, z);
1018 glVertex3f(x, y, zt);
1019 glVertex3f(xw, y, zt);
1020 glVertex3f(xw, y, z);
1022 glNormal3f(-1, 0, 0);
1023 glVertex3f(x, y, z);
1024 glVertex3f(x, y, zt);
1025 glVertex3f(x, yh, zt);
1026 glVertex3f(x, yh, z);
1028 glNormal3f(1, 0, 0);
1029 glVertex3f(xw, y, z);
1030 glVertex3f(xw, y, zt);
1031 glVertex3f(xw, yh, zt);
1032 glVertex3f(xw, yh, z);
1038 void ICLeg(GLfloat x, GLfloat y, GLfloat z, int dir)
1041 Rect(x-0.1, y, z, 0.1, 0.1, 0.02);
1042 Rect(x-0.1, y, z, 0.02, 0.1, 0.1);
1043 Rect(x-0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
1045 Rect(x, y, z, 0.1, 0.1, 0.02);
1046 Rect(x+0.8*0.1, y, z, 0.02, 0.1, 0.1);
1047 Rect(x+0.8*0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
1057 GLfloat col[] = {0.1, 0.1, 0.1, 0};
1058 GLfloat col2[] = {0.2, 0.2, 0.2, 0};
1059 GLfloat spec[] = {0.6, 0.6, 0.6, 0};
1061 GLfloat lspec[] = {0.6, 0.6, 0.6, 0};
1062 GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
1063 GLfloat lshine = 40;
1064 float mult, th, size;
1067 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1068 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1069 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1070 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
1087 glEnable(GL_POLYGON_OFFSET_FILL);
1088 glPolygonOffset(1.0, 1.0);
1090 glNormal3f(0, 0, 1);
1091 glVertex3f(w, h, 0.1);
1092 glVertex3f(w, -h, 0.1);
1093 glVertex3f(-w, -h, 0.1);
1094 glVertex3f(-w, h, 0.1);
1095 glNormal3f(0, 0, -1);
1096 glVertex3f(w, h, -0.1);
1097 glVertex3f(w, -h, -0.1);
1098 glVertex3f(-w, -h, -0.1);
1099 glVertex3f(-w, h, -0.1);
1100 glNormal3f(1, 0, 0);
1101 glVertex3f(w, h, -0.1);
1102 glVertex3f(w, -h, -0.1);
1103 glVertex3f(w, -h, 0.1);
1104 glVertex3f(w, h, 0.1);
1105 glNormal3f(0, -1, 0);
1106 glVertex3f(w, -h, -0.1);
1107 glVertex3f(w, -h, 0.1);
1108 glVertex3f(-w, -h, 0.1);
1109 glVertex3f(-w, -h, -0.1);
1110 glNormal3f(-1, 0, 0);
1111 glVertex3f(-w, h, -0.1);
1112 glVertex3f(-w, h, 0.1);
1113 glVertex3f(-w, -h, 0.1);
1114 glVertex3f(-w, -h, -0.1);
1115 glNormal3f(0, -1, 0);
1116 glVertex3f(-w, h, -0.1);
1117 glVertex3f(w, h, -0.1);
1118 glVertex3f(w, h, 0.1);
1119 glVertex3f(-w, h, 0.1);
1121 glDisable(GL_POLYGON_OFFSET_FILL);
1122 if (c->tnum) glBindTexture(GL_TEXTURE_2D, c->tnum);
1123 glEnable(GL_TEXTURE_2D);
1130 mult = size*c->tw / c->th;
1132 glBegin(GL_QUADS); /* text markings */
1133 glNormal3f(0, 0, 1);
1135 glVertex3f(th, mult, 0.1);
1137 glVertex3f(th, -mult, 0.1);
1139 glVertex3f(-th, -mult, 0.1);
1141 glVertex3f(-th, mult, 0.1);
1143 glDisable(GL_TEXTURE_2D);
1144 glDisable(GL_BLEND);
1145 d = (h*2-0.1) / c->pins;
1147 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
1148 glMaterialfv(GL_FRONT, GL_SPECULAR, lspec);
1149 glMaterialfv(GL_FRONT, GL_SHININESS, &lshine);
1150 for (z = 0 ; z < c->pins/2 ; z++) {
1151 ICLeg(w, -h + z*d + d/2, 0, 0);
1153 for (z = 0 ; z < c->pins/2 ; z++) {
1154 ICLeg(-w, -h + z*d + d/2, 0, 1);
1156 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col2);
1157 glTranslatef(-w+0.3, h-0.3, 0.1);
1158 glRotatef(90, 0, 1, 0);
1163 void DrawDisp(Disp *d)
1165 GLfloat col[] = {0.8, 0.8, 0.8, 1.0}; /* body colour */
1166 GLfloat front[] = {0.2, 0.2, 0.2, 1.0}; /* front colour */
1167 GLfloat on[] = {0.9, 0, 0, 1}; /* 'on' segment */
1168 GLfloat off[] = {0.3, 0, 0, 1}; /* 'off' segment */
1170 GLfloat x, y; /* for the pins */
1171 GLfloat spec[] = {0.6, 0.6, 0.6, 0};
1172 GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
1174 static GLfloat vdata_h[6][2] = {
1182 static GLfloat vdata_v[6][2] = {
1191 static GLfloat seg_start[7][2] = {
1201 static int nums[10][7] = {
1202 {1, 1, 1, 1, 1, 1, 0}, /* 0 */
1203 {0, 1, 1, 0, 0, 0, 0}, /* 1 */
1204 {1, 1, 0, 1, 1, 0, 1}, /* 2 */
1205 {1, 1, 1, 1, 0, 0, 1}, /* 3 */
1206 {0, 1, 1, 0, 0, 1, 1}, /* 4 */
1207 {1, 0, 1, 1, 0, 1, 1}, /* 5 */
1208 {1, 0, 1, 1, 1, 1, 1}, /* 6 */
1209 {1, 1, 1, 0, 0, 0, 0}, /* 7 */
1210 {1, 1, 1, 1, 1, 1, 1}, /* 8 */
1211 {1, 1, 1, 0, 0, 1, 1} /* 9 */
1214 glTranslatef(-0.9, -1.8, 0);
1215 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1216 Rect(0, 0, -0.01, 1.8, 2.6, 0.7);
1217 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, front);
1219 glVertex2f(-0.05, -0.05);
1220 glVertex2f(-0.05, 2.65);
1221 glVertex2f(1.85, 2.65);
1222 glVertex2f(1.85, -0.05);
1224 glDisable(GL_LIGHTING); /* lit segments dont need light */
1225 if (!seven && (random() % 30) == 19) { /* randomly change value */
1226 d->value = random() % 10;
1228 for (j = 0 ; j < 7 ; j++) { /* draw the segments */
1229 GLfloat xx[6], yy[6];
1230 if (nums[d->value][j])
1234 for (k = 0 ; k < 6 ; k++) {
1235 if (j == 0 || j == 3 || j == 6) {
1236 xx[k] = seg_start[j][0] + vdata_h[k][0];
1237 yy[k] = seg_start[j][1] + vdata_h[k][1];
1239 xx[k] = seg_start[j][0] + vdata_v[k][0];
1240 yy[k] = seg_start[j][1] + vdata_v[k][1];
1243 glBegin(GL_POLYGON);
1244 for(i = 0 ; i < 6 ; i++) {
1245 glVertex3f(xx[i], yy[i], 0.01);
1252 glVertex3f(1.5, 0.2, 0.01);
1254 glEnable(GL_LIGHTING);
1255 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
1256 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1257 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
1258 for (x = 0.35 ; x <= 1.5 ; x+= 1.15) {
1259 for ( y = 0.2 ; y <= 2.4 ; y += 0.3) {
1260 ICLeg(x, y, -0.7, 1);
1265 void HoledRectangle(GLfloat w, GLfloat h, GLfloat d, GLfloat radius, int p)
1268 GLfloat x1, y1, x2, y2;
1269 GLfloat yr, yr1, xr, xr1, side, side1;
1273 x1 = radius; y1 = 0;
1278 for (a = 0 ; a <= 360 ; a+= step) {
1279 y2=radius*(float)sin_table[(int)a];
1280 x2=radius*(float)cos_table[(int)a];
1282 if (a < 45 || a > 315) {
1284 yr = side1 * tan_table[a];
1286 } else if (a <= 135 || a >= 225) {
1287 xr = side/tan_table[a];
1298 yr = -side1 * tan_table[a];
1302 glNormal3f(-x1, -y1, 0); /* cylinder */
1303 glVertex3f(x1,y1,0);
1304 glVertex3f(x1,y1,-d);
1305 glVertex3f(x2,y2,-d);
1306 glVertex3f(x2,y2,0);
1308 glNormal3f(0, 0, 1); /* front face */
1309 glVertex3f(x1,y1,0);
1310 glVertex3f(xr1, yr1, 0);
1311 glVertex3f(xr, yr, 0);
1312 glVertex3f(x2, y2, 0);
1314 glNormal3f(nx, ny, 0); /* side */
1315 glVertex3f(xr, yr, 0);
1316 glVertex3f(xr, yr, -d);
1317 glVertex3f(xr1, yr1, -d);
1318 glVertex3f(xr1, yr1, 0);
1320 glNormal3f(0, 0, -1); /* back */
1321 glVertex3f(xr, yr, -d);
1322 glVertex3f(x2, y2, -d);
1323 glVertex3f(x1, y1, -d);
1324 glVertex3f(xr1, yr1, -d);
1333 void DrawTransistor(Transistor *t)
1335 static GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
1336 static GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
1337 static GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
1341 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1342 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col);
1343 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1344 if (t->type == 1) { /* TO-92 style */
1346 mult = 1.5*t->th/t->tw;
1349 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1350 glRotatef(90, 0, 1, 0);
1351 glRotatef(90, 0, 0, 1);
1352 createCylinder(1.0, 0.4, 1, 1);
1353 Rect(0, -0.2, 0.4, 1, 0.2, 0.8);
1354 /* Draw the markings */
1355 glEnable(GL_TEXTURE_2D);
1356 if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
1358 glDepthMask(GL_FALSE);
1360 glNormal3f(0, 0, 1);
1362 glVertex3f(y1, -0.21, 0.3);
1364 glVertex3f(y1, -0.21, -0.3);
1366 glVertex3f(y2, -0.21, -0.3);
1368 glVertex3f(y2, -0.21, 0.3);
1370 glDisable(GL_TEXTURE_2D);
1371 glDisable(GL_BLEND);
1372 glDepthMask(GL_TRUE);
1373 glTranslatef(-2, 0, -0.2);
1375 glTranslatef(0, 0, 0.2);
1377 glTranslatef(0, 0, 0.2);
1379 } else if (t->type == 0) { /* TO-220 Style */
1381 mult = 1.5*t->th/t->tw;
1384 Rect(0, 0, 0, 1.5, 1.5, 0.5);
1385 glEnable(GL_TEXTURE_2D);
1386 if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
1388 glDepthMask(GL_FALSE);
1390 glNormal3f(0, 0, 1);
1392 glVertex3f(0, y1, 0.01);
1394 glVertex3f(1.5, y1, 0.01);
1396 glVertex3f(1.5, y2, 0.01);
1398 glVertex3f(0, y2, 0.01);
1400 glDisable(GL_TEXTURE_2D);
1401 glDisable(GL_BLEND);
1402 glDepthMask(GL_TRUE);
1403 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1404 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1405 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1406 Rect(0, 0, -0.5, 1.5, 1.5, 0.30);
1407 if (!glIsEnabled(GL_NORMALIZE)) glEnable(GL_NORMALIZE);
1408 glTranslatef(0.75, 1.875, -0.55);
1409 HoledRectangle(1.5, 0.75, 0.25, 0.2, 8);
1410 glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
1411 glTranslatef(-0.375, -1.875, 0);
1412 glRotatef(90, 0, 0, -1);
1414 glTranslatef(0, 0.375, 0);
1416 glTranslatef(0, 0.375, 0);
1418 } else { /* SMC transistor */
1420 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1421 glTranslatef(-0.5, -0.25, 0.1);
1422 Rect(0, 0, 0, 1, 0.5, 0.2);
1423 /* Draw the markings */
1424 glEnable(GL_TEXTURE_2D);
1425 if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
1427 glDepthMask(GL_FALSE);
1429 glNormal3f(0, 0, 1);
1431 glVertex3f(0.2, 0, 0.01);
1433 glVertex3f(0.8, 0, 0.01);
1435 glVertex3f(0.8, 0.5, 0.01);
1437 glVertex3f(0.2, 0.5, 0.01);
1439 glDisable(GL_TEXTURE_2D);
1440 glDisable(GL_BLEND);
1441 glDepthMask(GL_TRUE);
1442 /* Now draw the legs */
1443 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1444 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1445 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1446 Rect(0.25, -0.1, -0.05, 0.1, 0.1, 0.2);
1447 Rect(0.75, -0.1, -0.05, 0.1, 0.1, 0.2);
1448 Rect(0.5, 0.5, -0.05, 0.1, 0.1, 0.2);
1449 Rect(0.25, -0.2, -0.2, 0.1, 0.15, 0.1);
1450 Rect(0.75, -0.2, -0.2, 0.1, 0.15, 0.1);
1451 Rect(0.5, 0.5, -0.2, 0.1, 0.15, 0.1);
1456 Component * NewComponent(void)
1461 c = malloc(sizeof(Component));
1462 c->angle = RAND_RANGE(0,360);
1464 if (rnd < 0.25) { /* come from the top */
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 = 0 - RAND_RANGE(0.5, 2);
1472 } else if (rnd < 0.5) { /* come from the bottom */
1474 c->x = RAND_RANGE(0, XMAX) - XMAX/2;
1476 c->dx = 0 - RAND_RANGE(0.5, 2);
1478 c->dx = RAND_RANGE(0.5, 2);
1479 c->dy = RAND_RANGE(0.5, 2);
1480 } else if (rnd < 0.75) { /* come from the left */
1482 c->y = RAND_RANGE(0, YMAX) - YMAX/2;
1483 c->dx = RAND_RANGE(0.5, 2);
1485 c->dy = 0 - RAND_RANGE(0.5, 2);
1487 c->dy = RAND_RANGE(0.5, 2);
1488 } else { /* come from the right */
1490 c->y = RAND_RANGE(0, YMAX) - YMAX/2;
1491 c->dx = 0 - RAND_RANGE(0.5, 2);
1493 c->dy = 0 - RAND_RANGE(0.5, 2);
1495 c->dy = RAND_RANGE(0.5, 2);
1497 c->z = RAND_RANGE(0, 7) - 9;
1501 c->drot = f_rand() * 3;
1503 c->dz = f_rand()*2 - 1;
1505 c->alpha = 0; /* explicitly set to 1 later */
1506 rnd = random() % 11;
1508 c->c = NewResistor();
1511 c->norm = 1; /* some resistors shine */
1512 } else if (rnd < 2) {
1515 c->norm = 1; /* some diodes shine */
1517 } else if (rnd < 3) {
1518 c->c = NewTransistor();
1521 } else if (rnd < 4) {
1522 c->c = NewCapacitor();
1525 } else if (rnd < 5) {
1529 } else if (rnd < 6) {
1534 } else if (rnd < 7) {
1539 } else if (rnd < 8) {
1543 } else if (rnd < 9) {
1544 c->c = NewThreeFive();
1547 } else if (rnd < 10) {
1558 Transistor *NewTransistor(void)
1561 float texfg[] = {0.7, 0.7, 0.7, 1.0};
1562 float texbg[] = {0.3, 0.3, 0.3, 0.1};
1566 t = malloc(sizeof(Transistor));
1567 t->type = (random() % 3);
1569 val = transistortypes[random() % countof(transistortypes)];
1570 tn = fonttexturealloc(val, texfg, texbg);
1572 fprintf(stderr, "Error getting a texture for a string!\n");
1576 t->tw = tn->w; t->th = tn->h;
1579 } else if (t->type == 2) {
1580 val = smctypes[random() % countof(smctypes)];
1581 tn = fonttexturealloc(val, texfg, texbg);
1583 fprintf(stderr, "Error getting a texture for a string!\n");
1587 t->tw = tn->w; t->th = tn->h;
1590 } else if (t->type == 1) {
1591 val = to92types[random() % countof(to92types)];
1592 tn = fonttexturealloc(val, texfg, texbg);
1594 fprintf(stderr, "Error getting a texture for a string!\n");
1598 t->tw = tn->w; t->th = tn->h;
1606 Capacitor *NewCapacitor(void)
1610 c = malloc(sizeof(Capacitor));
1611 c->type = (f_rand() < 0.5);
1613 c->length = RAND_RANGE(0.5, 1);
1614 c->width = RAND_RANGE(0.5, 1);
1616 c->width = RAND_RANGE(0.3, 1);
1621 /* 7 segment display */
1627 d = malloc(sizeof(Disp));
1631 d->value = RAND_RANGE(0, 10);
1641 float texfg[] = {0.7, 0.7, 0.7, 1.0};
1642 float texbg[] = {0.1, 0.1, 0.1, 0};
1645 int types[countof(ictypes)], i, n = 0;
1647 c = malloc(sizeof(IC));
1649 switch((int)RAND_RANGE(0,4)) {
1664 for (i = 0 ; i < countof(ictypes) ; i++) {
1665 if (ictypes[i].pins == pins) {
1671 if (n > countof(types)) abort();
1672 val = ictypes[types[random() % n]].val;
1673 str = malloc(strlen(val) + 1 + 4 + 1); /* add space for production date */
1674 sprintf(str, "%s\n%02d%02d", val, (int)RAND_RANGE(80, 100), (int)RAND_RANGE(1,53));
1675 tn = fonttexturealloc(str, texfg, texbg);
1678 fprintf(stderr, "Error allocating font texture for '%s'\n", val);
1681 c->tw = tn->w; c->th = tn->h;
1694 l = malloc(sizeof(LED));
1697 if (!light && (f_rand() < 0.4)) {
1702 l->r = 0.9; l->g = 0; l->b = 0;
1703 } else if (r < 0.4) {
1704 l->r = 0.3; l->g = 0.9; l->b = 0;
1705 } else if (r < 0.6) {
1706 l->r = 0.8; l->g = 0.9; l->b = 0;
1707 } else if (r < 0.8) {
1708 l->r = 0.0; l->g = 0.2; l->b = 0.8;
1710 l->r = 0.9, l->g = 0.55, l->b = 0;
1719 f = malloc(sizeof(Fuse));
1727 r = malloc(sizeof(RCA));
1728 r->col = (random() % 10 < 5);
1732 ThreeFive *NewThreeFive(void)
1736 r = malloc(sizeof(ThreeFive));
1740 Switch *NewSwitch(void)
1744 s = malloc(sizeof(Switch));
1749 Diode *NewDiode(void)
1754 ret = malloc(sizeof(Diode));
1755 b = malloc(sizeof(Band));
1758 if (f_rand() < 0.5) {
1762 ret->r = 0.7; ret->g = 0.1 ; ret->b = 0.1;
1767 ret->r = 0.2; ret->g = 0.2 ; ret->b = 0.2;
1774 Resistor * NewResistor(void)
1776 int v, m, t; /* value, multiplier, tolerance */
1781 t = (RAND(10) < 5) ? 10 : 11;
1782 ret = malloc(sizeof(Resistor));
1785 ret->b[0] = ret->b[1] = ret->b[2] = 7;
1787 ret->b[0] = values[v][0];
1788 ret->b[1] = values[v][1];
1796 void makebandlist(void)
1799 GLfloat col[] = {0,0,0,0};
1800 GLfloat spec[] = {0.8,0.8,0.8,0};
1803 for (i = 0 ; i < 12 ; i++) {
1804 band_list[i] = glGenLists(i);
1805 glNewList(band_list[i], GL_COMPILE);
1806 col[0] = colorcodes[i][0];
1807 col[1] = colorcodes[i][1];
1808 col[2] = colorcodes[i][2];
1809 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
1810 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
1811 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
1812 createCylinder(0.1, 0.42, 0, 0);
1818 void bandedCylinder(float radius, float l, GLfloat r, GLfloat g, GLfloat bl,
1819 Band **b, int nbands)
1821 int n; /* band number */
1822 int p = 0; /* prev number + 1; */
1823 GLfloat col[] = {0,0,0,0};
1825 col[0] = r; col[1] = g; col[2] = bl;
1826 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1827 createCylinder(l, radius, 1, 0); /* body */
1828 for (n = 0 ; n < nbands ; n++) {
1830 glTranslatef(b[n]->pos*l, 0, 0);
1831 col[0] = b[n]->r; col[1] = b[n]->g; col[2] = b[n]->b;
1832 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1833 createCylinder(b[n]->len*l, radius*1.05, 0, 0); /* band */
1842 static GLfloat col[] = {0, 0.25, 0.05};
1843 static GLfloat col2[] = {0, 0.125, 0.05};
1844 GLfloat col3[] = {0, 0.8, 0};
1845 static GLfloat sx, sy; /* bright spot co-ords */
1846 static int sdir; /* 0 = left-right, 1 = right-left, 2 = up->dn, 3 = dn->up */
1847 static int s = 0; /* if spot is enabled */
1848 static float ds; /* speed of spot */
1851 if (f_rand() < ((rotate) ? 0.05 : 0.01)) {
1852 sdir = RAND_RANGE(0, 4);
1853 ds = RAND_RANGE(0.4, 0.8);
1857 sy = ((int)RAND_RANGE(0, YMAX/2))*2 - YMAX/2;
1861 sy = ((int)RAND_RANGE(0, YMAX/2))*2 - YMAX/2;
1865 sx = ((int)RAND_RANGE(0, XMAX/2))*2 - XMAX/2;
1869 sx = ((int)RAND_RANGE(0, XMAX/2))*2 - XMAX/2;
1874 } else if (!rotate) {
1875 if (col[1] < 0.25) {
1876 col[1] += 0.025; col[2] += 0.005;
1877 col2[1] += 0.015 ; col2[2] += 0.005;
1881 glDisable(GL_LIGHTING);
1885 glTranslatef(sx, sy, -10);
1886 sphere(0.1, 10, 10, 0, 10, 0, 10);
1888 glTranslatef(-ds, 0, 0);
1890 glTranslatef(ds, 0, 0);
1892 glTranslatef(0, ds, 0);
1894 glTranslatef(0, -ds, 0);
1895 sphere(0.05, 10, 10, 0, 10, 0, 10);
1917 } else if (!rotate) {
1919 col[1] -= 0.0025; col[2] -= 0.0005;
1920 col2[1] -= 0.0015 ; col2[2] -= 0.0005;
1923 for (x = -XMAX/2 ; x <= XMAX/2 ; x+= 2) {
1926 glVertex3f(x, YMAX/2, -10);
1927 glVertex3f(x, -YMAX/2, -10);
1929 glVertex3f(x-0.02, YMAX/2, -10);
1930 glVertex3f(x-0.02, -YMAX/2, -10);
1931 glVertex3f(x+0.02, YMAX/2, -10);
1932 glVertex3f(x+0.02, -YMAX/2, -10);
1935 for (y = -YMAX/2 ; y <= YMAX/2 ; y+= 2) {
1938 glVertex3f(-XMAX/2, y, -10);
1939 glVertex3f(XMAX/2, y, -10);
1941 glVertex3f(-XMAX/2, y-0.02, -10);
1942 glVertex3f(XMAX/2, y-0.02, -10);
1943 glVertex3f(-XMAX/2, y+0.02, -10);
1944 glVertex3f(XMAX/2, y+0.02, -10);
1947 glEnable(GL_LIGHTING);
1952 static Component *c[MAX_COMPONENTS];
1954 GLfloat light_sp[] = {0.8, 0.8, 0.8, 1.0};
1955 GLfloat black[] = {0, 0, 0, 1.0};
1956 static GLfloat rotate_angle = 0; /* when 'rotate' is enabled */
1960 for (i = 0 ; i < maxparts ; i++) {
1964 glEnable(GL_LIGHTING);
1965 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
1967 gluLookAt(viewer[0], viewer[1], viewer[2], 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
1970 glRotatef(rotate_angle, 0, 0, 1);
1971 rotate_angle += 0.01 * (float)rotatespeed;
1972 if (rotate_angle >= 360) rotate_angle = 0;
1974 glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
1975 glLightfv(GL_LIGHT0, GL_SPECULAR, light_sp);
1976 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_sp);
1977 glLighti(GL_LIGHT0, GL_CONSTANT_ATTENUATION, (GLfloat)1);
1978 glLighti(GL_LIGHT0, GL_LINEAR_ATTENUATION, (GLfloat)0.5);
1979 glLighti(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, (GLfloat)0);
1981 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light_sp);
1982 if (f_rand() < 0.05) {
1983 for (j = 0 ; j < maxparts ; j++) {
1985 c[j] = NewComponent();
1991 for (j = 0 ; j < maxparts ; j++) {
1992 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, black);
1993 glMaterialfv(GL_FRONT, GL_EMISSION, black);
1994 glMaterialfv(GL_FRONT, GL_SPECULAR, black);
1996 if (DrawComponent(c[j])) {
1997 free(c[j]); c[j] = NULL;
2005 void freetexture (GLuint texture) {
2007 if (s_refs[texture] < 1) {
2008 glDeleteTextures(1, &texture);
2012 TexNum * fonttexturealloc (const char *str, float *fg, float *bg)
2014 static char *strings[50]; /* max of 40 textures */
2015 static int w[50], h[50];
2023 for (i = 0 ; i < 50 ; i++) {
2030 for (i = 0 ; i < 50 ; i++) {
2031 if (!s_refs[i] && strings[i]) {
2035 if (strings[i] && !strcmp(str, strings[i])) { /* if one matches */
2036 t = malloc(sizeof(TexNum));
2037 t->w = w[i]; t->h = h[i];
2043 /* at this point we need to make the new texture */
2044 ximage = text_to_ximage (modeinfo->xgwa.screen,
2045 modeinfo->xgwa.visual,
2048 for (i = 0 ; strings[i] != NULL ; i++) { /* set i to the next unused value */
2050 fprintf(stderr, "Texture cache full!\n");
2057 glBindTexture(GL_TEXTURE_2D, i);
2058 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2059 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2060 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2063 status = gluBuild2DMipmaps(GL_TEXTURE_2D, 4, ximage->width, ximage->height,
2064 GL_RGBA, GL_UNSIGNED_BYTE, ximage->data);
2067 const char *s = (char *) gluErrorString (status);
2068 fprintf (stderr, "%s: error mipmapping %dx%d texture: %s\n",
2069 progname, ximage->width, ximage->height,
2070 (s ? s : "(unknown)"));
2073 check_gl_error("mipmapping");
2075 t = malloc(sizeof(TexNum));
2076 t->w = ximage->width;
2077 t->h = ximage->height;
2078 w[i] = t->w; h[i] = t->h;
2082 c = malloc(strlen(str)+1);
2083 strncpy(c, str, strlen(str)+1);
2090 /* ensure transparent components are at the end */
2091 void reorder(Component *c[])
2094 Component *c1[MAX_COMPONENTS];
2095 Component *c2[MAX_COMPONENTS];
2098 for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
2102 for (i = 0 ; i < maxparts ; i++) {
2103 if (c[i] == NULL) continue;
2104 if (c[i]->alpha) { /* transparent parts go to c1 */
2107 } else { /* opaque parts go to c2 */
2111 for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
2115 for (i = 0 ; i < maxparts ; i++) { /* insert opaque part */
2116 if (c2[i] != NULL) {
2121 for (i = 0 ; i < j ; i++) { /* insert transparent parts */
2127 void reshape_circuit(ModeInfo *mi, int width, int height)
2129 GLfloat h = (GLfloat) height / (GLfloat) width;
2130 glViewport(0,0,(GLint)width, (GLint) height);
2131 glMatrixMode(GL_PROJECTION);
2133 glFrustum(-1.0,1.0,-h,h,1.5,35.0);
2134 glMatrixMode(GL_MODELVIEW);
2135 win_h = height; win_w = width;
2140 void init_circuit(ModeInfo *mi)
2142 int screen = MI_SCREEN(mi);
2145 if (circuit == NULL) {
2146 if ((circuit = (Circuit *) calloc(MI_NUM_SCREENS(mi),
2147 sizeof(Circuit))) == NULL)
2150 c = &circuit[screen];
2151 c->window = MI_WINDOW(mi);
2154 if ((c->glx_context = init_GL(mi)) != NULL) {
2155 reshape_circuit(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
2161 glClearColor(0.0,0.0,0.0,0.0);
2162 glShadeModel(GL_SMOOTH);
2163 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
2164 glEnable(GL_DEPTH_TEST);
2165 glEnable(GL_LIGHTING);
2166 glEnable(GL_LIGHT0);
2167 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2173 void draw_circuit(ModeInfo *mi)
2175 Circuit *c = &circuit[MI_SCREEN(mi)];
2176 Window w = MI_WINDOW(mi);
2177 Display *disp = MI_DISPLAY(mi);
2179 if (!c->glx_context)
2183 glXMakeCurrent(disp, w, *(c->glx_context));
2187 if(mi->fps_p) do_fps(mi);
2189 glXSwapBuffers(disp, w);
2192 void release_circuit(ModeInfo *mi)
2194 if (circuit != NULL) {
2195 (void) free((void *) circuit);