2 * circuit - Random electronic components floating around
6 * Since version 1.1: added to-220 transistor, added fuse
7 * Since version 1.2: random display digits, LED improvements (flickering)
8 * Since version 1.3: ICs look better, font textures, improved normals to
9 * eliminate segmenting on curved surfaces, speedups
10 * Since version 1.4: Added RCA connector, 3.5mm connector, slide switch,
11 * surface mount, to-92 markings. Fixed ~5min crash.
12 * Better LED illumination. Other minor changes.
14 * Copyright (C) 2001,2002 Ben Buxton (bb@cactii.net)
16 * Permission to use, copy, modify, distribute, and sell this software and its
17 * documentation for any purpose is hereby granted without fee, provided that
18 * the above copyright notice appear in all copies and that both that
19 * copyright notice and this permission notice appear in supporting
20 * documentation. No representations are made about the suitability of this
21 * software for any purpose. It is provided "as is" without express or
25 /* Written over a few days in a (successful) bid to learn GL coding
27 * -seven option is dedicated to all the Slarkeners
29 * try "-rotate -rotate-speed 0"
31 * This hack uses lookup tables for sin, cos and tan - it can do a lot
35 #define DEFAULTS "*delay: 20000 \n" \
38 # define refresh_circuit 0
39 # define circuit_handle_event 0
40 # include "xlockmore.h" /* from the xscreensaver distribution */
41 #else /* !STANDALONE */
42 # include "xlock.h" /* from the xlockmore distribution */
43 #endif /* !STANDALONE */
45 #define DEF_SPIN "True"
46 #define DEF_SEVEN "False"
47 #define DEF_PARTS "10"
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;
70 #define countof(x) (sizeof((x))/sizeof((*x)))
72 static XrmOptionDescRec opts[] = {
73 {"-parts", ".circuit.parts", XrmoptionSepArg, "10" },
74 {"-font", ".circuit.font", XrmoptionSepArg, "fixed" },
75 {"-rotate-speed", ".circuit.rotatespeed", XrmoptionSepArg, "1" },
76 {"+spin", ".circuit.spin", XrmoptionNoArg, "false" },
77 {"-spin", ".circuit.spin", XrmoptionNoArg, "true" },
78 {"+light", ".circuit.light", XrmoptionNoArg, "false" },
79 {"-light", ".circuit.light", XrmoptionNoArg, "true" },
80 {"+seven", ".circuit.seven", XrmoptionNoArg, "false" },
81 {"-seven", ".circuit.seven", XrmoptionNoArg, "true" },
82 {"+rotate", ".circuit.rotate", XrmoptionNoArg, "false" },
83 {"-rotate", ".circuit.rotate", XrmoptionNoArg, "true" },
86 static argtype vars[] = {
87 {&maxparts, "parts", "Parts", DEF_PARTS, t_Int},
88 {&font, "font", "Font", "fixed", t_String},
89 {&rotatespeed, "rotatespeed", "Rotatespeed", "1", t_Int},
90 {&spin, "spin", "Spin", DEF_SPIN, t_Bool},
91 {&rotate, "rotate", "Rotate", "False", t_Bool},
92 {&uselight, "light", "Light", "True", t_Bool},
93 {&seven, "seven", "Seven", DEF_SEVEN, t_Bool},
96 ENTRYPOINT ModeSpecOpt circuit_opts = {countof(opts), opts, countof(vars), vars, NULL};
99 ModStruct circuit_description =
100 {"circuit", "init_circuit", "draw_circuit", "release_circuit",
101 "draw_circuit", "init_circuit", NULL, &circuit_opts,
102 1000, 1, 2, 1, 4, 1.0, "",
103 "Flying electronic components", 0, NULL};
107 #define MAX_COMPONENTS 31
108 #define MOVE_MULT 0.02
110 static float f_rand(void)
112 return ((float)RAND(10000)/(float)10000);
115 #define RAND_RANGE(min, max) ((min) + (max - min) * f_rand())
117 /* used for allocating font textures */
119 int num; /* index number */
124 /* Represents a band on a resistor/diode/etc */
126 float pos; /* relative position from start/previous band */
127 GLfloat r, g, b; /* colour of the band */
128 float len; /* length as a fraction of total length */
132 Band *b1, *b2, *b3, *b4; /* bands */
138 GLfloat r, g, b; /* body colour */
141 static const char * const transistortypes[] = {
157 static const char * const to92types[] = {
172 static const char * const smctypes[] = {
183 int type; /* package type. 0 = to-92, 1 = to-220 */
184 GLfloat tw, th; /* texture dimensions */
185 GLuint tnum; /* texture binding */
189 GLfloat r,g,b; /* LED colour */
190 int light; /* are we the light source? */
194 int type; /* 0 = electro, 1 = ceramic */
195 float width; /* width of an electro/ceramic */
196 float length; /* length of an electro */
214 static const ICTypes ictypes[] = {
257 int type; /* 0 = DIL, 1 = flat square */
259 float tw, th; /* texture dimensions for markings */
260 int tnum; /* texture number */
263 /* 7 segment display */
266 int value; /* displayed number */
279 GLfloat x, y, z; /* current co-ordinates */
280 GLfloat dx, dy, dz; /* current direction */
281 GLfloat rotx, roty, rotz; /* rotation vector */
282 GLfloat drot; /* rotation velocity (degrees per frame) */
283 int norm; /* Normalize this component (for shine) */
284 int rdeg; /* current rotation degrees */
285 int angle; /* angle about the z axis */
286 int alpha; /* 0 if not a transparent component */
287 int type; /* 0 = resistor, 1 = diode, 2 = transistor, 3 = LED, 4 = cap, 5=IC,
289 void * c; /* pointer to the component */
292 /* standard colour codes */
294 static const GLfloat colorcodes [12][3] = {
295 {0.0,0.0,0.0}, /* black 0 */
296 {0.49,0.25,0.08}, /* brown 1 */
297 {1.0,0.0,0.0}, /* red 2 */
298 {1.0,0.5,0.0}, /* orange 3 */
299 {1.0,1.0,0.0}, /* yellow 4 */
300 {0.0,1.0,0.0}, /* green 5 */
301 {0.0,0.5,1.0}, /* blue 6 */
302 {0.7,0.2,1.0}, /* violet 7 */
303 {0.5,0.5,0.5}, /* grey 8 */
304 {1.0,1.0,1.0}, /* white 9 */
305 {0.66,0.56,0.2}, /* gold 10 */
306 {0.8,0.8,0.8}, /* silver 11 */
309 /* base values for components - we can multiply by 0 - 1M */
310 static const int values [9][2] = {
323 GLXContext *glx_context;
329 /* one lucky led gets to be a light source , unless -no-light*/
333 /* stores refs to textures */
339 float sin_table[720];
340 float cos_table[720];
341 float tan_table[720];
343 Component *components[MAX_COMPONENTS];
346 GLfloat grid_col[3], grid_col2[3];
349 GLfloat rotate_angle;
351 char *font_strings[50]; /* max of 40 textures */
352 int font_w[50], font_h[50];
355 GLfloat draw_sx, draw_sy; /* bright spot co-ords */
356 int draw_sdir; /* 0 = left-right, 1 = right-left, 2 = up->dn, 3 = dn->up */
357 int draw_s; /* if spot is enabled */
358 float draw_ds; /* speed of spot */
362 static Circuit *circuit = NULL;
365 static void DrawResistor(Circuit *, Resistor *);
366 static void DrawDiode(Circuit *, Diode *);
367 static void DrawTransistor(Circuit *, Transistor *);
368 static void DrawLED(Circuit *, LED *);
369 static void DrawIC(Circuit *, IC *);
370 static void DrawCapacitor(Circuit *, Capacitor *);
371 static void DrawDisp(Circuit *, Disp *);
372 static void DrawFuse(Circuit *, Fuse *);
373 static void DrawRCA(Circuit *, RCA *);
374 static void DrawThreeFive(Circuit *, ThreeFive *);
375 static void DrawSwitch(Circuit *, Switch *);
377 static void freetexture(Circuit *, GLuint);
378 static void reorder(Component *[]);
379 static void circle(Circuit *, float, int,int);
380 static void bandedCylinder(Circuit *,
381 float, float , GLfloat, GLfloat , GLfloat,
383 static TexNum *fonttexturealloc(ModeInfo *, const char *, float *, float *);
384 static void Rect(GLfloat , GLfloat , GLfloat, GLfloat , GLfloat ,GLfloat);
385 static void ICLeg(GLfloat, GLfloat, GLfloat, int);
386 static void HoledRectangle(Circuit *ci,
387 GLfloat, GLfloat, GLfloat, GLfloat, int);
388 static Resistor *NewResistor(void);
389 static Diode *NewDiode(void);
390 static Transistor *NewTransistor(ModeInfo *);
391 static LED * NewLED(Circuit *);
392 static Capacitor *NewCapacitor(Circuit *);
393 static IC* NewIC(ModeInfo *);
394 static Disp* NewDisp(Circuit *);
395 static Fuse *NewFuse(Circuit *);
396 static RCA *NewRCA(Circuit *);
397 static ThreeFive *NewThreeFive(Circuit *);
398 static Switch *NewSwitch(Circuit *);
400 /* we use trig tables to speed things up - 200 calls to sin()
401 in one frame can be a bit harsh..
404 static void make_tables(Circuit *ci)
409 f = 360 / (M_PI * 2);
410 for (i = 0 ; i < 720 ; i++) {
411 ci->sin_table[i] = sin(i/f);
413 for (i = 0 ; i < 720 ; i++) {
414 ci->cos_table[i] = cos(i/f);
416 for (i = 0 ; i < 720 ; i++) {
417 ci->tan_table[i] = tan(i/f);
422 static void createCylinder (Circuit *ci,
423 float length, float radius, int endcaps, int half)
425 int a; /* current angle around cylinder */
427 float z1, y1, z2, y2,ex;
432 nsegs = radius*MAX(ci->win_w, ci->win_h)/20;
433 nsegs = MAX(nsegs, 4);
436 angle = (half) ? (180 - 90/nsegs) : 374;
440 for (a = 0 ; a <= angle ; a+= angle/nsegs) {
441 y2=radius*(float)ci->sin_table[(int)a];
442 z2=radius*(float)ci->cos_table[(int)a];
443 glNormal3f(0, y1, z1);
445 glVertex3f(length,y1,z1);
446 glNormal3f(0, y2, z2);
447 glVertex3f(length,y2,z2);
456 glVertex3f(0, 0, radius);
457 glVertex3f(length, 0, radius);
458 glVertex3f(length, 0, 0 - radius);
459 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);
483 static void circle(Circuit *ci, float radius, int segments, int half)
485 float x1 = 0, x2 = 0;
486 float y1 = 0, y2 = 0;
495 glBegin(GL_TRIANGLES);
500 x2=radius*(float)ci->cos_table[(int)angle];
501 y2=radius*(float)ci->sin_table[(int)angle];
511 static void wire(Circuit *ci, float len)
513 GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
514 GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
515 GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
519 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
520 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
521 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
522 n = glIsEnabled(GL_NORMALIZE);
523 if (!n) glEnable(GL_NORMALIZE);
524 createCylinder(ci, len, 0.05, 1, 0);
525 if (!n) glDisable(GL_NORMALIZE);
526 glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
530 static void ring(GLfloat inner, GLfloat outer, int nsegs)
532 GLfloat z1, z2, y1, y2;
533 GLfloat Z1, Z2, Y1, Y2;
540 for(i=0; i <=360 ; i+= 360/nsegs)
543 z2=inner*(float)ci->sin_table[(int)angle];
544 y2=inner*(float)ci->cos_table[(int)angle];
545 Z2=outer*(float)ci->sin_table[(int)angle];
546 Y2=outer*(float)ci->cos_table[(int)angle];
547 glVertex3f(0, Y1, Z1);
548 glVertex3f(0, y1, z1);
549 glVertex3f(0, y2, z2);
550 glVertex3f(0, Y2, Z2);
560 static void sphere(Circuit *ci, GLfloat r, float stacks, float slices,
561 int startstack, int endstack, int startslice,
564 GLfloat d, d1, dr, dr1, Dr, Dr1, D, D1, z1, z2, y1, y2, Y1, Z1, Y2, Z2;
565 int a, a1, b, b1, c0, c1;
570 a1 = startstack * step;
571 b1 = startslice * sstep;
572 y1 = z1 = Y1 = Z1 = 0;
573 c0 = (endslice / slices) * 360;
574 c1 = (endstack/stacks)*180;
576 for (a = startstack * step ; a <= c1 ; a+= step) {
578 d1=ci->sin_table[a1];
580 D1=ci->cos_table[a1];
585 for (b = b1 ; b <= c0 ; b+= sstep) {
586 y2=dr*ci->sin_table[b];
587 z2=dr*ci->cos_table[b];
588 Y2=dr1*ci->sin_table[b];
589 Z2=dr1*ci->cos_table[b];
590 glNormal3f(Dr, y1, z1);
591 glVertex3f(Dr,y1,z1);
592 glNormal3f(Dr, y2, z2);
593 glVertex3f(Dr,y2,z2);
594 glNormal3f(Dr1, Y2, Z2);
595 glVertex3f(Dr1,Y2,Z2);
596 glNormal3f(Dr1, Y1, Z1);
597 glVertex3f(Dr1,Y1,Z1);
608 static int DrawComponent(Circuit *ci, Component *c)
610 int ret = 0; /* return 1 if component is freed */
613 glTranslatef(c->x, c->y, c->z);
615 glRotatef(c->angle, c->rotx, c->roty, c->rotz);
618 glRotatef(c->rdeg, c->rotx, c->roty, c->rotz);
623 glEnable(GL_NORMALIZE);
625 glDisable(GL_NORMALIZE);
627 /* call object draw routine here */
629 DrawResistor(ci, c->c);
630 } else if (c->type == 1) {
632 } else if (c->type == 2) {
633 DrawTransistor(ci, c->c);
634 } else if (c->type == 3) {
635 if (((LED *)c->c)->light && ci->light) {
636 GLfloat lp[] = {0.1, 0, 0, 1};
638 glLightfv(GL_LIGHT1, GL_POSITION, lp);
641 } else if (c->type == 4) {
642 DrawCapacitor(ci, c->c);
643 } else if (c->type == 5) {
645 } else if (c->type == 6) {
647 } else if (c->type == 7) {
649 } else if (c->type == 8) {
651 } else if (c->type == 9) {
652 DrawThreeFive(ci, c->c);
653 } else if (c->type == 10) {
654 DrawSwitch(ci, c->c);
656 c->x += c->dx * MOVE_MULT;
657 c->y += c->dy * MOVE_MULT;
658 if (c->x > ci->XMAX/2 || c->x < 0 - ci->XMAX/2 ||
659 c->y > ci->YMAX/2 || c->y < 0 - ci->YMAX/2) {
660 if (c->type == 3 && ((LED *)c->c)->light && ci->light) {
661 glDisable(GL_LIGHT1);
662 ci->light = 0; ci->lighton = 0;
665 if (((IC *)c->c)->tnum)
666 freetexture(ci, ((IC *)c->c)->tnum);
669 if (((Transistor *)c->c)->tnum)
670 freetexture(ci, ((Transistor *)c->c)->tnum);
673 free(((Diode *)c->c)->band); /* remember to free diode band */
679 glDisable(GL_NORMALIZE);
683 /* draw a resistor */
685 static void DrawResistor(Circuit *ci, Resistor *r)
688 GLfloat col[] = {0.74, 0.62, 0.46, 1.0};
689 GLfloat spec[] = {0.8, 0.8, 0.8, 1.0};
692 glTranslatef(-4, 0, 0);
694 glTranslatef(3, 0, 0);
695 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
696 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
697 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
698 createCylinder(ci, 1.8, 0.4, 1, 0);
700 for (i = 0 ; i < 4 ; i++) {
701 glTranslatef(0.35, 0, 0);
702 glCallList(ci->band_list[r->b[i]]);
705 glTranslatef(1.8, 0, 0);
709 static void DrawRCA(Circuit *ci, RCA *rca)
711 GLfloat col[] = {0.6, 0.6, 0.6, 1.0}; /* metal */
712 GLfloat red[] = {1.0, 0.0, 0.0, 1.0}; /* red */
713 GLfloat white[] = {1.0, 1.0, 1.0, 1.0}; /* white */
714 GLfloat spec[] = {1, 1, 1, 1}; /* glass */
717 glTranslatef(0.3, 0, 0);
718 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
719 glMateriali(GL_FRONT, GL_SHININESS, 40);
720 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
721 createCylinder(ci, 0.7, 0.45, 0, 0);
722 glTranslatef(0.4, 0, 0);
723 createCylinder(ci, 0.9, 0.15, 1, 0);
724 glTranslatef(-1.9, 0, 0);
725 glMateriali(GL_FRONT, GL_SHININESS, 20);
726 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, rca->col ? white : red);
727 createCylinder(ci, 1.5, 0.6, 1, 0);
728 glTranslatef(-0.9, 0, 0);
729 createCylinder(ci, 0.9, 0.25, 0, 0);
730 glTranslatef(0.1, 0, 0);
731 createCylinder(ci, 0.2, 0.3, 0, 0);
732 glTranslatef(0.3, 0, 0);
733 createCylinder(ci, 0.2, 0.3, 1, 0);
734 glTranslatef(0.3, 0, 0);
735 createCylinder(ci, 0.2, 0.3, 1, 0);
739 static void DrawSwitch(Circuit *ci, Switch *f)
741 GLfloat col[] = {0.6, 0.6, 0.6, 0}; /* metal */
742 GLfloat dark[] = {0.1, 0.1, 0.1, 1.0}; /* dark */
743 GLfloat brown[] = {0.69, 0.32, 0, 1.0}; /* brown */
744 GLfloat spec[] = {0.9, 0.9, 0.9, 1}; /* shiny */
747 glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
748 glMaterialfv(GL_FRONT, GL_AMBIENT, dark);
749 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
750 glMateriali(GL_FRONT, GL_SHININESS, 90);
751 Rect(-0.25, 0, 0, 1.5, 0.5, 0.75);
752 /* Rect(-0.5, 0.5, 0, 2, 0.1, 0.75); */
754 glRotatef(90, 1, 0, 0);
755 glTranslatef(-0.5, -0.4, -0.4);
756 HoledRectangle(ci, 0.5, 0.75, 0.1, 0.15, 8);
757 glTranslatef(2, 0, 0);
758 HoledRectangle(ci, 0.5, 0.75, 0.1, 0.15, 8);
760 Rect(0.1, -0.4, -0.25, 0.1, 0.4, 0.05);
761 Rect(0.5, -0.4, -0.25, 0.1, 0.4, 0.05);
762 Rect(0.9, -0.4, -0.25, 0.1, 0.4, 0.05);
763 Rect(0.1, -0.4, -0.5, 0.1, 0.4, 0.05);
764 Rect(0.5, -0.4, -0.5, 0.1, 0.4, 0.05);
765 Rect(0.9, -0.4, -0.5, 0.1, 0.4, 0.05);
766 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, dark);
767 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
768 Rect(0, 0.5, -0.1, 1, 0.05, 0.5);
769 Rect(0, 0.6, -0.1, 0.5, 0.6, 0.5);
770 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, brown);
771 Rect(-0.2, -0.01, -0.1, 1.4, 0.1, 0.55);
776 static void DrawFuse(Circuit *ci, Fuse *f)
778 GLfloat col[] = {0.5, 0.5, 0.5, 1.0}; /* endcaps */
779 GLfloat glass[] = {0.4, 0.4, 0.4, 0.3}; /* glass */
780 GLfloat spec[] = {1, 1, 1, 1}; /* glass */
783 glTranslatef(-1.8, 0, 0);
784 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
785 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
786 glMateriali(GL_FRONT, GL_SHININESS, 40);
787 createCylinder(ci, 0.8, 0.45, 1, 0);
788 glTranslatef(0.8, 0, 0);
790 glDepthMask(GL_FALSE);
791 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, glass);
792 glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 40);
793 createCylinder(ci, 2, 0.4, 0, 0);
794 createCylinder(ci, 2, 0.3, 0, 0);
796 glDepthMask(GL_TRUE);
797 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
798 glMateriali(GL_FRONT, GL_SHININESS, 40);
801 glVertex3f(2, 0. ,0);
803 glTranslatef(2, 0, 0);
804 createCylinder(ci, 0.8, 0.45, 1, 0);
809 static void DrawCapacitor(Circuit *ci, Capacitor *c)
811 GLfloat col[] = {0, 0, 0, 0};
812 GLfloat spec[] = {0.8, 0.8, 0.8, 0};
813 GLfloat brown[] = {0.84, 0.5, 0};
818 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, brown);
819 sphere(ci, c->width, 15, 15, 0, 4 ,0, 15);
820 glTranslatef(1.35*c->width, 0, 0);
821 sphere(ci, c->width, 15, 15, 11, 15, 0, 15);
822 glRotatef(90, 0, 0, 1);
823 glTranslatef(0, 0.7*c->width, 0.3*c->width);
824 wire(ci, 3*c->width);
825 glTranslatef(0, 0, -0.6*c->width);
826 wire(ci, 3*c->width);
828 glTranslatef(0-c->length*2, 0, 0);
829 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
830 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
831 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
833 glVertex3f(0, 0.82*c->width, -0.1);
834 glVertex3f(3*c->length, 0.82*c->width, -0.1);
835 glVertex3f(3*c->length, 0.82*c->width, 0.1);
836 glVertex3f(0, 0.82*c->width, 0.1);
841 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
842 glEnable(GL_POLYGON_OFFSET_FILL);
843 glPolygonOffset(1.0, 1.0);
844 createCylinder(ci, 3.0*c->length, 0.8*c->width, 1, 0);
845 glDisable(GL_POLYGON_OFFSET_FILL);
849 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
850 circle(ci, 0.6*c->width, 30, 0);
854 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
855 glTranslatef(3.0*c->length, 0.0, 0);
856 circle(ci, 0.6*c->width, 30, 0);
857 glTranslatef(0, 0.4*c->width, 0);
858 wire(ci, 3*c->length);
859 glTranslatef(0.0, -0.8*c->width, 0);
860 wire(ci, 3.3*c->length);
865 static void DrawLED(Circuit *ci, LED *l)
867 GLfloat col[] = {0, 0, 0, 0.6};
868 GLfloat black[] = {0, 0, 0, 0.6};
870 col[0] = l->r; col[1] = l->g; col[2] = l->b;
871 if (l->light && ci->light) {
872 GLfloat dir[] = {-1, 0, 0};
873 glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, dir);
875 glLightfv(GL_LIGHT1, GL_SPECULAR, col);
876 glLightfv(GL_LIGHT1, GL_AMBIENT, black);
877 col[0] /= 1.5; col[1] /= 1.5; col[2] /= 1.5;
878 glLightfv(GL_LIGHT1, GL_DIFFUSE, col);
879 glLighti(GL_LIGHT1, GL_SPOT_CUTOFF, (GLint) 90);
880 glLighti(GL_LIGHT1, GL_CONSTANT_ATTENUATION, (GLfloat)1);
881 glLighti(GL_LIGHT1, GL_LINEAR_ATTENUATION, (GLfloat)0);
882 glLighti(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, (GLfloat)0);
883 glLighti(GL_LIGHT1, GL_SPOT_EXPONENT, (GLint) 20);
887 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
888 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
889 /* no transparency when LED is lit */
892 glDepthMask(GL_FALSE);
893 glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
895 glTranslatef(-0.9, 0, 0);
896 createCylinder(ci, 1.2, 0.3, 0, 0);
897 if (l->light && ci->light) {
898 glDisable(GL_LIGHTING);
901 sphere(ci, 0.3, 7, 7, 3, 7, 0, 7);
902 if (l->light && ci->light) {
903 glEnable(GL_LIGHTING);
905 glDepthMask(GL_TRUE);
909 glTranslatef(1.2, 0, 0);
910 createCylinder(ci, 0.1, 0.38, 1, 0);
911 glTranslatef(-0.3, 0.15, 0);
913 glTranslatef(0, -0.3, 0);
915 if (random() % 50 == 25) {
917 l->light = 0; ci->light = 0; ci->lighton = 0;
918 glDisable(GL_LIGHT1);
919 } else if (!ci->light) {
927 static void DrawThreeFive(Circuit *ci, ThreeFive *d)
930 GLfloat const dark[] = {0.3, 0.3, 0.3, 0};
931 GLfloat const light[] = {0.6, 0.6, 0.6, 0};
932 GLfloat const cream[] = {0.8, 0.8, 0.6, 0};
933 GLfloat const spec[] = {0.7, 0.7, 0.7, 0};
936 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
937 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cream);
938 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
940 glTranslatef(-2.0, 0, 0);
941 createCylinder(ci, 0.7, 0.2, 0, 0);
942 glTranslatef(0.7, 0, 0);
943 createCylinder(ci, 1.3, 0.4, 1, 0);
944 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light);
945 glTranslatef(1.3, 0, 0);
946 createCylinder(ci, 1.3, 0.2, 0, 0);
947 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, dark);
948 glTranslatef(0.65, 0, 0);
949 createCylinder(ci, 0.15, 0.21, 0, 0);
950 glTranslatef(0.3, 0, 0);
951 createCylinder(ci, 0.15, 0.21, 0, 0);
952 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light);
953 glTranslatef(0.4, 0, 0);
954 sphere(ci, 0.23, 7, 7, 0, 5, 0, 7);
959 static void DrawDiode(Circuit *ci, Diode *d)
962 GLfloat col[] = {0.3, 0.3, 0.3, 0};
963 GLfloat spec[] = {0.7, 0.7, 0.7, 0};
966 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
967 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
968 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
969 glTranslatef(-4, 0, 0);
971 glTranslatef(3, 0, 0);
972 bandedCylinder(ci, 0.3, 1.5, d->r, d->g, d->b, &(d->band), 1);
973 glTranslatef(1.5, 0, 0);
978 static void Rect(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h,
985 yh = y+h; xw = x+w; zt = z - t;
987 glBegin(GL_QUADS); /* front */
990 glVertex3f(x, yh, z);
991 glVertex3f(xw, yh, z);
992 glVertex3f(xw, y, z);
994 glNormal3f(0, 0, -1);
995 glVertex3f(x, y, zt);
996 glVertex3f(x, yh, zt);
997 glVertex3f(xw, yh, zt);
998 glVertex3f(xw, y, zt);
1000 glNormal3f(0, 1, 0);
1001 glVertex3f(x, yh, z);
1002 glVertex3f(x, yh, zt);
1003 glVertex3f(xw, yh, zt);
1004 glVertex3f(xw, yh, z);
1006 glNormal3f(0, -1, 0);
1007 glVertex3f(x, y, z);
1008 glVertex3f(x, y, zt);
1009 glVertex3f(xw, y, zt);
1010 glVertex3f(xw, y, z);
1012 glNormal3f(-1, 0, 0);
1013 glVertex3f(x, y, z);
1014 glVertex3f(x, y, zt);
1015 glVertex3f(x, yh, zt);
1016 glVertex3f(x, yh, z);
1018 glNormal3f(1, 0, 0);
1019 glVertex3f(xw, y, z);
1020 glVertex3f(xw, y, zt);
1021 glVertex3f(xw, yh, zt);
1022 glVertex3f(xw, yh, z);
1028 static void ICLeg(GLfloat x, GLfloat y, GLfloat z, int dir)
1031 Rect(x-0.1, y, z, 0.1, 0.1, 0.02);
1032 Rect(x-0.1, y, z, 0.02, 0.1, 0.1);
1033 Rect(x-0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
1035 Rect(x, y, z, 0.1, 0.1, 0.02);
1036 Rect(x+0.8*0.1, y, z, 0.02, 0.1, 0.1);
1037 Rect(x+0.8*0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
1043 static void DrawIC(Circuit *ci, IC *c)
1047 GLfloat col[] = {0.1, 0.1, 0.1, 0};
1048 GLfloat col2[] = {0.2, 0.2, 0.2, 0};
1049 GLfloat spec[] = {0.6, 0.6, 0.6, 0};
1051 GLfloat lspec[] = {0.6, 0.6, 0.6, 0};
1052 GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
1053 GLfloat lshine = 40;
1054 float mult, th, size;
1057 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1058 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1059 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1060 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
1077 glEnable(GL_POLYGON_OFFSET_FILL);
1078 glPolygonOffset(1.0, 1.0);
1080 glNormal3f(0, 0, 1);
1081 glVertex3f(w, h, 0.1);
1082 glVertex3f(w, -h, 0.1);
1083 glVertex3f(-w, -h, 0.1);
1084 glVertex3f(-w, h, 0.1);
1085 glNormal3f(0, 0, -1);
1086 glVertex3f(w, h, -0.1);
1087 glVertex3f(w, -h, -0.1);
1088 glVertex3f(-w, -h, -0.1);
1089 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);
1095 glNormal3f(0, -1, 0);
1096 glVertex3f(w, -h, -0.1);
1097 glVertex3f(w, -h, 0.1);
1098 glVertex3f(-w, -h, 0.1);
1099 glVertex3f(-w, -h, -0.1);
1100 glNormal3f(-1, 0, 0);
1101 glVertex3f(-w, h, -0.1);
1102 glVertex3f(-w, h, 0.1);
1103 glVertex3f(-w, -h, 0.1);
1104 glVertex3f(-w, -h, -0.1);
1105 glNormal3f(0, -1, 0);
1106 glVertex3f(-w, h, -0.1);
1107 glVertex3f(w, h, -0.1);
1108 glVertex3f(w, h, 0.1);
1109 glVertex3f(-w, h, 0.1);
1111 glDisable(GL_POLYGON_OFFSET_FILL);
1112 if (c->tnum) glBindTexture(GL_TEXTURE_2D, c->tnum);
1113 glEnable(GL_TEXTURE_2D);
1120 mult = size*c->tw / c->th;
1122 glBegin(GL_QUADS); /* text markings */
1123 glNormal3f(0, 0, 1);
1125 glVertex3f(th, mult, 0.1);
1127 glVertex3f(th, -mult, 0.1);
1129 glVertex3f(-th, -mult, 0.1);
1131 glVertex3f(-th, mult, 0.1);
1133 glDisable(GL_TEXTURE_2D);
1134 glDisable(GL_BLEND);
1135 d = (h*2-0.1) / c->pins;
1137 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
1138 glMaterialfv(GL_FRONT, GL_SPECULAR, lspec);
1139 glMaterialfv(GL_FRONT, GL_SHININESS, &lshine);
1140 for (z = 0 ; z < c->pins/2 ; z++) {
1141 ICLeg(w, -h + z*d + d/2, 0, 0);
1143 for (z = 0 ; z < c->pins/2 ; z++) {
1144 ICLeg(-w, -h + z*d + d/2, 0, 1);
1146 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col2);
1147 glTranslatef(-w+0.3, h-0.3, 0.1);
1148 glRotatef(90, 0, 1, 0);
1149 circle(ci, 0.1, 7, 0);
1153 static void 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 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);
1214 glDisable(GL_LIGHTING); /* lit segments dont need light */
1215 if (!seven && (random() % 30) == 19) { /* randomly change value */
1216 d->value = random() % 10;
1218 for (j = 0 ; j < 7 ; j++) { /* draw the segments */
1219 GLfloat xx[6], yy[6];
1220 if (nums[d->value][j])
1224 for (k = 0 ; k < 6 ; k++) {
1225 if (j == 0 || j == 3 || j == 6) {
1226 xx[k] = seg_start[j][0] + vdata_h[k][0];
1227 yy[k] = seg_start[j][1] + vdata_h[k][1];
1229 xx[k] = seg_start[j][0] + vdata_v[k][0];
1230 yy[k] = seg_start[j][1] + vdata_v[k][1];
1233 glBegin(GL_POLYGON);
1234 for(i = 0 ; i < 6 ; i++) {
1235 glVertex3f(xx[i], yy[i], 0.01);
1242 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 ICLeg(x, y, -0.7, 1);
1255 static void HoledRectangle(Circuit *ci,
1256 GLfloat w, GLfloat h, GLfloat d, GLfloat radius,
1260 GLfloat x1, y1, x2, y2;
1261 GLfloat yr, yr1, xr, xr1, side, side1;
1265 x1 = radius; y1 = 0;
1270 for (a = 0 ; a <= 360 ; a+= step) {
1271 y2=radius*(float)ci->sin_table[(int)a];
1272 x2=radius*(float)ci->cos_table[(int)a];
1274 if (a < 45 || a > 315) {
1276 yr = side1 * ci->tan_table[a];
1278 } else if (a <= 135 || a >= 225) {
1279 xr = side/ci->tan_table[a];
1290 yr = -side1 * ci->tan_table[a];
1294 glNormal3f(-x1, -y1, 0); /* cylinder */
1295 glVertex3f(x1,y1,0);
1296 glVertex3f(x1,y1,-d);
1297 glVertex3f(x2,y2,-d);
1298 glVertex3f(x2,y2,0);
1300 glNormal3f(0, 0, 1); /* front face */
1301 glVertex3f(x1,y1,0);
1302 glVertex3f(xr1, yr1, 0);
1303 glVertex3f(xr, yr, 0);
1304 glVertex3f(x2, y2, 0);
1306 glNormal3f(nx, ny, 0); /* side */
1307 glVertex3f(xr, yr, 0);
1308 glVertex3f(xr, yr, -d);
1309 glVertex3f(xr1, yr1, -d);
1310 glVertex3f(xr1, yr1, 0);
1312 glNormal3f(0, 0, -1); /* back */
1313 glVertex3f(xr, yr, -d);
1314 glVertex3f(x2, y2, -d);
1315 glVertex3f(x1, y1, -d);
1316 glVertex3f(xr1, yr1, -d);
1325 static void DrawTransistor(Circuit *ci, Transistor *t)
1327 GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
1328 GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
1329 GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
1333 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1334 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col);
1335 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1336 if (t->type == 1) { /* TO-92 style */
1338 mult = 1.5*t->th/t->tw;
1341 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1342 glRotatef(90, 0, 1, 0);
1343 glRotatef(90, 0, 0, 1);
1344 createCylinder(ci, 1.0, 0.4, 1, 1);
1345 Rect(0, -0.2, 0.4, 1, 0.2, 0.8);
1346 /* Draw the markings */
1347 glEnable(GL_TEXTURE_2D);
1348 if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
1350 glDepthMask(GL_FALSE);
1352 glNormal3f(0, 0, 1);
1354 glVertex3f(y1, -0.21, 0.3);
1356 glVertex3f(y1, -0.21, -0.3);
1358 glVertex3f(y2, -0.21, -0.3);
1360 glVertex3f(y2, -0.21, 0.3);
1362 glDisable(GL_TEXTURE_2D);
1363 glDisable(GL_BLEND);
1364 glDepthMask(GL_TRUE);
1365 glTranslatef(-2, 0, -0.2);
1367 glTranslatef(0, 0, 0.2);
1369 glTranslatef(0, 0, 0.2);
1371 } else if (t->type == 0) { /* TO-220 Style */
1373 mult = 1.5*t->th/t->tw;
1376 Rect(0, 0, 0, 1.5, 1.5, 0.5);
1377 glEnable(GL_TEXTURE_2D);
1378 if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
1380 glDepthMask(GL_FALSE);
1382 glNormal3f(0, 0, 1);
1384 glVertex3f(0, y1, 0.01);
1386 glVertex3f(1.5, y1, 0.01);
1388 glVertex3f(1.5, y2, 0.01);
1390 glVertex3f(0, y2, 0.01);
1392 glDisable(GL_TEXTURE_2D);
1393 glDisable(GL_BLEND);
1394 glDepthMask(GL_TRUE);
1395 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1396 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1397 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1398 Rect(0, 0, -0.5, 1.5, 1.5, 0.30);
1399 if (!glIsEnabled(GL_NORMALIZE)) glEnable(GL_NORMALIZE);
1400 glTranslatef(0.75, 1.875, -0.55);
1401 HoledRectangle(ci, 1.5, 0.75, 0.25, 0.2, 8);
1402 glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
1403 glTranslatef(-0.375, -1.875, 0);
1404 glRotatef(90, 0, 0, -1);
1406 glTranslatef(0, 0.375, 0);
1408 glTranslatef(0, 0.375, 0);
1410 } else { /* SMC transistor */
1412 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1413 glTranslatef(-0.5, -0.25, 0.1);
1414 Rect(0, 0, 0, 1, 0.5, 0.2);
1415 /* Draw the markings */
1416 glEnable(GL_TEXTURE_2D);
1417 if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
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);
1431 glDisable(GL_TEXTURE_2D);
1432 glDisable(GL_BLEND);
1433 glDepthMask(GL_TRUE);
1434 /* Now draw the legs */
1435 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1436 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1437 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1438 Rect(0.25, -0.1, -0.05, 0.1, 0.1, 0.2);
1439 Rect(0.75, -0.1, -0.05, 0.1, 0.1, 0.2);
1440 Rect(0.5, 0.5, -0.05, 0.1, 0.1, 0.2);
1441 Rect(0.25, -0.2, -0.2, 0.1, 0.15, 0.1);
1442 Rect(0.75, -0.2, -0.2, 0.1, 0.15, 0.1);
1443 Rect(0.5, 0.5, -0.2, 0.1, 0.15, 0.1);
1448 static Component * NewComponent(ModeInfo *mi)
1450 Circuit *ci = &circuit[MI_SCREEN(mi)];
1454 c = malloc(sizeof(Component));
1455 c->angle = RAND_RANGE(0,360);
1457 if (rnd < 0.25) { /* come from the top */
1459 c->x = RAND_RANGE(0, ci->XMAX) - ci->XMAX/2;
1461 c->dx = 0 - RAND_RANGE(0.5, 2);
1463 c->dx = RAND_RANGE(0.5, 2);
1464 c->dy = 0 - RAND_RANGE(0.5, 2);
1465 } else if (rnd < 0.5) { /* come from the bottom */
1466 c->y = 0 - ci->YMAX/2;
1467 c->x = RAND_RANGE(0, ci->XMAX) - ci->XMAX/2;
1469 c->dx = 0 - RAND_RANGE(0.5, 2);
1471 c->dx = RAND_RANGE(0.5, 2);
1472 c->dy = RAND_RANGE(0.5, 2);
1473 } else if (rnd < 0.75) { /* come from the left */
1474 c->x = 0 - ci->XMAX/2;
1475 c->y = RAND_RANGE(0, ci->YMAX) - ci->YMAX/2;
1476 c->dx = RAND_RANGE(0.5, 2);
1478 c->dy = 0 - RAND_RANGE(0.5, 2);
1480 c->dy = RAND_RANGE(0.5, 2);
1481 } else { /* come from the right */
1483 c->y = RAND_RANGE(0, ci->YMAX) - ci->YMAX/2;
1484 c->dx = 0 - RAND_RANGE(0.5, 2);
1486 c->dy = 0 - RAND_RANGE(0.5, 2);
1488 c->dy = RAND_RANGE(0.5, 2);
1490 c->z = RAND_RANGE(0, 7) - 9;
1494 c->drot = f_rand() * 3;
1496 c->dz = f_rand()*2 - 1;
1498 c->alpha = 0; /* explicitly set to 1 later */
1499 rnd = random() % 11;
1501 c->c = NewResistor();
1504 c->norm = 1; /* some resistors shine */
1505 } else if (rnd < 2) {
1508 c->norm = 1; /* some diodes shine */
1510 } else if (rnd < 3) {
1511 c->c = NewTransistor(mi);
1514 } else if (rnd < 4) {
1515 c->c = NewCapacitor(ci);
1518 } else if (rnd < 5) {
1522 } else if (rnd < 6) {
1527 } else if (rnd < 7) {
1532 } else if (rnd < 8) {
1536 } else if (rnd < 9) {
1537 c->c = NewThreeFive(ci);
1540 } else if (rnd < 10) {
1541 c->c = NewSwitch(ci);
1551 static Transistor *NewTransistor(ModeInfo *mi)
1554 float texfg[] = {0.7, 0.7, 0.7, 1.0};
1555 float texbg[] = {0.3, 0.3, 0.3, 0.1};
1559 t = malloc(sizeof(Transistor));
1560 t->type = (random() % 3);
1562 val = transistortypes[random() % countof(transistortypes)];
1563 tn = fonttexturealloc(mi, val, texfg, texbg);
1565 fprintf(stderr, "Error getting a texture for a string!\n");
1569 t->tw = tn->w; t->th = tn->h;
1572 } else if (t->type == 2) {
1573 val = smctypes[random() % countof(smctypes)];
1574 tn = fonttexturealloc(mi, val, texfg, texbg);
1576 fprintf(stderr, "Error getting a texture for a string!\n");
1580 t->tw = tn->w; t->th = tn->h;
1583 } else if (t->type == 1) {
1584 val = to92types[random() % countof(to92types)];
1585 tn = fonttexturealloc(mi, val, texfg, texbg);
1587 fprintf(stderr, "Error getting a texture for a string!\n");
1591 t->tw = tn->w; t->th = tn->h;
1599 static Capacitor *NewCapacitor(Circuit *ci)
1603 c = malloc(sizeof(Capacitor));
1604 c->type = (f_rand() < 0.5);
1606 c->length = RAND_RANGE(0.5, 1);
1607 c->width = RAND_RANGE(0.5, 1);
1609 c->width = RAND_RANGE(0.3, 1);
1614 /* 7 segment display */
1616 static Disp *NewDisp(Circuit *ci)
1620 d = malloc(sizeof(Disp));
1624 d->value = RAND_RANGE(0, 10);
1629 static IC *NewIC(ModeInfo *mi)
1634 float texfg[] = {0.7, 0.7, 0.7, 1.0};
1635 float texbg[] = {0.1, 0.1, 0.1, 0};
1638 int types[countof(ictypes)], i, n = 0;
1640 c = malloc(sizeof(IC));
1642 switch((int)RAND_RANGE(0,4)) {
1657 for (i = 0 ; i < countof(ictypes) ; i++) {
1658 if (ictypes[i].pins == pins) {
1664 if (n > countof(types)) abort();
1665 val = ictypes[types[random() % n]].val;
1666 str = malloc(strlen(val) + 1 + 4 + 1); /* add space for production date */
1667 sprintf(str, "%s\n%02d%02d", val, (int)RAND_RANGE(80, 100), (int)RAND_RANGE(1,53));
1668 tn = fonttexturealloc(mi, str, texfg, texbg);
1671 fprintf(stderr, "Error allocating font texture for '%s'\n", val);
1674 c->tw = tn->w; c->th = tn->h;
1682 static LED *NewLED(Circuit *ci)
1687 l = malloc(sizeof(LED));
1690 if (!ci->light && (f_rand() < 0.4)) {
1695 l->r = 0.9; l->g = 0; l->b = 0;
1696 } else if (r < 0.4) {
1697 l->r = 0.3; l->g = 0.9; l->b = 0;
1698 } else if (r < 0.6) {
1699 l->r = 0.8; l->g = 0.9; l->b = 0;
1700 } else if (r < 0.8) {
1701 l->r = 0.0; l->g = 0.2; l->b = 0.8;
1703 l->r = 0.9, l->g = 0.55, l->b = 0;
1708 static Fuse *NewFuse(Circuit *ci)
1712 f = malloc(sizeof(Fuse));
1716 static RCA *NewRCA(Circuit *ci)
1720 r = malloc(sizeof(RCA));
1721 r->col = (random() % 10 < 5);
1725 static ThreeFive *NewThreeFive(Circuit *ci)
1729 r = malloc(sizeof(ThreeFive));
1733 static Switch *NewSwitch(Circuit *ci)
1737 s = malloc(sizeof(Switch));
1742 static Diode *NewDiode(void)
1747 ret = malloc(sizeof(Diode));
1748 b = malloc(sizeof(Band));
1751 if (f_rand() < 0.5) {
1755 ret->r = 0.7; ret->g = 0.1 ; ret->b = 0.1;
1760 ret->r = 0.2; ret->g = 0.2 ; ret->b = 0.2;
1767 static Resistor * NewResistor(void)
1769 int v, m, t; /* value, multiplier, tolerance */
1774 t = (RAND(10) < 5) ? 10 : 11;
1775 ret = malloc(sizeof(Resistor));
1778 ret->b[0] = ret->b[1] = ret->b[2] = 7;
1780 ret->b[0] = values[v][0];
1781 ret->b[1] = values[v][1];
1789 static void makebandlist(Circuit *ci)
1792 GLfloat col[] = {0,0,0,0};
1793 GLfloat spec[] = {0.8,0.8,0.8,0};
1796 for (i = 0 ; i < 12 ; i++) {
1797 ci->band_list[i] = glGenLists(i);
1798 glNewList(ci->band_list[i], GL_COMPILE);
1799 col[0] = colorcodes[i][0];
1800 col[1] = colorcodes[i][1];
1801 col[2] = colorcodes[i][2];
1802 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
1803 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
1804 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
1805 createCylinder(ci, 0.1, 0.42, 0, 0);
1811 static void bandedCylinder(Circuit *ci,
1812 float radius, float l,
1813 GLfloat r, GLfloat g, GLfloat bl,
1814 Band **b, int nbands)
1816 int n; /* band number */
1817 int p = 0; /* prev number + 1; */
1818 GLfloat col[] = {0,0,0,0};
1820 col[0] = r; col[1] = g; col[2] = bl;
1821 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1822 createCylinder(ci, l, radius, 1, 0); /* body */
1823 for (n = 0 ; n < nbands ; n++) {
1825 glTranslatef(b[n]->pos*l, 0, 0);
1826 col[0] = b[n]->r; col[1] = b[n]->g; col[2] = b[n]->b;
1827 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1828 createCylinder(ci, b[n]->len*l, radius*1.05, 0, 0); /* band */
1834 static void drawgrid(Circuit *ci)
1837 GLfloat col3[] = {0, 0.8, 0};
1840 if (f_rand() < ((rotate) ? 0.05 : 0.01)) {
1841 ci->draw_sdir = RAND_RANGE(0, 4);
1842 ci->draw_ds = RAND_RANGE(0.4, 0.8);
1843 switch (ci->draw_sdir) {
1845 ci->draw_sx = -ci->XMAX/2;
1846 ci->draw_sy = ((int)RAND_RANGE(0, ci->YMAX/2))*2 - ci->YMAX/2;
1849 ci->draw_sx = ci->XMAX/2;
1850 ci->draw_sy = ((int)RAND_RANGE(0, ci->YMAX/2))*2 - ci->YMAX/2;
1853 ci->draw_sy = ci->YMAX/2;
1854 ci->draw_sx = ((int)RAND_RANGE(0, ci->XMAX/2))*2 - ci->XMAX/2;
1857 ci->draw_sy = -ci->YMAX/2;
1858 ci->draw_sx = ((int)RAND_RANGE(0, ci->XMAX/2))*2 - ci->XMAX/2;
1863 } else if (!rotate) {
1864 if (ci->grid_col[1] < 0.25) {
1865 ci->grid_col[1] += 0.025; ci->grid_col[2] += 0.005;
1866 ci->grid_col2[1] += 0.015 ; ci->grid_col2[2] += 0.005;
1870 glDisable(GL_LIGHTING);
1874 glTranslatef(ci->draw_sx, ci->draw_sy, -10);
1875 sphere(ci, 0.1, 10, 10, 0, 10, 0, 10);
1876 if (ci->draw_sdir == 0)
1877 glTranslatef(-ci->draw_ds, 0, 0);
1878 if (ci->draw_sdir == 1)
1879 glTranslatef(ci->draw_ds, 0, 0);
1880 if (ci->draw_sdir == 2)
1881 glTranslatef(0, ci->draw_ds, 0);
1882 if (ci->draw_sdir == 3)
1883 glTranslatef(0, -ci->draw_ds, 0);
1884 sphere(ci, 0.05, 10, 10, 0, 10, 0, 10);
1886 if (ci->draw_sdir == 0) {
1887 ci->draw_sx += ci->draw_ds;
1888 if (ci->draw_sx > ci->XMAX/2)
1891 if (ci->draw_sdir == 1) {
1892 ci->draw_sx -= ci->draw_ds;
1893 if (ci->draw_sx < -ci->XMAX/2)
1896 if (ci->draw_sdir == 2) {
1897 ci->draw_sy -= ci->draw_ds;
1898 if (ci->draw_sy < ci->YMAX/2)
1901 if (ci->draw_sdir == 3) {
1902 ci->draw_sy += ci->draw_ds;
1903 if (ci->draw_sy > ci->YMAX/2)
1906 } else if (!rotate) {
1907 if (ci->grid_col[1] > 0) {
1908 ci->grid_col[1] -= 0.0025; ci->grid_col[2] -= 0.0005;
1909 ci->grid_col2[1] -= 0.0015 ; ci->grid_col2[2] -= 0.0005;
1912 for (x = -ci->XMAX/2 ; x <= ci->XMAX/2 ; x+= 2) {
1913 glColor3fv(ci->grid_col);
1915 glVertex3f(x, ci->YMAX/2, -10);
1916 glVertex3f(x, -ci->YMAX/2, -10);
1917 glColor3fv(ci->grid_col2);
1918 glVertex3f(x-0.02, ci->YMAX/2, -10);
1919 glVertex3f(x-0.02, -ci->YMAX/2, -10);
1920 glVertex3f(x+0.02, ci->YMAX/2, -10);
1921 glVertex3f(x+0.02, -ci->YMAX/2, -10);
1924 for (y = -ci->YMAX/2 ; y <= ci->YMAX/2 ; y+= 2) {
1925 glColor3fv(ci->grid_col);
1927 glVertex3f(-ci->XMAX/2, y, -10);
1928 glVertex3f(ci->XMAX/2, y, -10);
1929 glColor3fv(ci->grid_col2);
1930 glVertex3f(-ci->XMAX/2, y-0.02, -10);
1931 glVertex3f(ci->XMAX/2, y-0.02, -10);
1932 glVertex3f(-ci->XMAX/2, y+0.02, -10);
1933 glVertex3f(ci->XMAX/2, y+0.02, -10);
1936 glEnable(GL_LIGHTING);
1939 static void display(ModeInfo *mi)
1941 Circuit *ci = &circuit[MI_SCREEN(mi)];
1942 GLfloat light_sp[] = {0.8, 0.8, 0.8, 1.0};
1943 GLfloat black[] = {0, 0, 0, 1.0};
1946 if (ci->display_i == 0) {
1947 for (ci->display_i = 0 ; ci->display_i < maxparts ; ci->display_i++) {
1948 ci->components[ci->display_i] = NULL;
1951 glEnable(GL_LIGHTING);
1952 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
1954 gluLookAt(ci->viewer[0], ci->viewer[1], ci->viewer[2],
1959 glRotatef(ci->rotate_angle, 0, 0, 1);
1960 ci->rotate_angle += 0.01 * (float)rotatespeed;
1961 if (ci->rotate_angle >= 360) ci->rotate_angle = 0;
1963 glLightfv(GL_LIGHT0, GL_POSITION, ci->lightpos);
1964 glLightfv(GL_LIGHT0, GL_SPECULAR, light_sp);
1965 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_sp);
1966 glLighti(GL_LIGHT0, GL_CONSTANT_ATTENUATION, (GLfloat)1);
1967 glLighti(GL_LIGHT0, GL_LINEAR_ATTENUATION, (GLfloat)0.5);
1968 glLighti(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, (GLfloat)0);
1970 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light_sp);
1971 if (f_rand() < 0.05) {
1972 for (j = 0 ; j < maxparts ; j++) {
1973 if (ci->components[j] == NULL) {
1974 ci->components[j] = NewComponent(mi);
1978 reorder(&ci->components[0]);
1980 for (j = 0 ; j < maxparts ; j++) {
1981 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, black);
1982 glMaterialfv(GL_FRONT, GL_EMISSION, black);
1983 glMaterialfv(GL_FRONT, GL_SPECULAR, black);
1984 if (ci->components[j] != NULL) {
1985 if (DrawComponent(ci, ci->components[j])) {
1986 free(ci->components[j]); ci->components[j] = NULL;
1994 static void freetexture (Circuit *ci, GLuint texture)
1996 ci->s_refs[texture]--;
1997 if (ci->s_refs[texture] < 1) {
1998 glDeleteTextures(1, &texture);
2002 static TexNum * fonttexturealloc (ModeInfo *mi,
2003 const char *str, float *fg, float *bg)
2005 Circuit *ci = &circuit[MI_SCREEN(mi)];
2011 if (ci->font_init == 0) {
2012 for (i = 0 ; i < 50 ; i++) {
2013 ci->font_strings[i] = NULL;
2015 ci->font_w[i] = 0; ci->font_h[i] = 0;
2019 for (i = 0 ; i < 50 ; i++) {
2020 if (!ci->s_refs[i] && ci->font_strings[i]) {
2021 free (ci->font_strings[i]);
2022 ci->font_strings[i] = NULL;
2024 if (ci->font_strings[i] && !strcmp(str, ci->font_strings[i])) { /* if one matches */
2025 t = malloc(sizeof(TexNum));
2026 t->w = ci->font_w[i]; t->h = ci->font_h[i];
2033 /* at this point we need to make the new texture */
2034 ximage = text_to_ximage (mi->xgwa.screen,
2038 for (i = 0 ; ci->font_strings[i] != NULL ; i++) { /* set i to the next unused value */
2040 fprintf(stderr, "Texture cache full!\n");
2048 glBindTexture(GL_TEXTURE_2D, i);
2049 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2050 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2051 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2054 status = gluBuild2DMipmaps(GL_TEXTURE_2D, 4, ximage->width, ximage->height,
2055 GL_RGBA, GL_UNSIGNED_BYTE, ximage->data);
2058 const char *s = (char *) gluErrorString (status);
2059 fprintf (stderr, "%s: error mipmapping %dx%d texture: %s\n",
2060 progname, ximage->width, ximage->height,
2061 (s ? s : "(unknown)"));
2064 check_gl_error("mipmapping");
2066 t = malloc(sizeof(TexNum));
2067 t->w = ximage->width;
2068 t->h = ximage->height;
2069 ci->font_w[i] = t->w; ci->font_h[i] = t->h;
2073 c = malloc(strlen(str)+1);
2074 strncpy(c, str, strlen(str)+1);
2075 ci->font_strings[i] = c;
2081 /* ensure transparent components are at the end */
2082 static void reorder(Component *c[])
2085 Component *c1[MAX_COMPONENTS];
2086 Component *c2[MAX_COMPONENTS];
2089 for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
2093 for (i = 0 ; i < maxparts ; i++) {
2094 if (c[i] == NULL) continue;
2095 if (c[i]->alpha) { /* transparent parts go to c1 */
2098 } else { /* opaque parts go to c2 */
2102 for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
2106 for (i = 0 ; i < maxparts ; i++) { /* insert opaque part */
2107 if (c2[i] != NULL) {
2112 for (i = 0 ; i < j ; i++) { /* insert transparent parts */
2118 ENTRYPOINT void reshape_circuit(ModeInfo *mi, int width, int height)
2120 Circuit *ci = &circuit[MI_SCREEN(mi)];
2121 GLfloat h = (GLfloat) height / (GLfloat) width;
2122 glViewport(0,0,(GLint)width, (GLint) height);
2123 glMatrixMode(GL_PROJECTION);
2125 glFrustum(-1.0,1.0,-h,h,1.5,35.0);
2126 glMatrixMode(GL_MODELVIEW);
2129 ci->YMAX = ci->XMAX * h;
2133 ENTRYPOINT void init_circuit(ModeInfo *mi)
2135 int screen = MI_SCREEN(mi);
2138 if (circuit == NULL) {
2139 if ((circuit = (Circuit *) calloc(MI_NUM_SCREENS(mi),
2140 sizeof(Circuit))) == NULL)
2143 ci = &circuit[screen];
2144 ci->window = MI_WINDOW(mi);
2146 ci->XMAX = ci->YMAX = 30;
2148 ci->lightpos[0] = 7;
2149 ci->lightpos[1] = 7;
2150 ci->lightpos[2] = 15;
2151 ci->lightpos[3] = 1;
2153 ci->grid_col[1] = 0.25;
2154 ci->grid_col[2] = 0.05;
2155 ci->grid_col2[1] = 0.125;
2156 ci->grid_col2[2] = 0.05;
2158 if (maxparts >= MAX_COMPONENTS)
2159 maxparts = MAX_COMPONENTS-1;
2161 if ((ci->glx_context = init_GL(mi)) != NULL) {
2162 reshape_circuit(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
2168 glClearColor(0.0,0.0,0.0,0.0);
2169 glShadeModel(GL_SMOOTH);
2170 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
2171 glEnable(GL_DEPTH_TEST);
2172 glEnable(GL_LIGHTING);
2173 glEnable(GL_LIGHT0);
2174 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2180 ENTRYPOINT void draw_circuit(ModeInfo *mi)
2182 Circuit *ci = &circuit[MI_SCREEN(mi)];
2183 Window w = MI_WINDOW(mi);
2184 Display *disp = MI_DISPLAY(mi);
2186 if (!ci->glx_context)
2189 glXMakeCurrent(disp, w, *(ci->glx_context));
2193 if(mi->fps_p) do_fps(mi);
2195 glXSwapBuffers(disp, w);
2198 ENTRYPOINT void release_circuit(ModeInfo *mi)
2200 if (circuit != NULL) {
2201 (void) free((void *) circuit);
2207 XSCREENSAVER_MODULE ("Circuit", circuit)