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-2015 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 * This hack uses lookup tables for sin, cos and tan - it can do a lot
33 #define DEFAULTS "*delay: 20000 \n" \
34 "*showFPS: False \n" \
35 "*componentFont: -*-courier-bold-r-normal-*-*-140-*-*-*-*-*-*"
37 # define refresh_circuit 0
38 # define circuit_handle_event 0
39 # include "xlockmore.h" /* from the xscreensaver distribution */
40 #else /* !STANDALONE */
41 # include "xlock.h" /* from the xlockmore distribution */
42 #endif /* !STANDALONE */
44 #define DEF_SPIN "True"
45 #define DEF_SEVEN "False"
46 #define DEF_PARTS "10"
47 #define DEF_ROTATESPEED "1"
48 #define DEF_LIGHT "True"
50 /* lifted from lament.c */
51 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
52 #define RANDSIGN() ((random() & 1) ? 1 : -1)
60 #define countof(x) (sizeof((x))/sizeof((*x)))
63 static int rotatespeed;
69 #define countof(x) (sizeof((x))/sizeof((*x)))
71 static XrmOptionDescRec opts[] = {
72 {"-parts", ".circuit.parts", XrmoptionSepArg, 0 },
73 {"-rotate-speed", ".circuit.rotatespeed", XrmoptionSepArg, 0 },
74 {"+spin", ".circuit.spin", XrmoptionNoArg, "false" },
75 {"-spin", ".circuit.spin", XrmoptionNoArg, "true" },
76 {"+light", ".circuit.light", XrmoptionNoArg, "false" },
77 {"-light", ".circuit.light", XrmoptionNoArg, "true" },
78 {"+seven", ".circuit.seven", XrmoptionNoArg, "false" },
79 {"-seven", ".circuit.seven", XrmoptionNoArg, "true" },
82 static argtype vars[] = {
83 {&maxparts, "parts", "Parts", DEF_PARTS, t_Int},
84 {&rotatespeed, "rotatespeed", "Rotatespeed", DEF_ROTATESPEED, t_Int},
85 {&spin, "spin", "Spin", DEF_SPIN, t_Bool},
86 {&uselight, "light", "Light", DEF_LIGHT, t_Bool},
87 {&seven, "seven", "Seven", DEF_SEVEN, t_Bool},
90 ENTRYPOINT ModeSpecOpt circuit_opts = {countof(opts), opts, countof(vars), vars, NULL};
93 ModStruct circuit_description =
94 {"circuit", "init_circuit", "draw_circuit", "release_circuit",
95 "draw_circuit", "init_circuit", NULL, &circuit_opts,
96 1000, 1, 2, 1, 4, 1.0, "",
97 "Flying electronic components", 0, NULL};
101 #define MAX_COMPONENTS 400
102 #define MOVE_MULT 0.02
104 static float f_rand(void)
106 return ((float)RAND(10000)/(float)10000);
109 #define RAND_RANGE(min, max) ((min) + (max - min) * f_rand())
111 /* Represents a band on a resistor/diode/etc */
113 float pos; /* relative position from start/previous band */
114 GLfloat r, g, b; /* colour of the band */
115 float len; /* length as a fraction of total length */
119 Band *b1, *b2, *b3, *b4; /* bands */
125 GLfloat r, g, b; /* body colour */
128 static const char * const transistortypes[] = {
144 static const char * const to92types[] = {
159 static const char * const smctypes[] = {
170 int type; /* package type. 0 = to-92, 1 = to-220 */
175 GLfloat r,g,b; /* LED colour */
176 int light; /* are we the light source? */
180 int type; /* 0 = electro, 1 = ceramic */
181 float width; /* width of an electro/ceramic */
182 float length; /* length of an electro */
200 static const ICTypes ictypes[] = {
243 int type; /* 0 = DIL, 1 = flat square */
248 /* 7 segment display */
251 int value; /* displayed number */
264 GLfloat x, y, z; /* current co-ordinates */
265 GLfloat dx, dy, dz; /* current direction */
266 GLfloat rotx, roty, rotz; /* rotation vector */
267 GLfloat drot; /* rotation velocity (degrees per frame) */
268 int norm; /* Normalize this component (for shine) */
269 int rdeg; /* current rotation degrees */
270 int angle; /* angle about the z axis */
271 int alpha; /* 0 if not a transparent component */
272 int type; /* 0 = resistor, 1 = diode, 2 = transistor, 3 = LED, 4 = cap, 5=IC,
274 void * c; /* pointer to the component */
277 /* standard colour codes */
279 static const GLfloat colorcodes [12][3] = {
280 {0.0,0.0,0.0}, /* black 0 */
281 {0.49,0.25,0.08}, /* brown 1 */
282 {1.0,0.0,0.0}, /* red 2 */
283 {1.0,0.5,0.0}, /* orange 3 */
284 {1.0,1.0,0.0}, /* yellow 4 */
285 {0.0,1.0,0.0}, /* green 5 */
286 {0.0,0.5,1.0}, /* blue 6 */
287 {0.7,0.2,1.0}, /* violet 7 */
288 {0.5,0.5,0.5}, /* grey 8 */
289 {1.0,1.0,1.0}, /* white 9 */
290 {0.66,0.56,0.2}, /* gold 10 */
291 {0.8,0.8,0.8}, /* silver 11 */
294 /* base values for components - we can multiply by 0 - 1M */
295 static const int values [9][2] = {
308 GLXContext *glx_context;
314 /* one lucky led gets to be a light source , unless -no-light*/
318 /* stores refs to textures */
324 float sin_table[720];
325 float cos_table[720];
326 float tan_table[720];
328 Component *components[MAX_COMPONENTS];
330 int band_list_polys[12];
332 GLfloat grid_col[3], grid_col2[3];
335 GLfloat rotate_angle;
337 texture_font_data *font;
338 char *font_strings[50]; /* max of 40 textures */
339 int font_w[50], font_h[50];
342 GLfloat draw_sx, draw_sy; /* bright spot co-ords */
343 int draw_sdir; /* 0 = left-right, 1 = right-left, 2 = up->dn, 3 = dn->up */
344 int draw_s; /* if spot is enabled */
345 float draw_ds; /* speed of spot */
349 static Circuit *circuit = NULL;
352 static int DrawResistor(Circuit *, Resistor *);
353 static int DrawDiode(Circuit *, Diode *);
354 static int DrawTransistor(Circuit *, Transistor *);
355 static int DrawLED(Circuit *, LED *);
356 static int DrawIC(Circuit *, IC *);
357 static int DrawCapacitor(Circuit *, Capacitor *);
358 static int DrawDisp(Circuit *, Disp *);
359 static int DrawFuse(Circuit *, Fuse *);
360 static int DrawRCA(Circuit *, RCA *);
361 static int DrawThreeFive(Circuit *, ThreeFive *);
362 static int DrawSwitch(Circuit *, Switch *);
364 static void reorder(Component *[]);
365 static int circle(Circuit *, float, int,int);
366 static int bandedCylinder(Circuit *,
367 float, float , GLfloat, GLfloat , GLfloat,
369 static int Rect(GLfloat , GLfloat , GLfloat, GLfloat , GLfloat ,GLfloat);
370 static int ICLeg(GLfloat, GLfloat, GLfloat, int);
371 static int HoledRectangle(Circuit *ci,
372 GLfloat, GLfloat, GLfloat, GLfloat, int);
373 static Resistor *NewResistor(void);
374 static Diode *NewDiode(void);
375 static Transistor *NewTransistor(ModeInfo *);
376 static LED * NewLED(Circuit *);
377 static Capacitor *NewCapacitor(Circuit *);
378 static IC* NewIC(ModeInfo *);
379 static Disp* NewDisp(Circuit *);
380 static Fuse *NewFuse(Circuit *);
381 static RCA *NewRCA(Circuit *);
382 static ThreeFive *NewThreeFive(Circuit *);
383 static Switch *NewSwitch(Circuit *);
385 /* we use trig tables to speed things up - 200 calls to sin()
386 in one frame can be a bit harsh..
389 static void make_tables(Circuit *ci)
394 f = 360 / (M_PI * 2);
395 for (i = 0 ; i < 720 ; i++) {
396 ci->sin_table[i] = sin(i/f);
398 for (i = 0 ; i < 720 ; i++) {
399 ci->cos_table[i] = cos(i/f);
401 for (i = 0 ; i < 720 ; i++) {
402 ci->tan_table[i] = tan(i/f);
407 static int createCylinder (Circuit *ci,
408 float length, float radius, int endcaps, int half)
411 int a; /* current angle around cylinder */
413 float z1, y1, z2, y2,ex;
417 nsegs = radius*MAX(ci->win_w, ci->win_h)/20;
418 nsegs = MAX(nsegs, 4);
421 angle = (half) ? (180 - 90/nsegs) : 374;
424 for (a = 0 ; a <= angle ; a+= angle/nsegs) {
425 y2=radius*(float)ci->sin_table[(int)a];
426 z2=radius*(float)ci->cos_table[(int)a];
427 glNormal3f(0, y1, z1);
429 glVertex3f(length,y1,z1);
430 glNormal3f(0, y2, z2);
431 glVertex3f(length,y2,z2);
441 glVertex3f(0, 0, radius);
442 glVertex3f(length, 0, radius);
443 glVertex3f(length, 0, 0 - radius);
444 glVertex3f(0, 0, 0 - radius);
449 for(ex = 0 ; ex <= length ; ex += length) {
451 norm = (ex == length) ? 1 : -1;
452 glBegin(GL_TRIANGLES);
453 glNormal3f(norm, 0, 0);
454 for (a = 0 ; a <= angle ; a+= angle/nsegs) {
455 y2=radius*(float)ci->sin_table[(int)a];
456 z2=radius*(float)ci->cos_table[(int)a];
458 glVertex3f(ex,y1,z1);
459 glVertex3f(ex,y2,z2);
471 static int circle(Circuit *ci, float radius, int segments, int half)
474 float x1 = 0, x2 = 0;
475 float y1 = 0, y2 = 0;
484 glBegin(GL_TRIANGLES);
489 x2=radius*(float)ci->cos_table[(int)angle];
490 y2=radius*(float)ci->sin_table[(int)angle];
502 static int wire(Circuit *ci, float len)
505 GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
506 GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
507 GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
511 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
512 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
513 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
514 n = glIsEnabled(GL_NORMALIZE);
515 if (!n) glEnable(GL_NORMALIZE);
516 polys += createCylinder(ci, len, 0.05, 1, 0);
517 if (!n) glDisable(GL_NORMALIZE);
518 glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
522 static int sphere(Circuit *ci, GLfloat r, float stacks, float slices,
523 int startstack, int endstack, int startslice,
527 GLfloat d, d1, dr, dr1, Dr, Dr1, D, D1, z1, z2, y1, y2, Y1, Z1, Y2, Z2;
528 int a, a1, b, b1, c0, c1;
533 a1 = startstack * step;
534 b1 = startslice * sstep;
535 y1 = z1 = Y1 = Z1 = 0;
536 c0 = (endslice / slices) * 360;
537 c1 = (endstack/stacks)*180;
539 for (a = startstack * step ; a <= c1 ; a+= step) {
541 d1=ci->sin_table[a1];
543 D1=ci->cos_table[a1];
548 for (b = b1 ; b <= c0 ; b+= sstep) {
549 y2=dr*ci->sin_table[b];
550 z2=dr*ci->cos_table[b];
551 Y2=dr1*ci->sin_table[b];
552 Z2=dr1*ci->cos_table[b];
553 glNormal3f(Dr, y1, z1);
554 glVertex3f(Dr,y1,z1);
555 glNormal3f(Dr, y2, z2);
556 glVertex3f(Dr,y2,z2);
557 glNormal3f(Dr1, Y2, Z2);
558 glVertex3f(Dr1,Y2,Z2);
559 glNormal3f(Dr1, Y1, Z1);
560 glVertex3f(Dr1,Y1,Z1);
573 static int DrawComponent(Circuit *ci, Component *c, unsigned long *polysP)
576 int ret = 0; /* return 1 if component is freed */
579 glTranslatef(c->x, c->y, c->z);
581 glRotatef(c->angle, c->rotx, c->roty, c->rotz);
584 glRotatef(c->rdeg, c->rotx, c->roty, c->rotz);
589 glEnable(GL_NORMALIZE);
591 glDisable(GL_NORMALIZE);
593 /* call object draw routine here */
595 polys += DrawResistor(ci, c->c);
596 } else if (c->type == 1) {
597 polys += DrawDiode(ci, c->c);
598 } else if (c->type == 2) {
599 polys += DrawTransistor(ci, c->c);
600 } else if (c->type == 3) {
601 if (((LED *)c->c)->light && ci->light) {
602 GLfloat lp[] = {0.1, 0, 0, 1};
604 glLightfv(GL_LIGHT1, GL_POSITION, lp);
606 polys += DrawLED(ci, c->c);
607 } else if (c->type == 4) {
608 polys += DrawCapacitor(ci, c->c);
609 } else if (c->type == 5) {
610 polys += DrawIC(ci, c->c);
611 } else if (c->type == 6) {
612 polys += DrawDisp(ci, c->c);
613 } else if (c->type == 7) {
614 polys += DrawFuse(ci, c->c);
615 } else if (c->type == 8) {
616 polys += DrawRCA(ci, c->c);
617 } else if (c->type == 9) {
618 polys += DrawThreeFive(ci, c->c);
619 } else if (c->type == 10) {
620 polys += DrawSwitch(ci, c->c);
622 c->x += c->dx * MOVE_MULT;
623 c->y += c->dy * MOVE_MULT;
624 if (c->x > ci->XMAX/2 || c->x < 0 - ci->XMAX/2 ||
625 c->y > ci->YMAX/2 || c->y < 0 - ci->YMAX/2) {
626 if (c->type == 3 && ((LED *)c->c)->light && ci->light) {
627 glDisable(GL_LIGHT1);
628 ci->light = 0; ci->lighton = 0;
631 free(((Diode *)c->c)->band); /* remember to free diode band */
637 glDisable(GL_NORMALIZE);
642 /* draw a resistor */
644 static int DrawResistor(Circuit *ci, Resistor *r)
648 GLfloat col[] = {0.74, 0.62, 0.46, 1.0};
649 GLfloat spec[] = {0.8, 0.8, 0.8, 1.0};
652 glTranslatef(-4, 0, 0);
653 polys += wire(ci, 3);
654 glTranslatef(3, 0, 0);
655 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
656 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
657 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
658 polys += createCylinder(ci, 1.8, 0.4, 1, 0);
660 for (i = 0 ; i < 4 ; i++) {
661 glTranslatef(0.35, 0, 0);
662 glCallList(ci->band_list[r->b[i]]);
663 polys += ci->band_list_polys[r->b[i]];
666 glTranslatef(1.8, 0, 0);
667 polys += wire(ci, 3);
671 static int DrawRCA(Circuit *ci, RCA *rca)
674 GLfloat col[] = {0.6, 0.6, 0.6, 1.0}; /* metal */
675 GLfloat red[] = {1.0, 0.0, 0.0, 1.0}; /* red */
676 GLfloat white[] = {1.0, 1.0, 1.0, 1.0}; /* white */
677 GLfloat spec[] = {1, 1, 1, 1}; /* glass */
680 glTranslatef(0.3, 0, 0);
681 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
682 glMateriali(GL_FRONT, GL_SHININESS, 40);
683 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
684 polys += createCylinder(ci, 0.7, 0.45, 0, 0);
685 glTranslatef(0.4, 0, 0);
686 polys += createCylinder(ci, 0.9, 0.15, 1, 0);
687 glTranslatef(-1.9, 0, 0);
688 glMateriali(GL_FRONT, GL_SHININESS, 20);
689 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, rca->col ? white : red);
690 polys += createCylinder(ci, 1.5, 0.6, 1, 0);
691 glTranslatef(-0.9, 0, 0);
692 polys += createCylinder(ci, 0.9, 0.25, 0, 0);
693 glTranslatef(0.1, 0, 0);
694 polys += createCylinder(ci, 0.2, 0.3, 0, 0);
695 glTranslatef(0.3, 0, 0);
696 polys += createCylinder(ci, 0.2, 0.3, 1, 0);
697 glTranslatef(0.3, 0, 0);
698 polys += createCylinder(ci, 0.2, 0.3, 1, 0);
703 static int DrawSwitch(Circuit *ci, Switch *f)
706 GLfloat col[] = {0.6, 0.6, 0.6, 0}; /* metal */
707 GLfloat dark[] = {0.1, 0.1, 0.1, 1.0}; /* dark */
708 GLfloat brown[] = {0.69, 0.32, 0, 1.0}; /* brown */
709 GLfloat spec[] = {0.9, 0.9, 0.9, 1}; /* shiny */
712 glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
713 glMaterialfv(GL_FRONT, GL_AMBIENT, dark);
714 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
715 glMateriali(GL_FRONT, GL_SHININESS, 90);
716 polys += Rect(-0.25, 0, 0, 1.5, 0.5, 0.75);
717 /* polys += Rect(-0.5, 0.5, 0, 2, 0.1, 0.75); */
719 glRotatef(90, 1, 0, 0);
720 glTranslatef(-0.5, -0.4, -0.4);
721 polys += HoledRectangle(ci, 0.5, 0.75, 0.1, 0.15, 8);
722 glTranslatef(2, 0, 0);
723 polys += HoledRectangle(ci, 0.5, 0.75, 0.1, 0.15, 8);
725 polys += Rect(0.1, -0.4, -0.25, 0.1, 0.4, 0.05);
726 polys += Rect(0.5, -0.4, -0.25, 0.1, 0.4, 0.05);
727 polys += Rect(0.9, -0.4, -0.25, 0.1, 0.4, 0.05);
728 polys += Rect(0.1, -0.4, -0.5, 0.1, 0.4, 0.05);
729 polys += Rect(0.5, -0.4, -0.5, 0.1, 0.4, 0.05);
730 polys += Rect(0.9, -0.4, -0.5, 0.1, 0.4, 0.05);
731 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, dark);
732 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
733 polys += Rect(0, 0.5, -0.1, 1, 0.05, 0.5);
734 polys += Rect(0, 0.6, -0.1, 0.5, 0.6, 0.5);
735 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, brown);
736 polys += Rect(-0.2, -0.01, -0.1, 1.4, 0.1, 0.55);
742 static int DrawFuse(Circuit *ci, Fuse *f)
745 GLfloat col[] = {0.5, 0.5, 0.5, 1.0}; /* endcaps */
746 GLfloat glass[] = {0.4, 0.4, 0.4, 0.3}; /* glass */
747 GLfloat spec[] = {1, 1, 1, 1}; /* glass */
750 glTranslatef(-1.8, 0, 0);
751 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
752 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
753 glMateriali(GL_FRONT, GL_SHININESS, 40);
754 polys += createCylinder(ci, 0.8, 0.45, 1, 0);
755 glTranslatef(0.8, 0, 0);
757 glDepthMask(GL_FALSE);
758 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, glass);
759 glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 40);
760 polys += createCylinder(ci, 2, 0.4, 0, 0);
761 polys += createCylinder(ci, 2, 0.3, 0, 0);
763 glDepthMask(GL_TRUE);
764 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
765 glMateriali(GL_FRONT, GL_SHININESS, 40);
768 glVertex3f(2, 0. ,0);
770 glTranslatef(2, 0, 0);
771 polys += createCylinder(ci, 0.8, 0.45, 1, 0);
777 static int DrawCapacitor(Circuit *ci, Capacitor *c)
780 GLfloat col[] = {0, 0, 0, 0};
781 GLfloat spec[] = {0.8, 0.8, 0.8, 0};
782 GLfloat brown[] = {0.84, 0.5, 0};
787 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, brown);
788 polys += sphere(ci, c->width, 15, 15, 0, 4 ,0, 15);
789 glTranslatef(1.35*c->width, 0, 0);
790 polys += sphere(ci, c->width, 15, 15, 11, 15, 0, 15);
791 glRotatef(90, 0, 0, 1);
792 glTranslatef(0, 0.7*c->width, 0.3*c->width);
793 polys += wire(ci, 3*c->width);
794 glTranslatef(0, 0, -0.6*c->width);
795 polys += wire(ci, 3*c->width);
797 glTranslatef(0-c->length*2, 0, 0);
798 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
799 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
800 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
802 glVertex3f(0, 0.82*c->width, -0.1);
803 glVertex3f(3*c->length, 0.82*c->width, -0.1);
804 glVertex3f(3*c->length, 0.82*c->width, 0.1);
805 glVertex3f(0, 0.82*c->width, 0.1);
810 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
811 glEnable(GL_POLYGON_OFFSET_FILL);
812 glPolygonOffset(1.0, 1.0);
813 polys += createCylinder(ci, 3.0*c->length, 0.8*c->width, 1, 0);
814 glDisable(GL_POLYGON_OFFSET_FILL);
818 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
819 polys += circle(ci, 0.6*c->width, 30, 0);
823 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
824 glTranslatef(3.0*c->length, 0.0, 0);
825 polys += circle(ci, 0.6*c->width, 30, 0);
826 glTranslatef(0, 0.4*c->width, 0);
827 polys += wire(ci, 3*c->length);
828 glTranslatef(0.0, -0.8*c->width, 0);
829 polys += wire(ci, 3.3*c->length);
835 static int DrawLED(Circuit *ci, LED *l)
838 GLfloat col[] = {0, 0, 0, 0.6};
839 GLfloat black[] = {0, 0, 0, 0.6};
841 col[0] = l->r; col[1] = l->g; col[2] = l->b;
842 if (l->light && ci->light) {
843 GLfloat dir[] = {-1, 0, 0};
844 glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, dir);
846 glLightfv(GL_LIGHT1, GL_SPECULAR, col);
847 glLightfv(GL_LIGHT1, GL_AMBIENT, black);
848 col[0] /= 1.5; col[1] /= 1.5; col[2] /= 1.5;
849 glLightfv(GL_LIGHT1, GL_DIFFUSE, col);
850 glLighti(GL_LIGHT1, GL_SPOT_CUTOFF, (GLint) 90);
851 glLighti(GL_LIGHT1, GL_CONSTANT_ATTENUATION, (GLfloat)1);
852 glLighti(GL_LIGHT1, GL_LINEAR_ATTENUATION, (GLfloat)0);
853 glLighti(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, (GLfloat)0);
854 glLighti(GL_LIGHT1, GL_SPOT_EXPONENT, (GLint) 20);
858 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
859 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
860 /* no transparency when LED is lit */
863 glDepthMask(GL_FALSE);
864 glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
866 glTranslatef(-0.9, 0, 0);
867 polys += createCylinder(ci, 1.2, 0.3, 0, 0);
868 if (l->light && ci->light) {
869 glDisable(GL_LIGHTING);
872 polys += sphere(ci, 0.3, 7, 7, 3, 7, 0, 7);
873 if (l->light && ci->light) {
874 glEnable(GL_LIGHTING);
876 glDepthMask(GL_TRUE);
880 glTranslatef(1.2, 0, 0);
881 polys += createCylinder(ci, 0.1, 0.38, 1, 0);
882 glTranslatef(-0.3, 0.15, 0);
883 polys += wire(ci, 3);
884 glTranslatef(0, -0.3, 0);
885 polys += wire(ci, 3.3);
886 if (random() % 50 == 25) {
888 l->light = 0; ci->light = 0; ci->lighton = 0;
889 glDisable(GL_LIGHT1);
890 } else if (!ci->light) {
899 static int DrawThreeFive(Circuit *ci, ThreeFive *d)
903 GLfloat const dark[] = {0.3, 0.3, 0.3, 0};
904 GLfloat const light[] = {0.6, 0.6, 0.6, 0};
905 GLfloat const cream[] = {0.8, 0.8, 0.6, 0};
906 GLfloat const spec[] = {0.7, 0.7, 0.7, 0};
909 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
910 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cream);
911 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
913 glTranslatef(-2.0, 0, 0);
914 polys += createCylinder(ci, 0.7, 0.2, 0, 0);
915 glTranslatef(0.7, 0, 0);
916 polys += createCylinder(ci, 1.3, 0.4, 1, 0);
917 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light);
918 glTranslatef(1.3, 0, 0);
919 polys += createCylinder(ci, 1.3, 0.2, 0, 0);
920 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, dark);
921 glTranslatef(0.65, 0, 0);
922 polys += createCylinder(ci, 0.15, 0.21, 0, 0);
923 glTranslatef(0.3, 0, 0);
924 polys += createCylinder(ci, 0.15, 0.21, 0, 0);
925 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light);
926 glTranslatef(0.4, 0, 0);
927 polys += sphere(ci, 0.23, 7, 7, 0, 5, 0, 7);
933 static int DrawDiode(Circuit *ci, Diode *d)
937 GLfloat col[] = {0.3, 0.3, 0.3, 0};
938 GLfloat spec[] = {0.7, 0.7, 0.7, 0};
941 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
942 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
943 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
944 glTranslatef(-4, 0, 0);
945 polys += wire(ci, 3);
946 glTranslatef(3, 0, 0);
947 polys += bandedCylinder(ci, 0.3, 1.5, d->r, d->g, d->b, &(d->band), 1);
948 glTranslatef(1.5, 0, 0);
949 polys += wire(ci, 3);
954 static int Rect(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h,
962 yh = y+h; xw = x+w; zt = z - t;
964 glBegin(GL_QUADS); /* front */
967 glVertex3f(x, yh, z);
968 glVertex3f(xw, yh, z);
969 glVertex3f(xw, y, z);
972 glNormal3f(0, 0, -1);
973 glVertex3f(x, y, zt);
974 glVertex3f(x, yh, zt);
975 glVertex3f(xw, yh, zt);
976 glVertex3f(xw, y, zt);
980 glVertex3f(x, yh, z);
981 glVertex3f(x, yh, zt);
982 glVertex3f(xw, yh, zt);
983 glVertex3f(xw, yh, z);
986 glNormal3f(0, -1, 0);
988 glVertex3f(x, y, zt);
989 glVertex3f(xw, y, zt);
990 glVertex3f(xw, y, z);
993 glNormal3f(-1, 0, 0);
995 glVertex3f(x, y, zt);
996 glVertex3f(x, yh, zt);
997 glVertex3f(x, yh, z);
1000 glNormal3f(1, 0, 0);
1001 glVertex3f(xw, y, z);
1002 glVertex3f(xw, y, zt);
1003 glVertex3f(xw, yh, zt);
1004 glVertex3f(xw, yh, z);
1012 static int ICLeg(GLfloat x, GLfloat y, GLfloat z, int dir)
1016 polys += Rect(x-0.1, y, z, 0.1, 0.1, 0.02);
1017 polys += Rect(x-0.1, y, z, 0.02, 0.1, 0.1);
1018 polys += Rect(x-0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
1020 polys += Rect(x, y, z, 0.1, 0.1, 0.02);
1021 polys += Rect(x+0.8*0.1, y, z, 0.02, 0.1, 0.1);
1022 polys += Rect(x+0.8*0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
1028 static int DrawIC(Circuit *ci, IC *c)
1033 GLfloat col[] = {0.1, 0.1, 0.1, 0};
1034 GLfloat col2[] = {0.2, 0.2, 0.2, 0};
1035 GLfloat spec[] = {0.6, 0.6, 0.6, 0};
1037 GLfloat lspec[] = {0.6, 0.6, 0.6, 0};
1038 GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
1039 GLfloat lshine = 40;
1043 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1044 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1045 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1046 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
1063 glEnable(GL_POLYGON_OFFSET_FILL);
1064 glPolygonOffset(1.0, 1.0);
1066 glNormal3f(0, 0, 1);
1067 glVertex3f(w, h, 0.1);
1068 glVertex3f(w, -h, 0.1);
1069 glVertex3f(-w, -h, 0.1);
1070 glVertex3f(-w, h, 0.1);
1072 glNormal3f(0, 0, -1);
1073 glVertex3f(w, h, -0.1);
1074 glVertex3f(w, -h, -0.1);
1075 glVertex3f(-w, -h, -0.1);
1076 glVertex3f(-w, h, -0.1);
1078 glNormal3f(1, 0, 0);
1079 glVertex3f(w, h, -0.1);
1080 glVertex3f(w, -h, -0.1);
1081 glVertex3f(w, -h, 0.1);
1082 glVertex3f(w, h, 0.1);
1084 glNormal3f(0, -1, 0);
1085 glVertex3f(w, -h, -0.1);
1086 glVertex3f(w, -h, 0.1);
1087 glVertex3f(-w, -h, 0.1);
1088 glVertex3f(-w, -h, -0.1);
1090 glNormal3f(-1, 0, 0);
1091 glVertex3f(-w, h, -0.1);
1092 glVertex3f(-w, h, 0.1);
1093 glVertex3f(-w, -h, 0.1);
1094 glVertex3f(-w, -h, -0.1);
1096 glNormal3f(0, -1, 0);
1097 glVertex3f(-w, h, -0.1);
1098 glVertex3f(w, h, -0.1);
1099 glVertex3f(w, h, 0.1);
1100 glVertex3f(-w, h, 0.1);
1103 glDisable(GL_POLYGON_OFFSET_FILL);
1104 glEnable(GL_TEXTURE_2D);
1113 GLfloat texfg[] = {0.7, 0.7, 0.7, 1.0};
1117 texture_string_metrics (ci->font, c->text, &e, 0, 0);
1119 h = e.ascent + e.descent;
1122 glTranslatef (0, 0, 0.1);
1123 glRotatef (90, 0, 0, 1);
1125 glTranslatef (-w/2, 0, 0);
1127 print_texture_string (ci->font, c->text);
1131 glDisable(GL_TEXTURE_2D);
1132 glDisable(GL_BLEND);
1133 d = (h*2-0.1) / c->pins;
1135 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
1136 glMaterialfv(GL_FRONT, GL_SPECULAR, lspec);
1137 glMaterialfv(GL_FRONT, GL_SHININESS, &lshine);
1138 for (z = 0 ; z < c->pins/2 ; z++) {
1139 polys += ICLeg(w, -h + z*d + d/2, 0, 0);
1141 for (z = 0 ; z < c->pins/2 ; z++) {
1142 polys += ICLeg(-w, -h + z*d + d/2, 0, 1);
1144 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col2);
1145 glTranslatef(-w+0.3, h-0.3, 0.1);
1146 glRotatef(90, 0, 1, 0);
1147 polys += circle(ci, 0.1, 7, 0);
1152 static int DrawDisp(Circuit *ci, Disp *d)
1155 GLfloat col[] = {0.8, 0.8, 0.8, 1.0}; /* body colour */
1156 GLfloat front[] = {0.2, 0.2, 0.2, 1.0}; /* front colour */
1157 GLfloat on[] = {0.9, 0, 0, 1}; /* 'on' segment */
1158 GLfloat off[] = {0.3, 0, 0, 1}; /* 'off' segment */
1160 GLfloat x, y; /* for the pins */
1161 GLfloat spec[] = {0.6, 0.6, 0.6, 0};
1162 GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
1164 static const GLfloat vdata_h[6][2] = {
1172 static const GLfloat vdata_v[6][2] = {
1181 static const GLfloat seg_start[7][2] = {
1191 static const int nums[10][7] = {
1192 {1, 1, 1, 1, 1, 1, 0}, /* 0 */
1193 {0, 1, 1, 0, 0, 0, 0}, /* 1 */
1194 {1, 1, 0, 1, 1, 0, 1}, /* 2 */
1195 {1, 1, 1, 1, 0, 0, 1}, /* 3 */
1196 {0, 1, 1, 0, 0, 1, 1}, /* 4 */
1197 {1, 0, 1, 1, 0, 1, 1}, /* 5 */
1198 {1, 0, 1, 1, 1, 1, 1}, /* 6 */
1199 {1, 1, 1, 0, 0, 0, 0}, /* 7 */
1200 {1, 1, 1, 1, 1, 1, 1}, /* 8 */
1201 {1, 1, 1, 0, 0, 1, 1} /* 9 */
1204 glTranslatef(-0.9, -1.8, 0);
1205 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1206 polys += Rect(0, 0, -0.01, 1.8, 2.6, 0.7);
1207 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, front);
1209 glVertex2f(-0.05, -0.05);
1210 glVertex2f(-0.05, 2.65);
1211 glVertex2f(1.85, 2.65);
1212 glVertex2f(1.85, -0.05);
1215 glDisable(GL_LIGHTING); /* lit segments dont need light */
1216 if (!seven && (random() % 30) == 19) { /* randomly change value */
1217 d->value = random() % 10;
1219 for (j = 0 ; j < 7 ; j++) { /* draw the segments */
1220 GLfloat xx[6], yy[6];
1221 if (nums[d->value][j])
1225 for (k = 0 ; k < 6 ; k++) {
1226 if (j == 0 || j == 3 || j == 6) {
1227 xx[k] = seg_start[j][0] + vdata_h[k][0];
1228 yy[k] = seg_start[j][1] + vdata_h[k][1];
1230 xx[k] = seg_start[j][0] + vdata_v[k][0];
1231 yy[k] = seg_start[j][1] + vdata_v[k][1];
1234 glBegin(GL_POLYGON);
1235 for(i = 0 ; i < 6 ; i++) {
1236 glVertex3f(xx[i], yy[i], 0.01);
1244 glVertex3f(1.5, 0.2, 0.01);
1247 glEnable(GL_LIGHTING);
1248 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
1249 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1250 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
1251 for (x = 0.35 ; x <= 1.5 ; x+= 1.15) {
1252 for ( y = 0.2 ; y <= 2.4 ; y += 0.3) {
1253 polys += ICLeg(x, y, -0.7, 1);
1259 static int HoledRectangle(Circuit *ci,
1260 GLfloat w, GLfloat h, GLfloat d, GLfloat radius,
1265 GLfloat x1, y1, x2, y2;
1266 GLfloat yr, yr1, xr, xr1, side, side1;
1270 x1 = radius; y1 = 0;
1275 for (a = 0 ; a <= 360 ; a+= step) {
1276 y2=radius*(float)ci->sin_table[(int)a];
1277 x2=radius*(float)ci->cos_table[(int)a];
1279 if (a < 45 || a > 315) {
1281 yr = side1 * ci->tan_table[a];
1283 } else if (a <= 135 || a >= 225) {
1284 xr = side/ci->tan_table[a];
1295 yr = -side1 * ci->tan_table[a];
1299 glNormal3f(-x1, -y1, 0); /* cylinder */
1300 glVertex3f(x1,y1,0);
1301 glVertex3f(x1,y1,-d);
1302 glVertex3f(x2,y2,-d);
1303 glVertex3f(x2,y2,0);
1306 glNormal3f(0, 0, 1); /* front face */
1307 glVertex3f(x1,y1,0);
1308 glVertex3f(xr1, yr1, 0);
1309 glVertex3f(xr, yr, 0);
1310 glVertex3f(x2, y2, 0);
1313 glNormal3f(nx, ny, 0); /* side */
1314 glVertex3f(xr, yr, 0);
1315 glVertex3f(xr, yr, -d);
1316 glVertex3f(xr1, yr1, -d);
1317 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);
1335 static int DrawTransistor(Circuit *ci, Transistor *t)
1338 GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
1339 GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
1340 GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
1344 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1345 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col);
1346 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1347 if (t->type == 1) { /* TO-92 style */
1348 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1349 glRotatef(90, 0, 1, 0);
1350 glRotatef(90, 0, 0, 1);
1351 polys += createCylinder(ci, 1.0, 0.4, 1, 1);
1352 polys += Rect(0, -0.2, 0.4, 1, 0.2, 0.8);
1353 /* Draw the markings */
1356 GLfloat texfg[] = {0.7, 0.7, 0.7, 1.0};
1360 texture_string_metrics (ci->font, t->text, &e, 0, 0);
1362 h = e.ascent + e.descent;
1364 glRotatef (90, 1, 0, 0);
1365 glTranslatef (0.5, -0.05, 0.21);
1367 glTranslatef (-w/2, 0, 0);
1369 print_texture_string (ci->font, t->text);
1373 glDisable(GL_TEXTURE_2D);
1374 glDisable(GL_BLEND);
1375 glDepthMask(GL_TRUE);
1376 glTranslatef(-2, 0, -0.2);
1377 polys += wire(ci, 2);
1378 glTranslatef(0, 0, 0.2);
1379 polys += wire(ci, 2);
1380 glTranslatef(0, 0, 0.2);
1381 polys += wire(ci, 2);
1382 } else if (t->type == 0) { /* TO-220 Style */
1383 polys += Rect(0, 0, 0, 1.5, 1.5, 0.5);
1385 GLfloat texfg[] = {0.7, 0.7, 0.7, 1.0};
1389 texture_string_metrics (ci->font, t->text, &e, 0, 0);
1391 h = e.ascent + e.descent;
1393 glTranslatef (0.75, 0.75, 0.01);
1395 glTranslatef (-w/2, 0, 0);
1397 print_texture_string (ci->font, t->text);
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 polys += 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 polys += HoledRectangle(ci, 1.5, 0.75, 0.25, 0.2, 8);
1410 glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
1411 glTranslatef(-0.375, -1.875, 0);
1412 glRotatef(90, 0, 0, -1);
1413 polys += wire(ci, 2);
1414 glTranslatef(0, 0.375, 0);
1415 polys += wire(ci, 2);
1416 glTranslatef(0, 0.375, 0);
1417 polys += wire(ci, 2);
1418 } else { /* SMC transistor */
1420 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1421 glTranslatef(-0.5, -0.25, 0.1);
1422 polys += Rect(0, 0, 0, 1, 0.5, 0.2);
1423 /* Draw the markings */
1424 glEnable(GL_TEXTURE_2D);
1426 glDepthMask(GL_FALSE);
1428 glNormal3f(0, 0, 1);
1430 glVertex3f(0.2, 0, 0.01);
1432 glVertex3f(0.8, 0, 0.01);
1434 glVertex3f(0.8, 0.5, 0.01);
1436 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 polys += Rect(0.25, -0.1, -0.05, 0.1, 0.1, 0.2);
1447 polys += Rect(0.75, -0.1, -0.05, 0.1, 0.1, 0.2);
1448 polys += Rect(0.5, 0.5, -0.05, 0.1, 0.1, 0.2);
1449 polys += Rect(0.25, -0.2, -0.2, 0.1, 0.15, 0.1);
1450 polys += Rect(0.75, -0.2, -0.2, 0.1, 0.15, 0.1);
1451 polys += Rect(0.5, 0.5, -0.2, 0.1, 0.15, 0.1);
1457 static Component * NewComponent(ModeInfo *mi)
1459 Circuit *ci = &circuit[MI_SCREEN(mi)];
1463 c = malloc(sizeof(Component));
1464 c->angle = RAND_RANGE(0,360);
1466 if (rnd < 0.25) { /* come from the top */
1468 c->x = RAND_RANGE(0, ci->XMAX) - ci->XMAX/2;
1470 c->dx = 0 - RAND_RANGE(0.5, 2);
1472 c->dx = RAND_RANGE(0.5, 2);
1473 c->dy = 0 - RAND_RANGE(0.5, 2);
1474 } else if (rnd < 0.5) { /* come from the bottom */
1475 c->y = 0 - ci->YMAX/2;
1476 c->x = RAND_RANGE(0, ci->XMAX) - ci->XMAX/2;
1478 c->dx = 0 - RAND_RANGE(0.5, 2);
1480 c->dx = RAND_RANGE(0.5, 2);
1481 c->dy = RAND_RANGE(0.5, 2);
1482 } else if (rnd < 0.75) { /* come from the left */
1483 c->x = 0 - ci->XMAX/2;
1484 c->y = RAND_RANGE(0, ci->YMAX) - ci->YMAX/2;
1485 c->dx = RAND_RANGE(0.5, 2);
1487 c->dy = 0 - RAND_RANGE(0.5, 2);
1489 c->dy = RAND_RANGE(0.5, 2);
1490 } else { /* come from the right */
1492 c->y = RAND_RANGE(0, ci->YMAX) - ci->YMAX/2;
1493 c->dx = 0 - RAND_RANGE(0.5, 2);
1495 c->dy = 0 - RAND_RANGE(0.5, 2);
1497 c->dy = RAND_RANGE(0.5, 2);
1499 c->z = RAND_RANGE(0, 7) - 9;
1503 c->drot = f_rand() * 3;
1505 c->dz = f_rand()*2 - 1;
1507 c->alpha = 0; /* explicitly set to 1 later */
1508 rnd = random() % 11;
1510 c->c = NewResistor();
1513 c->norm = 1; /* some resistors shine */
1514 } else if (rnd < 2) {
1517 c->norm = 1; /* some diodes shine */
1519 } else if (rnd < 3) {
1520 c->c = NewTransistor(mi);
1523 } else if (rnd < 4) {
1524 c->c = NewCapacitor(ci);
1527 } else if (rnd < 5) {
1531 } else if (rnd < 6) {
1536 } else if (rnd < 7) {
1541 } else if (rnd < 8) {
1545 } else if (rnd < 9) {
1546 c->c = NewThreeFive(ci);
1549 } else if (rnd < 10) {
1550 c->c = NewSwitch(ci);
1560 static Transistor *NewTransistor(ModeInfo *mi)
1564 t = malloc(sizeof(Transistor));
1565 t->type = (random() % 3);
1567 t->text = transistortypes[random() % countof(transistortypes)];
1568 } else if (t->type == 2) {
1569 t->text = smctypes[random() % countof(smctypes)];
1570 } else if (t->type == 1) {
1571 t->text = to92types[random() % countof(to92types)];
1576 static Capacitor *NewCapacitor(Circuit *ci)
1580 c = malloc(sizeof(Capacitor));
1581 c->type = (f_rand() < 0.5);
1583 c->length = RAND_RANGE(0.5, 1);
1584 c->width = RAND_RANGE(0.5, 1);
1586 c->width = RAND_RANGE(0.3, 1);
1591 /* 7 segment display */
1593 static Disp *NewDisp(Circuit *ci)
1597 d = malloc(sizeof(Disp));
1601 d->value = RAND_RANGE(0, 10);
1606 static IC *NewIC(ModeInfo *mi)
1611 int types[countof(ictypes)], i, n = 0;
1613 c = malloc(sizeof(IC));
1615 switch((int)RAND_RANGE(0,4)) {
1630 for (i = 0 ; i < countof(ictypes) ; i++) {
1631 if (ictypes[i].pins == pins) {
1637 if (n > countof(types)) abort();
1638 val = ictypes[types[random() % n]].val;
1639 sprintf(c->text, "%s\n%02d%02d", val,
1640 (int)RAND_RANGE(80, 100), (int)RAND_RANGE(1,53));
1645 static LED *NewLED(Circuit *ci)
1650 l = malloc(sizeof(LED));
1653 if (!ci->light && (f_rand() < 0.4)) {
1658 l->r = 0.9; l->g = 0; l->b = 0;
1659 } else if (r < 0.4) {
1660 l->r = 0.3; l->g = 0.9; l->b = 0;
1661 } else if (r < 0.6) {
1662 l->r = 0.8; l->g = 0.9; l->b = 0;
1663 } else if (r < 0.8) {
1664 l->r = 0.0; l->g = 0.2; l->b = 0.8;
1666 l->r = 0.9, l->g = 0.55, l->b = 0;
1671 static Fuse *NewFuse(Circuit *ci)
1675 f = malloc(sizeof(Fuse));
1679 static RCA *NewRCA(Circuit *ci)
1683 r = malloc(sizeof(RCA));
1684 r->col = (random() % 10 < 5);
1688 static ThreeFive *NewThreeFive(Circuit *ci)
1692 r = malloc(sizeof(ThreeFive));
1696 static Switch *NewSwitch(Circuit *ci)
1700 s = malloc(sizeof(Switch));
1705 static Diode *NewDiode(void)
1710 ret = malloc(sizeof(Diode));
1711 b = malloc(sizeof(Band));
1714 if (f_rand() < 0.5) {
1718 ret->r = 0.7; ret->g = 0.1 ; ret->b = 0.1;
1723 ret->r = 0.2; ret->g = 0.2 ; ret->b = 0.2;
1730 static Resistor * NewResistor(void)
1732 int v, m, t; /* value, multiplier, tolerance */
1737 t = (RAND(10) < 5) ? 10 : 11;
1738 ret = malloc(sizeof(Resistor));
1741 ret->b[0] = ret->b[1] = ret->b[2] = 7;
1743 ret->b[0] = values[v][0];
1744 ret->b[1] = values[v][1];
1752 static void makebandlist(Circuit *ci)
1755 GLfloat col[] = {0,0,0,0};
1756 GLfloat spec[] = {0.8,0.8,0.8,0};
1759 for (i = 0 ; i < 12 ; i++) {
1760 ci->band_list[i] = glGenLists(1);
1761 glNewList(ci->band_list[i], GL_COMPILE);
1762 col[0] = colorcodes[i][0];
1763 col[1] = colorcodes[i][1];
1764 col[2] = colorcodes[i][2];
1765 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
1766 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
1767 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
1768 ci->band_list_polys[i] = createCylinder(ci, 0.1, 0.42, 0, 0);
1774 static int bandedCylinder(Circuit *ci,
1775 float radius, float l,
1776 GLfloat r, GLfloat g, GLfloat bl,
1777 Band **b, int nbands)
1780 int n; /* band number */
1781 GLfloat col[] = {0,0,0,0};
1783 col[0] = r; col[1] = g; col[2] = bl;
1784 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1785 polys += createCylinder(ci, l, radius, 1, 0); /* body */
1786 for (n = 0 ; n < nbands ; n++) {
1788 glTranslatef(b[n]->pos*l, 0, 0);
1789 col[0] = b[n]->r; col[1] = b[n]->g; col[2] = b[n]->b;
1790 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1791 polys += createCylinder(ci, b[n]->len*l, radius*1.05, 0, 0); /* band */
1797 static int drawgrid(Circuit *ci)
1801 GLfloat col3[] = {0, 0.8, 0};
1804 if (f_rand() < ((rotatespeed > 0) ? 0.05 : 0.01)) {
1805 ci->draw_sdir = RAND_RANGE(0, 4);
1806 ci->draw_ds = RAND_RANGE(0.4, 0.8);
1807 switch (ci->draw_sdir) {
1809 ci->draw_sx = -ci->XMAX/2;
1810 ci->draw_sy = ((int)RAND_RANGE(0, ci->YMAX/2))*2 - ci->YMAX/2;
1813 ci->draw_sx = ci->XMAX/2;
1814 ci->draw_sy = ((int)RAND_RANGE(0, ci->YMAX/2))*2 - ci->YMAX/2;
1817 ci->draw_sy = ci->YMAX/2;
1818 ci->draw_sx = ((int)RAND_RANGE(0, ci->XMAX/2))*2 - ci->XMAX/2;
1821 ci->draw_sy = -ci->YMAX/2;
1822 ci->draw_sx = ((int)RAND_RANGE(0, ci->XMAX/2))*2 - ci->XMAX/2;
1827 } else if (rotatespeed <= 0) {
1828 if (ci->grid_col[1] < 0.25) {
1829 ci->grid_col[1] += 0.025; ci->grid_col[2] += 0.005;
1830 ci->grid_col2[1] += 0.015 ; ci->grid_col2[2] += 0.005;
1834 glDisable(GL_LIGHTING);
1838 glTranslatef(ci->draw_sx, ci->draw_sy, -10);
1839 polys += sphere(ci, 0.1, 10, 10, 0, 10, 0, 10);
1840 if (ci->draw_sdir == 0)
1841 glTranslatef(-ci->draw_ds, 0, 0);
1842 if (ci->draw_sdir == 1)
1843 glTranslatef(ci->draw_ds, 0, 0);
1844 if (ci->draw_sdir == 2)
1845 glTranslatef(0, ci->draw_ds, 0);
1846 if (ci->draw_sdir == 3)
1847 glTranslatef(0, -ci->draw_ds, 0);
1848 polys += sphere(ci, 0.05, 10, 10, 0, 10, 0, 10);
1850 if (ci->draw_sdir == 0) {
1851 ci->draw_sx += ci->draw_ds;
1852 if (ci->draw_sx > ci->XMAX/2)
1855 if (ci->draw_sdir == 1) {
1856 ci->draw_sx -= ci->draw_ds;
1857 if (ci->draw_sx < -ci->XMAX/2)
1860 if (ci->draw_sdir == 2) {
1861 ci->draw_sy -= ci->draw_ds;
1862 if (ci->draw_sy < ci->YMAX/2)
1865 if (ci->draw_sdir == 3) {
1866 ci->draw_sy += ci->draw_ds;
1867 if (ci->draw_sy > ci->YMAX/2)
1870 } else if (rotatespeed <= 0) {
1871 if (ci->grid_col[1] > 0) {
1872 ci->grid_col[1] -= 0.0025; ci->grid_col[2] -= 0.0005;
1873 ci->grid_col2[1] -= 0.0015 ; ci->grid_col2[2] -= 0.0005;
1876 for (x = -ci->XMAX/2 ; x <= ci->XMAX/2 ; x+= 2) {
1877 glColor3fv(ci->grid_col);
1879 glVertex3f(x, ci->YMAX/2, -10);
1880 glVertex3f(x, -ci->YMAX/2, -10);
1881 glColor3fv(ci->grid_col2);
1882 glVertex3f(x-0.02, ci->YMAX/2, -10);
1883 glVertex3f(x-0.02, -ci->YMAX/2, -10);
1884 glVertex3f(x+0.02, ci->YMAX/2, -10);
1885 glVertex3f(x+0.02, -ci->YMAX/2, -10);
1888 for (y = -ci->YMAX/2 ; y <= ci->YMAX/2 ; y+= 2) {
1889 glColor3fv(ci->grid_col);
1891 glVertex3f(-ci->XMAX/2, y, -10);
1892 glVertex3f(ci->XMAX/2, y, -10);
1893 glColor3fv(ci->grid_col2);
1894 glVertex3f(-ci->XMAX/2, y-0.02, -10);
1895 glVertex3f(ci->XMAX/2, y-0.02, -10);
1896 glVertex3f(-ci->XMAX/2, y+0.02, -10);
1897 glVertex3f(ci->XMAX/2, y+0.02, -10);
1900 glEnable(GL_LIGHTING);
1904 static void display(ModeInfo *mi)
1906 Circuit *ci = &circuit[MI_SCREEN(mi)];
1907 GLfloat light_sp[] = {0.8, 0.8, 0.8, 1.0};
1908 GLfloat black[] = {0, 0, 0, 1.0};
1911 mi->polygon_count = 0;
1913 if (ci->display_i == 0) {
1914 for (ci->display_i = 0 ; ci->display_i < maxparts ; ci->display_i++) {
1915 ci->components[ci->display_i] = NULL;
1918 glEnable(GL_LIGHTING);
1919 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
1921 /* glRotatef(current_device_rotation(), 0, 0, 1); */
1922 gluLookAt(ci->viewer[0], ci->viewer[1], ci->viewer[2],
1926 glRotatef(ci->rotate_angle, 0, 0, 1);
1927 ci->rotate_angle += 0.01 * (float)rotatespeed;
1928 if (ci->rotate_angle >= 360) ci->rotate_angle = 0;
1930 glLightfv(GL_LIGHT0, GL_POSITION, ci->lightpos);
1931 glLightfv(GL_LIGHT0, GL_SPECULAR, light_sp);
1932 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_sp);
1933 glLighti(GL_LIGHT0, GL_CONSTANT_ATTENUATION, (GLfloat)1);
1934 glLighti(GL_LIGHT0, GL_LINEAR_ATTENUATION, (GLfloat)0.5);
1935 glLighti(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, (GLfloat)0);
1936 mi->polygon_count += drawgrid(ci);
1937 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light_sp);
1938 if (f_rand() < 0.05) {
1939 for (j = 0 ; j < maxparts ; j++) {
1940 if (ci->components[j] == NULL) {
1941 ci->components[j] = NewComponent(mi);
1945 reorder(&ci->components[0]);
1947 for (j = 0 ; j < maxparts ; j++) {
1948 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, black);
1949 glMaterialfv(GL_FRONT, GL_EMISSION, black);
1950 glMaterialfv(GL_FRONT, GL_SPECULAR, black);
1951 if (ci->components[j] != NULL) {
1952 if (DrawComponent(ci, ci->components[j], &mi->polygon_count)) {
1953 free(ci->components[j]); ci->components[j] = NULL;
1961 /* ensure transparent components are at the end */
1962 static void reorder(Component *c[])
1965 Component *c1[MAX_COMPONENTS];
1966 Component *c2[MAX_COMPONENTS];
1969 for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
1973 for (i = 0 ; i < maxparts ; i++) {
1974 if (c[i] == NULL) continue;
1975 if (c[i]->alpha) { /* transparent parts go to c1 */
1978 } else { /* opaque parts go to c2 */
1982 for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
1986 for (i = 0 ; i < maxparts ; i++) { /* insert opaque part */
1987 if (c2[i] != NULL) {
1992 for (i = 0 ; i < j ; i++) { /* insert transparent parts */
1998 ENTRYPOINT void reshape_circuit(ModeInfo *mi, int width, int height)
2000 Circuit *ci = &circuit[MI_SCREEN(mi)];
2001 GLfloat h = (GLfloat) height / (GLfloat) width;
2002 glViewport(0,0,(GLint)width, (GLint) height);
2003 glMatrixMode(GL_PROJECTION);
2005 glFrustum(-1.0,1.0,-h,h,1.5,35.0);
2006 glMatrixMode(GL_MODELVIEW);
2009 ci->YMAX = ci->XMAX * h;
2013 ENTRYPOINT void init_circuit(ModeInfo *mi)
2015 int screen = MI_SCREEN(mi);
2018 if (circuit == NULL) {
2019 if ((circuit = (Circuit *) calloc(MI_NUM_SCREENS(mi),
2020 sizeof(Circuit))) == NULL)
2023 ci = &circuit[screen];
2024 ci->window = MI_WINDOW(mi);
2026 ci->XMAX = ci->YMAX = 50;
2028 ci->lightpos[0] = 7;
2029 ci->lightpos[1] = 7;
2030 ci->lightpos[2] = 15;
2031 ci->lightpos[3] = 1;
2033 ci->grid_col[1] = 0.25;
2034 ci->grid_col[2] = 0.05;
2035 ci->grid_col2[1] = 0.125;
2036 ci->grid_col2[2] = 0.05;
2038 ci->font = load_texture_font (MI_DISPLAY(mi), "componentFont");
2040 if (maxparts >= MAX_COMPONENTS)
2041 maxparts = MAX_COMPONENTS-1;
2043 if ((ci->glx_context = init_GL(mi)) != NULL) {
2044 reshape_circuit(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
2050 glShadeModel(GL_SMOOTH);
2051 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
2052 glEnable(GL_DEPTH_TEST);
2053 glEnable(GL_LIGHTING);
2054 glEnable(GL_LIGHT0);
2055 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2061 ENTRYPOINT void draw_circuit(ModeInfo *mi)
2063 Circuit *ci = &circuit[MI_SCREEN(mi)];
2064 Window w = MI_WINDOW(mi);
2065 Display *disp = MI_DISPLAY(mi);
2067 if (!ci->glx_context)
2070 glXMakeCurrent(disp, w, *(ci->glx_context));
2074 if(mi->fps_p) do_fps(mi);
2076 glXSwapBuffers(disp, w);
2079 ENTRYPOINT void release_circuit(ModeInfo *mi)
2081 Circuit *ci = &circuit[MI_SCREEN(mi)];
2083 free_texture_font (ci->font);
2087 XSCREENSAVER_MODULE ("Circuit", circuit)