2 * circuit - Random electronic components floating around
6 * Since version 1.1: added to-220 transistor, added fuse
7 * Since version 1.2: random display digits, LED improvements (flickering)
8 * Since version 1.3: ICs look better, font textures, improved normals to
9 * eliminate segmenting on curved surfaces, speedups
10 * Since version 1.4: Added RCA connector, 3.5mm connector, slide switch,
11 * surface mount, to-92 markings. Fixed ~5min crash.
12 * Better LED illumination. Other minor changes.
14 * Copyright (C) 2001-2015 Ben Buxton (bb@cactii.net)
16 * Permission to use, copy, modify, distribute, and sell this software and its
17 * documentation for any purpose is hereby granted without fee, provided that
18 * the above copyright notice appear in all copies and that both that
19 * copyright notice and this permission notice appear in supporting
20 * documentation. No representations are made about the suitability of this
21 * software for any purpose. It is provided "as is" without express or
25 /* Written over a few days in a (successful) bid to learn GL coding
27 * -seven option is dedicated to all the Slarkeners
29 * This hack uses lookup tables for sin, cos and tan - it can do a lot
33 #define DEFAULTS "*delay: 20000 \n" \
34 "*showFPS: False \n" \
35 "*suppressRotationAnimation: True\n" \
36 "*componentFont: -*-courier-bold-r-normal-*-*-140-*-*-*-*-*-*"
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"
48 #define DEF_ROTATESPEED "1"
49 #define DEF_LIGHT "True"
51 /* lifted from lament.c */
52 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
53 #define RANDSIGN() ((random() & 1) ? 1 : -1)
61 #define countof(x) (sizeof((x))/sizeof((*x)))
64 static int rotatespeed;
70 #define countof(x) (sizeof((x))/sizeof((*x)))
72 static XrmOptionDescRec opts[] = {
73 {"-parts", ".circuit.parts", 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 {&rotatespeed, "rotatespeed", "Rotatespeed", DEF_ROTATESPEED, t_Int},
86 {&spin, "spin", "Spin", DEF_SPIN, t_Bool},
87 {&uselight, "light", "Light", DEF_LIGHT, t_Bool},
88 {&seven, "seven", "Seven", DEF_SEVEN, t_Bool},
91 ENTRYPOINT ModeSpecOpt circuit_opts = {countof(opts), opts, countof(vars), vars, NULL};
94 ModStruct circuit_description =
95 {"circuit", "init_circuit", "draw_circuit", "release_circuit",
96 "draw_circuit", "init_circuit", NULL, &circuit_opts,
97 1000, 1, 2, 1, 4, 1.0, "",
98 "Flying electronic components", 0, NULL};
102 #define MAX_COMPONENTS 400
103 #define MOVE_MULT 0.02
105 static float f_rand(void)
107 return ((float)RAND(10000)/(float)10000);
110 #define RAND_RANGE(min, max) ((min) + (max - min) * f_rand())
112 /* Represents a band on a resistor/diode/etc */
114 float pos; /* relative position from start/previous band */
115 GLfloat r, g, b; /* colour of the band */
116 float len; /* length as a fraction of total length */
120 Band *b1, *b2, *b3, *b4; /* bands */
126 GLfloat r, g, b; /* body colour */
129 static const char * const transistortypes[] = {
145 static const char * const to92types[] = {
160 static const char * const smctypes[] = {
171 int type; /* package type. 0 = to-92, 1 = to-220 */
176 GLfloat r,g,b; /* LED colour */
177 int light; /* are we the light source? */
181 int type; /* 0 = electro, 1 = ceramic */
182 float width; /* width of an electro/ceramic */
183 float length; /* length of an electro */
201 static const ICTypes ictypes[] = {
244 int type; /* 0 = DIL, 1 = flat square */
249 /* 7 segment display */
252 int value; /* displayed number */
265 GLfloat x, y, z; /* current co-ordinates */
266 GLfloat dx, dy, dz; /* current direction */
267 GLfloat rotx, roty, rotz; /* rotation vector */
268 GLfloat drot; /* rotation velocity (degrees per frame) */
269 int norm; /* Normalize this component (for shine) */
270 int rdeg; /* current rotation degrees */
271 int angle; /* angle about the z axis */
272 int alpha; /* 0 if not a transparent component */
273 int type; /* 0 = resistor, 1 = diode, 2 = transistor, 3 = LED, 4 = cap, 5=IC,
275 void * c; /* pointer to the component */
278 /* standard colour codes */
280 static const GLfloat colorcodes [12][3] = {
281 {0.0,0.0,0.0}, /* black 0 */
282 {0.49,0.25,0.08}, /* brown 1 */
283 {1.0,0.0,0.0}, /* red 2 */
284 {1.0,0.5,0.0}, /* orange 3 */
285 {1.0,1.0,0.0}, /* yellow 4 */
286 {0.0,1.0,0.0}, /* green 5 */
287 {0.0,0.5,1.0}, /* blue 6 */
288 {0.7,0.2,1.0}, /* violet 7 */
289 {0.5,0.5,0.5}, /* grey 8 */
290 {1.0,1.0,1.0}, /* white 9 */
291 {0.66,0.56,0.2}, /* gold 10 */
292 {0.8,0.8,0.8}, /* silver 11 */
295 /* base values for components - we can multiply by 0 - 1M */
296 static const int values [9][2] = {
309 GLXContext *glx_context;
315 /* one lucky led gets to be a light source , unless -no-light*/
319 /* stores refs to textures */
325 float sin_table[720];
326 float cos_table[720];
327 float tan_table[720];
329 Component *components[MAX_COMPONENTS];
331 int band_list_polys[12];
333 GLfloat grid_col[3], grid_col2[3];
336 GLfloat rotate_angle;
338 texture_font_data *font;
339 char *font_strings[50]; /* max of 40 textures */
340 int font_w[50], font_h[50];
343 GLfloat draw_sx, draw_sy; /* bright spot co-ords */
344 int draw_sdir; /* 0 = left-right, 1 = right-left, 2 = up->dn, 3 = dn->up */
345 int draw_s; /* if spot is enabled */
346 float draw_ds; /* speed of spot */
350 static Circuit *circuit = NULL;
353 static int DrawResistor(Circuit *, Resistor *);
354 static int DrawDiode(Circuit *, Diode *);
355 static int DrawTransistor(Circuit *, Transistor *);
356 static int DrawLED(Circuit *, LED *);
357 static int DrawIC(Circuit *, IC *);
358 static int DrawCapacitor(Circuit *, Capacitor *);
359 static int DrawDisp(Circuit *, Disp *);
360 static int DrawFuse(Circuit *, Fuse *);
361 static int DrawRCA(Circuit *, RCA *);
362 static int DrawThreeFive(Circuit *, ThreeFive *);
363 static int DrawSwitch(Circuit *, Switch *);
365 static void reorder(Component *[]);
366 static int circle(Circuit *, float, int,int);
367 static int bandedCylinder(Circuit *,
368 float, float , GLfloat, GLfloat , GLfloat,
370 static int Rect(GLfloat , GLfloat , GLfloat, GLfloat , GLfloat ,GLfloat);
371 static int ICLeg(GLfloat, GLfloat, GLfloat, int);
372 static int HoledRectangle(Circuit *ci,
373 GLfloat, GLfloat, GLfloat, GLfloat, int);
374 static Resistor *NewResistor(void);
375 static Diode *NewDiode(void);
376 static Transistor *NewTransistor(ModeInfo *);
377 static LED * NewLED(Circuit *);
378 static Capacitor *NewCapacitor(Circuit *);
379 static IC* NewIC(ModeInfo *);
380 static Disp* NewDisp(Circuit *);
381 static Fuse *NewFuse(Circuit *);
382 static RCA *NewRCA(Circuit *);
383 static ThreeFive *NewThreeFive(Circuit *);
384 static Switch *NewSwitch(Circuit *);
386 /* we use trig tables to speed things up - 200 calls to sin()
387 in one frame can be a bit harsh..
390 static void make_tables(Circuit *ci)
395 f = 360 / (M_PI * 2);
396 for (i = 0 ; i < 720 ; i++) {
397 ci->sin_table[i] = sin(i/f);
399 for (i = 0 ; i < 720 ; i++) {
400 ci->cos_table[i] = cos(i/f);
402 for (i = 0 ; i < 720 ; i++) {
403 ci->tan_table[i] = tan(i/f);
408 static int createCylinder (Circuit *ci,
409 float length, float radius, int endcaps, int half)
412 int a; /* current angle around cylinder */
414 float z1, y1, z2, y2,ex;
418 nsegs = radius*MAX(ci->win_w, ci->win_h)/20;
419 nsegs = MAX(nsegs, 4);
422 angle = (half) ? (180 - 90/nsegs) : 374;
425 for (a = 0 ; a <= angle ; a+= angle/nsegs) {
426 y2=radius*(float)ci->sin_table[(int)a];
427 z2=radius*(float)ci->cos_table[(int)a];
428 glNormal3f(0, y1, z1);
430 glVertex3f(length,y1,z1);
431 glNormal3f(0, y2, z2);
432 glVertex3f(length,y2,z2);
442 glVertex3f(0, 0, radius);
443 glVertex3f(length, 0, radius);
444 glVertex3f(length, 0, 0 - radius);
445 glVertex3f(0, 0, 0 - radius);
450 for(ex = 0 ; ex <= length ; ex += length) {
452 norm = (ex == length) ? 1 : -1;
453 glBegin(GL_TRIANGLES);
454 glNormal3f(norm, 0, 0);
455 for (a = 0 ; a <= angle ; a+= angle/nsegs) {
456 y2=radius*(float)ci->sin_table[(int)a];
457 z2=radius*(float)ci->cos_table[(int)a];
459 glVertex3f(ex,y1,z1);
460 glVertex3f(ex,y2,z2);
472 static int circle(Circuit *ci, float radius, int segments, int half)
475 float x1 = 0, x2 = 0;
476 float y1 = 0, y2 = 0;
485 glBegin(GL_TRIANGLES);
490 x2=radius*(float)ci->cos_table[(int)angle];
491 y2=radius*(float)ci->sin_table[(int)angle];
503 static int wire(Circuit *ci, float len)
506 GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
507 GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
508 GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
512 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
513 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
514 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
515 n = glIsEnabled(GL_NORMALIZE);
516 if (!n) glEnable(GL_NORMALIZE);
517 polys += createCylinder(ci, len, 0.05, 1, 0);
518 if (!n) glDisable(GL_NORMALIZE);
519 glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
523 static int sphere(Circuit *ci, GLfloat r, float stacks, float slices,
524 int startstack, int endstack, int startslice,
528 GLfloat d, d1, dr, dr1, Dr, Dr1, D, D1, z1, z2, y1, y2, Y1, Z1, Y2, Z2;
529 int a, a1, b, b1, c0, c1;
534 a1 = startstack * step;
535 b1 = startslice * sstep;
536 y1 = z1 = Y1 = Z1 = 0;
537 c0 = (endslice / slices) * 360;
538 c1 = (endstack/stacks)*180;
540 for (a = startstack * step ; a <= c1 ; a+= step) {
542 d1=ci->sin_table[a1];
544 D1=ci->cos_table[a1];
549 for (b = b1 ; b <= c0 ; b+= sstep) {
550 y2=dr*ci->sin_table[b];
551 z2=dr*ci->cos_table[b];
552 Y2=dr1*ci->sin_table[b];
553 Z2=dr1*ci->cos_table[b];
554 glNormal3f(Dr, y1, z1);
555 glVertex3f(Dr,y1,z1);
556 glNormal3f(Dr, y2, z2);
557 glVertex3f(Dr,y2,z2);
558 glNormal3f(Dr1, Y2, Z2);
559 glVertex3f(Dr1,Y2,Z2);
560 glNormal3f(Dr1, Y1, Z1);
561 glVertex3f(Dr1,Y1,Z1);
574 static int DrawComponent(Circuit *ci, Component *c, unsigned long *polysP)
577 int ret = 0; /* return 1 if component is freed */
580 glTranslatef(c->x, c->y, c->z);
582 glRotatef(c->angle, c->rotx, c->roty, c->rotz);
585 glRotatef(c->rdeg, c->rotx, c->roty, c->rotz);
590 glEnable(GL_NORMALIZE);
592 glDisable(GL_NORMALIZE);
594 /* call object draw routine here */
596 polys += DrawResistor(ci, c->c);
597 } else if (c->type == 1) {
598 polys += DrawDiode(ci, c->c);
599 } else if (c->type == 2) {
600 polys += DrawTransistor(ci, c->c);
601 } else if (c->type == 3) {
602 if (((LED *)c->c)->light && ci->light) {
603 GLfloat lp[] = {0.1, 0, 0, 1};
605 glLightfv(GL_LIGHT1, GL_POSITION, lp);
607 polys += DrawLED(ci, c->c);
608 } else if (c->type == 4) {
609 polys += DrawCapacitor(ci, c->c);
610 } else if (c->type == 5) {
611 polys += DrawIC(ci, c->c);
612 } else if (c->type == 6) {
613 polys += DrawDisp(ci, c->c);
614 } else if (c->type == 7) {
615 polys += DrawFuse(ci, c->c);
616 } else if (c->type == 8) {
617 polys += DrawRCA(ci, c->c);
618 } else if (c->type == 9) {
619 polys += DrawThreeFive(ci, c->c);
620 } else if (c->type == 10) {
621 polys += DrawSwitch(ci, c->c);
623 c->x += c->dx * MOVE_MULT;
624 c->y += c->dy * MOVE_MULT;
625 if (c->x > ci->XMAX/2 || c->x < 0 - ci->XMAX/2 ||
626 c->y > ci->YMAX/2 || c->y < 0 - ci->YMAX/2) {
627 if (c->type == 3 && ((LED *)c->c)->light && ci->light) {
628 glDisable(GL_LIGHT1);
629 ci->light = 0; ci->lighton = 0;
632 free(((Diode *)c->c)->band); /* remember to free diode band */
638 glDisable(GL_NORMALIZE);
643 /* draw a resistor */
645 static int DrawResistor(Circuit *ci, Resistor *r)
649 GLfloat col[] = {0.74, 0.62, 0.46, 1.0};
650 GLfloat spec[] = {0.8, 0.8, 0.8, 1.0};
653 glTranslatef(-4, 0, 0);
654 polys += wire(ci, 3);
655 glTranslatef(3, 0, 0);
656 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
657 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
658 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
659 polys += createCylinder(ci, 1.8, 0.4, 1, 0);
661 for (i = 0 ; i < 4 ; i++) {
662 glTranslatef(0.35, 0, 0);
663 glCallList(ci->band_list[r->b[i]]);
664 polys += ci->band_list_polys[r->b[i]];
667 glTranslatef(1.8, 0, 0);
668 polys += wire(ci, 3);
672 static int DrawRCA(Circuit *ci, RCA *rca)
675 GLfloat col[] = {0.6, 0.6, 0.6, 1.0}; /* metal */
676 GLfloat red[] = {1.0, 0.0, 0.0, 1.0}; /* red */
677 GLfloat white[] = {1.0, 1.0, 1.0, 1.0}; /* white */
678 GLfloat spec[] = {1, 1, 1, 1}; /* glass */
681 glTranslatef(0.3, 0, 0);
682 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
683 glMateriali(GL_FRONT, GL_SHININESS, 40);
684 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
685 polys += createCylinder(ci, 0.7, 0.45, 0, 0);
686 glTranslatef(0.4, 0, 0);
687 polys += createCylinder(ci, 0.9, 0.15, 1, 0);
688 glTranslatef(-1.9, 0, 0);
689 glMateriali(GL_FRONT, GL_SHININESS, 20);
690 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, rca->col ? white : red);
691 polys += createCylinder(ci, 1.5, 0.6, 1, 0);
692 glTranslatef(-0.9, 0, 0);
693 polys += createCylinder(ci, 0.9, 0.25, 0, 0);
694 glTranslatef(0.1, 0, 0);
695 polys += createCylinder(ci, 0.2, 0.3, 0, 0);
696 glTranslatef(0.3, 0, 0);
697 polys += createCylinder(ci, 0.2, 0.3, 1, 0);
698 glTranslatef(0.3, 0, 0);
699 polys += createCylinder(ci, 0.2, 0.3, 1, 0);
704 static int DrawSwitch(Circuit *ci, Switch *f)
707 GLfloat col[] = {0.6, 0.6, 0.6, 0}; /* metal */
708 GLfloat dark[] = {0.1, 0.1, 0.1, 1.0}; /* dark */
709 GLfloat brown[] = {0.69, 0.32, 0, 1.0}; /* brown */
710 GLfloat spec[] = {0.9, 0.9, 0.9, 1}; /* shiny */
713 glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
714 glMaterialfv(GL_FRONT, GL_AMBIENT, dark);
715 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
716 glMateriali(GL_FRONT, GL_SHININESS, 90);
717 polys += Rect(-0.25, 0, 0, 1.5, 0.5, 0.75);
718 /* polys += Rect(-0.5, 0.5, 0, 2, 0.1, 0.75); */
720 glRotatef(90, 1, 0, 0);
721 glTranslatef(-0.5, -0.4, -0.4);
722 polys += HoledRectangle(ci, 0.5, 0.75, 0.1, 0.15, 8);
723 glTranslatef(2, 0, 0);
724 polys += HoledRectangle(ci, 0.5, 0.75, 0.1, 0.15, 8);
726 polys += Rect(0.1, -0.4, -0.25, 0.1, 0.4, 0.05);
727 polys += Rect(0.5, -0.4, -0.25, 0.1, 0.4, 0.05);
728 polys += Rect(0.9, -0.4, -0.25, 0.1, 0.4, 0.05);
729 polys += Rect(0.1, -0.4, -0.5, 0.1, 0.4, 0.05);
730 polys += Rect(0.5, -0.4, -0.5, 0.1, 0.4, 0.05);
731 polys += Rect(0.9, -0.4, -0.5, 0.1, 0.4, 0.05);
732 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, dark);
733 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
734 polys += Rect(0, 0.5, -0.1, 1, 0.05, 0.5);
735 polys += Rect(0, 0.6, -0.1, 0.5, 0.6, 0.5);
736 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, brown);
737 polys += Rect(-0.2, -0.01, -0.1, 1.4, 0.1, 0.55);
743 static int DrawFuse(Circuit *ci, Fuse *f)
746 GLfloat col[] = {0.5, 0.5, 0.5, 1.0}; /* endcaps */
747 GLfloat glass[] = {0.4, 0.4, 0.4, 0.3}; /* glass */
748 GLfloat spec[] = {1, 1, 1, 1}; /* glass */
751 glTranslatef(-1.8, 0, 0);
752 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
753 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
754 glMateriali(GL_FRONT, GL_SHININESS, 40);
755 polys += createCylinder(ci, 0.8, 0.45, 1, 0);
756 glTranslatef(0.8, 0, 0);
758 glDepthMask(GL_FALSE);
759 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, glass);
760 glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 40);
761 polys += createCylinder(ci, 2, 0.4, 0, 0);
762 polys += createCylinder(ci, 2, 0.3, 0, 0);
764 glDepthMask(GL_TRUE);
765 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
766 glMateriali(GL_FRONT, GL_SHININESS, 40);
769 glVertex3f(2, 0. ,0);
771 glTranslatef(2, 0, 0);
772 polys += createCylinder(ci, 0.8, 0.45, 1, 0);
778 static int DrawCapacitor(Circuit *ci, Capacitor *c)
781 GLfloat col[] = {0, 0, 0, 0};
782 GLfloat spec[] = {0.8, 0.8, 0.8, 0};
783 GLfloat brown[] = {0.84, 0.5, 0};
788 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, brown);
789 polys += sphere(ci, c->width, 15, 15, 0, 4 ,0, 15);
790 glTranslatef(1.35*c->width, 0, 0);
791 polys += sphere(ci, c->width, 15, 15, 11, 15, 0, 15);
792 glRotatef(90, 0, 0, 1);
793 glTranslatef(0, 0.7*c->width, 0.3*c->width);
794 polys += wire(ci, 3*c->width);
795 glTranslatef(0, 0, -0.6*c->width);
796 polys += wire(ci, 3*c->width);
798 glTranslatef(0-c->length*2, 0, 0);
799 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
800 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
801 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
803 glVertex3f(0, 0.82*c->width, -0.1);
804 glVertex3f(3*c->length, 0.82*c->width, -0.1);
805 glVertex3f(3*c->length, 0.82*c->width, 0.1);
806 glVertex3f(0, 0.82*c->width, 0.1);
811 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
812 glEnable(GL_POLYGON_OFFSET_FILL);
813 glPolygonOffset(1.0, 1.0);
814 polys += createCylinder(ci, 3.0*c->length, 0.8*c->width, 1, 0);
815 glDisable(GL_POLYGON_OFFSET_FILL);
819 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
820 polys += circle(ci, 0.6*c->width, 30, 0);
824 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
825 glTranslatef(3.0*c->length, 0.0, 0);
826 polys += circle(ci, 0.6*c->width, 30, 0);
827 glTranslatef(0, 0.4*c->width, 0);
828 polys += wire(ci, 3*c->length);
829 glTranslatef(0.0, -0.8*c->width, 0);
830 polys += wire(ci, 3.3*c->length);
836 static int DrawLED(Circuit *ci, LED *l)
839 GLfloat col[] = {0, 0, 0, 0.6};
840 GLfloat black[] = {0, 0, 0, 0.6};
842 col[0] = l->r; col[1] = l->g; col[2] = l->b;
843 if (l->light && ci->light) {
844 GLfloat dir[] = {-1, 0, 0};
845 glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, dir);
847 glLightfv(GL_LIGHT1, GL_SPECULAR, col);
848 glLightfv(GL_LIGHT1, GL_AMBIENT, black);
849 col[0] /= 1.5; col[1] /= 1.5; col[2] /= 1.5;
850 glLightfv(GL_LIGHT1, GL_DIFFUSE, col);
851 glLighti(GL_LIGHT1, GL_SPOT_CUTOFF, (GLint) 90);
852 glLighti(GL_LIGHT1, GL_CONSTANT_ATTENUATION, (GLfloat)1);
853 glLighti(GL_LIGHT1, GL_LINEAR_ATTENUATION, (GLfloat)0);
854 glLighti(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, (GLfloat)0);
855 glLighti(GL_LIGHT1, GL_SPOT_EXPONENT, (GLint) 20);
859 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
860 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
861 /* no transparency when LED is lit */
864 glDepthMask(GL_FALSE);
865 glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
867 glTranslatef(-0.9, 0, 0);
868 polys += createCylinder(ci, 1.2, 0.3, 0, 0);
869 if (l->light && ci->light) {
870 glDisable(GL_LIGHTING);
873 polys += sphere(ci, 0.3, 7, 7, 3, 7, 0, 7);
874 if (l->light && ci->light) {
875 glEnable(GL_LIGHTING);
877 glDepthMask(GL_TRUE);
881 glTranslatef(1.2, 0, 0);
882 polys += createCylinder(ci, 0.1, 0.38, 1, 0);
883 glTranslatef(-0.3, 0.15, 0);
884 polys += wire(ci, 3);
885 glTranslatef(0, -0.3, 0);
886 polys += wire(ci, 3.3);
887 if (random() % 50 == 25) {
889 l->light = 0; ci->light = 0; ci->lighton = 0;
890 glDisable(GL_LIGHT1);
891 } else if (!ci->light) {
900 static int DrawThreeFive(Circuit *ci, ThreeFive *d)
904 GLfloat const dark[] = {0.3, 0.3, 0.3, 0};
905 GLfloat const light[] = {0.6, 0.6, 0.6, 0};
906 GLfloat const cream[] = {0.8, 0.8, 0.6, 0};
907 GLfloat const spec[] = {0.7, 0.7, 0.7, 0};
910 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
911 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cream);
912 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
914 glTranslatef(-2.0, 0, 0);
915 polys += createCylinder(ci, 0.7, 0.2, 0, 0);
916 glTranslatef(0.7, 0, 0);
917 polys += createCylinder(ci, 1.3, 0.4, 1, 0);
918 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light);
919 glTranslatef(1.3, 0, 0);
920 polys += createCylinder(ci, 1.3, 0.2, 0, 0);
921 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, dark);
922 glTranslatef(0.65, 0, 0);
923 polys += createCylinder(ci, 0.15, 0.21, 0, 0);
924 glTranslatef(0.3, 0, 0);
925 polys += createCylinder(ci, 0.15, 0.21, 0, 0);
926 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light);
927 glTranslatef(0.4, 0, 0);
928 polys += sphere(ci, 0.23, 7, 7, 0, 5, 0, 7);
934 static int DrawDiode(Circuit *ci, Diode *d)
938 GLfloat col[] = {0.3, 0.3, 0.3, 0};
939 GLfloat spec[] = {0.7, 0.7, 0.7, 0};
942 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
943 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
944 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
945 glTranslatef(-4, 0, 0);
946 polys += wire(ci, 3);
947 glTranslatef(3, 0, 0);
948 polys += bandedCylinder(ci, 0.3, 1.5, d->r, d->g, d->b, &(d->band), 1);
949 glTranslatef(1.5, 0, 0);
950 polys += wire(ci, 3);
955 static int Rect(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h,
963 yh = y+h; xw = x+w; zt = z - t;
965 glBegin(GL_QUADS); /* front */
968 glVertex3f(x, yh, z);
969 glVertex3f(xw, yh, z);
970 glVertex3f(xw, y, z);
973 glNormal3f(0, 0, -1);
974 glVertex3f(x, y, zt);
975 glVertex3f(x, yh, zt);
976 glVertex3f(xw, yh, zt);
977 glVertex3f(xw, y, zt);
981 glVertex3f(x, yh, z);
982 glVertex3f(x, yh, zt);
983 glVertex3f(xw, yh, zt);
984 glVertex3f(xw, yh, z);
987 glNormal3f(0, -1, 0);
989 glVertex3f(x, y, zt);
990 glVertex3f(xw, y, zt);
991 glVertex3f(xw, y, z);
994 glNormal3f(-1, 0, 0);
996 glVertex3f(x, y, zt);
997 glVertex3f(x, yh, zt);
998 glVertex3f(x, yh, z);
1001 glNormal3f(1, 0, 0);
1002 glVertex3f(xw, y, z);
1003 glVertex3f(xw, y, zt);
1004 glVertex3f(xw, yh, zt);
1005 glVertex3f(xw, yh, z);
1013 static int ICLeg(GLfloat x, GLfloat y, GLfloat z, int dir)
1017 polys += Rect(x-0.1, y, z, 0.1, 0.1, 0.02);
1018 polys += Rect(x-0.1, y, z, 0.02, 0.1, 0.1);
1019 polys += Rect(x-0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
1021 polys += Rect(x, y, z, 0.1, 0.1, 0.02);
1022 polys += Rect(x+0.8*0.1, y, z, 0.02, 0.1, 0.1);
1023 polys += Rect(x+0.8*0.1, y+0.03, z-0.1, 0.02, 0.05, 0.3);
1029 static int DrawIC(Circuit *ci, IC *c)
1034 GLfloat col[] = {0.1, 0.1, 0.1, 0};
1035 GLfloat col2[] = {0.2, 0.2, 0.2, 0};
1036 GLfloat spec[] = {0.6, 0.6, 0.6, 0};
1038 GLfloat lspec[] = {0.6, 0.6, 0.6, 0};
1039 GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
1040 GLfloat lshine = 40;
1043 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1044 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1045 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1046 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
1063 glEnable(GL_POLYGON_OFFSET_FILL);
1064 glPolygonOffset(1.0, 1.0);
1066 glNormal3f(0, 0, 1);
1067 glVertex3f(w, h, 0.1);
1068 glVertex3f(w, -h, 0.1);
1069 glVertex3f(-w, -h, 0.1);
1070 glVertex3f(-w, h, 0.1);
1072 glNormal3f(0, 0, -1);
1073 glVertex3f(w, h, -0.1);
1074 glVertex3f(w, -h, -0.1);
1075 glVertex3f(-w, -h, -0.1);
1076 glVertex3f(-w, h, -0.1);
1078 glNormal3f(1, 0, 0);
1079 glVertex3f(w, h, -0.1);
1080 glVertex3f(w, -h, -0.1);
1081 glVertex3f(w, -h, 0.1);
1082 glVertex3f(w, h, 0.1);
1084 glNormal3f(0, -1, 0);
1085 glVertex3f(w, -h, -0.1);
1086 glVertex3f(w, -h, 0.1);
1087 glVertex3f(-w, -h, 0.1);
1088 glVertex3f(-w, -h, -0.1);
1090 glNormal3f(-1, 0, 0);
1091 glVertex3f(-w, h, -0.1);
1092 glVertex3f(-w, h, 0.1);
1093 glVertex3f(-w, -h, 0.1);
1094 glVertex3f(-w, -h, -0.1);
1096 glNormal3f(0, -1, 0);
1097 glVertex3f(-w, h, -0.1);
1098 glVertex3f(w, h, -0.1);
1099 glVertex3f(w, h, 0.1);
1100 glVertex3f(-w, h, 0.1);
1103 glDisable(GL_POLYGON_OFFSET_FILL);
1104 glEnable(GL_TEXTURE_2D);
1108 GLfloat texfg[] = {0.7, 0.7, 0.7, 1.0};
1111 texture_string_metrics (ci->font, c->text, &e, 0, 0);
1114 glTranslatef (0, 0, 0.1);
1115 glRotatef (90, 0, 0, 1);
1117 glTranslatef (-w/2, 0, 0);
1119 print_texture_string (ci->font, c->text);
1123 glDisable(GL_TEXTURE_2D);
1124 glDisable(GL_BLEND);
1125 d = (h*2-0.1) / c->pins;
1127 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
1128 glMaterialfv(GL_FRONT, GL_SPECULAR, lspec);
1129 glMaterialfv(GL_FRONT, GL_SHININESS, &lshine);
1130 for (z = 0 ; z < c->pins/2 ; z++) {
1131 polys += ICLeg(w, -h + z*d + d/2, 0, 0);
1133 for (z = 0 ; z < c->pins/2 ; z++) {
1134 polys += ICLeg(-w, -h + z*d + d/2, 0, 1);
1136 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col2);
1137 glTranslatef(-w+0.3, h-0.3, 0.1);
1138 glRotatef(90, 0, 1, 0);
1139 polys += circle(ci, 0.1, 7, 0);
1144 static int DrawDisp(Circuit *ci, Disp *d)
1147 GLfloat col[] = {0.8, 0.8, 0.8, 1.0}; /* body colour */
1148 GLfloat front[] = {0.2, 0.2, 0.2, 1.0}; /* front colour */
1149 GLfloat on[] = {0.9, 0, 0, 1}; /* 'on' segment */
1150 GLfloat off[] = {0.3, 0, 0, 1}; /* 'off' segment */
1152 GLfloat x, y; /* for the pins */
1153 GLfloat spec[] = {0.6, 0.6, 0.6, 0};
1154 GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
1156 static const GLfloat vdata_h[6][2] = {
1164 static const GLfloat vdata_v[6][2] = {
1173 static const GLfloat seg_start[7][2] = {
1183 static const int nums[10][7] = {
1184 {1, 1, 1, 1, 1, 1, 0}, /* 0 */
1185 {0, 1, 1, 0, 0, 0, 0}, /* 1 */
1186 {1, 1, 0, 1, 1, 0, 1}, /* 2 */
1187 {1, 1, 1, 1, 0, 0, 1}, /* 3 */
1188 {0, 1, 1, 0, 0, 1, 1}, /* 4 */
1189 {1, 0, 1, 1, 0, 1, 1}, /* 5 */
1190 {1, 0, 1, 1, 1, 1, 1}, /* 6 */
1191 {1, 1, 1, 0, 0, 0, 0}, /* 7 */
1192 {1, 1, 1, 1, 1, 1, 1}, /* 8 */
1193 {1, 1, 1, 0, 0, 1, 1} /* 9 */
1196 glTranslatef(-0.9, -1.8, 0);
1197 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1198 polys += Rect(0, 0, -0.01, 1.8, 2.6, 0.7);
1199 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, front);
1201 glVertex2f(-0.05, -0.05);
1202 glVertex2f(-0.05, 2.65);
1203 glVertex2f(1.85, 2.65);
1204 glVertex2f(1.85, -0.05);
1207 glDisable(GL_LIGHTING); /* lit segments dont need light */
1208 if (!seven && (random() % 30) == 19) { /* randomly change value */
1209 d->value = random() % 10;
1211 for (j = 0 ; j < 7 ; j++) { /* draw the segments */
1212 GLfloat xx[6], yy[6];
1213 if (nums[d->value][j])
1217 for (k = 0 ; k < 6 ; k++) {
1218 if (j == 0 || j == 3 || j == 6) {
1219 xx[k] = seg_start[j][0] + vdata_h[k][0];
1220 yy[k] = seg_start[j][1] + vdata_h[k][1];
1222 xx[k] = seg_start[j][0] + vdata_v[k][0];
1223 yy[k] = seg_start[j][1] + vdata_v[k][1];
1226 glBegin(GL_POLYGON);
1227 for(i = 0 ; i < 6 ; i++) {
1228 glVertex3f(xx[i], yy[i], 0.01);
1236 glVertex3f(1.5, 0.2, 0.01);
1239 glEnable(GL_LIGHTING);
1240 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lcol);
1241 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1242 glMaterialfv(GL_FRONT, GL_SHININESS, &shine);
1243 for (x = 0.35 ; x <= 1.5 ; x+= 1.15) {
1244 for ( y = 0.2 ; y <= 2.4 ; y += 0.3) {
1245 polys += ICLeg(x, y, -0.7, 1);
1251 static int HoledRectangle(Circuit *ci,
1252 GLfloat w, GLfloat h, GLfloat d, GLfloat radius,
1257 GLfloat x1, y1, x2, y2;
1258 GLfloat yr, yr1, xr, xr1, side, side1;
1262 x1 = radius; y1 = 0;
1267 for (a = 0 ; a <= 360 ; a+= step) {
1268 y2=radius*(float)ci->sin_table[(int)a];
1269 x2=radius*(float)ci->cos_table[(int)a];
1271 if (a < 45 || a > 315) {
1273 yr = side1 * ci->tan_table[a];
1275 } else if (a <= 135 || a >= 225) {
1276 xr = side/ci->tan_table[a];
1287 yr = -side1 * ci->tan_table[a];
1291 glNormal3f(-x1, -y1, 0); /* cylinder */
1292 glVertex3f(x1,y1,0);
1293 glVertex3f(x1,y1,-d);
1294 glVertex3f(x2,y2,-d);
1295 glVertex3f(x2,y2,0);
1298 glNormal3f(0, 0, 1); /* front face */
1299 glVertex3f(x1,y1,0);
1300 glVertex3f(xr1, yr1, 0);
1301 glVertex3f(xr, yr, 0);
1302 glVertex3f(x2, y2, 0);
1305 glNormal3f(nx, ny, 0); /* side */
1306 glVertex3f(xr, yr, 0);
1307 glVertex3f(xr, yr, -d);
1308 glVertex3f(xr1, yr1, -d);
1309 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);
1327 static int DrawTransistor(Circuit *ci, Transistor *t)
1330 GLfloat col[] = {0.3, 0.3, 0.3, 1.0};
1331 GLfloat spec[] = {0.9, 0.9, 0.9, 1.0};
1332 GLfloat nospec[] = {0.4, 0.4, 0.4, 1.0};
1336 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1337 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col);
1338 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1339 if (t->type == 1) { /* TO-92 style */
1340 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1341 glRotatef(90, 0, 1, 0);
1342 glRotatef(90, 0, 0, 1);
1343 polys += createCylinder(ci, 1.0, 0.4, 1, 1);
1344 polys += Rect(0, -0.2, 0.4, 1, 0.2, 0.8);
1345 /* Draw the markings */
1348 GLfloat texfg[] = {0.7, 0.7, 0.7, 1.0};
1352 texture_string_metrics (ci->font, t->text, &e, 0, 0);
1355 glRotatef (90, 1, 0, 0);
1356 glTranslatef (0.5, -0.05, 0.21);
1358 glTranslatef (-w/2, 0, 0);
1360 print_texture_string (ci->font, t->text);
1364 glDisable(GL_TEXTURE_2D);
1365 glDisable(GL_BLEND);
1366 glDepthMask(GL_TRUE);
1367 glTranslatef(-2, 0, -0.2);
1368 polys += wire(ci, 2);
1369 glTranslatef(0, 0, 0.2);
1370 polys += wire(ci, 2);
1371 glTranslatef(0, 0, 0.2);
1372 polys += wire(ci, 2);
1373 } else if (t->type == 0) { /* TO-220 Style */
1374 polys += Rect(0, 0, 0, 1.5, 1.5, 0.5);
1376 GLfloat texfg[] = {0.7, 0.7, 0.7, 1.0};
1380 texture_string_metrics (ci->font, t->text, &e, 0, 0);
1383 glTranslatef (0.75, 0.75, 0.01);
1385 glTranslatef (-w/2, 0, 0);
1387 print_texture_string (ci->font, t->text);
1390 glDisable(GL_TEXTURE_2D);
1391 glDisable(GL_BLEND);
1392 glDepthMask(GL_TRUE);
1393 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1394 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1395 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1396 polys += Rect(0, 0, -0.5, 1.5, 1.5, 0.30);
1397 if (!glIsEnabled(GL_NORMALIZE)) glEnable(GL_NORMALIZE);
1398 glTranslatef(0.75, 1.875, -0.55);
1399 polys += HoledRectangle(ci, 1.5, 0.75, 0.25, 0.2, 8);
1400 glMaterialfv(GL_FRONT, GL_SPECULAR, nospec);
1401 glTranslatef(-0.375, -1.875, 0);
1402 glRotatef(90, 0, 0, -1);
1403 polys += wire(ci, 2);
1404 glTranslatef(0, 0.375, 0);
1405 polys += wire(ci, 2);
1406 glTranslatef(0, 0.375, 0);
1407 polys += wire(ci, 2);
1408 } else { /* SMC transistor */
1410 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
1411 glTranslatef(-0.5, -0.25, 0.1);
1412 polys += Rect(0, 0, 0, 1, 0.5, 0.2);
1413 /* Draw the markings */
1414 glEnable(GL_TEXTURE_2D);
1416 glDepthMask(GL_FALSE);
1418 glNormal3f(0, 0, 1);
1420 glVertex3f(0.2, 0, 0.01);
1422 glVertex3f(0.8, 0, 0.01);
1424 glVertex3f(0.8, 0.5, 0.01);
1426 glVertex3f(0.2, 0.5, 0.01);
1429 glDisable(GL_TEXTURE_2D);
1430 glDisable(GL_BLEND);
1431 glDepthMask(GL_TRUE);
1432 /* Now draw the legs */
1433 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1434 glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1435 glMaterialfv(GL_FRONT, GL_SHININESS, &shin);
1436 polys += Rect(0.25, -0.1, -0.05, 0.1, 0.1, 0.2);
1437 polys += Rect(0.75, -0.1, -0.05, 0.1, 0.1, 0.2);
1438 polys += Rect(0.5, 0.5, -0.05, 0.1, 0.1, 0.2);
1439 polys += Rect(0.25, -0.2, -0.2, 0.1, 0.15, 0.1);
1440 polys += Rect(0.75, -0.2, -0.2, 0.1, 0.15, 0.1);
1441 polys += Rect(0.5, 0.5, -0.2, 0.1, 0.15, 0.1);
1447 static Component * NewComponent(ModeInfo *mi)
1449 Circuit *ci = &circuit[MI_SCREEN(mi)];
1453 c = malloc(sizeof(Component));
1454 c->angle = RAND_RANGE(0,360);
1456 if (rnd < 0.25) { /* come from the top */
1458 c->x = RAND_RANGE(0, ci->XMAX) - ci->XMAX/2;
1460 c->dx = 0 - RAND_RANGE(0.5, 2);
1462 c->dx = RAND_RANGE(0.5, 2);
1463 c->dy = 0 - RAND_RANGE(0.5, 2);
1464 } else if (rnd < 0.5) { /* come from the bottom */
1465 c->y = 0 - ci->YMAX/2;
1466 c->x = RAND_RANGE(0, ci->XMAX) - ci->XMAX/2;
1468 c->dx = 0 - RAND_RANGE(0.5, 2);
1470 c->dx = RAND_RANGE(0.5, 2);
1471 c->dy = RAND_RANGE(0.5, 2);
1472 } else if (rnd < 0.75) { /* come from the left */
1473 c->x = 0 - ci->XMAX/2;
1474 c->y = RAND_RANGE(0, ci->YMAX) - ci->YMAX/2;
1475 c->dx = RAND_RANGE(0.5, 2);
1477 c->dy = 0 - RAND_RANGE(0.5, 2);
1479 c->dy = RAND_RANGE(0.5, 2);
1480 } else { /* come from the right */
1482 c->y = RAND_RANGE(0, ci->YMAX) - ci->YMAX/2;
1483 c->dx = 0 - RAND_RANGE(0.5, 2);
1485 c->dy = 0 - RAND_RANGE(0.5, 2);
1487 c->dy = RAND_RANGE(0.5, 2);
1489 c->z = RAND_RANGE(0, 7) - 9;
1493 c->drot = f_rand() * 3;
1495 c->dz = f_rand()*2 - 1;
1497 c->alpha = 0; /* explicitly set to 1 later */
1498 rnd = random() % 11;
1500 c->c = NewResistor();
1503 c->norm = 1; /* some resistors shine */
1504 } else if (rnd < 2) {
1507 c->norm = 1; /* some diodes shine */
1509 } else if (rnd < 3) {
1510 c->c = NewTransistor(mi);
1513 } else if (rnd < 4) {
1514 c->c = NewCapacitor(ci);
1517 } else if (rnd < 5) {
1521 } else if (rnd < 6) {
1526 } else if (rnd < 7) {
1531 } else if (rnd < 8) {
1535 } else if (rnd < 9) {
1536 c->c = NewThreeFive(ci);
1539 } else if (rnd < 10) {
1540 c->c = NewSwitch(ci);
1550 static Transistor *NewTransistor(ModeInfo *mi)
1554 t = malloc(sizeof(Transistor));
1555 t->type = (random() % 3);
1557 t->text = transistortypes[random() % countof(transistortypes)];
1558 } else if (t->type == 2) {
1559 t->text = smctypes[random() % countof(smctypes)];
1560 } else if (t->type == 1) {
1561 t->text = to92types[random() % countof(to92types)];
1566 static Capacitor *NewCapacitor(Circuit *ci)
1570 c = malloc(sizeof(Capacitor));
1571 c->type = (f_rand() < 0.5);
1573 c->length = RAND_RANGE(0.5, 1);
1574 c->width = RAND_RANGE(0.5, 1);
1576 c->width = RAND_RANGE(0.3, 1);
1581 /* 7 segment display */
1583 static Disp *NewDisp(Circuit *ci)
1587 d = malloc(sizeof(Disp));
1591 d->value = RAND_RANGE(0, 10);
1596 static IC *NewIC(ModeInfo *mi)
1601 int types[countof(ictypes)], i, n = 0;
1603 c = malloc(sizeof(IC));
1605 switch((int)RAND_RANGE(0,4)) {
1620 for (i = 0 ; i < countof(ictypes) ; i++) {
1621 if (ictypes[i].pins == pins) {
1627 if (n > countof(types)) abort();
1628 val = ictypes[types[random() % n]].val;
1629 sprintf(c->text, "%s\n%02d%02d", val,
1630 (int)RAND_RANGE(80, 100), (int)RAND_RANGE(1,53));
1635 static LED *NewLED(Circuit *ci)
1640 l = malloc(sizeof(LED));
1643 if (!ci->light && (f_rand() < 0.4)) {
1648 l->r = 0.9; l->g = 0; l->b = 0;
1649 } else if (r < 0.4) {
1650 l->r = 0.3; l->g = 0.9; l->b = 0;
1651 } else if (r < 0.6) {
1652 l->r = 0.8; l->g = 0.9; l->b = 0;
1653 } else if (r < 0.8) {
1654 l->r = 0.0; l->g = 0.2; l->b = 0.8;
1656 l->r = 0.9, l->g = 0.55, l->b = 0;
1661 static Fuse *NewFuse(Circuit *ci)
1665 f = malloc(sizeof(Fuse));
1669 static RCA *NewRCA(Circuit *ci)
1673 r = malloc(sizeof(RCA));
1674 r->col = (random() % 10 < 5);
1678 static ThreeFive *NewThreeFive(Circuit *ci)
1682 r = malloc(sizeof(ThreeFive));
1686 static Switch *NewSwitch(Circuit *ci)
1690 s = malloc(sizeof(Switch));
1695 static Diode *NewDiode(void)
1700 ret = malloc(sizeof(Diode));
1701 b = malloc(sizeof(Band));
1704 if (f_rand() < 0.5) {
1708 ret->r = 0.7; ret->g = 0.1 ; ret->b = 0.1;
1713 ret->r = 0.2; ret->g = 0.2 ; ret->b = 0.2;
1720 static Resistor * NewResistor(void)
1722 int v, m, t; /* value, multiplier, tolerance */
1727 t = (RAND(10) < 5) ? 10 : 11;
1728 ret = malloc(sizeof(Resistor));
1731 ret->b[0] = ret->b[1] = ret->b[2] = 7;
1733 ret->b[0] = values[v][0];
1734 ret->b[1] = values[v][1];
1742 static void makebandlist(Circuit *ci)
1745 GLfloat col[] = {0,0,0,0};
1746 GLfloat spec[] = {0.8,0.8,0.8,0};
1749 for (i = 0 ; i < 12 ; i++) {
1750 ci->band_list[i] = glGenLists(1);
1751 glNewList(ci->band_list[i], GL_COMPILE);
1752 col[0] = colorcodes[i][0];
1753 col[1] = colorcodes[i][1];
1754 col[2] = colorcodes[i][2];
1755 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
1756 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
1757 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shine);
1758 ci->band_list_polys[i] = createCylinder(ci, 0.1, 0.42, 0, 0);
1764 static int bandedCylinder(Circuit *ci,
1765 float radius, float l,
1766 GLfloat r, GLfloat g, GLfloat bl,
1767 Band **b, int nbands)
1770 int n; /* band number */
1771 GLfloat col[] = {0,0,0,0};
1773 col[0] = r; col[1] = g; col[2] = bl;
1774 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1775 polys += createCylinder(ci, l, radius, 1, 0); /* body */
1776 for (n = 0 ; n < nbands ; n++) {
1778 glTranslatef(b[n]->pos*l, 0, 0);
1779 col[0] = b[n]->r; col[1] = b[n]->g; col[2] = b[n]->b;
1780 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
1781 polys += createCylinder(ci, b[n]->len*l, radius*1.05, 0, 0); /* band */
1787 static int drawgrid(Circuit *ci)
1791 GLfloat col3[] = {0, 0.8, 0};
1794 if (f_rand() < ((rotatespeed > 0) ? 0.05 : 0.01)) {
1795 ci->draw_sdir = RAND_RANGE(0, 4);
1796 ci->draw_ds = RAND_RANGE(0.4, 0.8);
1797 switch (ci->draw_sdir) {
1799 ci->draw_sx = -ci->XMAX/2;
1800 ci->draw_sy = ((int)RAND_RANGE(0, ci->YMAX/2))*2 - ci->YMAX/2;
1803 ci->draw_sx = ci->XMAX/2;
1804 ci->draw_sy = ((int)RAND_RANGE(0, ci->YMAX/2))*2 - ci->YMAX/2;
1807 ci->draw_sy = ci->YMAX/2;
1808 ci->draw_sx = ((int)RAND_RANGE(0, ci->XMAX/2))*2 - ci->XMAX/2;
1811 ci->draw_sy = -ci->YMAX/2;
1812 ci->draw_sx = ((int)RAND_RANGE(0, ci->XMAX/2))*2 - ci->XMAX/2;
1817 } else if (rotatespeed <= 0) {
1818 if (ci->grid_col[1] < 0.25) {
1819 ci->grid_col[1] += 0.025; ci->grid_col[2] += 0.005;
1820 ci->grid_col2[1] += 0.015 ; ci->grid_col2[2] += 0.005;
1824 glDisable(GL_LIGHTING);
1828 glTranslatef(ci->draw_sx, ci->draw_sy, -10);
1829 polys += sphere(ci, 0.1, 10, 10, 0, 10, 0, 10);
1830 if (ci->draw_sdir == 0)
1831 glTranslatef(-ci->draw_ds, 0, 0);
1832 if (ci->draw_sdir == 1)
1833 glTranslatef(ci->draw_ds, 0, 0);
1834 if (ci->draw_sdir == 2)
1835 glTranslatef(0, ci->draw_ds, 0);
1836 if (ci->draw_sdir == 3)
1837 glTranslatef(0, -ci->draw_ds, 0);
1838 polys += sphere(ci, 0.05, 10, 10, 0, 10, 0, 10);
1840 if (ci->draw_sdir == 0) {
1841 ci->draw_sx += ci->draw_ds;
1842 if (ci->draw_sx > ci->XMAX/2)
1845 if (ci->draw_sdir == 1) {
1846 ci->draw_sx -= ci->draw_ds;
1847 if (ci->draw_sx < -ci->XMAX/2)
1850 if (ci->draw_sdir == 2) {
1851 ci->draw_sy -= ci->draw_ds;
1852 if (ci->draw_sy < ci->YMAX/2)
1855 if (ci->draw_sdir == 3) {
1856 ci->draw_sy += ci->draw_ds;
1857 if (ci->draw_sy > ci->YMAX/2)
1860 } else if (rotatespeed <= 0) {
1861 if (ci->grid_col[1] > 0) {
1862 ci->grid_col[1] -= 0.0025; ci->grid_col[2] -= 0.0005;
1863 ci->grid_col2[1] -= 0.0015 ; ci->grid_col2[2] -= 0.0005;
1866 for (x = -ci->XMAX/2 ; x <= ci->XMAX/2 ; x+= 2) {
1867 glColor3fv(ci->grid_col);
1869 glVertex3f(x, ci->YMAX/2, -10);
1870 glVertex3f(x, -ci->YMAX/2, -10);
1871 glColor3fv(ci->grid_col2);
1872 glVertex3f(x-0.02, ci->YMAX/2, -10);
1873 glVertex3f(x-0.02, -ci->YMAX/2, -10);
1874 glVertex3f(x+0.02, ci->YMAX/2, -10);
1875 glVertex3f(x+0.02, -ci->YMAX/2, -10);
1878 for (y = -ci->YMAX/2 ; y <= ci->YMAX/2 ; y+= 2) {
1879 glColor3fv(ci->grid_col);
1881 glVertex3f(-ci->XMAX/2, y, -10);
1882 glVertex3f(ci->XMAX/2, y, -10);
1883 glColor3fv(ci->grid_col2);
1884 glVertex3f(-ci->XMAX/2, y-0.02, -10);
1885 glVertex3f(ci->XMAX/2, y-0.02, -10);
1886 glVertex3f(-ci->XMAX/2, y+0.02, -10);
1887 glVertex3f(ci->XMAX/2, y+0.02, -10);
1890 glEnable(GL_LIGHTING);
1894 static void display(ModeInfo *mi)
1896 Circuit *ci = &circuit[MI_SCREEN(mi)];
1897 GLfloat light_sp[] = {0.8, 0.8, 0.8, 1.0};
1898 GLfloat black[] = {0, 0, 0, 1.0};
1901 mi->polygon_count = 0;
1903 if (ci->display_i == 0) {
1904 for (ci->display_i = 0 ; ci->display_i < maxparts ; ci->display_i++) {
1905 ci->components[ci->display_i] = NULL;
1908 glEnable(GL_LIGHTING);
1909 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
1911 gluLookAt(ci->viewer[0], ci->viewer[1], ci->viewer[2],
1915 glRotatef(ci->rotate_angle, 0, 0, 1);
1916 ci->rotate_angle += 0.01 * (float)rotatespeed;
1917 if (ci->rotate_angle >= 360) ci->rotate_angle = 0;
1919 glLightfv(GL_LIGHT0, GL_POSITION, ci->lightpos);
1920 glLightfv(GL_LIGHT0, GL_SPECULAR, light_sp);
1921 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_sp);
1922 glLighti(GL_LIGHT0, GL_CONSTANT_ATTENUATION, (GLfloat)1);
1923 glLighti(GL_LIGHT0, GL_LINEAR_ATTENUATION, (GLfloat)0.5);
1924 glLighti(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, (GLfloat)0);
1926 # ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */
1928 GLfloat h = MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi);
1929 int o = (int) current_device_rotation();
1930 if (o != 0 && o != 180 && o != -180)
1937 mi->polygon_count += drawgrid(ci);
1938 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light_sp);
1939 if (f_rand() < 0.05) {
1940 for (j = 0 ; j < maxparts ; j++) {
1941 if (ci->components[j] == NULL) {
1942 ci->components[j] = NewComponent(mi);
1946 reorder(&ci->components[0]);
1948 for (j = 0 ; j < maxparts ; j++) {
1949 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, black);
1950 glMaterialfv(GL_FRONT, GL_EMISSION, black);
1951 glMaterialfv(GL_FRONT, GL_SPECULAR, black);
1952 if (ci->components[j] != NULL) {
1953 if (DrawComponent(ci, ci->components[j], &mi->polygon_count)) {
1954 free(ci->components[j]); ci->components[j] = NULL;
1962 /* ensure transparent components are at the end */
1963 static void reorder(Component *c[])
1966 Component *c1[MAX_COMPONENTS];
1967 Component *c2[MAX_COMPONENTS];
1970 for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
1974 for (i = 0 ; i < maxparts ; i++) {
1975 if (c[i] == NULL) continue;
1976 if (c[i]->alpha) { /* transparent parts go to c1 */
1979 } else { /* opaque parts go to c2 */
1983 for (i = 0 ; i < maxparts ; i++) { /* clear old matrix */
1987 for (i = 0 ; i < maxparts ; i++) { /* insert opaque part */
1988 if (c2[i] != NULL) {
1993 for (i = 0 ; i < j ; i++) { /* insert transparent parts */
1999 ENTRYPOINT void reshape_circuit(ModeInfo *mi, int width, int height)
2001 Circuit *ci = &circuit[MI_SCREEN(mi)];
2002 GLfloat h = (GLfloat) height / (GLfloat) width;
2003 glViewport(0,0,(GLint)width, (GLint) height);
2004 glMatrixMode(GL_PROJECTION);
2006 glFrustum(-1.0,1.0,-h,h,1.5,35.0);
2007 glMatrixMode(GL_MODELVIEW);
2010 ci->YMAX = ci->XMAX * h;
2014 ENTRYPOINT void init_circuit(ModeInfo *mi)
2016 int screen = MI_SCREEN(mi);
2019 if (circuit == NULL) {
2020 if ((circuit = (Circuit *) calloc(MI_NUM_SCREENS(mi),
2021 sizeof(Circuit))) == NULL)
2024 ci = &circuit[screen];
2025 ci->window = MI_WINDOW(mi);
2027 ci->XMAX = ci->YMAX = 50;
2029 ci->lightpos[0] = 7;
2030 ci->lightpos[1] = 7;
2031 ci->lightpos[2] = 15;
2032 ci->lightpos[3] = 1;
2034 ci->grid_col[1] = 0.25;
2035 ci->grid_col[2] = 0.05;
2036 ci->grid_col2[1] = 0.125;
2037 ci->grid_col2[2] = 0.05;
2039 ci->font = load_texture_font (MI_DISPLAY(mi), "componentFont");
2041 if (maxparts >= MAX_COMPONENTS)
2042 maxparts = MAX_COMPONENTS-1;
2044 if ((ci->glx_context = init_GL(mi)) != NULL) {
2045 reshape_circuit(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
2051 glShadeModel(GL_SMOOTH);
2052 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
2053 glEnable(GL_DEPTH_TEST);
2054 glEnable(GL_LIGHTING);
2055 glEnable(GL_LIGHT0);
2056 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2062 ENTRYPOINT void draw_circuit(ModeInfo *mi)
2064 Circuit *ci = &circuit[MI_SCREEN(mi)];
2065 Window w = MI_WINDOW(mi);
2066 Display *disp = MI_DISPLAY(mi);
2068 if (!ci->glx_context)
2071 glXMakeCurrent(disp, w, *(ci->glx_context));
2075 if(mi->fps_p) do_fps(mi);
2077 glXSwapBuffers(disp, w);
2080 ENTRYPOINT void release_circuit(ModeInfo *mi)
2082 Circuit *ci = &circuit[MI_SCREEN(mi)];
2084 free_texture_font (ci->font);
2088 XSCREENSAVER_MODULE ("Circuit", circuit)