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)
9 * Copyright (C) 2001 Ben Buxton (bb@cactii.net)
11 * Permission to use, copy, modify, distribute, and sell this software and its
12 * documentation for any purpose is hereby granted without fee, provided that
13 * the above copyright notice appear in all copies and that both that
14 * copyright notice and this permission notice appear in supporting
15 * documentation. No representations are made about the suitability of this
16 * software for any purpose. It is provided "as is" without express or
20 /* Written over a few days in a (successful) bid to learn GL coding
22 * -seven option is dedicated to all the Slarkeners
24 * try "-rotate -rotate-speed 0"
26 * This hack uses lookup tables for sin, cos and tan - it can do a lot
30 #include <X11/Intrinsic.h>
33 # define PROGCLASS "Circuit"
34 # define HACK_INIT init_circuit
35 # define HACK_DRAW draw_circuit
36 # define HACK_RESHAPE reshape_circuit
37 # define circuit_opts xlockmore_opts
38 /* insert defaults here */
40 #define DEF_SPIN "True"
41 #define DEF_SEVEN "False"
42 #define DEF_PARTS "10"
45 #define DEFAULTS "*parts: " DEF_PARTS " \n" \
46 "*spin: " DEF_SPIN "\n" \
48 "*showFPS: False \n" \
49 "*seven: " DEF_SEVEN "\n" \
54 # include "xlockmore.h" /* from the xscreensaver distribution */
55 #else /* !STANDALONE */
56 # include "xlock.h" /* from the xlockmore distribution */
57 #endif /* !STANDALONE */
59 /* lifted from lament.c */
60 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
61 #define RANDSIGN() ((random() & 1) ? 1 : -1)
73 static int rotatespeed;
78 #define countof(x) (sizeof((x))/sizeof((*x)))
80 static XrmOptionDescRec opts[] = {
81 {"-parts", ".circuit.parts", XrmoptionSepArg, "10" },
82 {"-rotate-speed", ".circuit.rotatespeed", XrmoptionSepArg, "1" },
83 {"+spin", ".circuit.spin", XrmoptionNoArg, (caddr_t) "false" },
84 {"-spin", ".circuit.spin", XrmoptionNoArg, (caddr_t) "true" },
85 {"+light", ".circuit.light", XrmoptionNoArg, (caddr_t) "false" },
86 {"-light", ".circuit.light", XrmoptionNoArg, (caddr_t) "true" },
87 {"+seven", ".circuit.seven", XrmoptionNoArg, (caddr_t) "false" },
88 {"-seven", ".circuit.seven", XrmoptionNoArg, (caddr_t) "true" },
89 {"+rotate", ".circuit.rotate", XrmoptionNoArg, (caddr_t) "false" },
90 {"-rotate", ".circuit.rotate", XrmoptionNoArg, (caddr_t) "true" },
93 static argtype vars[] = {
94 {(caddr_t *) &maxparts, "parts", "Parts", DEF_PARTS, t_Int},
95 {(caddr_t *) &rotatespeed, "rotatespeed", "Rotatespeed", "1", t_Int},
96 {(caddr_t *) &spin, "spin", "Spin", DEF_SPIN, t_Bool},
97 {(caddr_t *) &rotate, "rotate", "Rotate", "False", t_Bool},
98 {(caddr_t *) &uselight, "light", "Light", "True", t_Bool},
99 {(caddr_t *) &seven, "seven", "Seven", DEF_SEVEN, t_Bool},
102 ModeSpecOpt circuit_opts = {countof(opts), opts, countof(vars), vars, NULL};
105 ModStruct circuit_description =
106 {"circuit", "init_circuit", "draw_circuit", "release_circuit",
107 "draw_circuit", "init_circuit", NULL, &circuit_opts,
108 1000, 1, 2, 1, 4, 1.0, "",
109 "Flying electronic components", 0, NULL};
115 GLXContext *glx_context;
119 static Circuit *circuit = NULL;
122 #include <sys/time.h>
127 #define M_PI 3.14159265
130 /* window width, height */
133 /* width and height of viewport */
138 #define MAX_COMPONENTS 30
140 #define MOVE_MULT 0.05
142 static float f_rand(void) {
143 return ((float)RAND(10000)/(float)10000);
146 #define RAND_RANGE(min, max) ((min) + (max - min) * f_rand())
148 /* one lucky led gets to be a light source , unless -no-light*/
152 static GLfloat viewer[] = {0.0, 0.0, 14.0};
153 static GLfloat lightpos[] = {7.0, 7.0, 15, 1.0};
155 float sin_table[720];
156 float cos_table[720];
157 float tan_table[720];
160 /* Represents a band on a resistor/diode/etc */
162 float pos; /* relative position from start/previous band */
163 GLfloat r, g, b; /* colour of the band */
164 float len; /* length as a fraction of total length */
168 Band *b1, *b2, *b3, *b4; /* bands */
174 GLfloat r, g, b; /* body colour */
178 int type; /* package type. 0 = to-92, 1 = to-220 */
182 GLfloat r,g,b; /* LED colour */
183 int light; /* are we the light source? */
187 int type; /* 0 = electro, 1 = ceramic */
188 float width; /* width of an electro/ceramic */
189 float length; /* length of an electro */
193 int type; /* 0 = DIL, 1 = flat square */
197 /* 7 segment display */
200 int value; /* displayed number */
208 GLfloat x, y, z; /* current co-ordinates */
209 GLfloat dx, dy, dz; /* current direction */
210 GLfloat rotx, roty, rotz; /* rotation vector */
211 GLfloat drot; /* rotation velocity (degrees per frame) */
212 int norm; /* Normalize this component (for shine) */
213 int rdeg; /* current rotation degrees */
214 int angle; /* angle about the z axis */
215 int alpha; /* 0 if not a transparent component */
216 int type; /* 0 = resistor, 1 = diode, 2 = transistor, 3 = LED, 4 = cap, 5=IC,
218 void * c; /* pointer to the component */
221 static int band_list[12];
223 /* standard colour codes */
225 static GLfloat colorcodes [12][3] = {
226 {0.0,0.0,0.0}, /* black 0 */
227 {0.49,0.25,0.08}, /* brown 1 */
228 {1.0,0.0,0.0}, /* red 2 */
229 {1.0,0.5,0.0}, /* orange 3 */
230 {1.0,1.0,0.0}, /* yellow 4 */
231 {0.0,1.0,0.0}, /* green 5 */
232 {0.0,0.5,1.0}, /* blue 6 */
233 {0.7,0.2,1.0}, /* violet 7 */
234 {0.5,0.5,0.5}, /* grey 8 */
235 {1.0,1.0,1.0}, /* white 9 */
236 {0.66,0.56,0.2}, /* gold 10 */
237 {0.8,0.8,0.8}, /* silver 11 */
240 /* base values for components - we can multiply by 0 - 1M */
241 static int values [9][2] = {
253 void DrawResistor(Resistor *);
254 void DrawDiode(Diode *);
255 void DrawTransistor(Transistor *);
258 void DrawCapacitor(Capacitor *);
259 void DrawDisp(Disp *);
260 void DrawFuse(Fuse *);
262 void reorder(Component *[]);
263 void circle(float, int,int);
264 void bandedCylinder(float, float , GLfloat, GLfloat , GLfloat, Band **, int);
265 Resistor *NewResistor(void);
266 Diode *NewDiode(void);
267 Transistor *NewTransistor(void);
269 Capacitor *NewCapacitor(void);
274 /* we use trig tables to speed things up - 200 calls to sin()
275 in one frame can be a bit harsh..
278 void make_tables(void) {
282 f = 360 / (M_PI * 2);
283 for (i = 0 ; i < 720 ; i++) {
284 sin_table[i] = sin(i/f);
286 for (i = 0 ; i < 720 ; i++) {
287 cos_table[i] = cos(i/f);
289 for (i = 0 ; i < 720 ; i++) {
290 tan_table[i] = tan(i/f);
295 void createCylinder (float length, float radius, int endcaps, int half) {
296 int a; /* current angle around cylinder */
298 float z1, y1, z2, y2, ex;
302 nsegs = radius*MAX(win_w, win_h)/10;
303 nsegs = MAX(nsegs, 6);
306 angle = (half) ? (180 - 90/nsegs) : 374;
309 for (a = 0 ; a <= angle ; a+= angle/nsegs) {
310 y2=radius*(float)sin_table[(int)a];
311 z2=radius*(float)cos_table[(int)a];
312 glNormal3f(0, y1, z1);
314 glVertex3f(length,y1,z1);
315 glVertex3f(length,y2,z2);
324 glVertex3f(0, 0, radius);
325 glVertex3f(length, 0, radius);
326 glVertex3f(length, 0, 0 - radius);
327 glVertex3f(0, 0, 0 - radius);
331 for(ex = 0 ; ex <= length ; ex += length) {
333 norm = (ex == length) ? 1 : -1;
334 for (a = 0 ; a <= angle ; a+= angle/nsegs) {
335 y2=radius*(float)sin_table[(int)a];
336 z2=radius*(float)cos_table[(int)a];
337 glBegin(GL_TRIANGLES);
338 glNormal3f(norm, 0, 0);
340 glVertex3f(ex,y1,z1);
341 glVertex3f(ex,y2,z2);
351 void circle(float radius, int segments, int half) {
352 float x1 = 0, x2 = 0;
353 float y1 = 0, y2 = 0;
362 glBegin(GL_TRIANGLES);
367 x2=radius*(float)cos_table[(int)angle];
368 y2=radius*(float)sin_table[(int)angle];
378 void wire(float len) {
379 static GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
380 static GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
381 static GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
385 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
386 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
387 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
388 n = glIsEnabled(GL_NORMALIZE);
389 if (!n) glEnable(GL_NORMALIZE);
390 createCylinder(len, 0.05, 1, 0);
391 if (!n) glDisable(GL_NORMALIZE);
392 glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
395 void ring(GLfloat inner, GLfloat outer, int nsegs) {
396 GLfloat z1, z2, y1, y2;
397 GLfloat Z1, Z2, Y1, Y2;
404 for(i=0; i <=360 ; i+= 360/nsegs)
407 z2=inner*(float)sin_table[(int)angle];
408 y2=inner*(float)cos_table[(int)angle];
409 Z2=outer*(float)sin_table[(int)angle];
410 Y2=outer*(float)cos_table[(int)angle];
411 glVertex3f(0, Y1, Z1);
412 glVertex3f(0, y1, z1);
413 glVertex3f(0, y2, z2);
414 glVertex3f(0, Y2, Z2);
423 void sphere(GLfloat r, float stacks, float slices,
424 int startstack, int endstack, int startslice,
426 GLfloat d, d1, dr, dr1, Dr, Dr1, D, D1, z1, z2, y1, y2, Y1, Z1, Y2, Z2;
427 int a, a1, b, b1, c, c1;
432 a1 = startstack * step;
433 b1 = startslice * sstep;
434 y1 = z1 = Y1 = Z1 = 0;
435 c = (endslice / slices) * 360;
436 c1 = (endstack/stacks)*180;
438 for (a = startstack * step ; a <= c1 ; a+= step) {
447 for (b = b1 ; b <= c ; b+= sstep) {
452 glNormal3f(D, y1, z1);
453 glVertex3f(Dr,y1,z1);
454 glVertex3f(Dr,y2,z2);
455 glVertex3f(Dr1,Y2,Z2);
456 glVertex3f(Dr1,Y1,Z1);
467 int DrawComponent(Component *c) {
468 int ret = 0; /* return 1 if component is freed */
471 glTranslatef(c->x, c->y, c->z);
473 glRotatef(c->angle, 0, 0, 1);
476 glRotatef(c->rdeg, c->rotx, c->roty, c->rotz);
481 glEnable(GL_NORMALIZE);
483 glDisable(GL_NORMALIZE);
485 /* call object draw routine here */
488 } else if (c->type == 1) {
490 } else if (c->type == 2) {
491 DrawTransistor(c->c);
492 } else if (c->type == 3) {
493 if (((LED *)c->c)->light && light) {
494 GLfloat lp[] = {0.1, 0, 0, 1};
496 glLightfv(GL_LIGHT1, GL_POSITION, lp);
499 } else if (c->type == 4) {
501 } else if (c->type == 5) {
503 } else if (c->type == 6) {
505 } else if (c->type == 7) {
508 c->x += c->dx * MOVE_MULT;
509 c->y += c->dy * MOVE_MULT;
510 if (c->x > XMAX/2 || c->x < 0 - XMAX/2 ||
511 c->y > YMAX/2 || c->y < 0 - YMAX/2) {
512 if (c->type == 3 && ((LED *)c->c)->light && light) {
513 glDisable(GL_LIGHT1);
514 light = 0; lighton = 0;
521 glDisable(GL_NORMALIZE);
524 /* draw a resistor */
526 void DrawResistor(Resistor *r) {
528 GLfloat col[] = {0.74, 0.62, 0.46, 1.0};
529 GLfloat spec[] = {0.8, 0.8, 0.8, 1.0};
532 glTranslatef(-4, 0, 0);
534 glTranslatef(3, 0, 0);
535 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
536 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
537 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
538 createCylinder(1.8, 0.4, 1, 0);
540 for (i = 0 ; i < 4 ; i++) {
541 glTranslatef(0.35, 0, 0);
542 glCallList(band_list[r->b[i]]);
545 glTranslatef(1.8, 0, 0);
549 void DrawFuse(Fuse *f) {
550 static GLfloat col[] = {0.5, 0.5, 0.5, 1.0}; /* endcaps */
551 static GLfloat glass[] = {0.4, 0.4, 0.4, 0.3}; /* glass */
552 static GLfloat spec[] = {1, 1, 1, 1}; /* glass */
555 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
556 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
557 glMateriali(GL_FRONT, GL_SHININESS, 40);
558 createCylinder(0.8, 0.45, 1, 0);
559 glTranslatef(0.8, 0, 0);
561 glDepthMask(GL_FALSE);
562 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
563 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, glass);
564 glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 40);
565 createCylinder(2, 0.4, 0, 0);
566 createCylinder(2, 0.3, 0, 0);
568 glDepthMask(GL_TRUE);
569 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
570 glMateriali(GL_FRONT, GL_SHININESS, 40);
573 glVertex3f(2, 0. ,0);
575 glTranslatef(2, 0, 0);
576 createCylinder(0.8, 0.45, 1, 0);
581 void DrawCapacitor(Capacitor *c) {
582 static GLfloat col[] = {0, 0, 0, 0};
583 static GLfloat spec[] = {0.8, 0.8, 0.8, 0};
584 GLfloat brown[] = {0.84, 0.5, 0};
585 static GLfloat shine = 40;
589 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, brown);
590 sphere(c->width, 20, 20, 0, 5 ,0, 20);
591 glTranslatef(1.45*c->width, 0, 0);
592 sphere(c->width, 20, 20, 15, 20, 0, 20);
593 glRotatef(90, 0, 0, 1);
594 glTranslatef(0, 0.7*c->width, 0.3*c->width);
596 glTranslatef(0, 0, -0.6*c->width);
599 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
600 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
601 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
603 glVertex3f(0, 0.82*c->width, -0.1);
604 glVertex3f(3*c->length, 0.82*c->width, -0.1);
605 glVertex3f(3*c->length, 0.82*c->width, 0.1);
606 glVertex3f(0, 0.82*c->width, 0.1);
611 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
612 circle(0.6*c->width, 30, 0);
616 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
617 ring(0.6*c->width, 0.8*c->width, 30);
618 glTranslatef(0.01, 0.0, 0);
619 createCylinder(3.0*c->length, 0.8*c->width, 1, 0);
623 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
624 glTranslatef(3.01*c->length, 0.0, 0);
625 circle(0.6*c->width, 30, 0);
626 glTranslatef(0, 0.4*c->width, 0);
628 glTranslatef(0.0, -0.8*c->width, 0);
634 void DrawLED(LED *l) {
635 GLfloat col[] = {0, 0, 0, 0.6};
637 col[0] = l->r; col[1] = l->g; col[2] = l->b;
638 if (l->light && light) {
639 GLfloat dir[] = {-1, 0, 0};
640 glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, dir);
642 glLightfv(GL_LIGHT1, GL_SPECULAR, col);
643 glLightfv(GL_LIGHT1, GL_AMBIENT, col);
644 glLightfv(GL_LIGHT1, GL_DIFFUSE, col);
645 glLighti(GL_LIGHT1, GL_SPOT_CUTOFF, (GLint) 90);
646 glLighti(GL_LIGHT1, GL_CONSTANT_ATTENUATION, (GLfloat)1);
647 glLighti(GL_LIGHT1, GL_LINEAR_ATTENUATION, (GLfloat)0);
648 glLighti(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, (GLfloat)0);
649 glLighti(GL_LIGHT1, GL_SPOT_EXPONENT, (GLint) 20);
653 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
654 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
655 /* no transparency when LED is lit */
658 glDepthMask(GL_FALSE);
659 glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
661 createCylinder(1.2, 0.3, 0, 0);
662 if (l->light && light) {
663 glDisable(GL_LIGHTING);
666 sphere(0.3, 10, 10, 5, 10, 0, 10);
667 if (l->light && light) {
668 glEnable(GL_LIGHTING);
670 glDepthMask(GL_TRUE);
674 glTranslatef(1.2, 0, 0);
675 createCylinder(0.1, 0.38, 1, 0);
676 glTranslatef(-0.3, 0.15, 0);
678 glTranslatef(0, -0.3, 0);
680 if (random() % 50 == 25) {
682 l->light = 0; light = 0; lighton = 0;
683 glDisable(GL_LIGHT1);
685 l->light = 1; light = 1;
692 void DrawDiode(Diode *d) {
694 GLfloat col[] = {0.3, 0.3, 0.3, 0};
695 GLfloat spec[] = {0.7, 0.7, 0.7, 0};
698 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
699 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
700 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
701 glTranslatef(-4, 0, 0);
703 glTranslatef(3, 0, 0);
704 bandedCylinder(0.3, 1.5, d->r, d->g, d->b, &(d->band), 1);
705 glTranslatef(1.5, 0, 0);
710 void Rect(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h,
716 yh = y+h; xw = x+w; zt = z - t;
718 glBegin(GL_QUADS); /* front */
721 glVertex3f(x, yh, z);
722 glVertex3f(xw, yh, z);
723 glVertex3f(xw, y, z);
725 glNormal3f(0, 0, -1);
726 glVertex3f(x, y, zt);
727 glVertex3f(x, yh, zt);
728 glVertex3f(xw, yh, zt);
729 glVertex3f(xw, y, zt);
732 glVertex3f(x, yh, z);
733 glVertex3f(x, yh, zt);
734 glVertex3f(xw, yh, zt);
735 glVertex3f(xw, yh, z);
737 glNormal3f(0, -1, 0);
739 glVertex3f(x, y, zt);
740 glVertex3f(xw, y, zt);
741 glVertex3f(xw, y, z);
743 glNormal3f(-1, 0, 0);
745 glVertex3f(x, y, zt);
746 glVertex3f(x, yh, zt);
747 glVertex3f(x, yh, z);
750 glVertex3f(xw, y, z);
751 glVertex3f(xw, y, zt);
752 glVertex3f(xw, yh, zt);
753 glVertex3f(xw, yh, z);
759 void ICLeg(GLfloat x, GLfloat y, GLfloat z, int dir) {
763 Rect(x-0.1, y, z, 0.1, 0.1, 0.02);
764 Rect(x-0.1, y, z, 0.02, 0.1, 0.1);
765 Rect(x-0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
767 Rect(x, y, z, 0.1, 0.1, 0.02);
768 Rect(x+0.8*0.1, y, z, 0.02, 0.1, 0.1);
769 Rect(x+0.8*0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
778 GLfloat col[] = {0.1, 0.1, 0.1, 0};
779 GLfloat spec[] = {0.6, 0.6, 0.6, 0};
781 GLfloat lspec[] = {0.6, 0.6, 0.6, 0};
782 GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
786 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
787 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
788 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
807 glVertex3f(w, h, 0.1);
808 glVertex3f(w, -h, 0.1);
809 glVertex3f(-w, -h, 0.1);
810 glVertex3f(-w, h, 0.1);
811 glNormal3f(0, 0, -1);
812 glVertex3f(w, h, -0.1);
813 glVertex3f(w, -h, -0.1);
814 glVertex3f(-w, -h, -0.1);
815 glVertex3f(-w, h, -0.1);
817 glVertex3f(w, h, -0.1);
818 glVertex3f(w, -h, -0.1);
819 glVertex3f(w, -h, 0.1);
820 glVertex3f(w, h, 0.1);
821 glNormal3f(0, -1, 0);
822 glVertex3f(w, -h, -0.1);
823 glVertex3f(w, -h, 0.1);
824 glVertex3f(-w, -h, 0.1);
825 glVertex3f(-w, -h, -0.1);
826 glNormal3f(-1, 0, 0);
827 glVertex3f(-w, h, -0.1);
828 glVertex3f(-w, h, 0.1);
829 glVertex3f(-w, -h, 0.1);
830 glVertex3f(-w, -h, -0.1);
831 glNormal3f(0, -1, 0);
832 glVertex3f(-w, h, -0.1);
833 glVertex3f(w, h, -0.1);
834 glVertex3f(w, h, 0.1);
835 glVertex3f(-w, h, 0.1);
837 d = (h*2-0.1) / c->pins;
839 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
840 glMaterialfv(GL_FRONT, GL_SPECULAR, lspec);
841 glMaterialfv(GL_FRONT, GL_SHININESS, &lshine);
842 for (z = 0 ; z < c->pins/2 ; z++) {
843 ICLeg(w, -h + z*d + d/2, 0, 0);
845 for (z = 0 ; z < c->pins/2 ; z++) {
846 ICLeg(-w, -h + z*d + d/2, 0, 1);
851 void DrawDisp(Disp *d) {
852 GLfloat col[] = {0.8, 0.8, 0.8, 1.0}; /* body colour */
853 GLfloat front[] = {0.2, 0.2, 0.2, 1.0}; /* front colour */
854 GLfloat on[] = {0.9, 0, 0, 1}; /* 'on' segment */
855 GLfloat off[] = {0.3, 0, 0, 1}; /* 'off' segment */
857 GLfloat x, y; /* for the pins */
858 GLfloat spec[] = {0.6, 0.6, 0.6, 0};
859 GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
861 static GLfloat vdata_h[6][2] =
870 static GLfloat vdata_v[6][2] =
880 static GLfloat seg_start[7][2] =
892 static int nums[10][7] =
894 {1, 1, 1, 1, 1, 1, 0}, /* 0 */
895 {0, 1, 1, 0, 0, 0, 0}, /* 1 */
896 {1, 1, 0, 1, 1, 0, 1}, /* 2 */
897 {1, 1, 1, 1, 0, 0, 1}, /* 3 */
898 {0, 1, 1, 0, 0, 1, 1}, /* 4 */
899 {1, 0, 1, 1, 0, 1, 1}, /* 5 */
900 {1, 0, 1, 1, 1, 1, 1}, /* 6 */
901 {1, 1, 1, 0, 0, 0, 0}, /* 7 */
902 {1, 1, 1, 1, 1, 1, 1}, /* 8 */
903 {1, 1, 1, 0, 0, 1, 1} /* 9 */
906 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
907 Rect(0, 0, -0.01, 1.8, 2.6, 0.7);
908 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, front);
910 glVertex2f(-0.05, -0.05);
911 glVertex2f(-0.05, 2.65);
912 glVertex2f(1.85, 2.65);
913 glVertex2f(1.85, -0.05);
915 glDisable(GL_LIGHTING); /* lit segments dont need light */
916 if (!seven && (random() % 30) == 19) { /* randomly change value */
917 d->value = random() % 10;
919 for (j = 0 ; j < 7 ; j++) { /* draw the segments */
920 GLfloat xx[6], yy[6];
921 if (nums[d->value][j])
925 for (k = 0 ; k < 6 ; k++) {
926 if (j == 0 || j == 3 || j == 6) {
927 xx[k] = seg_start[j][0] + vdata_h[k][0];
928 yy[k] = seg_start[j][1] + vdata_h[k][1];
930 xx[k] = seg_start[j][0] + vdata_v[k][0];
931 yy[k] = seg_start[j][1] + vdata_v[k][1];
935 for(i = 0 ; i < 6 ; i++) {
936 glVertex3f(xx[i], yy[i], 0.01);
943 glVertex3f(1.5, 0.2, 0.01);
945 glEnable(GL_LIGHTING);
946 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
947 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
948 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
949 for (x = 0.35 ; x <= 1.5 ; x+= 1.15) {
950 for ( y = 0.2 ; y <= 2.4 ; y += 0.3) {
951 ICLeg(x, y, -0.7, 1);
956 void HoledRectangle(GLfloat w, GLfloat h, GLfloat d, GLfloat radius, int p) {
958 GLfloat x1, y1, x2, y2;
959 GLfloat yr, yr1, xr, xr1, side, side1;
968 for (a = 0 ; a <= 360 ; a+= step) {
969 y2=radius*(float)sin_table[(int)a];
970 x2=radius*(float)cos_table[(int)a];
972 if (a < 45 || a > 315) {
974 yr = side1 * tan_table[a];
976 } else if (a <= 135 || a >= 225) {
977 xr = side/tan_table[a];
988 yr = -side1 * tan_table[a];
992 glNormal3f(-x1, -y1, 0); /* cylinder */
994 glVertex3f(x1,y1,-d);
995 glVertex3f(x2,y2,-d);
998 glNormal3f(0, 0, 1); /* front face */
1000 glVertex3f(xr1, yr1, 0);
1001 glVertex3f(xr, yr, 0);
1002 glVertex3f(x2, y2, 0);
1004 glNormal3f(nx, ny, 0); /* side */
1005 glVertex3f(xr, yr, 0);
1006 glVertex3f(xr, yr, -d);
1007 glVertex3f(xr1, yr1, -d);
1008 glVertex3f(xr1, yr1, 0);
1010 glNormal3f(0, 0, -1); /* back */
1011 glVertex3f(xr, yr, -d);
1012 glVertex3f(x2, y2, -d);
1013 glVertex3f(x1, y1, -d);
1014 glVertex3f(xr1, yr1, -d);
1023 void DrawTransistor(Transistor *t) {
1024 static GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
1025 static GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
1026 static GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
1030 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1031 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col);
1033 glRotatef(90, 0, 1, 0);
1034 glRotatef(90, 0, 0, 1);
1035 createCylinder(1.0, 0.4, 1, 1);
1036 Rect(0, -0.2, 0.4, 1, 0.2, 0.8);
1037 glTranslatef(-2, 0, -0.2);
1039 glTranslatef(0, 0, 0.2);
1041 glTranslatef(0, 0, 0.2);
1044 Rect(0, 0, 0, 1.5, 1.5, 0.75);
1045 glTranslatef(0.75, 1.875, -0.5);
1046 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1047 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1048 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1049 if (glIsEnabled(GL_NORMALIZE)) glEnable(GL_NORMALIZE);
1050 HoledRectangle(1.5, 0.75, 0.25, 0.2, 8);
1051 glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
1052 glTranslatef(-0.375, -1.875, 0);
1053 glRotatef(90, 0, 0, -1);
1055 glTranslatef(0, 0.375, 0);
1057 glTranslatef(0, 0.375, 0);
1063 Component * NewComponent(void) {
1067 c = malloc(sizeof(Component));
1068 c->angle = RAND_RANGE(0,360);
1070 if (rnd < 0.25) { /* come from the top */
1072 c->x = RAND_RANGE(0, XMAX) - XMAX/2;
1074 c->dx = 0 - RAND_RANGE(0.5, 2);
1076 c->dx = RAND_RANGE(0.5, 2);
1077 c->dy = 0 - RAND_RANGE(0.5, 2);
1078 } else if (rnd < 0.5) { /* come from the bottom */
1080 c->x = RAND_RANGE(0, XMAX) - XMAX/2;
1082 c->dx = 0 - RAND_RANGE(0.5, 2);
1084 c->dx = RAND_RANGE(0.5, 2);
1085 c->dy = RAND_RANGE(0.5, 2);
1086 } else if (rnd < 0.75) { /* come from the left */
1088 c->y = RAND_RANGE(0, YMAX) - YMAX/2;
1089 c->dx = RAND_RANGE(0.5, 2);
1091 c->dy = 0 - RAND_RANGE(0.5, 2);
1093 c->dy = RAND_RANGE(0.5, 2);
1094 } else { /* come from the right */
1096 c->y = RAND_RANGE(0, YMAX) - YMAX/2;
1097 c->dx = 0 - RAND_RANGE(0.5, 2);
1099 c->dy = 0 - RAND_RANGE(0.5, 2);
1101 c->dy = RAND_RANGE(0.5, 2);
1103 c->z = RAND_RANGE(0, 7) - 9;
1107 c->drot = f_rand() * 7;
1109 c->dz = f_rand()*2 - 1;
1111 c->alpha = 0; /* explicitly set to 1 later */
1114 c->c = NewResistor();
1117 c->norm = 1; /* some resistors shine */
1118 } else if (rnd < 0.2) {
1121 c->norm = 1; /* some diodes shine */
1123 } else if (rnd < 0.3) {
1124 c->c = NewTransistor();
1127 } else if (rnd < 0.4) {
1128 c->c = NewCapacitor();
1130 c->norm = 1; /* some capacitors shine */
1132 } else if (rnd < 0.6) {
1135 } else if (rnd < 0.7) {
1140 } else if (rnd < 0.8) {
1152 Transistor *NewTransistor(void) {
1155 t = malloc(sizeof(Transistor));
1156 t->type = (f_rand() < 0.5);
1160 Capacitor *NewCapacitor(void) {
1163 c = malloc(sizeof(Capacitor));
1164 c->type = (f_rand() < 0.5);
1166 c->length = RAND_RANGE(0.5, 1);
1167 c->width = RAND_RANGE(0.5, 1);
1169 c->width = RAND_RANGE(1, 2);
1174 /* 7 segment display */
1176 Disp *NewDisp(void) {
1179 d = malloc(sizeof(Disp));
1183 d->value = RAND_RANGE(0, 10);
1192 c = malloc(sizeof(IC));
1194 switch((int)RAND_RANGE(0,4)) {
1217 l = malloc(sizeof(LED));
1220 if (!light && (f_rand() < 0.4)) {
1225 l->r = 0.9; l->g = 0; l->b = 0;
1226 } else if (r < 0.4) {
1227 l->r = 0.3; l->g = 0.9; l->b = 0;
1228 } else if (r < 0.6) {
1229 l->r = 0.8; l->g = 0.9; l->b = 0;
1230 } else if (r < 0.8) {
1231 l->r = 0.0; l->g = 0.2; l->b = 0.8;
1233 l->r = 0.9, l->g = 0.55, l->b = 0;
1238 Fuse *NewFuse(void) {
1241 f = malloc(sizeof(Fuse));
1245 Diode *NewDiode(void) {
1249 ret = malloc(sizeof(Diode));
1250 b = malloc(sizeof(Band));
1253 if (f_rand() < 0.5) {
1257 ret->r = 0.7; ret->g = 0.1 ; ret->b = 0.1;
1262 ret->r = 0.2; ret->g = 0.2 ; ret->b = 0.2;
1269 Resistor * NewResistor(void) {
1270 int v, m, t; /* value, multiplier, tolerance */
1275 t = (RAND(10) < 5) ? 10 : 11;
1276 ret = malloc(sizeof(Resistor));
1279 ret->b[0] = ret->b[1] = ret->b[2] = 7;
1281 ret->b[0] = values[v][0];
1282 ret->b[1] = values[v][1];
1290 void makebandlist(void) {
1292 GLfloat col[] = {0,0,0,0};
1293 GLfloat spec[] = {0.8,0.8,0.8,0};
1296 for (i = 0 ; i < 12 ; i++) {
1297 band_list[i] = glGenLists(i);
1298 glNewList(band_list[i], GL_COMPILE);
1299 col[0] = colorcodes[i][0];
1300 col[1] = colorcodes[i][1];
1301 col[2] = colorcodes[i][2];
1302 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
1303 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
1304 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
1305 createCylinder(0.1, 0.42, 0, 0);
1311 void bandedCylinder(float radius, float l, GLfloat r, GLfloat g, GLfloat bl,
1312 Band **b, int nbands) {
1313 int n; /* band number */
1314 int p = 0; /* prev number + 1; */
1315 GLfloat col[] = {0,0,0,0};
1317 col[0] = r; col[1] = g; col[2] = bl;
1318 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1319 createCylinder(l, radius, 1, 0); /* body */
1320 for (n = 0 ; n < nbands ; n++) {
1322 glTranslatef(b[n]->pos*l, 0, 0);
1323 col[0] = b[n]->r; col[1] = b[n]->g; col[2] = b[n]->b;
1324 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1325 createCylinder(b[n]->len*l, radius*1.05, 0, 0); /* band */
1331 void drawgrid(void) {
1333 static GLfloat col[] = {0, 0.25, 0.05};
1334 static GLfloat col2[] = {0, 0.125, 0.05};
1335 GLfloat col3[] = {0, 0.8, 0};
1336 static GLfloat sx, sy; /* bright spot co-ords */
1337 static int sdir; /* 0 = left-right, 1 = right-left, 2 = up->dn, 3 = dn->up */
1338 static int s = 0; /* if spot is enabled */
1339 static float ds; /* speed of spot */
1342 if (f_rand() < ((rotate) ? 0.05 : 0.01)) {
1343 sdir = RAND_RANGE(0, 4);
1344 ds = RAND_RANGE(0.4, 0.8);
1348 sy = ((int)RAND_RANGE(0, YMAX/2))*2 - YMAX/2;
1352 sy = ((int)RAND_RANGE(0, YMAX/2))*2 - YMAX/2;
1356 sx = ((int)RAND_RANGE(0, XMAX/2))*2 - XMAX/2;
1360 sx = ((int)RAND_RANGE(0, XMAX/2))*2 - XMAX/2;
1365 } else if (!rotate) {
1366 if (col[1] < 0.25) {
1367 col[1] += 0.025; col[2] += 0.005;
1368 col2[1] += 0.015 ; col2[2] += 0.005;
1372 glDisable(GL_LIGHTING);
1376 glTranslatef(sx, sy, -10);
1377 sphere(0.1, 10, 10, 0, 10, 0, 10);
1379 glTranslatef(-ds, 0, 0);
1381 glTranslatef(ds, 0, 0);
1383 glTranslatef(0, ds, 0);
1385 glTranslatef(0, -ds, 0);
1386 sphere(0.05, 10, 10, 0, 10, 0, 10);
1408 } else if (!rotate) {
1410 col[1] -= 0.0025; col[2] -= 0.0005;
1411 col2[1] -= 0.0015 ; col2[2] -= 0.0005;
1414 for (x = -XMAX/2 ; x <= XMAX/2 ; x+= 2) {
1417 glVertex3f(x, YMAX/2, -10);
1418 glVertex3f(x, -YMAX/2, -10);
1420 glVertex3f(x-0.02, YMAX/2, -10);
1421 glVertex3f(x-0.02, -YMAX/2, -10);
1422 glVertex3f(x+0.02, YMAX/2, -10);
1423 glVertex3f(x+0.02, -YMAX/2, -10);
1426 for (y = -YMAX/2 ; y <= YMAX/2 ; y+= 2) {
1429 glVertex3f(-XMAX/2, y, -10);
1430 glVertex3f(XMAX/2, y, -10);
1432 glVertex3f(-XMAX/2, y-0.02, -10);
1433 glVertex3f(XMAX/2, y-0.02, -10);
1434 glVertex3f(-XMAX/2, y+0.02, -10);
1435 glVertex3f(XMAX/2, y+0.02, -10);
1438 glEnable(GL_LIGHTING);
1441 void display(void) {
1442 static Component *c[MAX_COMPONENTS];
1444 GLfloat light_sp[] = {0.8, 0.8, 0.8, 1.0};
1445 GLfloat black[] = {0, 0, 0, 1.0};
1446 static GLfloat rotate_angle = 0; /* when 'rotate' is enabled */
1450 for (i = 0 ; i < maxparts ; i++) {
1454 glEnable(GL_LIGHTING);
1455 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
1457 gluLookAt(viewer[0], viewer[1], viewer[2], 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
1460 glRotatef(rotate_angle, 0, 0, 1);
1461 rotate_angle += 0.01 * (float)rotatespeed;
1462 if (rotate_angle >= 360) rotate_angle = 0;
1464 glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
1465 glLightfv(GL_LIGHT0, GL_SPECULAR, light_sp);
1466 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_sp);
1467 glLighti(GL_LIGHT0, GL_CONSTANT_ATTENUATION, (GLfloat)1);
1468 glLighti(GL_LIGHT0, GL_LINEAR_ATTENUATION, (GLfloat)0.5);
1469 glLighti(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, (GLfloat)0);
1471 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light_sp);
1472 if (f_rand() < 0.05) {
1473 for (j = 0 ; j < maxparts ; j++) {
1475 c[j] = NewComponent();
1481 for (j = 0 ; j < maxparts ; j++) {
1482 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, black);
1483 glMaterialfv(GL_FRONT, GL_EMISSION, black);
1484 glMaterialfv(GL_FRONT, GL_SPECULAR, black);
1486 if (DrawComponent(c[j])) {
1487 free(c[j]); c[j] = NULL;
1495 /* ensure transparent components are at the end */
1496 void reorder(Component *c[]) {
1498 Component *c1[MAX_COMPONENTS];
1499 Component *c2[MAX_COMPONENTS];
1502 for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
1506 for (i = 0 ; i < maxparts ; i++) {
1507 if (c[i] == NULL) continue;
1508 if (c[i]->alpha) { /* transparent parts go to c1 */
1511 } else { /* opaque parts go to c2 */
1515 for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
1519 for (i = 0 ; i < maxparts ; i++) { /* insert opaque part */
1520 if (c2[i] != NULL) {
1525 for (i = 0 ; i < j ; i++) { /* insert transparent parts */
1531 void reshape_circuit(ModeInfo *mi, int width, int height)
1534 glViewport(0,0,(GLint)width, (GLint) height);
1535 glMatrixMode(GL_PROJECTION);
1537 glFrustum(-1.0,1.0,-1.0,1.0,1.5,35.0);
1538 glMatrixMode(GL_MODELVIEW);
1539 win_h = height; win_w = width;
1543 void init_circuit(ModeInfo *mi)
1545 int screen = MI_SCREEN(mi);
1548 if (circuit == NULL) {
1549 if ((circuit = (Circuit *) calloc(MI_NUM_SCREENS(mi),
1550 sizeof(Circuit))) == NULL)
1553 c = &circuit[screen];
1554 c->window = MI_WINDOW(mi);
1557 if ((c->glx_context = init_GL(mi)) != NULL) {
1558 reshape_circuit(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1564 glClearColor(0.0,0.0,0.0,0.0);
1565 glShadeModel(GL_SMOOTH);
1566 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
1567 glEnable(GL_DEPTH_TEST);
1568 glEnable(GL_LIGHTING);
1569 glEnable(GL_LIGHT0);
1575 void draw_circuit(ModeInfo *mi) {
1576 Circuit *c = &circuit[MI_SCREEN(mi)];
1577 Window w = MI_WINDOW(mi);
1578 Display *disp = MI_DISPLAY(mi);
1580 if (!c->glx_context)
1583 glXMakeCurrent(disp, w, *(c->glx_context));
1587 if(mi->fps_p) do_fps(mi);
1589 glXSwapBuffers(disp, w);
1592 void release_circuit(ModeInfo *mi) {
1594 if (circuit != NULL) {
1595 (void) free((void *) circuit);