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;
429 nsegs = radius*MAX(ci->win_w, ci->win_h)/20;
430 nsegs = MAX(nsegs, 4);
433 angle = (half) ? (180 - 90/nsegs) : 374;
436 for (a = 0 ; a <= angle ; a+= angle/nsegs) {
437 y2=radius*(float)ci->sin_table[(int)a];
438 z2=radius*(float)ci->cos_table[(int)a];
439 glNormal3f(0, y1, z1);
441 glVertex3f(length,y1,z1);
442 glNormal3f(0, y2, z2);
443 glVertex3f(length,y2,z2);
453 glVertex3f(0, 0, radius);
454 glVertex3f(length, 0, radius);
455 glVertex3f(length, 0, 0 - radius);
456 glVertex3f(0, 0, 0 - radius);
461 for(ex = 0 ; ex <= length ; ex += length) {
463 norm = (ex == length) ? 1 : -1;
464 glBegin(GL_TRIANGLES);
465 glNormal3f(norm, 0, 0);
466 for (a = 0 ; a <= angle ; a+= angle/nsegs) {
467 y2=radius*(float)ci->sin_table[(int)a];
468 z2=radius*(float)ci->cos_table[(int)a];
470 glVertex3f(ex,y1,z1);
471 glVertex3f(ex,y2,z2);
483 static int circle(Circuit *ci, float radius, int segments, int half)
486 float x1 = 0, x2 = 0;
487 float y1 = 0, y2 = 0;
496 glBegin(GL_TRIANGLES);
501 x2=radius*(float)ci->cos_table[(int)angle];
502 y2=radius*(float)ci->sin_table[(int)angle];
514 static int wire(Circuit *ci, float len)
517 GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
518 GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
519 GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
523 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
524 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
525 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
526 n = glIsEnabled(GL_NORMALIZE);
527 if (!n) glEnable(GL_NORMALIZE);
528 polys += createCylinder(ci, len, 0.05, 1, 0);
529 if (!n) glDisable(GL_NORMALIZE);
530 glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
535 static int ring(GLfloat inner, GLfloat outer, int nsegs)
538 GLfloat z1, z2, y1, y2;
539 GLfloat Z1, Z2, Y1, Y2;
546 for(i=0; i <=360 ; i+= 360/nsegs)
549 z2=inner*(float)ci->sin_table[(int)angle];
550 y2=inner*(float)ci->cos_table[(int)angle];
551 Z2=outer*(float)ci->sin_table[(int)angle];
552 Y2=outer*(float)ci->cos_table[(int)angle];
553 glVertex3f(0, Y1, Z1);
554 glVertex3f(0, y1, z1);
555 glVertex3f(0, y2, z2);
556 glVertex3f(0, Y2, Z2);
568 static int sphere(Circuit *ci, GLfloat r, float stacks, float slices,
569 int startstack, int endstack, int startslice,
573 GLfloat d, d1, dr, dr1, Dr, Dr1, D, D1, z1, z2, y1, y2, Y1, Z1, Y2, Z2;
574 int a, a1, b, b1, c0, c1;
579 a1 = startstack * step;
580 b1 = startslice * sstep;
581 y1 = z1 = Y1 = Z1 = 0;
582 c0 = (endslice / slices) * 360;
583 c1 = (endstack/stacks)*180;
585 for (a = startstack * step ; a <= c1 ; a+= step) {
587 d1=ci->sin_table[a1];
589 D1=ci->cos_table[a1];
594 for (b = b1 ; b <= c0 ; b+= sstep) {
595 y2=dr*ci->sin_table[b];
596 z2=dr*ci->cos_table[b];
597 Y2=dr1*ci->sin_table[b];
598 Z2=dr1*ci->cos_table[b];
599 glNormal3f(Dr, y1, z1);
600 glVertex3f(Dr,y1,z1);
601 glNormal3f(Dr, y2, z2);
602 glVertex3f(Dr,y2,z2);
603 glNormal3f(Dr1, Y2, Z2);
604 glVertex3f(Dr1,Y2,Z2);
605 glNormal3f(Dr1, Y1, Z1);
606 glVertex3f(Dr1,Y1,Z1);
619 static int DrawComponent(Circuit *ci, Component *c, unsigned long *polysP)
622 int ret = 0; /* return 1 if component is freed */
625 glTranslatef(c->x, c->y, c->z);
627 glRotatef(c->angle, c->rotx, c->roty, c->rotz);
630 glRotatef(c->rdeg, c->rotx, c->roty, c->rotz);
635 glEnable(GL_NORMALIZE);
637 glDisable(GL_NORMALIZE);
639 /* call object draw routine here */
641 polys += DrawResistor(ci, c->c);
642 } else if (c->type == 1) {
643 polys += DrawDiode(ci, c->c);
644 } else if (c->type == 2) {
645 polys += DrawTransistor(ci, c->c);
646 } else if (c->type == 3) {
647 if (((LED *)c->c)->light && ci->light) {
648 GLfloat lp[] = {0.1, 0, 0, 1};
650 glLightfv(GL_LIGHT1, GL_POSITION, lp);
652 polys += DrawLED(ci, c->c);
653 } else if (c->type == 4) {
654 polys += DrawCapacitor(ci, c->c);
655 } else if (c->type == 5) {
656 polys += DrawIC(ci, c->c);
657 } else if (c->type == 6) {
658 polys += DrawDisp(ci, c->c);
659 } else if (c->type == 7) {
660 polys += DrawFuse(ci, c->c);
661 } else if (c->type == 8) {
662 polys += DrawRCA(ci, c->c);
663 } else if (c->type == 9) {
664 polys += DrawThreeFive(ci, c->c);
665 } else if (c->type == 10) {
666 polys += DrawSwitch(ci, c->c);
668 c->x += c->dx * MOVE_MULT;
669 c->y += c->dy * MOVE_MULT;
670 if (c->x > ci->XMAX/2 || c->x < 0 - ci->XMAX/2 ||
671 c->y > ci->YMAX/2 || c->y < 0 - ci->YMAX/2) {
672 if (c->type == 3 && ((LED *)c->c)->light && ci->light) {
673 glDisable(GL_LIGHT1);
674 ci->light = 0; ci->lighton = 0;
677 if (((IC *)c->c)->tnum)
678 freetexture(ci, ((IC *)c->c)->tnum);
681 if (((Transistor *)c->c)->tnum)
682 freetexture(ci, ((Transistor *)c->c)->tnum);
685 free(((Diode *)c->c)->band); /* remember to free diode band */
691 glDisable(GL_NORMALIZE);
696 /* draw a resistor */
698 static int DrawResistor(Circuit *ci, Resistor *r)
702 GLfloat col[] = {0.74, 0.62, 0.46, 1.0};
703 GLfloat spec[] = {0.8, 0.8, 0.8, 1.0};
706 glTranslatef(-4, 0, 0);
707 polys += wire(ci, 3);
708 glTranslatef(3, 0, 0);
709 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
710 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
711 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
712 polys += createCylinder(ci, 1.8, 0.4, 1, 0);
714 for (i = 0 ; i < 4 ; i++) {
715 glTranslatef(0.35, 0, 0);
716 glCallList(ci->band_list[r->b[i]]);
717 polys += ci->band_list_polys[r->b[i]];
720 glTranslatef(1.8, 0, 0);
721 polys += wire(ci, 3);
725 static int DrawRCA(Circuit *ci, RCA *rca)
728 GLfloat col[] = {0.6, 0.6, 0.6, 1.0}; /* metal */
729 GLfloat red[] = {1.0, 0.0, 0.0, 1.0}; /* red */
730 GLfloat white[] = {1.0, 1.0, 1.0, 1.0}; /* white */
731 GLfloat spec[] = {1, 1, 1, 1}; /* glass */
734 glTranslatef(0.3, 0, 0);
735 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
736 glMateriali(GL_FRONT, GL_SHININESS, 40);
737 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
738 polys += createCylinder(ci, 0.7, 0.45, 0, 0);
739 glTranslatef(0.4, 0, 0);
740 polys += createCylinder(ci, 0.9, 0.15, 1, 0);
741 glTranslatef(-1.9, 0, 0);
742 glMateriali(GL_FRONT, GL_SHININESS, 20);
743 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, rca->col ? white : red);
744 polys += createCylinder(ci, 1.5, 0.6, 1, 0);
745 glTranslatef(-0.9, 0, 0);
746 polys += createCylinder(ci, 0.9, 0.25, 0, 0);
747 glTranslatef(0.1, 0, 0);
748 polys += createCylinder(ci, 0.2, 0.3, 0, 0);
749 glTranslatef(0.3, 0, 0);
750 polys += createCylinder(ci, 0.2, 0.3, 1, 0);
751 glTranslatef(0.3, 0, 0);
752 polys += createCylinder(ci, 0.2, 0.3, 1, 0);
757 static int DrawSwitch(Circuit *ci, Switch *f)
760 GLfloat col[] = {0.6, 0.6, 0.6, 0}; /* metal */
761 GLfloat dark[] = {0.1, 0.1, 0.1, 1.0}; /* dark */
762 GLfloat brown[] = {0.69, 0.32, 0, 1.0}; /* brown */
763 GLfloat spec[] = {0.9, 0.9, 0.9, 1}; /* shiny */
766 glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
767 glMaterialfv(GL_FRONT, GL_AMBIENT, dark);
768 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
769 glMateriali(GL_FRONT, GL_SHININESS, 90);
770 polys += Rect(-0.25, 0, 0, 1.5, 0.5, 0.75);
771 /* polys += Rect(-0.5, 0.5, 0, 2, 0.1, 0.75); */
773 glRotatef(90, 1, 0, 0);
774 glTranslatef(-0.5, -0.4, -0.4);
775 polys += HoledRectangle(ci, 0.5, 0.75, 0.1, 0.15, 8);
776 glTranslatef(2, 0, 0);
777 polys += HoledRectangle(ci, 0.5, 0.75, 0.1, 0.15, 8);
779 polys += Rect(0.1, -0.4, -0.25, 0.1, 0.4, 0.05);
780 polys += Rect(0.5, -0.4, -0.25, 0.1, 0.4, 0.05);
781 polys += Rect(0.9, -0.4, -0.25, 0.1, 0.4, 0.05);
782 polys += Rect(0.1, -0.4, -0.5, 0.1, 0.4, 0.05);
783 polys += Rect(0.5, -0.4, -0.5, 0.1, 0.4, 0.05);
784 polys += Rect(0.9, -0.4, -0.5, 0.1, 0.4, 0.05);
785 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, dark);
786 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
787 polys += Rect(0, 0.5, -0.1, 1, 0.05, 0.5);
788 polys += Rect(0, 0.6, -0.1, 0.5, 0.6, 0.5);
789 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, brown);
790 polys += Rect(-0.2, -0.01, -0.1, 1.4, 0.1, 0.55);
796 static int DrawFuse(Circuit *ci, Fuse *f)
799 GLfloat col[] = {0.5, 0.5, 0.5, 1.0}; /* endcaps */
800 GLfloat glass[] = {0.4, 0.4, 0.4, 0.3}; /* glass */
801 GLfloat spec[] = {1, 1, 1, 1}; /* glass */
804 glTranslatef(-1.8, 0, 0);
805 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
806 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
807 glMateriali(GL_FRONT, GL_SHININESS, 40);
808 polys += createCylinder(ci, 0.8, 0.45, 1, 0);
809 glTranslatef(0.8, 0, 0);
811 glDepthMask(GL_FALSE);
812 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, glass);
813 glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 40);
814 polys += createCylinder(ci, 2, 0.4, 0, 0);
815 polys += createCylinder(ci, 2, 0.3, 0, 0);
817 glDepthMask(GL_TRUE);
818 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
819 glMateriali(GL_FRONT, GL_SHININESS, 40);
822 glVertex3f(2, 0. ,0);
824 glTranslatef(2, 0, 0);
825 polys += createCylinder(ci, 0.8, 0.45, 1, 0);
831 static int DrawCapacitor(Circuit *ci, Capacitor *c)
834 GLfloat col[] = {0, 0, 0, 0};
835 GLfloat spec[] = {0.8, 0.8, 0.8, 0};
836 GLfloat brown[] = {0.84, 0.5, 0};
841 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, brown);
842 polys += sphere(ci, c->width, 15, 15, 0, 4 ,0, 15);
843 glTranslatef(1.35*c->width, 0, 0);
844 polys += sphere(ci, c->width, 15, 15, 11, 15, 0, 15);
845 glRotatef(90, 0, 0, 1);
846 glTranslatef(0, 0.7*c->width, 0.3*c->width);
847 polys += wire(ci, 3*c->width);
848 glTranslatef(0, 0, -0.6*c->width);
849 polys += wire(ci, 3*c->width);
851 glTranslatef(0-c->length*2, 0, 0);
852 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
853 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
854 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
856 glVertex3f(0, 0.82*c->width, -0.1);
857 glVertex3f(3*c->length, 0.82*c->width, -0.1);
858 glVertex3f(3*c->length, 0.82*c->width, 0.1);
859 glVertex3f(0, 0.82*c->width, 0.1);
864 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
865 glEnable(GL_POLYGON_OFFSET_FILL);
866 glPolygonOffset(1.0, 1.0);
867 polys += createCylinder(ci, 3.0*c->length, 0.8*c->width, 1, 0);
868 glDisable(GL_POLYGON_OFFSET_FILL);
872 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
873 polys += circle(ci, 0.6*c->width, 30, 0);
877 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
878 glTranslatef(3.0*c->length, 0.0, 0);
879 polys += circle(ci, 0.6*c->width, 30, 0);
880 glTranslatef(0, 0.4*c->width, 0);
881 polys += wire(ci, 3*c->length);
882 glTranslatef(0.0, -0.8*c->width, 0);
883 polys += wire(ci, 3.3*c->length);
889 static int DrawLED(Circuit *ci, LED *l)
892 GLfloat col[] = {0, 0, 0, 0.6};
893 GLfloat black[] = {0, 0, 0, 0.6};
895 col[0] = l->r; col[1] = l->g; col[2] = l->b;
896 if (l->light && ci->light) {
897 GLfloat dir[] = {-1, 0, 0};
898 glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, dir);
900 glLightfv(GL_LIGHT1, GL_SPECULAR, col);
901 glLightfv(GL_LIGHT1, GL_AMBIENT, black);
902 col[0] /= 1.5; col[1] /= 1.5; col[2] /= 1.5;
903 glLightfv(GL_LIGHT1, GL_DIFFUSE, col);
904 glLighti(GL_LIGHT1, GL_SPOT_CUTOFF, (GLint) 90);
905 glLighti(GL_LIGHT1, GL_CONSTANT_ATTENUATION, (GLfloat)1);
906 glLighti(GL_LIGHT1, GL_LINEAR_ATTENUATION, (GLfloat)0);
907 glLighti(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, (GLfloat)0);
908 glLighti(GL_LIGHT1, GL_SPOT_EXPONENT, (GLint) 20);
912 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
913 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
914 /* no transparency when LED is lit */
917 glDepthMask(GL_FALSE);
918 glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
920 glTranslatef(-0.9, 0, 0);
921 polys += createCylinder(ci, 1.2, 0.3, 0, 0);
922 if (l->light && ci->light) {
923 glDisable(GL_LIGHTING);
926 polys += sphere(ci, 0.3, 7, 7, 3, 7, 0, 7);
927 if (l->light && ci->light) {
928 glEnable(GL_LIGHTING);
930 glDepthMask(GL_TRUE);
934 glTranslatef(1.2, 0, 0);
935 polys += createCylinder(ci, 0.1, 0.38, 1, 0);
936 glTranslatef(-0.3, 0.15, 0);
937 polys += wire(ci, 3);
938 glTranslatef(0, -0.3, 0);
939 polys += wire(ci, 3.3);
940 if (random() % 50 == 25) {
942 l->light = 0; ci->light = 0; ci->lighton = 0;
943 glDisable(GL_LIGHT1);
944 } else if (!ci->light) {
953 static int DrawThreeFive(Circuit *ci, ThreeFive *d)
957 GLfloat const dark[] = {0.3, 0.3, 0.3, 0};
958 GLfloat const light[] = {0.6, 0.6, 0.6, 0};
959 GLfloat const cream[] = {0.8, 0.8, 0.6, 0};
960 GLfloat const spec[] = {0.7, 0.7, 0.7, 0};
963 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
964 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cream);
965 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
967 glTranslatef(-2.0, 0, 0);
968 polys += createCylinder(ci, 0.7, 0.2, 0, 0);
969 glTranslatef(0.7, 0, 0);
970 polys += createCylinder(ci, 1.3, 0.4, 1, 0);
971 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light);
972 glTranslatef(1.3, 0, 0);
973 polys += createCylinder(ci, 1.3, 0.2, 0, 0);
974 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, dark);
975 glTranslatef(0.65, 0, 0);
976 polys += createCylinder(ci, 0.15, 0.21, 0, 0);
977 glTranslatef(0.3, 0, 0);
978 polys += createCylinder(ci, 0.15, 0.21, 0, 0);
979 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light);
980 glTranslatef(0.4, 0, 0);
981 polys += sphere(ci, 0.23, 7, 7, 0, 5, 0, 7);
987 static int DrawDiode(Circuit *ci, Diode *d)
991 GLfloat col[] = {0.3, 0.3, 0.3, 0};
992 GLfloat spec[] = {0.7, 0.7, 0.7, 0};
995 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
996 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
997 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
998 glTranslatef(-4, 0, 0);
999 polys += wire(ci, 3);
1000 glTranslatef(3, 0, 0);
1001 polys += bandedCylinder(ci, 0.3, 1.5, d->r, d->g, d->b, &(d->band), 1);
1002 glTranslatef(1.5, 0, 0);
1003 polys += wire(ci, 3);
1008 static int Rect(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h,
1016 yh = y+h; xw = x+w; zt = z - t;
1018 glBegin(GL_QUADS); /* front */
1019 glNormal3f(0, 0, 1);
1020 glVertex3f(x, y, z);
1021 glVertex3f(x, yh, z);
1022 glVertex3f(xw, yh, z);
1023 glVertex3f(xw, y, z);
1026 glNormal3f(0, 0, -1);
1027 glVertex3f(x, y, zt);
1028 glVertex3f(x, yh, zt);
1029 glVertex3f(xw, yh, zt);
1030 glVertex3f(xw, y, zt);
1033 glNormal3f(0, 1, 0);
1034 glVertex3f(x, yh, z);
1035 glVertex3f(x, yh, zt);
1036 glVertex3f(xw, yh, zt);
1037 glVertex3f(xw, yh, z);
1040 glNormal3f(0, -1, 0);
1041 glVertex3f(x, y, z);
1042 glVertex3f(x, y, zt);
1043 glVertex3f(xw, y, zt);
1044 glVertex3f(xw, y, z);
1047 glNormal3f(-1, 0, 0);
1048 glVertex3f(x, y, z);
1049 glVertex3f(x, y, zt);
1050 glVertex3f(x, yh, zt);
1051 glVertex3f(x, yh, z);
1054 glNormal3f(1, 0, 0);
1055 glVertex3f(xw, y, z);
1056 glVertex3f(xw, y, zt);
1057 glVertex3f(xw, yh, zt);
1058 glVertex3f(xw, yh, z);
1066 static int ICLeg(GLfloat x, GLfloat y, GLfloat z, int dir)
1070 polys += Rect(x-0.1, y, z, 0.1, 0.1, 0.02);
1071 polys += Rect(x-0.1, y, z, 0.02, 0.1, 0.1);
1072 polys += Rect(x-0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
1074 polys += Rect(x, y, z, 0.1, 0.1, 0.02);
1075 polys += Rect(x+0.8*0.1, y, z, 0.02, 0.1, 0.1);
1076 polys += Rect(x+0.8*0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
1082 static int DrawIC(Circuit *ci, IC *c)
1087 GLfloat col[] = {0.1, 0.1, 0.1, 0};
1088 GLfloat col2[] = {0.2, 0.2, 0.2, 0};
1089 GLfloat spec[] = {0.6, 0.6, 0.6, 0};
1091 GLfloat lspec[] = {0.6, 0.6, 0.6, 0};
1092 GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
1093 GLfloat lshine = 40;
1094 float mult, th, size;
1097 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1098 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1099 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1100 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
1117 glEnable(GL_POLYGON_OFFSET_FILL);
1118 glPolygonOffset(1.0, 1.0);
1120 glNormal3f(0, 0, 1);
1121 glVertex3f(w, h, 0.1);
1122 glVertex3f(w, -h, 0.1);
1123 glVertex3f(-w, -h, 0.1);
1124 glVertex3f(-w, h, 0.1);
1126 glNormal3f(0, 0, -1);
1127 glVertex3f(w, h, -0.1);
1128 glVertex3f(w, -h, -0.1);
1129 glVertex3f(-w, -h, -0.1);
1130 glVertex3f(-w, h, -0.1);
1132 glNormal3f(1, 0, 0);
1133 glVertex3f(w, h, -0.1);
1134 glVertex3f(w, -h, -0.1);
1135 glVertex3f(w, -h, 0.1);
1136 glVertex3f(w, h, 0.1);
1138 glNormal3f(0, -1, 0);
1139 glVertex3f(w, -h, -0.1);
1140 glVertex3f(w, -h, 0.1);
1141 glVertex3f(-w, -h, 0.1);
1142 glVertex3f(-w, -h, -0.1);
1144 glNormal3f(-1, 0, 0);
1145 glVertex3f(-w, h, -0.1);
1146 glVertex3f(-w, h, 0.1);
1147 glVertex3f(-w, -h, 0.1);
1148 glVertex3f(-w, -h, -0.1);
1150 glNormal3f(0, -1, 0);
1151 glVertex3f(-w, h, -0.1);
1152 glVertex3f(w, h, -0.1);
1153 glVertex3f(w, h, 0.1);
1154 glVertex3f(-w, h, 0.1);
1157 glDisable(GL_POLYGON_OFFSET_FILL);
1158 if (c->tnum) glBindTexture(GL_TEXTURE_2D, c->tnum);
1159 glEnable(GL_TEXTURE_2D);
1166 mult = size*c->tw / c->th;
1168 glBegin(GL_QUADS); /* text markings */
1169 glNormal3f(0, 0, 1);
1171 glVertex3f(th, mult, 0.1);
1173 glVertex3f(th, -mult, 0.1);
1175 glVertex3f(-th, -mult, 0.1);
1177 glVertex3f(-th, mult, 0.1);
1180 glDisable(GL_TEXTURE_2D);
1181 glDisable(GL_BLEND);
1182 d = (h*2-0.1) / c->pins;
1184 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
1185 glMaterialfv(GL_FRONT, GL_SPECULAR, lspec);
1186 glMaterialfv(GL_FRONT, GL_SHININESS, &lshine);
1187 for (z = 0 ; z < c->pins/2 ; z++) {
1188 polys += ICLeg(w, -h + z*d + d/2, 0, 0);
1190 for (z = 0 ; z < c->pins/2 ; z++) {
1191 polys += ICLeg(-w, -h + z*d + d/2, 0, 1);
1193 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col2);
1194 glTranslatef(-w+0.3, h-0.3, 0.1);
1195 glRotatef(90, 0, 1, 0);
1196 polys += circle(ci, 0.1, 7, 0);
1201 static int DrawDisp(Circuit *ci, Disp *d)
1204 GLfloat col[] = {0.8, 0.8, 0.8, 1.0}; /* body colour */
1205 GLfloat front[] = {0.2, 0.2, 0.2, 1.0}; /* front colour */
1206 GLfloat on[] = {0.9, 0, 0, 1}; /* 'on' segment */
1207 GLfloat off[] = {0.3, 0, 0, 1}; /* 'off' segment */
1209 GLfloat x, y; /* for the pins */
1210 GLfloat spec[] = {0.6, 0.6, 0.6, 0};
1211 GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
1213 static const GLfloat vdata_h[6][2] = {
1221 static const GLfloat vdata_v[6][2] = {
1230 static const GLfloat seg_start[7][2] = {
1240 static const int nums[10][7] = {
1241 {1, 1, 1, 1, 1, 1, 0}, /* 0 */
1242 {0, 1, 1, 0, 0, 0, 0}, /* 1 */
1243 {1, 1, 0, 1, 1, 0, 1}, /* 2 */
1244 {1, 1, 1, 1, 0, 0, 1}, /* 3 */
1245 {0, 1, 1, 0, 0, 1, 1}, /* 4 */
1246 {1, 0, 1, 1, 0, 1, 1}, /* 5 */
1247 {1, 0, 1, 1, 1, 1, 1}, /* 6 */
1248 {1, 1, 1, 0, 0, 0, 0}, /* 7 */
1249 {1, 1, 1, 1, 1, 1, 1}, /* 8 */
1250 {1, 1, 1, 0, 0, 1, 1} /* 9 */
1253 glTranslatef(-0.9, -1.8, 0);
1254 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1255 polys += Rect(0, 0, -0.01, 1.8, 2.6, 0.7);
1256 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, front);
1258 glVertex2f(-0.05, -0.05);
1259 glVertex2f(-0.05, 2.65);
1260 glVertex2f(1.85, 2.65);
1261 glVertex2f(1.85, -0.05);
1264 glDisable(GL_LIGHTING); /* lit segments dont need light */
1265 if (!seven && (random() % 30) == 19) { /* randomly change value */
1266 d->value = random() % 10;
1268 for (j = 0 ; j < 7 ; j++) { /* draw the segments */
1269 GLfloat xx[6], yy[6];
1270 if (nums[d->value][j])
1274 for (k = 0 ; k < 6 ; k++) {
1275 if (j == 0 || j == 3 || j == 6) {
1276 xx[k] = seg_start[j][0] + vdata_h[k][0];
1277 yy[k] = seg_start[j][1] + vdata_h[k][1];
1279 xx[k] = seg_start[j][0] + vdata_v[k][0];
1280 yy[k] = seg_start[j][1] + vdata_v[k][1];
1283 glBegin(GL_POLYGON);
1284 for(i = 0 ; i < 6 ; i++) {
1285 glVertex3f(xx[i], yy[i], 0.01);
1293 glVertex3f(1.5, 0.2, 0.01);
1296 glEnable(GL_LIGHTING);
1297 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
1298 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1299 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
1300 for (x = 0.35 ; x <= 1.5 ; x+= 1.15) {
1301 for ( y = 0.2 ; y <= 2.4 ; y += 0.3) {
1302 polys += ICLeg(x, y, -0.7, 1);
1308 static int HoledRectangle(Circuit *ci,
1309 GLfloat w, GLfloat h, GLfloat d, GLfloat radius,
1314 GLfloat x1, y1, x2, y2;
1315 GLfloat yr, yr1, xr, xr1, side, side1;
1319 x1 = radius; y1 = 0;
1324 for (a = 0 ; a <= 360 ; a+= step) {
1325 y2=radius*(float)ci->sin_table[(int)a];
1326 x2=radius*(float)ci->cos_table[(int)a];
1328 if (a < 45 || a > 315) {
1330 yr = side1 * ci->tan_table[a];
1332 } else if (a <= 135 || a >= 225) {
1333 xr = side/ci->tan_table[a];
1344 yr = -side1 * ci->tan_table[a];
1348 glNormal3f(-x1, -y1, 0); /* cylinder */
1349 glVertex3f(x1,y1,0);
1350 glVertex3f(x1,y1,-d);
1351 glVertex3f(x2,y2,-d);
1352 glVertex3f(x2,y2,0);
1355 glNormal3f(0, 0, 1); /* front face */
1356 glVertex3f(x1,y1,0);
1357 glVertex3f(xr1, yr1, 0);
1358 glVertex3f(xr, yr, 0);
1359 glVertex3f(x2, y2, 0);
1362 glNormal3f(nx, ny, 0); /* side */
1363 glVertex3f(xr, yr, 0);
1364 glVertex3f(xr, yr, -d);
1365 glVertex3f(xr1, yr1, -d);
1366 glVertex3f(xr1, yr1, 0);
1369 glNormal3f(0, 0, -1); /* back */
1370 glVertex3f(xr, yr, -d);
1371 glVertex3f(x2, y2, -d);
1372 glVertex3f(x1, y1, -d);
1373 glVertex3f(xr1, yr1, -d);
1384 static int DrawTransistor(Circuit *ci, Transistor *t)
1387 GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
1388 GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
1389 GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
1393 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1394 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col);
1395 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1396 if (t->type == 1) { /* TO-92 style */
1398 mult = 1.5*t->th/t->tw;
1401 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1402 glRotatef(90, 0, 1, 0);
1403 glRotatef(90, 0, 0, 1);
1404 polys += createCylinder(ci, 1.0, 0.4, 1, 1);
1405 polys += Rect(0, -0.2, 0.4, 1, 0.2, 0.8);
1406 /* Draw the markings */
1407 glEnable(GL_TEXTURE_2D);
1408 if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
1410 glDepthMask(GL_FALSE);
1412 glNormal3f(0, 0, 1);
1414 glVertex3f(y1, -0.21, 0.3);
1416 glVertex3f(y1, -0.21, -0.3);
1418 glVertex3f(y2, -0.21, -0.3);
1420 glVertex3f(y2, -0.21, 0.3);
1423 glDisable(GL_TEXTURE_2D);
1424 glDisable(GL_BLEND);
1425 glDepthMask(GL_TRUE);
1426 glTranslatef(-2, 0, -0.2);
1427 polys += wire(ci, 2);
1428 glTranslatef(0, 0, 0.2);
1429 polys += wire(ci, 2);
1430 glTranslatef(0, 0, 0.2);
1431 polys += wire(ci, 2);
1432 } else if (t->type == 0) { /* TO-220 Style */
1434 mult = 1.5*t->th/t->tw;
1437 polys += Rect(0, 0, 0, 1.5, 1.5, 0.5);
1438 glEnable(GL_TEXTURE_2D);
1439 if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
1441 glDepthMask(GL_FALSE);
1443 glNormal3f(0, 0, 1);
1445 glVertex3f(0, y1, 0.01);
1447 glVertex3f(1.5, y1, 0.01);
1449 glVertex3f(1.5, y2, 0.01);
1451 glVertex3f(0, y2, 0.01);
1453 glDisable(GL_TEXTURE_2D);
1454 glDisable(GL_BLEND);
1455 glDepthMask(GL_TRUE);
1456 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1457 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1458 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1459 polys += Rect(0, 0, -0.5, 1.5, 1.5, 0.30);
1460 if (!glIsEnabled(GL_NORMALIZE)) glEnable(GL_NORMALIZE);
1461 glTranslatef(0.75, 1.875, -0.55);
1462 polys += HoledRectangle(ci, 1.5, 0.75, 0.25, 0.2, 8);
1463 glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
1464 glTranslatef(-0.375, -1.875, 0);
1465 glRotatef(90, 0, 0, -1);
1466 polys += wire(ci, 2);
1467 glTranslatef(0, 0.375, 0);
1468 polys += wire(ci, 2);
1469 glTranslatef(0, 0.375, 0);
1470 polys += wire(ci, 2);
1471 } else { /* SMC transistor */
1473 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1474 glTranslatef(-0.5, -0.25, 0.1);
1475 polys += Rect(0, 0, 0, 1, 0.5, 0.2);
1476 /* Draw the markings */
1477 glEnable(GL_TEXTURE_2D);
1478 if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
1480 glDepthMask(GL_FALSE);
1482 glNormal3f(0, 0, 1);
1484 glVertex3f(0.2, 0, 0.01);
1486 glVertex3f(0.8, 0, 0.01);
1488 glVertex3f(0.8, 0.5, 0.01);
1490 glVertex3f(0.2, 0.5, 0.01);
1493 glDisable(GL_TEXTURE_2D);
1494 glDisable(GL_BLEND);
1495 glDepthMask(GL_TRUE);
1496 /* Now draw the legs */
1497 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1498 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1499 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1500 polys += Rect(0.25, -0.1, -0.05, 0.1, 0.1, 0.2);
1501 polys += Rect(0.75, -0.1, -0.05, 0.1, 0.1, 0.2);
1502 polys += Rect(0.5, 0.5, -0.05, 0.1, 0.1, 0.2);
1503 polys += Rect(0.25, -0.2, -0.2, 0.1, 0.15, 0.1);
1504 polys += Rect(0.75, -0.2, -0.2, 0.1, 0.15, 0.1);
1505 polys += Rect(0.5, 0.5, -0.2, 0.1, 0.15, 0.1);
1511 static Component * NewComponent(ModeInfo *mi)
1513 Circuit *ci = &circuit[MI_SCREEN(mi)];
1517 c = malloc(sizeof(Component));
1518 c->angle = RAND_RANGE(0,360);
1520 if (rnd < 0.25) { /* come from the top */
1522 c->x = RAND_RANGE(0, ci->XMAX) - ci->XMAX/2;
1524 c->dx = 0 - RAND_RANGE(0.5, 2);
1526 c->dx = RAND_RANGE(0.5, 2);
1527 c->dy = 0 - RAND_RANGE(0.5, 2);
1528 } else if (rnd < 0.5) { /* come from the bottom */
1529 c->y = 0 - ci->YMAX/2;
1530 c->x = RAND_RANGE(0, ci->XMAX) - ci->XMAX/2;
1532 c->dx = 0 - RAND_RANGE(0.5, 2);
1534 c->dx = RAND_RANGE(0.5, 2);
1535 c->dy = RAND_RANGE(0.5, 2);
1536 } else if (rnd < 0.75) { /* come from the left */
1537 c->x = 0 - ci->XMAX/2;
1538 c->y = RAND_RANGE(0, ci->YMAX) - ci->YMAX/2;
1539 c->dx = RAND_RANGE(0.5, 2);
1541 c->dy = 0 - RAND_RANGE(0.5, 2);
1543 c->dy = RAND_RANGE(0.5, 2);
1544 } else { /* come from the right */
1546 c->y = RAND_RANGE(0, ci->YMAX) - ci->YMAX/2;
1547 c->dx = 0 - RAND_RANGE(0.5, 2);
1549 c->dy = 0 - RAND_RANGE(0.5, 2);
1551 c->dy = RAND_RANGE(0.5, 2);
1553 c->z = RAND_RANGE(0, 7) - 9;
1557 c->drot = f_rand() * 3;
1559 c->dz = f_rand()*2 - 1;
1561 c->alpha = 0; /* explicitly set to 1 later */
1562 rnd = random() % 11;
1564 c->c = NewResistor();
1567 c->norm = 1; /* some resistors shine */
1568 } else if (rnd < 2) {
1571 c->norm = 1; /* some diodes shine */
1573 } else if (rnd < 3) {
1574 c->c = NewTransistor(mi);
1577 } else if (rnd < 4) {
1578 c->c = NewCapacitor(ci);
1581 } else if (rnd < 5) {
1585 } else if (rnd < 6) {
1590 } else if (rnd < 7) {
1595 } else if (rnd < 8) {
1599 } else if (rnd < 9) {
1600 c->c = NewThreeFive(ci);
1603 } else if (rnd < 10) {
1604 c->c = NewSwitch(ci);
1614 static Transistor *NewTransistor(ModeInfo *mi)
1617 float texfg[] = {0.7, 0.7, 0.7, 1.0};
1618 float texbg[] = {0.3, 0.3, 0.3, 0.1};
1622 t = malloc(sizeof(Transistor));
1623 t->type = (random() % 3);
1625 val = transistortypes[random() % countof(transistortypes)];
1626 tn = fonttexturealloc(mi, val, texfg, texbg);
1628 fprintf(stderr, "Error getting a texture for a string!\n");
1632 t->tw = tn->w; t->th = tn->h;
1635 } else if (t->type == 2) {
1636 val = smctypes[random() % countof(smctypes)];
1637 tn = fonttexturealloc(mi, val, texfg, texbg);
1639 fprintf(stderr, "Error getting a texture for a string!\n");
1643 t->tw = tn->w; t->th = tn->h;
1646 } else if (t->type == 1) {
1647 val = to92types[random() % countof(to92types)];
1648 tn = fonttexturealloc(mi, val, texfg, texbg);
1650 fprintf(stderr, "Error getting a texture for a string!\n");
1654 t->tw = tn->w; t->th = tn->h;
1662 static Capacitor *NewCapacitor(Circuit *ci)
1666 c = malloc(sizeof(Capacitor));
1667 c->type = (f_rand() < 0.5);
1669 c->length = RAND_RANGE(0.5, 1);
1670 c->width = RAND_RANGE(0.5, 1);
1672 c->width = RAND_RANGE(0.3, 1);
1677 /* 7 segment display */
1679 static Disp *NewDisp(Circuit *ci)
1683 d = malloc(sizeof(Disp));
1687 d->value = RAND_RANGE(0, 10);
1692 static IC *NewIC(ModeInfo *mi)
1697 float texfg[] = {0.7, 0.7, 0.7, 1.0};
1698 float texbg[] = {0.1, 0.1, 0.1, 0};
1701 int types[countof(ictypes)], i, n = 0;
1703 c = malloc(sizeof(IC));
1705 switch((int)RAND_RANGE(0,4)) {
1720 for (i = 0 ; i < countof(ictypes) ; i++) {
1721 if (ictypes[i].pins == pins) {
1727 if (n > countof(types)) abort();
1728 val = ictypes[types[random() % n]].val;
1729 str = malloc(strlen(val) + 1 + 4 + 1); /* add space for production date */
1730 sprintf(str, "%s\n%02d%02d", val, (int)RAND_RANGE(80, 100), (int)RAND_RANGE(1,53));
1731 tn = fonttexturealloc(mi, str, texfg, texbg);
1734 fprintf(stderr, "Error allocating font texture for '%s'\n", val);
1737 c->tw = tn->w; c->th = tn->h;
1745 static LED *NewLED(Circuit *ci)
1750 l = malloc(sizeof(LED));
1753 if (!ci->light && (f_rand() < 0.4)) {
1758 l->r = 0.9; l->g = 0; l->b = 0;
1759 } else if (r < 0.4) {
1760 l->r = 0.3; l->g = 0.9; l->b = 0;
1761 } else if (r < 0.6) {
1762 l->r = 0.8; l->g = 0.9; l->b = 0;
1763 } else if (r < 0.8) {
1764 l->r = 0.0; l->g = 0.2; l->b = 0.8;
1766 l->r = 0.9, l->g = 0.55, l->b = 0;
1771 static Fuse *NewFuse(Circuit *ci)
1775 f = malloc(sizeof(Fuse));
1779 static RCA *NewRCA(Circuit *ci)
1783 r = malloc(sizeof(RCA));
1784 r->col = (random() % 10 < 5);
1788 static ThreeFive *NewThreeFive(Circuit *ci)
1792 r = malloc(sizeof(ThreeFive));
1796 static Switch *NewSwitch(Circuit *ci)
1800 s = malloc(sizeof(Switch));
1805 static Diode *NewDiode(void)
1810 ret = malloc(sizeof(Diode));
1811 b = malloc(sizeof(Band));
1814 if (f_rand() < 0.5) {
1818 ret->r = 0.7; ret->g = 0.1 ; ret->b = 0.1;
1823 ret->r = 0.2; ret->g = 0.2 ; ret->b = 0.2;
1830 static Resistor * NewResistor(void)
1832 int v, m, t; /* value, multiplier, tolerance */
1837 t = (RAND(10) < 5) ? 10 : 11;
1838 ret = malloc(sizeof(Resistor));
1841 ret->b[0] = ret->b[1] = ret->b[2] = 7;
1843 ret->b[0] = values[v][0];
1844 ret->b[1] = values[v][1];
1852 static void makebandlist(Circuit *ci)
1855 GLfloat col[] = {0,0,0,0};
1856 GLfloat spec[] = {0.8,0.8,0.8,0};
1859 for (i = 0 ; i < 12 ; i++) {
1860 ci->band_list[i] = glGenLists(1);
1861 glNewList(ci->band_list[i], GL_COMPILE);
1862 col[0] = colorcodes[i][0];
1863 col[1] = colorcodes[i][1];
1864 col[2] = colorcodes[i][2];
1865 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
1866 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
1867 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
1868 ci->band_list_polys[i] = createCylinder(ci, 0.1, 0.42, 0, 0);
1874 static int bandedCylinder(Circuit *ci,
1875 float radius, float l,
1876 GLfloat r, GLfloat g, GLfloat bl,
1877 Band **b, int nbands)
1880 int n; /* band number */
1881 GLfloat col[] = {0,0,0,0};
1883 col[0] = r; col[1] = g; col[2] = bl;
1884 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1885 polys += createCylinder(ci, l, radius, 1, 0); /* body */
1886 for (n = 0 ; n < nbands ; n++) {
1888 glTranslatef(b[n]->pos*l, 0, 0);
1889 col[0] = b[n]->r; col[1] = b[n]->g; col[2] = b[n]->b;
1890 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1891 polys += createCylinder(ci, b[n]->len*l, radius*1.05, 0, 0); /* band */
1897 static int drawgrid(Circuit *ci)
1901 GLfloat col3[] = {0, 0.8, 0};
1904 if (f_rand() < ((rotatespeed > 0) ? 0.05 : 0.01)) {
1905 ci->draw_sdir = RAND_RANGE(0, 4);
1906 ci->draw_ds = RAND_RANGE(0.4, 0.8);
1907 switch (ci->draw_sdir) {
1909 ci->draw_sx = -ci->XMAX/2;
1910 ci->draw_sy = ((int)RAND_RANGE(0, ci->YMAX/2))*2 - ci->YMAX/2;
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_sy = ci->YMAX/2;
1918 ci->draw_sx = ((int)RAND_RANGE(0, ci->XMAX/2))*2 - ci->XMAX/2;
1921 ci->draw_sy = -ci->YMAX/2;
1922 ci->draw_sx = ((int)RAND_RANGE(0, ci->XMAX/2))*2 - ci->XMAX/2;
1927 } else if (rotatespeed <= 0) {
1928 if (ci->grid_col[1] < 0.25) {
1929 ci->grid_col[1] += 0.025; ci->grid_col[2] += 0.005;
1930 ci->grid_col2[1] += 0.015 ; ci->grid_col2[2] += 0.005;
1934 glDisable(GL_LIGHTING);
1938 glTranslatef(ci->draw_sx, ci->draw_sy, -10);
1939 polys += sphere(ci, 0.1, 10, 10, 0, 10, 0, 10);
1940 if (ci->draw_sdir == 0)
1941 glTranslatef(-ci->draw_ds, 0, 0);
1942 if (ci->draw_sdir == 1)
1943 glTranslatef(ci->draw_ds, 0, 0);
1944 if (ci->draw_sdir == 2)
1945 glTranslatef(0, ci->draw_ds, 0);
1946 if (ci->draw_sdir == 3)
1947 glTranslatef(0, -ci->draw_ds, 0);
1948 polys += sphere(ci, 0.05, 10, 10, 0, 10, 0, 10);
1950 if (ci->draw_sdir == 0) {
1951 ci->draw_sx += ci->draw_ds;
1952 if (ci->draw_sx > ci->XMAX/2)
1955 if (ci->draw_sdir == 1) {
1956 ci->draw_sx -= ci->draw_ds;
1957 if (ci->draw_sx < -ci->XMAX/2)
1960 if (ci->draw_sdir == 2) {
1961 ci->draw_sy -= ci->draw_ds;
1962 if (ci->draw_sy < ci->YMAX/2)
1965 if (ci->draw_sdir == 3) {
1966 ci->draw_sy += ci->draw_ds;
1967 if (ci->draw_sy > ci->YMAX/2)
1970 } else if (rotatespeed <= 0) {
1971 if (ci->grid_col[1] > 0) {
1972 ci->grid_col[1] -= 0.0025; ci->grid_col[2] -= 0.0005;
1973 ci->grid_col2[1] -= 0.0015 ; ci->grid_col2[2] -= 0.0005;
1976 for (x = -ci->XMAX/2 ; x <= ci->XMAX/2 ; x+= 2) {
1977 glColor3fv(ci->grid_col);
1979 glVertex3f(x, ci->YMAX/2, -10);
1980 glVertex3f(x, -ci->YMAX/2, -10);
1981 glColor3fv(ci->grid_col2);
1982 glVertex3f(x-0.02, ci->YMAX/2, -10);
1983 glVertex3f(x-0.02, -ci->YMAX/2, -10);
1984 glVertex3f(x+0.02, ci->YMAX/2, -10);
1985 glVertex3f(x+0.02, -ci->YMAX/2, -10);
1988 for (y = -ci->YMAX/2 ; y <= ci->YMAX/2 ; y+= 2) {
1989 glColor3fv(ci->grid_col);
1991 glVertex3f(-ci->XMAX/2, y, -10);
1992 glVertex3f(ci->XMAX/2, y, -10);
1993 glColor3fv(ci->grid_col2);
1994 glVertex3f(-ci->XMAX/2, y-0.02, -10);
1995 glVertex3f(ci->XMAX/2, y-0.02, -10);
1996 glVertex3f(-ci->XMAX/2, y+0.02, -10);
1997 glVertex3f(ci->XMAX/2, y+0.02, -10);
2000 glEnable(GL_LIGHTING);
2004 static void display(ModeInfo *mi)
2006 Circuit *ci = &circuit[MI_SCREEN(mi)];
2007 GLfloat light_sp[] = {0.8, 0.8, 0.8, 1.0};
2008 GLfloat black[] = {0, 0, 0, 1.0};
2011 mi->polygon_count = 0;
2013 if (ci->display_i == 0) {
2014 for (ci->display_i = 0 ; ci->display_i < maxparts ; ci->display_i++) {
2015 ci->components[ci->display_i] = NULL;
2018 glEnable(GL_LIGHTING);
2019 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
2021 glRotatef(current_device_rotation(), 0, 0, 1);
2022 gluLookAt(ci->viewer[0], ci->viewer[1], ci->viewer[2],
2026 glRotatef(ci->rotate_angle, 0, 0, 1);
2027 ci->rotate_angle += 0.01 * (float)rotatespeed;
2028 if (ci->rotate_angle >= 360) ci->rotate_angle = 0;
2030 glLightfv(GL_LIGHT0, GL_POSITION, ci->lightpos);
2031 glLightfv(GL_LIGHT0, GL_SPECULAR, light_sp);
2032 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_sp);
2033 glLighti(GL_LIGHT0, GL_CONSTANT_ATTENUATION, (GLfloat)1);
2034 glLighti(GL_LIGHT0, GL_LINEAR_ATTENUATION, (GLfloat)0.5);
2035 glLighti(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, (GLfloat)0);
2036 mi->polygon_count += drawgrid(ci);
2037 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light_sp);
2038 if (f_rand() < 0.05) {
2039 for (j = 0 ; j < maxparts ; j++) {
2040 if (ci->components[j] == NULL) {
2041 ci->components[j] = NewComponent(mi);
2045 reorder(&ci->components[0]);
2047 for (j = 0 ; j < maxparts ; j++) {
2048 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, black);
2049 glMaterialfv(GL_FRONT, GL_EMISSION, black);
2050 glMaterialfv(GL_FRONT, GL_SPECULAR, black);
2051 if (ci->components[j] != NULL) {
2052 if (DrawComponent(ci, ci->components[j], &mi->polygon_count)) {
2053 free(ci->components[j]); ci->components[j] = NULL;
2061 static void freetexture (Circuit *ci, GLuint texture)
2063 ci->s_refs[texture]--;
2064 if (ci->s_refs[texture] < 1) {
2065 glDeleteTextures(1, &texture);
2069 static TexNum * fonttexturealloc (ModeInfo *mi,
2070 const char *str, float *fg, float *bg)
2072 Circuit *ci = &circuit[MI_SCREEN(mi)];
2078 if (ci->font_init == 0) {
2079 for (i = 0 ; i < 50 ; i++) {
2080 ci->font_strings[i] = NULL;
2082 ci->font_w[i] = 0; ci->font_h[i] = 0;
2086 for (i = 0 ; i < 50 ; i++) {
2087 if (!ci->s_refs[i] && ci->font_strings[i]) {
2088 free (ci->font_strings[i]);
2089 ci->font_strings[i] = NULL;
2091 if (ci->font_strings[i] && !strcmp(str, ci->font_strings[i])) { /* if one matches */
2092 t = malloc(sizeof(TexNum));
2093 t->w = ci->font_w[i]; t->h = ci->font_h[i];
2100 /* at this point we need to make the new texture */
2101 ximage = text_to_ximage (mi->xgwa.screen,
2105 glGenTextures (1, &mintex);
2106 for (i = mintex ; ci->font_strings[i] != NULL ; i++) { /* set i to the next unused value */
2108 fprintf(stderr, "Texture cache full!\n");
2116 glBindTexture(GL_TEXTURE_2D, i);
2117 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2118 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2119 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2123 i = gluBuild2DMipmaps(GL_TEXTURE_2D, 4,
2124 ximage->width, ximage->height,
2125 GL_RGBA, GL_UNSIGNED_BYTE, ximage->data);
2128 const char *s = (char *) gluErrorString (i);
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 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, ximage->width, ximage->height, 0,
2137 GL_RGBA, GL_UNSIGNED_BYTE, ximage->data);
2138 check_gl_error("texture");
2141 t = malloc(sizeof(TexNum));
2142 t->w = ximage->width;
2143 t->h = ximage->height;
2144 ci->font_w[i] = t->w; ci->font_h[i] = t->h;
2148 c = malloc(strlen(str)+1);
2149 strncpy(c, str, strlen(str)+1);
2150 ci->font_strings[i] = c;
2156 /* ensure transparent components are at the end */
2157 static void reorder(Component *c[])
2160 Component *c1[MAX_COMPONENTS];
2161 Component *c2[MAX_COMPONENTS];
2164 for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
2168 for (i = 0 ; i < maxparts ; i++) {
2169 if (c[i] == NULL) continue;
2170 if (c[i]->alpha) { /* transparent parts go to c1 */
2173 } else { /* opaque parts go to c2 */
2177 for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
2181 for (i = 0 ; i < maxparts ; i++) { /* insert opaque part */
2182 if (c2[i] != NULL) {
2187 for (i = 0 ; i < j ; i++) { /* insert transparent parts */
2193 ENTRYPOINT void reshape_circuit(ModeInfo *mi, int width, int height)
2195 Circuit *ci = &circuit[MI_SCREEN(mi)];
2196 GLfloat h = (GLfloat) height / (GLfloat) width;
2197 glViewport(0,0,(GLint)width, (GLint) height);
2198 glMatrixMode(GL_PROJECTION);
2200 glFrustum(-1.0,1.0,-h,h,1.5,35.0);
2201 glMatrixMode(GL_MODELVIEW);
2204 ci->YMAX = ci->XMAX * h;
2208 ENTRYPOINT void init_circuit(ModeInfo *mi)
2210 int screen = MI_SCREEN(mi);
2213 if (circuit == NULL) {
2214 if ((circuit = (Circuit *) calloc(MI_NUM_SCREENS(mi),
2215 sizeof(Circuit))) == NULL)
2218 ci = &circuit[screen];
2219 ci->window = MI_WINDOW(mi);
2221 ci->XMAX = ci->YMAX = 30;
2223 ci->lightpos[0] = 7;
2224 ci->lightpos[1] = 7;
2225 ci->lightpos[2] = 15;
2226 ci->lightpos[3] = 1;
2228 ci->grid_col[1] = 0.25;
2229 ci->grid_col[2] = 0.05;
2230 ci->grid_col2[1] = 0.125;
2231 ci->grid_col2[2] = 0.05;
2233 if (maxparts >= MAX_COMPONENTS)
2234 maxparts = MAX_COMPONENTS-1;
2236 if ((ci->glx_context = init_GL(mi)) != NULL) {
2237 reshape_circuit(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
2243 glShadeModel(GL_SMOOTH);
2244 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
2245 glEnable(GL_DEPTH_TEST);
2246 glEnable(GL_LIGHTING);
2247 glEnable(GL_LIGHT0);
2248 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2254 ENTRYPOINT void draw_circuit(ModeInfo *mi)
2256 Circuit *ci = &circuit[MI_SCREEN(mi)];
2257 Window w = MI_WINDOW(mi);
2258 Display *disp = MI_DISPLAY(mi);
2260 if (!ci->glx_context)
2263 glXMakeCurrent(disp, w, *(ci->glx_context));
2267 if(mi->fps_p) do_fps(mi);
2269 glXSwapBuffers(disp, w);
2272 ENTRYPOINT void release_circuit(ModeInfo *mi)
2274 if (circuit != NULL) {
2275 (void) free((void *) circuit);
2281 XSCREENSAVER_MODULE ("Circuit", circuit)