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 * 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};
1116 w = texture_string_width (ci->font, c->text, &h);
1119 glTranslatef (0, 0, 0.1);
1120 glRotatef (90, 0, 0, 1);
1122 glTranslatef (-w/2, 0, 0);
1124 print_texture_string (ci->font, c->text);
1128 glDisable(GL_TEXTURE_2D);
1129 glDisable(GL_BLEND);
1130 d = (h*2-0.1) / c->pins;
1132 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
1133 glMaterialfv(GL_FRONT, GL_SPECULAR, lspec);
1134 glMaterialfv(GL_FRONT, GL_SHININESS, &lshine);
1135 for (z = 0 ; z < c->pins/2 ; z++) {
1136 polys += ICLeg(w, -h + z*d + d/2, 0, 0);
1138 for (z = 0 ; z < c->pins/2 ; z++) {
1139 polys += ICLeg(-w, -h + z*d + d/2, 0, 1);
1141 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col2);
1142 glTranslatef(-w+0.3, h-0.3, 0.1);
1143 glRotatef(90, 0, 1, 0);
1144 polys += circle(ci, 0.1, 7, 0);
1149 static int DrawDisp(Circuit *ci, Disp *d)
1152 GLfloat col[] = {0.8, 0.8, 0.8, 1.0}; /* body colour */
1153 GLfloat front[] = {0.2, 0.2, 0.2, 1.0}; /* front colour */
1154 GLfloat on[] = {0.9, 0, 0, 1}; /* 'on' segment */
1155 GLfloat off[] = {0.3, 0, 0, 1}; /* 'off' segment */
1157 GLfloat x, y; /* for the pins */
1158 GLfloat spec[] = {0.6, 0.6, 0.6, 0};
1159 GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
1161 static const GLfloat vdata_h[6][2] = {
1169 static const GLfloat vdata_v[6][2] = {
1178 static const GLfloat seg_start[7][2] = {
1188 static const int nums[10][7] = {
1189 {1, 1, 1, 1, 1, 1, 0}, /* 0 */
1190 {0, 1, 1, 0, 0, 0, 0}, /* 1 */
1191 {1, 1, 0, 1, 1, 0, 1}, /* 2 */
1192 {1, 1, 1, 1, 0, 0, 1}, /* 3 */
1193 {0, 1, 1, 0, 0, 1, 1}, /* 4 */
1194 {1, 0, 1, 1, 0, 1, 1}, /* 5 */
1195 {1, 0, 1, 1, 1, 1, 1}, /* 6 */
1196 {1, 1, 1, 0, 0, 0, 0}, /* 7 */
1197 {1, 1, 1, 1, 1, 1, 1}, /* 8 */
1198 {1, 1, 1, 0, 0, 1, 1} /* 9 */
1201 glTranslatef(-0.9, -1.8, 0);
1202 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1203 polys += Rect(0, 0, -0.01, 1.8, 2.6, 0.7);
1204 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, front);
1206 glVertex2f(-0.05, -0.05);
1207 glVertex2f(-0.05, 2.65);
1208 glVertex2f(1.85, 2.65);
1209 glVertex2f(1.85, -0.05);
1212 glDisable(GL_LIGHTING); /* lit segments dont need light */
1213 if (!seven && (random() % 30) == 19) { /* randomly change value */
1214 d->value = random() % 10;
1216 for (j = 0 ; j < 7 ; j++) { /* draw the segments */
1217 GLfloat xx[6], yy[6];
1218 if (nums[d->value][j])
1222 for (k = 0 ; k < 6 ; k++) {
1223 if (j == 0 || j == 3 || j == 6) {
1224 xx[k] = seg_start[j][0] + vdata_h[k][0];
1225 yy[k] = seg_start[j][1] + vdata_h[k][1];
1227 xx[k] = seg_start[j][0] + vdata_v[k][0];
1228 yy[k] = seg_start[j][1] + vdata_v[k][1];
1231 glBegin(GL_POLYGON);
1232 for(i = 0 ; i < 6 ; i++) {
1233 glVertex3f(xx[i], yy[i], 0.01);
1241 glVertex3f(1.5, 0.2, 0.01);
1244 glEnable(GL_LIGHTING);
1245 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
1246 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1247 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
1248 for (x = 0.35 ; x <= 1.5 ; x+= 1.15) {
1249 for ( y = 0.2 ; y <= 2.4 ; y += 0.3) {
1250 polys += ICLeg(x, y, -0.7, 1);
1256 static int HoledRectangle(Circuit *ci,
1257 GLfloat w, GLfloat h, GLfloat d, GLfloat radius,
1262 GLfloat x1, y1, x2, y2;
1263 GLfloat yr, yr1, xr, xr1, side, side1;
1267 x1 = radius; y1 = 0;
1272 for (a = 0 ; a <= 360 ; a+= step) {
1273 y2=radius*(float)ci->sin_table[(int)a];
1274 x2=radius*(float)ci->cos_table[(int)a];
1276 if (a < 45 || a > 315) {
1278 yr = side1 * ci->tan_table[a];
1280 } else if (a <= 135 || a >= 225) {
1281 xr = side/ci->tan_table[a];
1292 yr = -side1 * ci->tan_table[a];
1296 glNormal3f(-x1, -y1, 0); /* cylinder */
1297 glVertex3f(x1,y1,0);
1298 glVertex3f(x1,y1,-d);
1299 glVertex3f(x2,y2,-d);
1300 glVertex3f(x2,y2,0);
1303 glNormal3f(0, 0, 1); /* front face */
1304 glVertex3f(x1,y1,0);
1305 glVertex3f(xr1, yr1, 0);
1306 glVertex3f(xr, yr, 0);
1307 glVertex3f(x2, y2, 0);
1310 glNormal3f(nx, ny, 0); /* side */
1311 glVertex3f(xr, yr, 0);
1312 glVertex3f(xr, yr, -d);
1313 glVertex3f(xr1, yr1, -d);
1314 glVertex3f(xr1, yr1, 0);
1317 glNormal3f(0, 0, -1); /* back */
1318 glVertex3f(xr, yr, -d);
1319 glVertex3f(x2, y2, -d);
1320 glVertex3f(x1, y1, -d);
1321 glVertex3f(xr1, yr1, -d);
1332 static int DrawTransistor(Circuit *ci, Transistor *t)
1335 GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
1336 GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
1337 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 */
1345 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1346 glRotatef(90, 0, 1, 0);
1347 glRotatef(90, 0, 0, 1);
1348 polys += createCylinder(ci, 1.0, 0.4, 1, 1);
1349 polys += Rect(0, -0.2, 0.4, 1, 0.2, 0.8);
1350 /* Draw the markings */
1353 GLfloat texfg[] = {0.7, 0.7, 0.7, 1.0};
1356 w = texture_string_width (ci->font, t->text, &h);
1359 glRotatef (90, 1, 0, 0);
1360 glTranslatef (0.5, -0.05, 0.21);
1362 glTranslatef (-w/2, 0, 0);
1364 print_texture_string (ci->font, t->text);
1368 glDisable(GL_TEXTURE_2D);
1369 glDisable(GL_BLEND);
1370 glDepthMask(GL_TRUE);
1371 glTranslatef(-2, 0, -0.2);
1372 polys += wire(ci, 2);
1373 glTranslatef(0, 0, 0.2);
1374 polys += wire(ci, 2);
1375 glTranslatef(0, 0, 0.2);
1376 polys += wire(ci, 2);
1377 } else if (t->type == 0) { /* TO-220 Style */
1378 polys += Rect(0, 0, 0, 1.5, 1.5, 0.5);
1380 GLfloat texfg[] = {0.7, 0.7, 0.7, 1.0};
1383 w = texture_string_width (ci->font, t->text, &h);
1386 glTranslatef (0.75, 0.75, 0.01);
1388 glTranslatef (-w/2, 0, 0);
1390 print_texture_string (ci->font, t->text);
1393 glDisable(GL_TEXTURE_2D);
1394 glDisable(GL_BLEND);
1395 glDepthMask(GL_TRUE);
1396 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1397 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1398 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1399 polys += Rect(0, 0, -0.5, 1.5, 1.5, 0.30);
1400 if (!glIsEnabled(GL_NORMALIZE)) glEnable(GL_NORMALIZE);
1401 glTranslatef(0.75, 1.875, -0.55);
1402 polys += HoledRectangle(ci, 1.5, 0.75, 0.25, 0.2, 8);
1403 glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
1404 glTranslatef(-0.375, -1.875, 0);
1405 glRotatef(90, 0, 0, -1);
1406 polys += wire(ci, 2);
1407 glTranslatef(0, 0.375, 0);
1408 polys += wire(ci, 2);
1409 glTranslatef(0, 0.375, 0);
1410 polys += wire(ci, 2);
1411 } else { /* SMC transistor */
1413 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1414 glTranslatef(-0.5, -0.25, 0.1);
1415 polys += Rect(0, 0, 0, 1, 0.5, 0.2);
1416 /* Draw the markings */
1417 glEnable(GL_TEXTURE_2D);
1419 glDepthMask(GL_FALSE);
1421 glNormal3f(0, 0, 1);
1423 glVertex3f(0.2, 0, 0.01);
1425 glVertex3f(0.8, 0, 0.01);
1427 glVertex3f(0.8, 0.5, 0.01);
1429 glVertex3f(0.2, 0.5, 0.01);
1432 glDisable(GL_TEXTURE_2D);
1433 glDisable(GL_BLEND);
1434 glDepthMask(GL_TRUE);
1435 /* Now draw the legs */
1436 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1437 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1438 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1439 polys += Rect(0.25, -0.1, -0.05, 0.1, 0.1, 0.2);
1440 polys += Rect(0.75, -0.1, -0.05, 0.1, 0.1, 0.2);
1441 polys += Rect(0.5, 0.5, -0.05, 0.1, 0.1, 0.2);
1442 polys += Rect(0.25, -0.2, -0.2, 0.1, 0.15, 0.1);
1443 polys += Rect(0.75, -0.2, -0.2, 0.1, 0.15, 0.1);
1444 polys += Rect(0.5, 0.5, -0.2, 0.1, 0.15, 0.1);
1450 static Component * NewComponent(ModeInfo *mi)
1452 Circuit *ci = &circuit[MI_SCREEN(mi)];
1456 c = malloc(sizeof(Component));
1457 c->angle = RAND_RANGE(0,360);
1459 if (rnd < 0.25) { /* come from the top */
1461 c->x = RAND_RANGE(0, ci->XMAX) - ci->XMAX/2;
1463 c->dx = 0 - RAND_RANGE(0.5, 2);
1465 c->dx = RAND_RANGE(0.5, 2);
1466 c->dy = 0 - RAND_RANGE(0.5, 2);
1467 } else if (rnd < 0.5) { /* come from the bottom */
1468 c->y = 0 - ci->YMAX/2;
1469 c->x = RAND_RANGE(0, ci->XMAX) - ci->XMAX/2;
1471 c->dx = 0 - RAND_RANGE(0.5, 2);
1473 c->dx = RAND_RANGE(0.5, 2);
1474 c->dy = RAND_RANGE(0.5, 2);
1475 } else if (rnd < 0.75) { /* come from the left */
1476 c->x = 0 - ci->XMAX/2;
1477 c->y = RAND_RANGE(0, ci->YMAX) - ci->YMAX/2;
1478 c->dx = RAND_RANGE(0.5, 2);
1480 c->dy = 0 - RAND_RANGE(0.5, 2);
1482 c->dy = RAND_RANGE(0.5, 2);
1483 } else { /* come from the right */
1485 c->y = RAND_RANGE(0, ci->YMAX) - ci->YMAX/2;
1486 c->dx = 0 - RAND_RANGE(0.5, 2);
1488 c->dy = 0 - RAND_RANGE(0.5, 2);
1490 c->dy = RAND_RANGE(0.5, 2);
1492 c->z = RAND_RANGE(0, 7) - 9;
1496 c->drot = f_rand() * 3;
1498 c->dz = f_rand()*2 - 1;
1500 c->alpha = 0; /* explicitly set to 1 later */
1501 rnd = random() % 11;
1503 c->c = NewResistor();
1506 c->norm = 1; /* some resistors shine */
1507 } else if (rnd < 2) {
1510 c->norm = 1; /* some diodes shine */
1512 } else if (rnd < 3) {
1513 c->c = NewTransistor(mi);
1516 } else if (rnd < 4) {
1517 c->c = NewCapacitor(ci);
1520 } else if (rnd < 5) {
1524 } else if (rnd < 6) {
1529 } else if (rnd < 7) {
1534 } else if (rnd < 8) {
1538 } else if (rnd < 9) {
1539 c->c = NewThreeFive(ci);
1542 } else if (rnd < 10) {
1543 c->c = NewSwitch(ci);
1553 static Transistor *NewTransistor(ModeInfo *mi)
1557 t = malloc(sizeof(Transistor));
1558 t->type = (random() % 3);
1560 t->text = transistortypes[random() % countof(transistortypes)];
1561 } else if (t->type == 2) {
1562 t->text = smctypes[random() % countof(smctypes)];
1563 } else if (t->type == 1) {
1564 t->text = to92types[random() % countof(to92types)];
1569 static Capacitor *NewCapacitor(Circuit *ci)
1573 c = malloc(sizeof(Capacitor));
1574 c->type = (f_rand() < 0.5);
1576 c->length = RAND_RANGE(0.5, 1);
1577 c->width = RAND_RANGE(0.5, 1);
1579 c->width = RAND_RANGE(0.3, 1);
1584 /* 7 segment display */
1586 static Disp *NewDisp(Circuit *ci)
1590 d = malloc(sizeof(Disp));
1594 d->value = RAND_RANGE(0, 10);
1599 static IC *NewIC(ModeInfo *mi)
1604 int types[countof(ictypes)], i, n = 0;
1606 c = malloc(sizeof(IC));
1608 switch((int)RAND_RANGE(0,4)) {
1623 for (i = 0 ; i < countof(ictypes) ; i++) {
1624 if (ictypes[i].pins == pins) {
1630 if (n > countof(types)) abort();
1631 val = ictypes[types[random() % n]].val;
1632 sprintf(c->text, "%s\n%02d%02d", val,
1633 (int)RAND_RANGE(80, 100), (int)RAND_RANGE(1,53));
1638 static LED *NewLED(Circuit *ci)
1643 l = malloc(sizeof(LED));
1646 if (!ci->light && (f_rand() < 0.4)) {
1651 l->r = 0.9; l->g = 0; l->b = 0;
1652 } else if (r < 0.4) {
1653 l->r = 0.3; l->g = 0.9; l->b = 0;
1654 } else if (r < 0.6) {
1655 l->r = 0.8; l->g = 0.9; l->b = 0;
1656 } else if (r < 0.8) {
1657 l->r = 0.0; l->g = 0.2; l->b = 0.8;
1659 l->r = 0.9, l->g = 0.55, l->b = 0;
1664 static Fuse *NewFuse(Circuit *ci)
1668 f = malloc(sizeof(Fuse));
1672 static RCA *NewRCA(Circuit *ci)
1676 r = malloc(sizeof(RCA));
1677 r->col = (random() % 10 < 5);
1681 static ThreeFive *NewThreeFive(Circuit *ci)
1685 r = malloc(sizeof(ThreeFive));
1689 static Switch *NewSwitch(Circuit *ci)
1693 s = malloc(sizeof(Switch));
1698 static Diode *NewDiode(void)
1703 ret = malloc(sizeof(Diode));
1704 b = malloc(sizeof(Band));
1707 if (f_rand() < 0.5) {
1711 ret->r = 0.7; ret->g = 0.1 ; ret->b = 0.1;
1716 ret->r = 0.2; ret->g = 0.2 ; ret->b = 0.2;
1723 static Resistor * NewResistor(void)
1725 int v, m, t; /* value, multiplier, tolerance */
1730 t = (RAND(10) < 5) ? 10 : 11;
1731 ret = malloc(sizeof(Resistor));
1734 ret->b[0] = ret->b[1] = ret->b[2] = 7;
1736 ret->b[0] = values[v][0];
1737 ret->b[1] = values[v][1];
1745 static void makebandlist(Circuit *ci)
1748 GLfloat col[] = {0,0,0,0};
1749 GLfloat spec[] = {0.8,0.8,0.8,0};
1752 for (i = 0 ; i < 12 ; i++) {
1753 ci->band_list[i] = glGenLists(1);
1754 glNewList(ci->band_list[i], GL_COMPILE);
1755 col[0] = colorcodes[i][0];
1756 col[1] = colorcodes[i][1];
1757 col[2] = colorcodes[i][2];
1758 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
1759 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
1760 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
1761 ci->band_list_polys[i] = createCylinder(ci, 0.1, 0.42, 0, 0);
1767 static int bandedCylinder(Circuit *ci,
1768 float radius, float l,
1769 GLfloat r, GLfloat g, GLfloat bl,
1770 Band **b, int nbands)
1773 int n; /* band number */
1774 GLfloat col[] = {0,0,0,0};
1776 col[0] = r; col[1] = g; col[2] = bl;
1777 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1778 polys += createCylinder(ci, l, radius, 1, 0); /* body */
1779 for (n = 0 ; n < nbands ; n++) {
1781 glTranslatef(b[n]->pos*l, 0, 0);
1782 col[0] = b[n]->r; col[1] = b[n]->g; col[2] = b[n]->b;
1783 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1784 polys += createCylinder(ci, b[n]->len*l, radius*1.05, 0, 0); /* band */
1790 static int drawgrid(Circuit *ci)
1794 GLfloat col3[] = {0, 0.8, 0};
1797 if (f_rand() < ((rotatespeed > 0) ? 0.05 : 0.01)) {
1798 ci->draw_sdir = RAND_RANGE(0, 4);
1799 ci->draw_ds = RAND_RANGE(0.4, 0.8);
1800 switch (ci->draw_sdir) {
1802 ci->draw_sx = -ci->XMAX/2;
1803 ci->draw_sy = ((int)RAND_RANGE(0, ci->YMAX/2))*2 - ci->YMAX/2;
1806 ci->draw_sx = ci->XMAX/2;
1807 ci->draw_sy = ((int)RAND_RANGE(0, ci->YMAX/2))*2 - ci->YMAX/2;
1810 ci->draw_sy = ci->YMAX/2;
1811 ci->draw_sx = ((int)RAND_RANGE(0, ci->XMAX/2))*2 - ci->XMAX/2;
1814 ci->draw_sy = -ci->YMAX/2;
1815 ci->draw_sx = ((int)RAND_RANGE(0, ci->XMAX/2))*2 - ci->XMAX/2;
1820 } else if (rotatespeed <= 0) {
1821 if (ci->grid_col[1] < 0.25) {
1822 ci->grid_col[1] += 0.025; ci->grid_col[2] += 0.005;
1823 ci->grid_col2[1] += 0.015 ; ci->grid_col2[2] += 0.005;
1827 glDisable(GL_LIGHTING);
1831 glTranslatef(ci->draw_sx, ci->draw_sy, -10);
1832 polys += sphere(ci, 0.1, 10, 10, 0, 10, 0, 10);
1833 if (ci->draw_sdir == 0)
1834 glTranslatef(-ci->draw_ds, 0, 0);
1835 if (ci->draw_sdir == 1)
1836 glTranslatef(ci->draw_ds, 0, 0);
1837 if (ci->draw_sdir == 2)
1838 glTranslatef(0, ci->draw_ds, 0);
1839 if (ci->draw_sdir == 3)
1840 glTranslatef(0, -ci->draw_ds, 0);
1841 polys += sphere(ci, 0.05, 10, 10, 0, 10, 0, 10);
1843 if (ci->draw_sdir == 0) {
1844 ci->draw_sx += ci->draw_ds;
1845 if (ci->draw_sx > ci->XMAX/2)
1848 if (ci->draw_sdir == 1) {
1849 ci->draw_sx -= ci->draw_ds;
1850 if (ci->draw_sx < -ci->XMAX/2)
1853 if (ci->draw_sdir == 2) {
1854 ci->draw_sy -= ci->draw_ds;
1855 if (ci->draw_sy < ci->YMAX/2)
1858 if (ci->draw_sdir == 3) {
1859 ci->draw_sy += ci->draw_ds;
1860 if (ci->draw_sy > ci->YMAX/2)
1863 } else if (rotatespeed <= 0) {
1864 if (ci->grid_col[1] > 0) {
1865 ci->grid_col[1] -= 0.0025; ci->grid_col[2] -= 0.0005;
1866 ci->grid_col2[1] -= 0.0015 ; ci->grid_col2[2] -= 0.0005;
1869 for (x = -ci->XMAX/2 ; x <= ci->XMAX/2 ; x+= 2) {
1870 glColor3fv(ci->grid_col);
1872 glVertex3f(x, ci->YMAX/2, -10);
1873 glVertex3f(x, -ci->YMAX/2, -10);
1874 glColor3fv(ci->grid_col2);
1875 glVertex3f(x-0.02, ci->YMAX/2, -10);
1876 glVertex3f(x-0.02, -ci->YMAX/2, -10);
1877 glVertex3f(x+0.02, ci->YMAX/2, -10);
1878 glVertex3f(x+0.02, -ci->YMAX/2, -10);
1881 for (y = -ci->YMAX/2 ; y <= ci->YMAX/2 ; y+= 2) {
1882 glColor3fv(ci->grid_col);
1884 glVertex3f(-ci->XMAX/2, y, -10);
1885 glVertex3f(ci->XMAX/2, y, -10);
1886 glColor3fv(ci->grid_col2);
1887 glVertex3f(-ci->XMAX/2, y-0.02, -10);
1888 glVertex3f(ci->XMAX/2, y-0.02, -10);
1889 glVertex3f(-ci->XMAX/2, y+0.02, -10);
1890 glVertex3f(ci->XMAX/2, y+0.02, -10);
1893 glEnable(GL_LIGHTING);
1897 static void display(ModeInfo *mi)
1899 Circuit *ci = &circuit[MI_SCREEN(mi)];
1900 GLfloat light_sp[] = {0.8, 0.8, 0.8, 1.0};
1901 GLfloat black[] = {0, 0, 0, 1.0};
1904 mi->polygon_count = 0;
1906 if (ci->display_i == 0) {
1907 for (ci->display_i = 0 ; ci->display_i < maxparts ; ci->display_i++) {
1908 ci->components[ci->display_i] = NULL;
1911 glEnable(GL_LIGHTING);
1912 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
1914 /* glRotatef(current_device_rotation(), 0, 0, 1); */
1915 gluLookAt(ci->viewer[0], ci->viewer[1], ci->viewer[2],
1919 glRotatef(ci->rotate_angle, 0, 0, 1);
1920 ci->rotate_angle += 0.01 * (float)rotatespeed;
1921 if (ci->rotate_angle >= 360) ci->rotate_angle = 0;
1923 glLightfv(GL_LIGHT0, GL_POSITION, ci->lightpos);
1924 glLightfv(GL_LIGHT0, GL_SPECULAR, light_sp);
1925 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_sp);
1926 glLighti(GL_LIGHT0, GL_CONSTANT_ATTENUATION, (GLfloat)1);
1927 glLighti(GL_LIGHT0, GL_LINEAR_ATTENUATION, (GLfloat)0.5);
1928 glLighti(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, (GLfloat)0);
1929 mi->polygon_count += drawgrid(ci);
1930 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light_sp);
1931 if (f_rand() < 0.05) {
1932 for (j = 0 ; j < maxparts ; j++) {
1933 if (ci->components[j] == NULL) {
1934 ci->components[j] = NewComponent(mi);
1938 reorder(&ci->components[0]);
1940 for (j = 0 ; j < maxparts ; j++) {
1941 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, black);
1942 glMaterialfv(GL_FRONT, GL_EMISSION, black);
1943 glMaterialfv(GL_FRONT, GL_SPECULAR, black);
1944 if (ci->components[j] != NULL) {
1945 if (DrawComponent(ci, ci->components[j], &mi->polygon_count)) {
1946 free(ci->components[j]); ci->components[j] = NULL;
1954 /* ensure transparent components are at the end */
1955 static void reorder(Component *c[])
1958 Component *c1[MAX_COMPONENTS];
1959 Component *c2[MAX_COMPONENTS];
1962 for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
1966 for (i = 0 ; i < maxparts ; i++) {
1967 if (c[i] == NULL) continue;
1968 if (c[i]->alpha) { /* transparent parts go to c1 */
1971 } else { /* opaque parts go to c2 */
1975 for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
1979 for (i = 0 ; i < maxparts ; i++) { /* insert opaque part */
1980 if (c2[i] != NULL) {
1985 for (i = 0 ; i < j ; i++) { /* insert transparent parts */
1991 ENTRYPOINT void reshape_circuit(ModeInfo *mi, int width, int height)
1993 Circuit *ci = &circuit[MI_SCREEN(mi)];
1994 GLfloat h = (GLfloat) height / (GLfloat) width;
1995 glViewport(0,0,(GLint)width, (GLint) height);
1996 glMatrixMode(GL_PROJECTION);
1998 glFrustum(-1.0,1.0,-h,h,1.5,35.0);
1999 glMatrixMode(GL_MODELVIEW);
2002 ci->YMAX = ci->XMAX * h;
2006 ENTRYPOINT void init_circuit(ModeInfo *mi)
2008 int screen = MI_SCREEN(mi);
2011 if (circuit == NULL) {
2012 if ((circuit = (Circuit *) calloc(MI_NUM_SCREENS(mi),
2013 sizeof(Circuit))) == NULL)
2016 ci = &circuit[screen];
2017 ci->window = MI_WINDOW(mi);
2019 ci->XMAX = ci->YMAX = 50;
2021 ci->lightpos[0] = 7;
2022 ci->lightpos[1] = 7;
2023 ci->lightpos[2] = 15;
2024 ci->lightpos[3] = 1;
2026 ci->grid_col[1] = 0.25;
2027 ci->grid_col[2] = 0.05;
2028 ci->grid_col2[1] = 0.125;
2029 ci->grid_col2[2] = 0.05;
2031 ci->font = load_texture_font (MI_DISPLAY(mi), "componentFont");
2033 if (maxparts >= MAX_COMPONENTS)
2034 maxparts = MAX_COMPONENTS-1;
2036 if ((ci->glx_context = init_GL(mi)) != NULL) {
2037 reshape_circuit(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
2043 glShadeModel(GL_SMOOTH);
2044 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
2045 glEnable(GL_DEPTH_TEST);
2046 glEnable(GL_LIGHTING);
2047 glEnable(GL_LIGHT0);
2048 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2054 ENTRYPOINT void draw_circuit(ModeInfo *mi)
2056 Circuit *ci = &circuit[MI_SCREEN(mi)];
2057 Window w = MI_WINDOW(mi);
2058 Display *disp = MI_DISPLAY(mi);
2060 if (!ci->glx_context)
2063 glXMakeCurrent(disp, w, *(ci->glx_context));
2067 if(mi->fps_p) do_fps(mi);
2069 glXSwapBuffers(disp, w);
2072 ENTRYPOINT void release_circuit(ModeInfo *mi)
2074 Circuit *ci = &circuit[MI_SCREEN(mi)];
2076 free_texture_font (ci->font);
2080 XSCREENSAVER_MODULE ("Circuit", circuit)