From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / hacks / glx / circuit.c
index b59b470b279e77537b35345a4ea1af18aed59320..e5723d5aec417f2c6e387d157ef6312e1fdfa93a 100644 (file)
@@ -11,7 +11,7 @@
  *                    surface mount, to-92 markings. Fixed ~5min crash.
  *                    Better LED illumination. Other minor changes.
  *
- * Copyright (C) 2001,2002 Ben Buxton (bb@cactii.net)
+ * Copyright (C) 2001-2015 Ben Buxton (bb@cactii.net)
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
 
 #ifdef STANDALONE
 #define DEFAULTS        "*delay:   20000 \n" \
-                        "*showFPS: False \n"
+                        "*showFPS: False \n" \
+                       "*suppressRotationAnimation: True\n" \
+               "*componentFont: -*-courier-bold-r-normal-*-*-140-*-*-*-*-*-*"
 
 # define refresh_circuit 0
+# define release_circuit 0
 # define circuit_handle_event 0
 # include "xlockmore.h"                         /* from the xscreensaver distribution */
 #else  /* !STANDALONE */
 
 #ifdef USE_GL
 
-#include "font-ximage.h"
+#include "texfont.h"
 
 #undef countof
 #define countof(x) (sizeof((x))/sizeof((*x)))
 
 static int maxparts;
-static char *font;
 static int rotatespeed;
 static int spin;
 static int uselight;
@@ -70,7 +72,6 @@ static int seven;
 
 static XrmOptionDescRec opts[] = {
   {"-parts", ".circuit.parts", XrmoptionSepArg, 0 },
-  {"-font", ".circuit.font", XrmoptionSepArg, 0 },
   {"-rotate-speed", ".circuit.rotatespeed", XrmoptionSepArg, 0 },
   {"+spin", ".circuit.spin", XrmoptionNoArg, "false" },
   {"-spin", ".circuit.spin", XrmoptionNoArg, "true" },
@@ -82,7 +83,6 @@ static XrmOptionDescRec opts[] = {
 
 static argtype vars[] = {
   {&maxparts, "parts", "Parts", DEF_PARTS, t_Int},
-  {&font, "font", "Font", "fixed", t_String},
   {&rotatespeed, "rotatespeed", "Rotatespeed", DEF_ROTATESPEED, t_Int},
   {&spin, "spin", "Spin", DEF_SPIN, t_Bool},
   {&uselight, "light", "Light", DEF_LIGHT, t_Bool},
@@ -93,7 +93,7 @@ ENTRYPOINT ModeSpecOpt circuit_opts = {countof(opts), opts, countof(vars), vars,
 
 #ifdef USE_MODULES
 ModStruct   circuit_description =
-{"circuit", "init_circuit", "draw_circuit", "release_circuit",
+{"circuit", "init_circuit", "draw_circuit", NULL,
  "draw_circuit", "init_circuit", NULL, &circuit_opts,
  1000, 1, 2, 1, 4, 1.0, "",
  "Flying electronic components", 0, NULL};
@@ -110,13 +110,6 @@ static float f_rand(void)
 
 #define RAND_RANGE(min, max) ((min) + (max - min) * f_rand())
 
-/* used for allocating font textures */
-typedef struct {
-  int num; /* index number */
-  int w;   /* width */
-  int h;   /* height */
-} TexNum;
-
 /* Represents a band on a resistor/diode/etc */
 typedef struct {
   float pos;     /* relative position from start/previous band */
@@ -177,8 +170,7 @@ static const char * const smctypes[] = {
 
 typedef struct {
   int type; /* package type. 0 = to-92, 1 = to-220 */
-  GLfloat tw, th; /* texture dimensions */
-  GLuint tnum; /* texture binding */
+  const char *text;
 } Transistor;
 
 typedef struct {
@@ -252,8 +244,7 @@ static const ICTypes ictypes[] = {
 typedef struct {
   int type; /* 0 = DIL, 1 = flat square */
   int pins; 
-  float tw, th; /* texture dimensions for markings */
-  int tnum; /* texture number */
+  char text[100];
 } IC;
 
 /* 7 segment display */
@@ -345,6 +336,7 @@ typedef struct {
   int display_i;
   GLfloat rotate_angle;
 
+  texture_font_data *font;
   char *font_strings[50]; /* max of 40 textures */
   int font_w[50], font_h[50];
   int font_init;
@@ -371,13 +363,11 @@ static int DrawRCA(Circuit *, RCA *);
 static int DrawThreeFive(Circuit *, ThreeFive *);
 static int DrawSwitch(Circuit *, Switch *);
 
-static void freetexture(Circuit *, GLuint);
 static void reorder(Component *[]);
 static int circle(Circuit *, float, int,int);
 static int bandedCylinder(Circuit *, 
                            float, float , GLfloat, GLfloat , GLfloat,  
                            Band **, int);
-static TexNum *fonttexturealloc(ModeInfo *, const char *, float *, float *);
 static int Rect(GLfloat , GLfloat , GLfloat, GLfloat , GLfloat ,GLfloat);
 static int ICLeg(GLfloat, GLfloat, GLfloat, int);
 static int HoledRectangle(Circuit *ci, 
@@ -531,40 +521,6 @@ static int wire(Circuit *ci, float len)
   return polys;
 }
 
-#if 0
-static int ring(GLfloat inner, GLfloat outer, int nsegs)
-{
-  int polys = 0;
-  GLfloat z1, z2, y1, y2;
-  GLfloat Z1, Z2, Y1, Y2;
-  int i;
-
-  z1 = inner; y1 = 0;
-  Z1 = outer; Y1 = 0;
-  glBegin(GL_QUADS);
-  glNormal3f(1, 0, 0);
-  for(i=0; i <=360 ; i+= 360/nsegs)
-  {
-    float angle=i;
-    z2=inner*(float)ci->sin_table[(int)angle];
-    y2=inner*(float)ci->cos_table[(int)angle];
-    Z2=outer*(float)ci->sin_table[(int)angle];
-    Y2=outer*(float)ci->cos_table[(int)angle];
-    glVertex3f(0, Y1, Z1);
-    glVertex3f(0, y1, z1);
-    glVertex3f(0, y2, z2);
-    glVertex3f(0, Y2, Z2);
-    polys++;
-    z1=z2;
-    y1=y2;
-    Z1=Z2;
-    Y1=Y2;
-  }
-  glEnd();
-  return polys;
-}
-#endif
-
 static int sphere(Circuit *ci, GLfloat r, float stacks, float slices,
              int startstack, int endstack, int startslice,
              int endslice)
@@ -673,14 +629,6 @@ static int DrawComponent(Circuit *ci, Component *c, unsigned long *polysP)
           glDisable(GL_LIGHT1);
           ci->light = 0; ci->lighton = 0;
         }
-       if (c->type == 5) {
-          if (((IC *)c->c)->tnum)
-            freetexture(ci, ((IC *)c->c)->tnum);
-       }
-       if (c->type == 2) {
-          if (((Transistor *)c->c)->tnum)
-            freetexture(ci, ((Transistor *)c->c)->tnum);
-       }
         if (c->type == 1)
           free(((Diode *)c->c)->band); /* remember to free diode band */
         free(c->c);
@@ -1091,7 +1039,6 @@ static int DrawIC(Circuit *ci, IC *c)
   GLfloat lspec[] = {0.6, 0.6, 0.6, 0};
   GLfloat lcol[] = {0.4, 0.4, 0.4, 0};
   GLfloat lshine = 40;
-  float mult, th, size;
 
   glPushMatrix();
   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
@@ -1155,28 +1102,25 @@ static int DrawIC(Circuit *ci, IC *c)
       polys++;
     glEnd();
     glDisable(GL_POLYGON_OFFSET_FILL);
-    if (c->tnum) glBindTexture(GL_TEXTURE_2D, c->tnum);
     glEnable(GL_TEXTURE_2D);
     glEnable(GL_BLEND);
-    if (c->pins == 8)
-      size = 0.4;
-    else
-      size = 0.6;
-    th = size*2/3;
-    mult = size*c->tw / c->th;
-    mult /= 2;
-    glBegin(GL_QUADS); /* text markings */
-     glNormal3f(0, 0, 1);
-     glTexCoord2f(0, 1);
-     glVertex3f(th, mult, 0.1);
-     glTexCoord2f(1, 1);
-     glVertex3f(th, -mult, 0.1);
-     glTexCoord2f(1, 0);
-     glVertex3f(-th, -mult, 0.1);
-     glTexCoord2f(0, 0);
-     glVertex3f(-th, mult, 0.1);
-      polys++;
-    glEnd();
+
+    {
+      GLfloat texfg[] = {0.7, 0.7, 0.7, 1.0};
+      GLfloat s = 0.015;
+      XCharStruct e;
+      texture_string_metrics (ci->font, c->text, &e, 0, 0);
+
+      glPushMatrix();
+      glTranslatef (0, 0, 0.1);
+      glRotatef (90, 0, 0, 1);
+      glScalef (s, s, s);
+      glTranslatef (-w/2, 0, 0);
+      glColor4fv (texfg);
+      print_texture_string (ci->font, c->text);
+      glPopMatrix();
+    }
+
     glDisable(GL_TEXTURE_2D);
     glDisable(GL_BLEND);
     d = (h*2-0.1) / c->pins;
@@ -1394,32 +1338,30 @@ static int DrawTransistor(Circuit *ci, Transistor *t)
   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col);
   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   if (t->type == 1) { /* TO-92 style */
-    float mult, y1, y2;
-    mult = 1.5*t->th/t->tw;
-    y1 = 0.2+mult/2;
-    y2 = 0.8-mult/2;
     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col);
     glRotatef(90, 0, 1, 0);
     glRotatef(90, 0, 0, 1);
     polys += createCylinder(ci, 1.0, 0.4, 1, 1);
     polys += Rect(0, -0.2, 0.4, 1, 0.2, 0.8);
 /* Draw the markings */
-    glEnable(GL_TEXTURE_2D);
-    if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
-    glEnable(GL_BLEND);
-    glDepthMask(GL_FALSE);
-    glBegin (GL_QUADS);
-     glNormal3f(0, 0, 1);
-     glTexCoord2f(0, 1);
-     glVertex3f(y1, -0.21, 0.3);
-     glTexCoord2f(1, 1);
-     glVertex3f(y1, -0.21, -0.3);
-     glTexCoord2f(1, 0);
-     glVertex3f(y2, -0.21, -0.3);
-     glTexCoord2f(0, 0);
-     glVertex3f(y2, -0.21, 0.3);
-     polys++;
-    glEnd();
+
+    {
+      GLfloat texfg[] = {0.7, 0.7, 0.7, 1.0};
+      GLfloat s = 0.015;
+      XCharStruct e;
+      int w;
+      texture_string_metrics (ci->font, t->text, &e, 0, 0);
+      w = e.width;
+      glPushMatrix();
+      glRotatef (90, 1, 0, 0);
+      glTranslatef (0.5, -0.05, 0.21);
+      glScalef (s, s, s);
+      glTranslatef (-w/2, 0, 0);
+      glColor4fv (texfg);
+      print_texture_string (ci->font, t->text);
+      glPopMatrix();
+    }
+
     glDisable(GL_TEXTURE_2D);
     glDisable(GL_BLEND);
     glDepthMask(GL_TRUE);
@@ -1430,26 +1372,22 @@ static int DrawTransistor(Circuit *ci, Transistor *t)
     glTranslatef(0, 0, 0.2);
     polys += wire(ci, 2);
   } else if (t->type == 0) { /* TO-220 Style */
-    float mult, y1, y2;
-    mult = 1.5*t->th/t->tw;
-    y1 = 0.75+mult/2;
-    y2 = 0.75-mult/2;
     polys += Rect(0, 0, 0, 1.5, 1.5, 0.5);
-    glEnable(GL_TEXTURE_2D);
-    if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
-    glEnable(GL_BLEND);
-    glDepthMask(GL_FALSE);
-    glBegin (GL_QUADS);
-     glNormal3f(0, 0, 1);
-     glTexCoord2f(0, 1);
-     glVertex3f(0, y1, 0.01);
-     glTexCoord2f(1, 1);
-     glVertex3f(1.5, y1, 0.01);
-     glTexCoord2f(1, 0);
-     glVertex3f(1.5, y2, 0.01);
-     glTexCoord2f(0, 0);
-     glVertex3f(0, y2, 0.01);
-    glEnd();
+    {
+      GLfloat texfg[] = {0.7, 0.7, 0.7, 1.0};
+      GLfloat s = 0.015;
+      XCharStruct e;
+      int w;
+      texture_string_metrics (ci->font, t->text, &e, 0, 0);
+      w = e.width;
+      glPushMatrix();
+      glTranslatef (0.75, 0.75, 0.01);
+      glScalef (s, s, s);
+      glTranslatef (-w/2, 0, 0);
+      glColor4fv (texfg);
+      print_texture_string (ci->font, t->text);
+      glPopMatrix();
+    }
     glDisable(GL_TEXTURE_2D);
     glDisable(GL_BLEND);
     glDepthMask(GL_TRUE);
@@ -1475,7 +1413,6 @@ static int DrawTransistor(Circuit *ci, Transistor *t)
     polys += Rect(0, 0, 0, 1, 0.5, 0.2);
 /* Draw the markings */
     glEnable(GL_TEXTURE_2D);
-    if (t->tnum) glBindTexture(GL_TEXTURE_2D, t->tnum);
     glEnable(GL_BLEND);
     glDepthMask(GL_FALSE);
     glBegin (GL_QUADS);
@@ -1614,48 +1551,16 @@ static Component * NewComponent(ModeInfo *mi)
 static Transistor *NewTransistor(ModeInfo *mi)
 {
   Transistor *t;
-  float texfg[] = {0.7, 0.7, 0.7, 1.0};
-  float texbg[] = {0.3, 0.3, 0.3, 0.1};
-  TexNum *tn;
-  const char *val;
 
   t = malloc(sizeof(Transistor));
   t->type = (random() % 3);
   if (t->type == 0) {
-    val = transistortypes[random() % countof(transistortypes)];
-    tn = fonttexturealloc(mi, val, texfg, texbg);
-    if (tn == NULL) {
-      fprintf(stderr, "Error getting a texture for a string!\n");
-      t->tnum = 0;
-    } else {
-      t->tnum = tn->num;
-      t->tw = tn->w; t->th = tn->h;
-      free(tn);
-    }
+    t->text = transistortypes[random() % countof(transistortypes)];
   } else if (t->type == 2) {
-    val = smctypes[random() % countof(smctypes)];
-    tn = fonttexturealloc(mi, val, texfg, texbg);
-    if (tn == NULL) {
-      fprintf(stderr, "Error getting a texture for a string!\n");
-      t->tnum = 0;
-    } else {
-      t->tnum = tn->num;
-      t->tw = tn->w; t->th = tn->h;
-      free(tn);
-    }
+    t->text = smctypes[random() % countof(smctypes)];
   } else if (t->type == 1) {
-    val = to92types[random() % countof(to92types)];
-    tn = fonttexturealloc(mi, val, texfg, texbg);
-    if (tn == NULL) {
-      fprintf(stderr, "Error getting a texture for a string!\n");
-      t->tnum = 0;
-    } else {
-      t->tnum = tn->num;
-      t->tw = tn->w; t->th = tn->h;
-      free(tn);
-    }
+    t->text = to92types[random() % countof(to92types)];
   }
-
   return t;
 }
 
@@ -1693,11 +1598,7 @@ static IC *NewIC(ModeInfo *mi)
 {
   IC *c;
   int pins;
-  TexNum *tn;
-  float texfg[] = {0.7, 0.7, 0.7, 1.0};
-  float texbg[] = {0.1, 0.1, 0.1, 0};
   const char *val;
-  char *str;
   int types[countof(ictypes)], i, n = 0;
 
   c = malloc(sizeof(IC));
@@ -1726,18 +1627,8 @@ static IC *NewIC(ModeInfo *mi)
 
   if (n > countof(types)) abort();
   val = ictypes[types[random() % n]].val;
-  str = malloc(strlen(val) + 1 + 4 + 1); /* add space for production date */
-  sprintf(str, "%s\n%02d%02d", val, (int)RAND_RANGE(80, 100), (int)RAND_RANGE(1,53));
-  tn = fonttexturealloc(mi, str, texfg, texbg);
-  free(str);
-  if (tn == NULL) {
-    fprintf(stderr, "Error allocating font texture for '%s'\n", val);
-    c->tnum = 0;
-  } else {
-    c->tw = tn->w; c->th = tn->h;
-    c->tnum = tn->num;
-    free(tn);
-  }
+  sprintf(c->text, "%s\n%02d%02d", val,
+          (int)RAND_RANGE(80, 100), (int)RAND_RANGE(1,53));
   c->pins = pins;
   return c;
 }
@@ -2018,7 +1909,6 @@ static void display(ModeInfo *mi)
   glEnable(GL_LIGHTING);
   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
   glLoadIdentity();
-  glRotatef(current_device_rotation(), 0, 0, 1);
   gluLookAt(ci->viewer[0], ci->viewer[1], ci->viewer[2], 
             0.0, 0.0, 0.0, 
             0.0, 1.0, 0.0);
@@ -2033,6 +1923,18 @@ static void display(ModeInfo *mi)
   glLighti(GL_LIGHT0, GL_CONSTANT_ATTENUATION, (GLfloat)1); 
   glLighti(GL_LIGHT0, GL_LINEAR_ATTENUATION, (GLfloat)0.5); 
   glLighti(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, (GLfloat)0); 
+
+# ifdef HAVE_MOBILE    /* Keep it the same relative size when rotated. */
+  {
+    GLfloat h = MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi);
+    int o = (int) current_device_rotation();
+    if (o != 0 && o != 180 && o != -180)
+      glScalef (h, h, h);
+    h = 2;
+    glScalef (h, h, h);
+  }
+# endif
+
   mi->polygon_count += drawgrid(ci);
   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, light_sp);
   if (f_rand() < 0.05) {
@@ -2058,101 +1960,6 @@ static void display(ModeInfo *mi)
   glFlush();
 }
 
-static void freetexture (Circuit *ci, GLuint texture) 
-{
-  ci->s_refs[texture]--;
-  if (ci->s_refs[texture] < 1) {
-    glDeleteTextures(1, &texture);
-  }
-}
-
-static TexNum * fonttexturealloc (ModeInfo *mi,
-                                  const char *str, float *fg, float *bg)
-{
-  Circuit *ci = &circuit[MI_SCREEN(mi)];
-  int i;
-  XImage *ximage;
-  char *c;
-  TexNum *t;
-  GLuint mintex;
-  if (ci->font_init == 0) {
-    for (i = 0 ; i < 50 ; i++) {
-      ci->font_strings[i] = NULL;
-      ci->s_refs[i] = 0;
-      ci->font_w[i] = 0; ci->font_h[i] = 0;
-    }
-    ci->font_init++;
-  }
-  for (i = 0 ; i < 50 ; i++) {
-    if (!ci->s_refs[i] && ci->font_strings[i]) {
-      free (ci->font_strings[i]);
-      ci->font_strings[i] = NULL;
-    }
-    if (ci->font_strings[i] && !strcmp(str, ci->font_strings[i])) { /* if one matches */
-      t = malloc(sizeof(TexNum));
-      t->w = ci->font_w[i]; t->h = ci->font_h[i];
-      t->num = i;
-      ci->s_refs[i]++;
-      return t;
-    }
-  }
-
-  /* at this point we need to make the new texture */
-  ximage = text_to_ximage (mi->xgwa.screen,
-                           mi->xgwa.visual,
-                           font, str,
-                           fg, bg);
-  glGenTextures (1, &mintex);
-  for (i = mintex ; ci->font_strings[i] != NULL ; i++) { /* set i to the next unused value */
-     if (i > 49) {
-        fprintf(stderr, "Texture cache full!\n");
-        free(ximage->data);
-        ximage->data = 0;
-        XFree (ximage);
-        return NULL;
-     }
-  }
-
-  glBindTexture(GL_TEXTURE_2D, i);
-  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
-  clear_gl_error();
-#if 0
-  i = gluBuild2DMipmaps(GL_TEXTURE_2D, 4,
-                        ximage->width, ximage->height,
-                        GL_RGBA, GL_UNSIGNED_BYTE, ximage->data);
-  if (i)
-    {
-      const char *s = (char *) gluErrorString (i);
-      fprintf (stderr, "%s: error mipmapping %dx%d texture: %s\n",
-               progname, ximage->width, ximage->height,
-               (s ? s : "(unknown)"));
-      abort();
-    }
-  check_gl_error("mipmapping");
-#else
-  glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, ximage->width, ximage->height, 0,
-                GL_RGBA, GL_UNSIGNED_BYTE, ximage->data);
-   check_gl_error("texture");
-#endif
-
-  t = malloc(sizeof(TexNum));
-  t->w = ximage->width;
-  t->h = ximage->height;
-  ci->font_w[i] = t->w; ci->font_h[i] = t->h;
-  free(ximage->data);
-  ximage->data = 0;
-  XFree (ximage);
-  c = malloc(strlen(str)+1);
-  strncpy(c, str, strlen(str)+1);
-  ci->font_strings[i] = c;
-  ci->s_refs[i]++;
-  t->num = i;
-  return t;
-}
-
 /* ensure transparent components are at the end */
 static void reorder(Component *c[])
 {
@@ -2205,20 +2012,18 @@ ENTRYPOINT void reshape_circuit(ModeInfo *mi, int width, int height)
 }
 
 
+static void free_circuit(ModeInfo *mi);
+
 ENTRYPOINT void init_circuit(ModeInfo *mi)
 {
 int screen = MI_SCREEN(mi);
 Circuit *ci;
 
- if (circuit == NULL) {
-   if ((circuit = (Circuit *) calloc(MI_NUM_SCREENS(mi),
-                                        sizeof(Circuit))) == NULL)
-          return;
- }
+ MI_INIT(mi, circuit, free_circuit);
  ci = &circuit[screen];
  ci->window = MI_WINDOW(mi);
 
- ci->XMAX = ci->YMAX = 30;
+ ci->XMAX = ci->YMAX = 50;
  ci->viewer[2] = 14;
  ci->lightpos[0] = 7;
  ci->lightpos[1] = 7;
@@ -2230,6 +2035,8 @@ Circuit *ci;
  ci->grid_col2[1] = 0.125;
  ci->grid_col2[2] = 0.05;
 
+ ci->font = load_texture_font (MI_DISPLAY(mi), "componentFont");
+
  if (maxparts >= MAX_COMPONENTS)
    maxparts = MAX_COMPONENTS-1;
 
@@ -2269,12 +2076,11 @@ ENTRYPOINT void draw_circuit(ModeInfo *mi)
   glXSwapBuffers(disp, w);
 }
 
-ENTRYPOINT void release_circuit(ModeInfo *mi)
+static void free_circuit(ModeInfo *mi)
 {
-  if (circuit != NULL) {
-   (void) free((void *) circuit);
-   circuit = NULL;
-  }
+  Circuit *ci = &circuit[MI_SCREEN(mi)];
+  if (ci->font)
+    free_texture_font (ci->font);
   FreeAllGL(mi);
 }