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" \
36 # define refresh_circuit 0
37 # define circuit_handle_event 0
38 # include "xlockmore.h" /* from the xscreensaver distribution */
39 #else /* !STANDALONE */
40 # include "xlock.h" /* from the xlockmore distribution */
41 #endif /* !STANDALONE */
43 #define DEF_SPIN "True"
44 #define DEF_SEVEN "False"
45 #define DEF_PARTS "10"
46 #define DEF_ROTATESPEED "1"
47 #define DEF_LIGHT "True"
49 /* lifted from lament.c */
50 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
51 #define RANDSIGN() ((random() & 1) ? 1 : -1)
56 #include "font-ximage.h"
59 #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 {"-font", ".circuit.font", XrmoptionSepArg, 0 },
74 {"-rotate-speed", ".circuit.rotatespeed", XrmoptionSepArg, 0 },
75 {"+spin", ".circuit.spin", XrmoptionNoArg, "false" },
76 {"-spin", ".circuit.spin", XrmoptionNoArg, "true" },
77 {"+light", ".circuit.light", XrmoptionNoArg, "false" },
78 {"-light", ".circuit.light", XrmoptionNoArg, "true" },
79 {"+seven", ".circuit.seven", XrmoptionNoArg, "false" },
80 {"-seven", ".circuit.seven", XrmoptionNoArg, "true" },
83 static argtype vars[] = {
84 {&maxparts, "parts", "Parts", DEF_PARTS, t_Int},
85 {&font, "font", "Font", "fixed", t_String},
86 {&rotatespeed, "rotatespeed", "Rotatespeed", DEF_ROTATESPEED, t_Int},
87 {&spin, "spin", "Spin", DEF_SPIN, t_Bool},
88 {&uselight, "light", "Light", DEF_LIGHT, t_Bool},
89 {&seven, "seven", "Seven", DEF_SEVEN, t_Bool},
92 ENTRYPOINT ModeSpecOpt circuit_opts = {countof(opts), opts, countof(vars), vars, NULL};
95 ModStruct circuit_description =
96 {"circuit", "init_circuit", "draw_circuit", "release_circuit",
97 "draw_circuit", "init_circuit", NULL, &circuit_opts,
98 1000, 1, 2, 1, 4, 1.0, "",
99 "Flying electronic components", 0, NULL};
103 #define MAX_COMPONENTS 400
104 #define MOVE_MULT 0.02
106 static float f_rand(void)
108 return ((float)RAND(10000)/(float)10000);
111 #define RAND_RANGE(min, max) ((min) + (max - min) * f_rand())
113 /* used for allocating font textures */
115 int num; /* index number */
120 /* Represents a band on a resistor/diode/etc */
122 float pos; /* relative position from start/previous band */
123 GLfloat r, g, b; /* colour of the band */
124 float len; /* length as a fraction of total length */
128 Band *b1, *b2, *b3, *b4; /* bands */
134 GLfloat r, g, b; /* body colour */
137 static const char * const transistortypes[] = {
153 static const char * const to92types[] = {
168 static const char * const smctypes[] = {
179 int type; /* package type. 0 = to-92, 1 = to-220 */
180 GLfloat tw, th; /* texture dimensions */
181 GLuint tnum; /* texture binding */
185 GLfloat r,g,b; /* LED colour */
186 int light; /* are we the light source? */
190 int type; /* 0 = electro, 1 = ceramic */
191 float width; /* width of an electro/ceramic */
192 float length; /* length of an electro */
210 static const ICTypes ictypes[] = {
253 int type; /* 0 = DIL, 1 = flat square */
255 float tw, th; /* texture dimensions for markings */
256 int tnum; /* texture number */
259 /* 7 segment display */
262 int value; /* displayed number */
275 GLfloat x, y, z; /* current co-ordinates */
276 GLfloat dx, dy, dz; /* current direction */
277 GLfloat rotx, roty, rotz; /* rotation vector */
278 GLfloat drot; /* rotation velocity (degrees per frame) */
279 int norm; /* Normalize this component (for shine) */
280 int rdeg; /* current rotation degrees */
281 int angle; /* angle about the z axis */
282 int alpha; /* 0 if not a transparent component */
283 int type; /* 0 = resistor, 1 = diode, 2 = transistor, 3 = LED, 4 = cap, 5=IC,
285 void * c; /* pointer to the component */
288 /* standard colour codes */
290 static const GLfloat colorcodes [12][3] = {
291 {0.0,0.0,0.0}, /* black 0 */
292 {0.49,0.25,0.08}, /* brown 1 */
293 {1.0,0.0,0.0}, /* red 2 */
294 {1.0,0.5,0.0}, /* orange 3 */
295 {1.0,1.0,0.0}, /* yellow 4 */
296 {0.0,1.0,0.0}, /* green 5 */
297 {0.0,0.5,1.0}, /* blue 6 */
298 {0.7,0.2,1.0}, /* violet 7 */
299 {0.5,0.5,0.5}, /* grey 8 */
300 {1.0,1.0,1.0}, /* white 9 */
301 {0.66,0.56,0.2}, /* gold 10 */
302 {0.8,0.8,0.8}, /* silver 11 */
305 /* base values for components - we can multiply by 0 - 1M */
306 static const int values [9][2] = {
319 GLXContext *glx_context;
325 /* one lucky led gets to be a light source , unless -no-light*/
329 /* stores refs to textures */
335 float sin_table[720];
336 float cos_table[720];
337 float tan_table[720];
339 Component *components[MAX_COMPONENTS];
341 int band_list_polys[12];
343 GLfloat grid_col[3], grid_col2[3];
346 GLfloat rotate_angle;
348 char *font_strings[50]; /* max of 40 textures */
349 int font_w[50], font_h[50];
352 GLfloat draw_sx, draw_sy; /* bright spot co-ords */
353 int draw_sdir; /* 0 = left-right, 1 = right-left, 2 = up->dn, 3 = dn->up */
354 int draw_s; /* if spot is enabled */
355 float draw_ds; /* speed of spot */
359 static Circuit *circuit = NULL;
362 static int DrawResistor(Circuit *, Resistor *);
363 static int DrawDiode(Circuit *, Diode *);
364 static int DrawTransistor(Circuit *, Transistor *);
365 static int DrawLED(Circuit *, LED *);
366 static int DrawIC(Circuit *, IC *);
367 static int DrawCapacitor(Circuit *, Capacitor *);
368 static int DrawDisp(Circuit *, Disp *);
369 static int DrawFuse(Circuit *, Fuse *);
370 static int DrawRCA(Circuit *, RCA *);
371 static int DrawThreeFive(Circuit *, ThreeFive *);
372 static int DrawSwitch(Circuit *, Switch *);
374 static void freetexture(Circuit *, GLuint);
375 static void reorder(Component *[]);
376 static int circle(Circuit *, float, int,int);
377 static int bandedCylinder(Circuit *,
378 float, float , GLfloat, GLfloat , GLfloat,
380 static TexNum *fonttexturealloc(ModeInfo *, const char *, float *, float *);
381 static int Rect(GLfloat , GLfloat , GLfloat, GLfloat , GLfloat ,GLfloat);
382 static int ICLeg(GLfloat, GLfloat, GLfloat, int);
383 static int HoledRectangle(Circuit *ci,
384 GLfloat, GLfloat, GLfloat, GLfloat, int);
385 static Resistor *NewResistor(void);
386 static Diode *NewDiode(void);
387 static Transistor *NewTransistor(ModeInfo *);
388 static LED * NewLED(Circuit *);
389 static Capacitor *NewCapacitor(Circuit *);
390 static IC* NewIC(ModeInfo *);
391 static Disp* NewDisp(Circuit *);
392 static Fuse *NewFuse(Circuit *);
393 static RCA *NewRCA(Circuit *);
394 static ThreeFive *NewThreeFive(Circuit *);
395 static Switch *NewSwitch(Circuit *);
397 /* we use trig tables to speed things up - 200 calls to sin()
398 in one frame can be a bit harsh..
401 static void make_tables(Circuit *ci)
406 f = 360 / (M_PI * 2);
407 for (i = 0 ; i < 720 ; i++) {
408 ci->sin_table[i] = sin(i/f);
410 for (i = 0 ; i < 720 ; i++) {
411 ci->cos_table[i] = cos(i/f);
413 for (i = 0 ; i < 720 ; i++) {
414 ci->tan_table[i] = tan(i/f);
419 static int createCylinder (Circuit *ci,
420 float length, float radius, int endcaps, int half)
423 int a; /* current angle around cylinder */
425 float z1, y1, z2, y2,ex;
430 nsegs = radius*MAX(ci->win_w, ci->win_h)/20;
431 nsegs = MAX(nsegs, 4);
434 angle = (half) ? (180 - 90/nsegs) : 374;
438 for (a = 0 ; a <= angle ; a+= angle/nsegs) {
439 y2=radius*(float)ci->sin_table[(int)a];
440 z2=radius*(float)ci->cos_table[(int)a];
441 glNormal3f(0, y1, z1);
443 glVertex3f(length,y1,z1);
444 glNormal3f(0, y2, z2);
445 glVertex3f(length,y2,z2);
455 glVertex3f(0, 0, radius);
456 glVertex3f(length, 0, radius);
457 glVertex3f(length, 0, 0 - radius);
458 glVertex3f(0, 0, 0 - radius);
463 for(ex = 0 ; ex <= length ; ex += length) {
465 norm = (ex == length) ? 1 : -1;
466 glBegin(GL_TRIANGLES);
467 glNormal3f(norm, 0, 0);
468 for (a = 0 ; a <= angle ; a+= angle/nsegs) {
469 y2=radius*(float)ci->sin_table[(int)a];
470 z2=radius*(float)ci->cos_table[(int)a];
472 glVertex3f(ex,y1,z1);
473 glVertex3f(ex,y2,z2);
485 static int circle(Circuit *ci, float radius, int segments, int half)
488 float x1 = 0, x2 = 0;
489 float y1 = 0, y2 = 0;
498 glBegin(GL_TRIANGLES);
503 x2=radius*(float)ci->cos_table[(int)angle];
504 y2=radius*(float)ci->sin_table[(int)angle];
516 static int wire(Circuit *ci, float len)
519 GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
520 GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
521 GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
525 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
526 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
527 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
528 n = glIsEnabled(GL_NORMALIZE);
529 if (!n) glEnable(GL_NORMALIZE);
530 polys += createCylinder(ci, len, 0.05, 1, 0);
531 if (!n) glDisable(GL_NORMALIZE);
532 glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
537 static int ring(GLfloat inner, GLfloat outer, int nsegs)
540 GLfloat z1, z2, y1, y2;
541 GLfloat Z1, Z2, Y1, Y2;
548 for(i=0; i <=360 ; i+= 360/nsegs)
551 z2=inner*(float)ci->sin_table[(int)angle];
552 y2=inner*(float)ci->cos_table[(int)angle];
553 Z2=outer*(float)ci->sin_table[(int)angle];
554 Y2=outer*(float)ci->cos_table[(int)angle];
555 glVertex3f(0, Y1, Z1);
556 glVertex3f(0, y1, z1);
557 glVertex3f(0, y2, z2);
558 glVertex3f(0, Y2, Z2);
570 static int sphere(Circuit *ci, GLfloat r, float stacks, float slices,
571 int startstack, int endstack, int startslice,
575 GLfloat d, d1, dr, dr1, Dr, Dr1, D, D1, z1, z2, y1, y2, Y1, Z1, Y2, Z2;
576 int a, a1, b, b1, c0, c1;
581 a1 = startstack * step;
582 b1 = startslice * sstep;
583 y1 = z1 = Y1 = Z1 = 0;
584 c0 = (endslice / slices) * 360;
585 c1 = (endstack/stacks)*180;
587 for (a = startstack * step ; a <= c1 ; a+= step) {
589 d1=ci->sin_table[a1];
591 D1=ci->cos_table[a1];
596 for (b = b1 ; b <= c0 ; b+= sstep) {
597 y2=dr*ci->sin_table[b];
598 z2=dr*ci->cos_table[b];
599 Y2=dr1*ci->sin_table[b];
600 Z2=dr1*ci->cos_table[b];
601 glNormal3f(Dr, y1, z1);
602 glVertex3f(Dr,y1,z1);
603 glNormal3f(Dr, y2, z2);
604 glVertex3f(Dr,y2,z2);
605 glNormal3f(Dr1, Y2, Z2);
606 glVertex3f(Dr1,Y2,Z2);
607 glNormal3f(Dr1, Y1, Z1);
608 glVertex3f(Dr1,Y1,Z1);
621 static int DrawComponent(Circuit *ci, Component *c, unsigned long *polysP)
624 int ret = 0; /* return 1 if component is freed */
627 glTranslatef(c->x, c->y, c->z);
629 glRotatef(c->angle, c->rotx, c->roty, c->rotz);
632 glRotatef(c->rdeg, c->rotx, c->roty, c->rotz);
637 glEnable(GL_NORMALIZE);
639 glDisable(GL_NORMALIZE);
641 /* call object draw routine here */
643 polys += DrawResistor(ci, c->c);
644 } else if (c->type == 1) {
645 polys += DrawDiode(ci, c->c);
646 } else if (c->type == 2) {
647 polys += DrawTransistor(ci, c->c);
648 } else if (c->type == 3) {
649 if (((LED *)c->c)->light && ci->light) {
650 GLfloat lp[] = {0.1, 0, 0, 1};
652 glLightfv(GL_LIGHT1, GL_POSITION, lp);
654 polys += DrawLED(ci, c->c);
655 } else if (c->type == 4) {
656 polys += DrawCapacitor(ci, c->c);
657 } else if (c->type == 5) {
658 polys += DrawIC(ci, c->c);
659 } else if (c->type == 6) {
660 polys += DrawDisp(ci, c->c);
661 } else if (c->type == 7) {
662 polys += DrawFuse(ci, c->c);
663 } else if (c->type == 8) {
664 polys += DrawRCA(ci, c->c);
665 } else if (c->type == 9) {
666 polys += DrawThreeFive(ci, c->c);
667 } else if (c->type == 10) {
668 polys += DrawSwitch(ci, c->c);
670 c->x += c->dx * MOVE_MULT;
671 c->y += c->dy * MOVE_MULT;
672 if (c->x > ci->XMAX/2 || c->x < 0 - ci->XMAX/2 ||
673 c->y > ci->YMAX/2 || c->y < 0 - ci->YMAX/2) {
674 if (c->type == 3 && ((LED *)c->c)->light && ci->light) {
675 glDisable(GL_LIGHT1);
676 ci->light = 0; ci->lighton = 0;
679 if (((IC *)c->c)->tnum)
680 freetexture(ci, ((IC *)c->c)->tnum);
683 if (((Transistor *)c->c)->tnum)
684 freetexture(ci, ((Transistor *)c->c)->tnum);
687 free(((Diode *)c->c)->band); /* remember to free diode band */
693 glDisable(GL_NORMALIZE);
698 /* draw a resistor */
700 static int DrawResistor(Circuit *ci, Resistor *r)
704 GLfloat col[] = {0.74, 0.62, 0.46, 1.0};
705 GLfloat spec[] = {0.8, 0.8, 0.8, 1.0};
708 glTranslatef(-4, 0, 0);
709 polys += wire(ci, 3);
710 glTranslatef(3, 0, 0);
711 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
712 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
713 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
714 polys += createCylinder(ci, 1.8, 0.4, 1, 0);
716 for (i = 0 ; i < 4 ; i++) {
717 glTranslatef(0.35, 0, 0);
718 glCallList(ci->band_list[r->b[i]]);
719 polys += ci->band_list_polys[r->b[i]];
722 glTranslatef(1.8, 0, 0);
723 polys += wire(ci, 3);
727 static int DrawRCA(Circuit *ci, RCA *rca)
730 GLfloat col[] = {0.6, 0.6, 0.6, 1.0}; /* metal */
731 GLfloat red[] = {1.0, 0.0, 0.0, 1.0}; /* red */
732 GLfloat white[] = {1.0, 1.0, 1.0, 1.0}; /* white */
733 GLfloat spec[] = {1, 1, 1, 1}; /* glass */
736 glTranslatef(0.3, 0, 0);
737 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
738 glMateriali(GL_FRONT, GL_SHININESS, 40);
739 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
740 polys += createCylinder(ci, 0.7, 0.45, 0, 0);
741 glTranslatef(0.4, 0, 0);
742 polys += createCylinder(ci, 0.9, 0.15, 1, 0);
743 glTranslatef(-1.9, 0, 0);
744 glMateriali(GL_FRONT, GL_SHININESS, 20);
745 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, rca->col ? white : red);
746 polys += createCylinder(ci, 1.5, 0.6, 1, 0);
747 glTranslatef(-0.9, 0, 0);
748 polys += createCylinder(ci, 0.9, 0.25, 0, 0);
749 glTranslatef(0.1, 0, 0);
750 polys += createCylinder(ci, 0.2, 0.3, 0, 0);
751 glTranslatef(0.3, 0, 0);
752 polys += createCylinder(ci, 0.2, 0.3, 1, 0);
753 glTranslatef(0.3, 0, 0);
754 polys += createCylinder(ci, 0.2, 0.3, 1, 0);
759 static int DrawSwitch(Circuit *ci, Switch *f)
762 GLfloat col[] = {0.6, 0.6, 0.6, 0}; /* metal */
763 GLfloat dark[] = {0.1, 0.1, 0.1, 1.0}; /* dark */
764 GLfloat brown[] = {0.69, 0.32, 0, 1.0}; /* brown */
765 GLfloat spec[] = {0.9, 0.9, 0.9, 1}; /* shiny */
768 glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
769 glMaterialfv(GL_FRONT, GL_AMBIENT, dark);
770 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
771 glMateriali(GL_FRONT, GL_SHININESS, 90);
772 polys += Rect(-0.25, 0, 0, 1.5, 0.5, 0.75);
773 /* polys += Rect(-0.5, 0.5, 0, 2, 0.1, 0.75); */
775 glRotatef(90, 1, 0, 0);
776 glTranslatef(-0.5, -0.4, -0.4);
777 polys += HoledRectangle(ci, 0.5, 0.75, 0.1, 0.15, 8);
778 glTranslatef(2, 0, 0);
779 polys += HoledRectangle(ci, 0.5, 0.75, 0.1, 0.15, 8);
781 polys += Rect(0.1, -0.4, -0.25, 0.1, 0.4, 0.05);
782 polys += Rect(0.5, -0.4, -0.25, 0.1, 0.4, 0.05);
783 polys += Rect(0.9, -0.4, -0.25, 0.1, 0.4, 0.05);
784 polys += Rect(0.1, -0.4, -0.5, 0.1, 0.4, 0.05);
785 polys += Rect(0.5, -0.4, -0.5, 0.1, 0.4, 0.05);
786 polys += Rect(0.9, -0.4, -0.5, 0.1, 0.4, 0.05);
787 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, dark);
788 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
789 polys += Rect(0, 0.5, -0.1, 1, 0.05, 0.5);
790 polys += Rect(0, 0.6, -0.1, 0.5, 0.6, 0.5);
791 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, brown);
792 polys += Rect(-0.2, -0.01, -0.1, 1.4, 0.1, 0.55);
798 static int DrawFuse(Circuit *ci, Fuse *f)
801 GLfloat col[] = {0.5, 0.5, 0.5, 1.0}; /* endcaps */
802 GLfloat glass[] = {0.4, 0.4, 0.4, 0.3}; /* glass */
803 GLfloat spec[] = {1, 1, 1, 1}; /* glass */
806 glTranslatef(-1.8, 0, 0);
807 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
808 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
809 glMateriali(GL_FRONT, GL_SHININESS, 40);
810 polys += createCylinder(ci, 0.8, 0.45, 1, 0);
811 glTranslatef(0.8, 0, 0);
813 glDepthMask(GL_FALSE);
814 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, glass);
815 glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 40);
816 polys += createCylinder(ci, 2, 0.4, 0, 0);
817 polys += createCylinder(ci, 2, 0.3, 0, 0);
819 glDepthMask(GL_TRUE);
820 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
821 glMateriali(GL_FRONT, GL_SHININESS, 40);
824 glVertex3f(2, 0. ,0);
826 glTranslatef(2, 0, 0);
827 polys += createCylinder(ci, 0.8, 0.45, 1, 0);
833 static int DrawCapacitor(Circuit *ci, Capacitor *c)
836 GLfloat col[] = {0, 0, 0, 0};
837 GLfloat spec[] = {0.8, 0.8, 0.8, 0};
838 GLfloat brown[] = {0.84, 0.5, 0};
843 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, brown);
844 polys += sphere(ci, c->width, 15, 15, 0, 4 ,0, 15);
845 glTranslatef(1.35*c->width, 0, 0);
846 polys += sphere(ci, c->width, 15, 15, 11, 15, 0, 15);
847 glRotatef(90, 0, 0, 1);
848 glTranslatef(0, 0.7*c->width, 0.3*c->width);
849 polys += wire(ci, 3*c->width);
850 glTranslatef(0, 0, -0.6*c->width);
851 polys += wire(ci, 3*c->width);
853 glTranslatef(0-c->length*2, 0, 0);
854 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
855 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
856 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
858 glVertex3f(0, 0.82*c->width, -0.1);
859 glVertex3f(3*c->length, 0.82*c->width, -0.1);
860 glVertex3f(3*c->length, 0.82*c->width, 0.1);
861 glVertex3f(0, 0.82*c->width, 0.1);
866 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
867 glEnable(GL_POLYGON_OFFSET_FILL);
868 glPolygonOffset(1.0, 1.0);
869 polys += createCylinder(ci, 3.0*c->length, 0.8*c->width, 1, 0);
870 glDisable(GL_POLYGON_OFFSET_FILL);
874 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
875 polys += circle(ci, 0.6*c->width, 30, 0);
879 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
880 glTranslatef(3.0*c->length, 0.0, 0);
881 polys += circle(ci, 0.6*c->width, 30, 0);
882 glTranslatef(0, 0.4*c->width, 0);
883 polys += wire(ci, 3*c->length);
884 glTranslatef(0.0, -0.8*c->width, 0);
885 polys += wire(ci, 3.3*c->length);
891 static int DrawLED(Circuit *ci, LED *l)
894 GLfloat col[] = {0, 0, 0, 0.6};
895 GLfloat black[] = {0, 0, 0, 0.6};
897 col[0] = l->r; col[1] = l->g; col[2] = l->b;
898 if (l->light && ci->light) {
899 GLfloat dir[] = {-1, 0, 0};
900 glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, dir);
902 glLightfv(GL_LIGHT1, GL_SPECULAR, col);
903 glLightfv(GL_LIGHT1, GL_AMBIENT, black);
904 col[0] /= 1.5; col[1] /= 1.5; col[2] /= 1.5;
905 glLightfv(GL_LIGHT1, GL_DIFFUSE, col);
906 glLighti(GL_LIGHT1, GL_SPOT_CUTOFF, (GLint) 90);
907 glLighti(GL_LIGHT1, GL_CONSTANT_ATTENUATION, (GLfloat)1);
908 glLighti(GL_LIGHT1, GL_LINEAR_ATTENUATION, (GLfloat)0);
909 glLighti(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, (GLfloat)0);
910 glLighti(GL_LIGHT1, GL_SPOT_EXPONENT, (GLint) 20);
914 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
915 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
916 /* no transparency when LED is lit */
919 glDepthMask(GL_FALSE);
920 glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
922 glTranslatef(-0.9, 0, 0);
923 polys += createCylinder(ci, 1.2, 0.3, 0, 0);
924 if (l->light && ci->light) {
925 glDisable(GL_LIGHTING);
928 polys += sphere(ci, 0.3, 7, 7, 3, 7, 0, 7);
929 if (l->light && ci->light) {
930 glEnable(GL_LIGHTING);
932 glDepthMask(GL_TRUE);
936 glTranslatef(1.2, 0, 0);
937 polys += createCylinder(ci, 0.1, 0.38, 1, 0);
938 glTranslatef(-0.3, 0.15, 0);
939 polys += wire(ci, 3);
940 glTranslatef(0, -0.3, 0);
941 polys += wire(ci, 3.3);
942 if (random() % 50 == 25) {
944 l->light = 0; ci->light = 0; ci->lighton = 0;
945 glDisable(GL_LIGHT1);
946 } else if (!ci->light) {
955 static int DrawThreeFive(Circuit *ci, ThreeFive *d)
959 GLfloat const dark[] = {0.3, 0.3, 0.3, 0};
960 GLfloat const light[] = {0.6, 0.6, 0.6, 0};
961 GLfloat const cream[] = {0.8, 0.8, 0.6, 0};
962 GLfloat const spec[] = {0.7, 0.7, 0.7, 0};
965 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
966 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cream);
967 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
969 glTranslatef(-2.0, 0, 0);
970 polys += createCylinder(ci, 0.7, 0.2, 0, 0);
971 glTranslatef(0.7, 0, 0);
972 polys += createCylinder(ci, 1.3, 0.4, 1, 0);
973 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light);
974 glTranslatef(1.3, 0, 0);
975 polys += createCylinder(ci, 1.3, 0.2, 0, 0);
976 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, dark);
977 glTranslatef(0.65, 0, 0);
978 polys += createCylinder(ci, 0.15, 0.21, 0, 0);
979 glTranslatef(0.3, 0, 0);
980 polys += createCylinder(ci, 0.15, 0.21, 0, 0);
981 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light);
982 glTranslatef(0.4, 0, 0);
983 polys += sphere(ci, 0.23, 7, 7, 0, 5, 0, 7);
989 static int DrawDiode(Circuit *ci, Diode *d)
993 GLfloat col[] = {0.3, 0.3, 0.3, 0};
994 GLfloat spec[] = {0.7, 0.7, 0.7, 0};
997 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
998 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
999 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1000 glTranslatef(-4, 0, 0);
1001 polys += wire(ci, 3);
1002 glTranslatef(3, 0, 0);
1003 polys += bandedCylinder(ci, 0.3, 1.5, d->r, d->g, d->b, &(d->band), 1);
1004 glTranslatef(1.5, 0, 0);
1005 polys += wire(ci, 3);
1010 static int Rect(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h,
1018 yh = y+h; xw = x+w; zt = z - t;
1020 glBegin(GL_QUADS); /* front */
1021 glNormal3f(0, 0, 1);
1022 glVertex3f(x, y, z);
1023 glVertex3f(x, yh, z);
1024 glVertex3f(xw, yh, z);
1025 glVertex3f(xw, y, z);
1028 glNormal3f(0, 0, -1);
1029 glVertex3f(x, y, zt);
1030 glVertex3f(x, yh, zt);
1031 glVertex3f(xw, yh, zt);
1032 glVertex3f(xw, y, zt);
1035 glNormal3f(0, 1, 0);
1036 glVertex3f(x, yh, z);
1037 glVertex3f(x, yh, zt);
1038 glVertex3f(xw, yh, zt);
1039 glVertex3f(xw, yh, z);
1042 glNormal3f(0, -1, 0);
1043 glVertex3f(x, y, z);
1044 glVertex3f(x, y, zt);
1045 glVertex3f(xw, y, zt);
1046 glVertex3f(xw, y, z);
1049 glNormal3f(-1, 0, 0);
1050 glVertex3f(x, y, z);
1051 glVertex3f(x, y, zt);
1052 glVertex3f(x, yh, zt);
1053 glVertex3f(x, yh, z);
1056 glNormal3f(1, 0, 0);
1057 glVertex3f(xw, y, z);
1058 glVertex3f(xw, y, zt);
1059 glVertex3f(xw, yh, zt);
1060 glVertex3f(xw, yh, z);
1068 static int ICLeg(GLfloat x, GLfloat y, GLfloat z, int dir)
1072 polys += Rect(x-0.1, y, z, 0.1, 0.1, 0.02);
1073 polys += Rect(x-0.1, y, z, 0.02, 0.1, 0.1);
1074 polys += Rect(x-0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
1076 polys += Rect(x, y, z, 0.1, 0.1, 0.02);
1077 polys += Rect(x+0.8*0.1, y, z, 0.02, 0.1, 0.1);
1078 polys += Rect(x+0.8*0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
1084 static int DrawIC(Circuit *ci, IC *c)
1089 GLfloat col[] = {0.1, 0.1, 0.1, 0};
1090 GLfloat col2[] = {0.2, 0.2, 0.2, 0};
1091 GLfloat spec[] = {0.6, 0.6, 0.6, 0};
1093 GLfloat lspec[] = {0.6, 0.6, 0.6, 0};
1094 GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
1095 GLfloat lshine = 40;
1096 float mult, th, size;
1099 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1100 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1101 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1102 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
1119 glEnable(GL_POLYGON_OFFSET_FILL);
1120 glPolygonOffset(1.0, 1.0);
1122 glNormal3f(0, 0, 1);
1123 glVertex3f(w, h, 0.1);
1124 glVertex3f(w, -h, 0.1);
1125 glVertex3f(-w, -h, 0.1);
1126 glVertex3f(-w, h, 0.1);
1128 glNormal3f(0, 0, -1);
1129 glVertex3f(w, h, -0.1);
1130 glVertex3f(w, -h, -0.1);
1131 glVertex3f(-w, -h, -0.1);
1132 glVertex3f(-w, h, -0.1);
1134 glNormal3f(1, 0, 0);
1135 glVertex3f(w, h, -0.1);
1136 glVertex3f(w, -h, -0.1);
1137 glVertex3f(w, -h, 0.1);
1138 glVertex3f(w, h, 0.1);
1140 glNormal3f(0, -1, 0);
1141 glVertex3f(w, -h, -0.1);
1142 glVertex3f(w, -h, 0.1);
1143 glVertex3f(-w, -h, 0.1);
1144 glVertex3f(-w, -h, -0.1);
1146 glNormal3f(-1, 0, 0);
1147 glVertex3f(-w, h, -0.1);
1148 glVertex3f(-w, h, 0.1);
1149 glVertex3f(-w, -h, 0.1);
1150 glVertex3f(-w, -h, -0.1);
1152 glNormal3f(0, -1, 0);
1153 glVertex3f(-w, h, -0.1);
1154 glVertex3f(w, h, -0.1);
1155 glVertex3f(w, h, 0.1);
1156 glVertex3f(-w, h, 0.1);
1159 glDisable(GL_POLYGON_OFFSET_FILL);
1160 if (c->tnum) glBindTexture(GL_TEXTURE_2D, c->tnum);
1161 glEnable(GL_TEXTURE_2D);
1168 mult = size*c->tw / c->th;
1170 glBegin(GL_QUADS); /* text markings */
1171 glNormal3f(0, 0, 1);
1173 glVertex3f(th, mult, 0.1);
1175 glVertex3f(th, -mult, 0.1);
1177 glVertex3f(-th, -mult, 0.1);
1179 glVertex3f(-th, mult, 0.1);
1182 glDisable(GL_TEXTURE_2D);
1183 glDisable(GL_BLEND);
1184 d = (h*2-0.1) / c->pins;
1186 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
1187 glMaterialfv(GL_FRONT, GL_SPECULAR, lspec);
1188 glMaterialfv(GL_FRONT, GL_SHININESS, &lshine);
1189 for (z = 0 ; z < c->pins/2 ; z++) {
1190 polys += ICLeg(w, -h + z*d + d/2, 0, 0);
1192 for (z = 0 ; z < c->pins/2 ; z++) {
1193 polys += ICLeg(-w, -h + z*d + d/2, 0, 1);
1195 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col2);
1196 glTranslatef(-w+0.3, h-0.3, 0.1);
1197 glRotatef(90, 0, 1, 0);
1198 polys += circle(ci, 0.1, 7, 0);
1203 static int DrawDisp(Circuit *ci, Disp *d)
1206 GLfloat col[] = {0.8, 0.8, 0.8, 1.0}; /* body colour */
1207 GLfloat front[] = {0.2, 0.2, 0.2, 1.0}; /* front colour */
1208 GLfloat on[] = {0.9, 0, 0, 1}; /* 'on' segment */
1209 GLfloat off[] = {0.3, 0, 0, 1}; /* 'off' segment */
1211 GLfloat x, y; /* for the pins */
1212 GLfloat spec[] = {0.6, 0.6, 0.6, 0};
1213 GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
1215 static const GLfloat vdata_h[6][2] = {
1223 static const GLfloat vdata_v[6][2] = {
1232 static const GLfloat seg_start[7][2] = {
1242 static const int nums[10][7] = {
1243 {1, 1, 1, 1, 1, 1, 0}, /* 0 */
1244 {0, 1, 1, 0, 0, 0, 0}, /* 1 */
1245 {1, 1, 0, 1, 1, 0, 1}, /* 2 */
1246 {1, 1, 1, 1, 0, 0, 1}, /* 3 */
1247 {0, 1, 1, 0, 0, 1, 1}, /* 4 */
1248 {1, 0, 1, 1, 0, 1, 1}, /* 5 */
1249 {1, 0, 1, 1, 1, 1, 1}, /* 6 */
1250 {1, 1, 1, 0, 0, 0, 0}, /* 7 */
1251 {1, 1, 1, 1, 1, 1, 1}, /* 8 */
1252 {1, 1, 1, 0, 0, 1, 1} /* 9 */
1255 glTranslatef(-0.9, -1.8, 0);
1256 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1257 polys += Rect(0, 0, -0.01, 1.8, 2.6, 0.7);
1258 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, front);
1260 glVertex2f(-0.05, -0.05);
1261 glVertex2f(-0.05, 2.65);
1262 glVertex2f(1.85, 2.65);
1263 glVertex2f(1.85, -0.05);
1266 glDisable(GL_LIGHTING); /* lit segments dont need light */
1267 if (!seven && (random() % 30) == 19) { /* randomly change value */
1268 d->value = random() % 10;
1270 for (j = 0 ; j < 7 ; j++) { /* draw the segments */
1271 GLfloat xx[6], yy[6];
1272 if (nums[d->value][j])
1276 for (k = 0 ; k < 6 ; k++) {
1277 if (j == 0 || j == 3 || j == 6) {
1278 xx[k] = seg_start[j][0] + vdata_h[k][0];
1279 yy[k] = seg_start[j][1] + vdata_h[k][1];
1281 xx[k] = seg_start[j][0] + vdata_v[k][0];
1282 yy[k] = seg_start[j][1] + vdata_v[k][1];
1285 glBegin(GL_POLYGON);
1286 for(i = 0 ; i < 6 ; i++) {
1287 glVertex3f(xx[i], yy[i], 0.01);
1295 glVertex3f(1.5, 0.2, 0.01);
1298 glEnable(GL_LIGHTING);
1299 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
1300 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1301 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
1302 for (x = 0.35 ; x <= 1.5 ; x+= 1.15) {
1303 for ( y = 0.2 ; y <= 2.4 ; y += 0.3) {
1304 polys += ICLeg(x, y, -0.7, 1);
1310 static int HoledRectangle(Circuit *ci,
1311 GLfloat w, GLfloat h, GLfloat d, GLfloat radius,
1316 GLfloat x1, y1, x2, y2;
1317 GLfloat yr, yr1, xr, xr1, side, side1;
1321 x1 = radius; y1 = 0;
1326 for (a = 0 ; a <= 360 ; a+= step) {
1327 y2=radius*(float)ci->sin_table[(int)a];
1328 x2=radius*(float)ci->cos_table[(int)a];
1330 if (a < 45 || a > 315) {
1332 yr = side1 * ci->tan_table[a];
1334 } else if (a <= 135 || a >= 225) {
1335 xr = side/ci->tan_table[a];
1346 yr = -side1 * ci->tan_table[a];
1350 glNormal3f(-x1, -y1, 0); /* cylinder */
1351 glVertex3f(x1,y1,0);
1352 glVertex3f(x1,y1,-d);
1353 glVertex3f(x2,y2,-d);
1354 glVertex3f(x2,y2,0);
1357 glNormal3f(0, 0, 1); /* front face */
1358 glVertex3f(x1,y1,0);
1359 glVertex3f(xr1, yr1, 0);
1360 glVertex3f(xr, yr, 0);
1361 glVertex3f(x2, y2, 0);
1364 glNormal3f(nx, ny, 0); /* side */
1365 glVertex3f(xr, yr, 0);
1366 glVertex3f(xr, yr, -d);
1367 glVertex3f(xr1, yr1, -d);
1368 glVertex3f(xr1, yr1, 0);
1371 glNormal3f(0, 0, -1); /* back */
1372 glVertex3f(xr, yr, -d);
1373 glVertex3f(x2, y2, -d);
1374 glVertex3f(x1, y1, -d);
1375 glVertex3f(xr1, yr1, -d);
1386 static int DrawTransistor(Circuit *ci, Transistor *t)
1389 GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
1390 GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
1391 GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
1395 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1396 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col);
1397 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1398 if (t->type == 1) { /* TO-92 style */
1400 mult = 1.5*t->th/t->tw;
1403 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1404 glRotatef(90, 0, 1, 0);
1405 glRotatef(90, 0, 0, 1);
1406 polys += createCylinder(ci, 1.0, 0.4, 1, 1);
1407 polys += Rect(0, -0.2, 0.4, 1, 0.2, 0.8);
1408 /* Draw the markings */
1409 glEnable(GL_TEXTURE_2D);
1410 if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
1412 glDepthMask(GL_FALSE);
1414 glNormal3f(0, 0, 1);
1416 glVertex3f(y1, -0.21, 0.3);
1418 glVertex3f(y1, -0.21, -0.3);
1420 glVertex3f(y2, -0.21, -0.3);
1422 glVertex3f(y2, -0.21, 0.3);
1425 glDisable(GL_TEXTURE_2D);
1426 glDisable(GL_BLEND);
1427 glDepthMask(GL_TRUE);
1428 glTranslatef(-2, 0, -0.2);
1429 polys += wire(ci, 2);
1430 glTranslatef(0, 0, 0.2);
1431 polys += wire(ci, 2);
1432 glTranslatef(0, 0, 0.2);
1433 polys += wire(ci, 2);
1434 } else if (t->type == 0) { /* TO-220 Style */
1436 mult = 1.5*t->th/t->tw;
1439 polys += Rect(0, 0, 0, 1.5, 1.5, 0.5);
1440 glEnable(GL_TEXTURE_2D);
1441 if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
1443 glDepthMask(GL_FALSE);
1445 glNormal3f(0, 0, 1);
1447 glVertex3f(0, y1, 0.01);
1449 glVertex3f(1.5, y1, 0.01);
1451 glVertex3f(1.5, y2, 0.01);
1453 glVertex3f(0, y2, 0.01);
1455 glDisable(GL_TEXTURE_2D);
1456 glDisable(GL_BLEND);
1457 glDepthMask(GL_TRUE);
1458 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1459 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1460 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1461 polys += Rect(0, 0, -0.5, 1.5, 1.5, 0.30);
1462 if (!glIsEnabled(GL_NORMALIZE)) glEnable(GL_NORMALIZE);
1463 glTranslatef(0.75, 1.875, -0.55);
1464 polys += HoledRectangle(ci, 1.5, 0.75, 0.25, 0.2, 8);
1465 glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
1466 glTranslatef(-0.375, -1.875, 0);
1467 glRotatef(90, 0, 0, -1);
1468 polys += wire(ci, 2);
1469 glTranslatef(0, 0.375, 0);
1470 polys += wire(ci, 2);
1471 glTranslatef(0, 0.375, 0);
1472 polys += wire(ci, 2);
1473 } else { /* SMC transistor */
1475 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1476 glTranslatef(-0.5, -0.25, 0.1);
1477 polys += Rect(0, 0, 0, 1, 0.5, 0.2);
1478 /* Draw the markings */
1479 glEnable(GL_TEXTURE_2D);
1480 if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
1482 glDepthMask(GL_FALSE);
1484 glNormal3f(0, 0, 1);
1486 glVertex3f(0.2, 0, 0.01);
1488 glVertex3f(0.8, 0, 0.01);
1490 glVertex3f(0.8, 0.5, 0.01);
1492 glVertex3f(0.2, 0.5, 0.01);
1495 glDisable(GL_TEXTURE_2D);
1496 glDisable(GL_BLEND);
1497 glDepthMask(GL_TRUE);
1498 /* Now draw the legs */
1499 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1500 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1501 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1502 polys += Rect(0.25, -0.1, -0.05, 0.1, 0.1, 0.2);
1503 polys += Rect(0.75, -0.1, -0.05, 0.1, 0.1, 0.2);
1504 polys += Rect(0.5, 0.5, -0.05, 0.1, 0.1, 0.2);
1505 polys += Rect(0.25, -0.2, -0.2, 0.1, 0.15, 0.1);
1506 polys += Rect(0.75, -0.2, -0.2, 0.1, 0.15, 0.1);
1507 polys += Rect(0.5, 0.5, -0.2, 0.1, 0.15, 0.1);
1513 static Component * NewComponent(ModeInfo *mi)
1515 Circuit *ci = &circuit[MI_SCREEN(mi)];
1519 c = malloc(sizeof(Component));
1520 c->angle = RAND_RANGE(0,360);
1522 if (rnd < 0.25) { /* come from the top */
1524 c->x = RAND_RANGE(0, ci->XMAX) - ci->XMAX/2;
1526 c->dx = 0 - RAND_RANGE(0.5, 2);
1528 c->dx = RAND_RANGE(0.5, 2);
1529 c->dy = 0 - RAND_RANGE(0.5, 2);
1530 } else if (rnd < 0.5) { /* come from the bottom */
1531 c->y = 0 - ci->YMAX/2;
1532 c->x = RAND_RANGE(0, ci->XMAX) - ci->XMAX/2;
1534 c->dx = 0 - RAND_RANGE(0.5, 2);
1536 c->dx = RAND_RANGE(0.5, 2);
1537 c->dy = RAND_RANGE(0.5, 2);
1538 } else if (rnd < 0.75) { /* come from the left */
1539 c->x = 0 - ci->XMAX/2;
1540 c->y = RAND_RANGE(0, ci->YMAX) - ci->YMAX/2;
1541 c->dx = RAND_RANGE(0.5, 2);
1543 c->dy = 0 - RAND_RANGE(0.5, 2);
1545 c->dy = RAND_RANGE(0.5, 2);
1546 } else { /* come from the right */
1548 c->y = RAND_RANGE(0, ci->YMAX) - ci->YMAX/2;
1549 c->dx = 0 - RAND_RANGE(0.5, 2);
1551 c->dy = 0 - RAND_RANGE(0.5, 2);
1553 c->dy = RAND_RANGE(0.5, 2);
1555 c->z = RAND_RANGE(0, 7) - 9;
1559 c->drot = f_rand() * 3;
1561 c->dz = f_rand()*2 - 1;
1563 c->alpha = 0; /* explicitly set to 1 later */
1564 rnd = random() % 11;
1566 c->c = NewResistor();
1569 c->norm = 1; /* some resistors shine */
1570 } else if (rnd < 2) {
1573 c->norm = 1; /* some diodes shine */
1575 } else if (rnd < 3) {
1576 c->c = NewTransistor(mi);
1579 } else if (rnd < 4) {
1580 c->c = NewCapacitor(ci);
1583 } else if (rnd < 5) {
1587 } else if (rnd < 6) {
1592 } else if (rnd < 7) {
1597 } else if (rnd < 8) {
1601 } else if (rnd < 9) {
1602 c->c = NewThreeFive(ci);
1605 } else if (rnd < 10) {
1606 c->c = NewSwitch(ci);
1616 static Transistor *NewTransistor(ModeInfo *mi)
1619 float texfg[] = {0.7, 0.7, 0.7, 1.0};
1620 float texbg[] = {0.3, 0.3, 0.3, 0.1};
1624 t = malloc(sizeof(Transistor));
1625 t->type = (random() % 3);
1627 val = transistortypes[random() % countof(transistortypes)];
1628 tn = fonttexturealloc(mi, val, texfg, texbg);
1630 fprintf(stderr, "Error getting a texture for a string!\n");
1634 t->tw = tn->w; t->th = tn->h;
1637 } else if (t->type == 2) {
1638 val = smctypes[random() % countof(smctypes)];
1639 tn = fonttexturealloc(mi, val, texfg, texbg);
1641 fprintf(stderr, "Error getting a texture for a string!\n");
1645 t->tw = tn->w; t->th = tn->h;
1648 } else if (t->type == 1) {
1649 val = to92types[random() % countof(to92types)];
1650 tn = fonttexturealloc(mi, val, texfg, texbg);
1652 fprintf(stderr, "Error getting a texture for a string!\n");
1656 t->tw = tn->w; t->th = tn->h;
1664 static Capacitor *NewCapacitor(Circuit *ci)
1668 c = malloc(sizeof(Capacitor));
1669 c->type = (f_rand() < 0.5);
1671 c->length = RAND_RANGE(0.5, 1);
1672 c->width = RAND_RANGE(0.5, 1);
1674 c->width = RAND_RANGE(0.3, 1);
1679 /* 7 segment display */
1681 static Disp *NewDisp(Circuit *ci)
1685 d = malloc(sizeof(Disp));
1689 d->value = RAND_RANGE(0, 10);
1694 static IC *NewIC(ModeInfo *mi)
1699 float texfg[] = {0.7, 0.7, 0.7, 1.0};
1700 float texbg[] = {0.1, 0.1, 0.1, 0};
1703 int types[countof(ictypes)], i, n = 0;
1705 c = malloc(sizeof(IC));
1707 switch((int)RAND_RANGE(0,4)) {
1722 for (i = 0 ; i < countof(ictypes) ; i++) {
1723 if (ictypes[i].pins == pins) {
1729 if (n > countof(types)) abort();
1730 val = ictypes[types[random() % n]].val;
1731 str = malloc(strlen(val) + 1 + 4 + 1); /* add space for production date */
1732 sprintf(str, "%s\n%02d%02d", val, (int)RAND_RANGE(80, 100), (int)RAND_RANGE(1,53));
1733 tn = fonttexturealloc(mi, str, texfg, texbg);
1736 fprintf(stderr, "Error allocating font texture for '%s'\n", val);
1739 c->tw = tn->w; c->th = tn->h;
1747 static LED *NewLED(Circuit *ci)
1752 l = malloc(sizeof(LED));
1755 if (!ci->light && (f_rand() < 0.4)) {
1760 l->r = 0.9; l->g = 0; l->b = 0;
1761 } else if (r < 0.4) {
1762 l->r = 0.3; l->g = 0.9; l->b = 0;
1763 } else if (r < 0.6) {
1764 l->r = 0.8; l->g = 0.9; l->b = 0;
1765 } else if (r < 0.8) {
1766 l->r = 0.0; l->g = 0.2; l->b = 0.8;
1768 l->r = 0.9, l->g = 0.55, l->b = 0;
1773 static Fuse *NewFuse(Circuit *ci)
1777 f = malloc(sizeof(Fuse));
1781 static RCA *NewRCA(Circuit *ci)
1785 r = malloc(sizeof(RCA));
1786 r->col = (random() % 10 < 5);
1790 static ThreeFive *NewThreeFive(Circuit *ci)
1794 r = malloc(sizeof(ThreeFive));
1798 static Switch *NewSwitch(Circuit *ci)
1802 s = malloc(sizeof(Switch));
1807 static Diode *NewDiode(void)
1812 ret = malloc(sizeof(Diode));
1813 b = malloc(sizeof(Band));
1816 if (f_rand() < 0.5) {
1820 ret->r = 0.7; ret->g = 0.1 ; ret->b = 0.1;
1825 ret->r = 0.2; ret->g = 0.2 ; ret->b = 0.2;
1832 static Resistor * NewResistor(void)
1834 int v, m, t; /* value, multiplier, tolerance */
1839 t = (RAND(10) < 5) ? 10 : 11;
1840 ret = malloc(sizeof(Resistor));
1843 ret->b[0] = ret->b[1] = ret->b[2] = 7;
1845 ret->b[0] = values[v][0];
1846 ret->b[1] = values[v][1];
1854 static void makebandlist(Circuit *ci)
1857 GLfloat col[] = {0,0,0,0};
1858 GLfloat spec[] = {0.8,0.8,0.8,0};
1861 for (i = 0 ; i < 12 ; i++) {
1862 ci->band_list[i] = glGenLists(i);
1863 glNewList(ci->band_list[i], GL_COMPILE);
1864 col[0] = colorcodes[i][0];
1865 col[1] = colorcodes[i][1];
1866 col[2] = colorcodes[i][2];
1867 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
1868 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
1869 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
1870 ci->band_list_polys[i] = createCylinder(ci, 0.1, 0.42, 0, 0);
1876 static int bandedCylinder(Circuit *ci,
1877 float radius, float l,
1878 GLfloat r, GLfloat g, GLfloat bl,
1879 Band **b, int nbands)
1882 int n; /* band number */
1883 int p = 0; /* prev number + 1; */
1884 GLfloat col[] = {0,0,0,0};
1886 col[0] = r; col[1] = g; col[2] = bl;
1887 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1888 polys += createCylinder(ci, l, radius, 1, 0); /* body */
1889 for (n = 0 ; n < nbands ; n++) {
1891 glTranslatef(b[n]->pos*l, 0, 0);
1892 col[0] = b[n]->r; col[1] = b[n]->g; col[2] = b[n]->b;
1893 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1894 polys += createCylinder(ci, b[n]->len*l, radius*1.05, 0, 0); /* band */
1901 static int drawgrid(Circuit *ci)
1905 GLfloat col3[] = {0, 0.8, 0};
1908 if (f_rand() < ((rotatespeed > 0) ? 0.05 : 0.01)) {
1909 ci->draw_sdir = RAND_RANGE(0, 4);
1910 ci->draw_ds = RAND_RANGE(0.4, 0.8);
1911 switch (ci->draw_sdir) {
1913 ci->draw_sx = -ci->XMAX/2;
1914 ci->draw_sy = ((int)RAND_RANGE(0, ci->YMAX/2))*2 - ci->YMAX/2;
1917 ci->draw_sx = ci->XMAX/2;
1918 ci->draw_sy = ((int)RAND_RANGE(0, ci->YMAX/2))*2 - ci->YMAX/2;
1921 ci->draw_sy = ci->YMAX/2;
1922 ci->draw_sx = ((int)RAND_RANGE(0, ci->XMAX/2))*2 - ci->XMAX/2;
1925 ci->draw_sy = -ci->YMAX/2;
1926 ci->draw_sx = ((int)RAND_RANGE(0, ci->XMAX/2))*2 - ci->XMAX/2;
1931 } else if (rotatespeed <= 0) {
1932 if (ci->grid_col[1] < 0.25) {
1933 ci->grid_col[1] += 0.025; ci->grid_col[2] += 0.005;
1934 ci->grid_col2[1] += 0.015 ; ci->grid_col2[2] += 0.005;
1938 glDisable(GL_LIGHTING);
1942 glTranslatef(ci->draw_sx, ci->draw_sy, -10);
1943 polys += sphere(ci, 0.1, 10, 10, 0, 10, 0, 10);
1944 if (ci->draw_sdir == 0)
1945 glTranslatef(-ci->draw_ds, 0, 0);
1946 if (ci->draw_sdir == 1)
1947 glTranslatef(ci->draw_ds, 0, 0);
1948 if (ci->draw_sdir == 2)
1949 glTranslatef(0, ci->draw_ds, 0);
1950 if (ci->draw_sdir == 3)
1951 glTranslatef(0, -ci->draw_ds, 0);
1952 polys += sphere(ci, 0.05, 10, 10, 0, 10, 0, 10);
1954 if (ci->draw_sdir == 0) {
1955 ci->draw_sx += ci->draw_ds;
1956 if (ci->draw_sx > ci->XMAX/2)
1959 if (ci->draw_sdir == 1) {
1960 ci->draw_sx -= ci->draw_ds;
1961 if (ci->draw_sx < -ci->XMAX/2)
1964 if (ci->draw_sdir == 2) {
1965 ci->draw_sy -= ci->draw_ds;
1966 if (ci->draw_sy < ci->YMAX/2)
1969 if (ci->draw_sdir == 3) {
1970 ci->draw_sy += ci->draw_ds;
1971 if (ci->draw_sy > ci->YMAX/2)
1974 } else if (rotatespeed <= 0) {
1975 if (ci->grid_col[1] > 0) {
1976 ci->grid_col[1] -= 0.0025; ci->grid_col[2] -= 0.0005;
1977 ci->grid_col2[1] -= 0.0015 ; ci->grid_col2[2] -= 0.0005;
1980 for (x = -ci->XMAX/2 ; x <= ci->XMAX/2 ; x+= 2) {
1981 glColor3fv(ci->grid_col);
1983 glVertex3f(x, ci->YMAX/2, -10);
1984 glVertex3f(x, -ci->YMAX/2, -10);
1985 glColor3fv(ci->grid_col2);
1986 glVertex3f(x-0.02, ci->YMAX/2, -10);
1987 glVertex3f(x-0.02, -ci->YMAX/2, -10);
1988 glVertex3f(x+0.02, ci->YMAX/2, -10);
1989 glVertex3f(x+0.02, -ci->YMAX/2, -10);
1992 for (y = -ci->YMAX/2 ; y <= ci->YMAX/2 ; y+= 2) {
1993 glColor3fv(ci->grid_col);
1995 glVertex3f(-ci->XMAX/2, y, -10);
1996 glVertex3f(ci->XMAX/2, y, -10);
1997 glColor3fv(ci->grid_col2);
1998 glVertex3f(-ci->XMAX/2, y-0.02, -10);
1999 glVertex3f(ci->XMAX/2, y-0.02, -10);
2000 glVertex3f(-ci->XMAX/2, y+0.02, -10);
2001 glVertex3f(ci->XMAX/2, y+0.02, -10);
2004 glEnable(GL_LIGHTING);
2008 static void display(ModeInfo *mi)
2010 Circuit *ci = &circuit[MI_SCREEN(mi)];
2011 GLfloat light_sp[] = {0.8, 0.8, 0.8, 1.0};
2012 GLfloat black[] = {0, 0, 0, 1.0};
2015 mi->polygon_count = 0;
2017 if (ci->display_i == 0) {
2018 for (ci->display_i = 0 ; ci->display_i < maxparts ; ci->display_i++) {
2019 ci->components[ci->display_i] = NULL;
2022 glEnable(GL_LIGHTING);
2023 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
2025 gluLookAt(ci->viewer[0], ci->viewer[1], ci->viewer[2],
2029 glRotatef(ci->rotate_angle, 0, 0, 1);
2030 ci->rotate_angle += 0.01 * (float)rotatespeed;
2031 if (ci->rotate_angle >= 360) ci->rotate_angle = 0;
2033 glLightfv(GL_LIGHT0, GL_POSITION, ci->lightpos);
2034 glLightfv(GL_LIGHT0, GL_SPECULAR, light_sp);
2035 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_sp);
2036 glLighti(GL_LIGHT0, GL_CONSTANT_ATTENUATION, (GLfloat)1);
2037 glLighti(GL_LIGHT0, GL_LINEAR_ATTENUATION, (GLfloat)0.5);
2038 glLighti(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, (GLfloat)0);
2039 mi->polygon_count += drawgrid(ci);
2040 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light_sp);
2041 if (f_rand() < 0.05) {
2042 for (j = 0 ; j < maxparts ; j++) {
2043 if (ci->components[j] == NULL) {
2044 ci->components[j] = NewComponent(mi);
2048 reorder(&ci->components[0]);
2050 for (j = 0 ; j < maxparts ; j++) {
2051 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, black);
2052 glMaterialfv(GL_FRONT, GL_EMISSION, black);
2053 glMaterialfv(GL_FRONT, GL_SPECULAR, black);
2054 if (ci->components[j] != NULL) {
2055 if (DrawComponent(ci, ci->components[j], &mi->polygon_count)) {
2056 free(ci->components[j]); ci->components[j] = NULL;
2064 static void freetexture (Circuit *ci, GLuint texture)
2066 ci->s_refs[texture]--;
2067 if (ci->s_refs[texture] < 1) {
2068 glDeleteTextures(1, &texture);
2072 static TexNum * fonttexturealloc (ModeInfo *mi,
2073 const char *str, float *fg, float *bg)
2075 Circuit *ci = &circuit[MI_SCREEN(mi)];
2081 if (ci->font_init == 0) {
2082 for (i = 0 ; i < 50 ; i++) {
2083 ci->font_strings[i] = NULL;
2085 ci->font_w[i] = 0; ci->font_h[i] = 0;
2089 for (i = 0 ; i < 50 ; i++) {
2090 if (!ci->s_refs[i] && ci->font_strings[i]) {
2091 free (ci->font_strings[i]);
2092 ci->font_strings[i] = NULL;
2094 if (ci->font_strings[i] && !strcmp(str, ci->font_strings[i])) { /* if one matches */
2095 t = malloc(sizeof(TexNum));
2096 t->w = ci->font_w[i]; t->h = ci->font_h[i];
2103 /* at this point we need to make the new texture */
2104 ximage = text_to_ximage (mi->xgwa.screen,
2108 for (i = 0 ; ci->font_strings[i] != NULL ; i++) { /* set i to the next unused value */
2110 fprintf(stderr, "Texture cache full!\n");
2118 glBindTexture(GL_TEXTURE_2D, i);
2119 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2120 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2121 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2124 status = gluBuild2DMipmaps(GL_TEXTURE_2D, 4, ximage->width, ximage->height,
2125 GL_RGBA, GL_UNSIGNED_BYTE, ximage->data);
2128 const char *s = (char *) gluErrorString (status);
2129 fprintf (stderr, "%s: error mipmapping %dx%d texture: %s\n",
2130 progname, ximage->width, ximage->height,
2131 (s ? s : "(unknown)"));
2134 check_gl_error("mipmapping");
2136 t = malloc(sizeof(TexNum));
2137 t->w = ximage->width;
2138 t->h = ximage->height;
2139 ci->font_w[i] = t->w; ci->font_h[i] = t->h;
2143 c = malloc(strlen(str)+1);
2144 strncpy(c, str, strlen(str)+1);
2145 ci->font_strings[i] = c;
2151 /* ensure transparent components are at the end */
2152 static void reorder(Component *c[])
2155 Component *c1[MAX_COMPONENTS];
2156 Component *c2[MAX_COMPONENTS];
2159 for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
2163 for (i = 0 ; i < maxparts ; i++) {
2164 if (c[i] == NULL) continue;
2165 if (c[i]->alpha) { /* transparent parts go to c1 */
2168 } else { /* opaque parts go to c2 */
2172 for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
2176 for (i = 0 ; i < maxparts ; i++) { /* insert opaque part */
2177 if (c2[i] != NULL) {
2182 for (i = 0 ; i < j ; i++) { /* insert transparent parts */
2188 ENTRYPOINT void reshape_circuit(ModeInfo *mi, int width, int height)
2190 Circuit *ci = &circuit[MI_SCREEN(mi)];
2191 GLfloat h = (GLfloat) height / (GLfloat) width;
2192 glViewport(0,0,(GLint)width, (GLint) height);
2193 glMatrixMode(GL_PROJECTION);
2195 glFrustum(-1.0,1.0,-h,h,1.5,35.0);
2196 glMatrixMode(GL_MODELVIEW);
2199 ci->YMAX = ci->XMAX * h;
2203 ENTRYPOINT void init_circuit(ModeInfo *mi)
2205 int screen = MI_SCREEN(mi);
2208 if (circuit == NULL) {
2209 if ((circuit = (Circuit *) calloc(MI_NUM_SCREENS(mi),
2210 sizeof(Circuit))) == NULL)
2213 ci = &circuit[screen];
2214 ci->window = MI_WINDOW(mi);
2216 ci->XMAX = ci->YMAX = 30;
2218 ci->lightpos[0] = 7;
2219 ci->lightpos[1] = 7;
2220 ci->lightpos[2] = 15;
2221 ci->lightpos[3] = 1;
2223 ci->grid_col[1] = 0.25;
2224 ci->grid_col[2] = 0.05;
2225 ci->grid_col2[1] = 0.125;
2226 ci->grid_col2[2] = 0.05;
2228 if (maxparts >= MAX_COMPONENTS)
2229 maxparts = MAX_COMPONENTS-1;
2231 if ((ci->glx_context = init_GL(mi)) != NULL) {
2232 reshape_circuit(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
2238 glClearColor(0.0,0.0,0.0,0.0);
2239 glShadeModel(GL_SMOOTH);
2240 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
2241 glEnable(GL_DEPTH_TEST);
2242 glEnable(GL_LIGHTING);
2243 glEnable(GL_LIGHT0);
2244 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2250 ENTRYPOINT void draw_circuit(ModeInfo *mi)
2252 Circuit *ci = &circuit[MI_SCREEN(mi)];
2253 Window w = MI_WINDOW(mi);
2254 Display *disp = MI_DISPLAY(mi);
2256 if (!ci->glx_context)
2259 glXMakeCurrent(disp, w, *(ci->glx_context));
2263 if(mi->fps_p) do_fps(mi);
2265 glXSwapBuffers(disp, w);
2268 ENTRYPOINT void release_circuit(ModeInfo *mi)
2270 if (circuit != NULL) {
2271 (void) free((void *) circuit);
2277 XSCREENSAVER_MODULE ("Circuit", circuit)