rnd-20030218-3-src
[rocksndiamonds.git] / src / libgame / text.c
index 48974eb74bb67ef34865e4cd0bccd71bee8ef379..bc2a366dbea15a8b8f87b17f8893409bc7e9c6ce 100644 (file)
 #include <stdarg.h>
 
 #include "text.h"
+#include "misc.h"
 
 
 /* ========================================================================= */
 /* font functions                                                            */
 /* ========================================================================= */
 
-#define NUM_FONTS              2
-#define NUM_FONT_COLORS                4
 #define NUM_FONT_CHARS         (FONT_LINES_PER_FONT * FONT_CHARS_PER_LINE)
 
 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
-static GC      tile_clip_gc = None;
-static Pixmap  tile_clipmask[NUM_FONTS][NUM_FONT_COLORS][NUM_FONT_CHARS];
-
-static struct
-{
-  Bitmap **bitmap;
-  int xsize, ysize;
-} font_info[NUM_FONTS] =
-{
-  { &font.bitmap_big,          FONT1_XSIZE, FONT1_YSIZE },
-  { &font.bitmap_medium,       FONT6_XSIZE, FONT6_YSIZE }
-};
+static GC      font_clip_gc = None;
 
 static void InitFontClipmasks()
 {
   static boolean clipmasks_initialized = FALSE;
-  boolean fonts_initialized = TRUE;
   XGCValues clip_gc_values;
   unsigned long clip_gc_valuemask;
   GC copy_clipmask_gc;
-  int i, j, k;
-
-  for (i=0; i<NUM_FONTS; i++)
-    if (*font_info[i].bitmap == NULL)
-      fonts_initialized = FALSE;
+  int i, j;
 
-  if (!fonts_initialized)
+  if (gfx.num_fonts == 0 || gfx.font[0].bitmap == NULL)
     return;
 
-  if (clipmasks_initialized)
-    for (i=0; i<NUM_FONTS; i++)
-      for (j=0; j<NUM_FONT_COLORS; j++)
-       for (k=0; k<NUM_FONT_CHARS; k++)
-         XFreePixmap(display, tile_clipmask[i][j][k]);
+  if (!clipmasks_initialized)
+  {
+    for (i=0; i < gfx.num_fonts; i++)
+      gfx.font[i].clip_mask = NULL;
+
+    clipmasks_initialized = TRUE;
+  }
 
-  if (tile_clip_gc)
-    XFreeGC(display, tile_clip_gc);
-  tile_clip_gc = None;
+  for (i=0; i < gfx.num_fonts; i++)
+  {
+    if (gfx.font[i].clip_mask)
+      for (j=0; j < NUM_FONT_CHARS; j++)
+       XFreePixmap(display, gfx.font[i].clip_mask[j]);
+    free(gfx.font[i].clip_mask);
+
+    gfx.font[i].clip_mask = NULL;
+  }
+
+  if (font_clip_gc)
+    XFreeGC(display, font_clip_gc);
+  font_clip_gc = None;
 
   /* This stuff is needed because X11 (XSetClipOrigin(), to be precise) is
      often very slow when preparing a masked XCopyArea() for big Pixmaps.
@@ -72,105 +67,96 @@ static void InitFontClipmasks()
 
   clip_gc_values.graphics_exposures = False;
   clip_gc_valuemask = GCGraphicsExposures;
-  tile_clip_gc = XCreateGC(display, window->drawable,
+  font_clip_gc = XCreateGC(display, window->drawable,
                           clip_gc_valuemask, &clip_gc_values);
 
   /* create graphic context structures needed for clipping */
   clip_gc_values.graphics_exposures = False;
   clip_gc_valuemask = GCGraphicsExposures;
-  copy_clipmask_gc = XCreateGC(display, (*font_info[0].bitmap)->clip_mask,
+  copy_clipmask_gc = XCreateGC(display, gfx.font[0].bitmap->clip_mask,
                               clip_gc_valuemask, &clip_gc_values);
 
   /* create only those clipping Pixmaps we really need */
-  for (i=0; i<NUM_FONTS; i++)
-    for (j=0; j<NUM_FONT_COLORS; j++)
-      for (k=0; k<NUM_FONT_CHARS; k++)
+  for (i=0; i < gfx.num_fonts; i++)
   {
-    Bitmap *src_bitmap = *font_info[i].bitmap;
-    Pixmap src_pixmap = src_bitmap->clip_mask;
-    int xpos = k % FONT_CHARS_PER_LINE;
-    int ypos = k / FONT_CHARS_PER_LINE;
-    int xsize = font_info[i].xsize;
-    int ysize = font_info[i].ysize;
-    int src_x = xsize * xpos;
-    int src_y = ysize * (ypos + j * FONT_LINES_PER_FONT);
-
-    tile_clipmask[i][j][k] =
-      XCreatePixmap(display, window->drawable, xsize, ysize, 1);
-
-    XCopyArea(display, src_pixmap, tile_clipmask[i][j][k], copy_clipmask_gc,
-             src_x, src_y, xsize, ysize, 0, 0);
+    if (gfx.font[i].bitmap == NULL)
+      continue;
+
+    gfx.font[i].clip_mask = checked_calloc(NUM_FONT_CHARS * sizeof(Pixmap));
+
+    for (j=0; j < NUM_FONT_CHARS; j++)
+    {
+      Bitmap *src_bitmap = gfx.font[i].bitmap;
+      Pixmap src_pixmap = src_bitmap->clip_mask;
+      int xpos = j % FONT_CHARS_PER_LINE;
+      int ypos = j / FONT_CHARS_PER_LINE;
+      int width  = gfx.font[i].width;
+      int height = gfx.font[i].height;
+      int src_x = gfx.font[i].src_x + xpos * width;
+      int src_y = gfx.font[i].src_y + ypos * height;
+
+      gfx.font[i].clip_mask[j] =
+       XCreatePixmap(display, window->drawable, width, height, 1);
+
+      XCopyArea(display, src_pixmap, gfx.font[i].clip_mask[j],
+               copy_clipmask_gc, src_x, src_y, width, height, 0, 0);
+    }
   }
 
   XFreeGC(display, copy_clipmask_gc);
-
-  clipmasks_initialized = TRUE;
 }
 #endif /* TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND */
 
-void InitFontInfo(Bitmap *bitmap_initial,
-                 Bitmap *bitmap_big, Bitmap *bitmap_medium,
-                 Bitmap *bitmap_small, Bitmap *bitmap_tile)
+void InitFontInfo(struct FontInfo *font_info, int num_fonts)
 {
-  font.bitmap_initial = bitmap_initial;
-  font.bitmap_big = bitmap_big;
-  font.bitmap_medium = bitmap_medium;
-  font.bitmap_small = bitmap_small;
-  font.bitmap_tile = bitmap_tile;
+  gfx.num_fonts = num_fonts;
+  gfx.font = font_info;
 
 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
   InitFontClipmasks();
 #endif
 }
 
-int getFontWidth(int font_size, int font_type)
+int getFontWidth(int font_nr)
 {
-  return (font_type == FC_SPECIAL1 ? FONT3_XSIZE :
-         font_type == FC_SPECIAL2 ? FONT4_XSIZE :
-         font_type == FC_SPECIAL3 ? FONT5_XSIZE :
-         font_size == FS_BIG ? FONT1_XSIZE :
-         font_size == FS_MEDIUM ? FONT6_XSIZE :
-         font_size == FS_SMALL ? FONT2_XSIZE :
-         FONT2_XSIZE);
+  return gfx.font[font_nr].width;
 }
 
-int getFontHeight(int font_size, int font_type)
+int getFontHeight(int font_nr)
 {
-  return (font_type == FC_SPECIAL1 ? FONT3_YSIZE :
-         font_type == FC_SPECIAL2 ? FONT4_YSIZE :
-         font_type == FC_SPECIAL3 ? FONT5_YSIZE :
-         font_size == FS_BIG ? FONT1_YSIZE :
-         font_size == FS_MEDIUM ? FONT6_YSIZE :
-         font_size == FS_SMALL ? FONT2_YSIZE :
-         FONT2_YSIZE);
+  return gfx.font[font_nr].height;
 }
 
-void DrawInitText(char *text, int ypos, int color)
+void DrawInitText(char *text, int ypos, int font_nr)
 {
-  if (window && font.bitmap_initial)
+  if (window && gfx.num_fonts > 0 && gfx.font[font_nr].bitmap != NULL)
   {
-    ClearRectangle(window, 0, ypos, video.width, FONT2_YSIZE);
-    DrawTextExt(window, (video.width - strlen(text) * FONT2_XSIZE)/2,
-               ypos, text, FS_INITIAL, color, FONT_OPAQUE);
+    int text_width = strlen(text) * gfx.font[font_nr].width;
+
+    ClearRectangle(window, 0, ypos, video.width, gfx.font[font_nr].height);
+    DrawTextExt(window, (video.width - text_width) / 2, ypos, text, font_nr,
+               FONT_OPAQUE);
     FlushDisplay();
   }
 }
 
-void DrawTextFCentered(int y, int font_type, char *format, ...)
+void DrawTextFCentered(int y, int font, char *format, ...)
 {
   char buffer[MAX_OUTPUT_LINESIZE + 1];
-  int font_width = getFontWidth(FS_SMALL, font_type);
   va_list ap;
 
   va_start(ap, format);
   vsprintf(buffer, format, ap);
   va_end(ap);
 
-  DrawText(gfx.sx + (gfx.sxsize - strlen(buffer) * font_width) / 2,
-          gfx.sy + y, buffer, FS_SMALL, font_type);
+  if (strlen(buffer) > MAX_OUTPUT_LINESIZE)
+    Error(ERR_EXIT, "string too long in DrawTextFCentered() -- aborting");
+
+  DrawText(gfx.sx + (gfx.sxsize - strlen(buffer) * gfx.font[font].width) / 2,
+          gfx.sy + y, buffer, font);
 }
 
-void DrawTextF(int x, int y, int font_type, char *format, ...)
+void DrawTextF(int x, int y, int font, char *format, ...)
 {
   char buffer[MAX_OUTPUT_LINESIZE + 1];
   va_list ap;
@@ -179,17 +165,20 @@ void DrawTextF(int x, int y, int font_type, char *format, ...)
   vsprintf(buffer, format, ap);
   va_end(ap);
 
-  DrawText(gfx.sx + x, gfx.sy + y, buffer, FS_SMALL, font_type);
+  if (strlen(buffer) > MAX_OUTPUT_LINESIZE)
+    Error(ERR_EXIT, "string too long in DrawTextF() -- aborting");
+
+  DrawText(gfx.sx + x, gfx.sy + y, buffer, font);
 }
 
-void DrawText(int x, int y, char *text, int font_size, int font_type)
+void DrawText(int x, int y, char *text, int font)
 {
   int mask_mode = FONT_OPAQUE;
 
   if (DrawingOnBackground(x, y))
     mask_mode = FONT_MASKED;
 
-  DrawTextExt(drawto, x, y, text, font_size, font_type, mask_mode);
+  DrawTextExt(drawto, x, y, text, font, mask_mode);
 
   if (x < gfx.dx)
     redraw_mask |= REDRAW_FIELD;
@@ -197,47 +186,24 @@ void DrawText(int x, int y, char *text, int font_size, int font_type)
     redraw_mask |= REDRAW_DOOR_1;
 }
 
-void DrawTextExt(DrawBuffer *bitmap, int x, int y, char *text,
-                int font_size, int font_type, int mask_mode)
+void DrawTextExt(DrawBuffer *dst_bitmap, int dst_x, int dst_y, char *text,
+                int font_nr, int mask_mode)
 {
-  Bitmap *font_bitmap;
-  int font_width, font_height, font_starty;
+  struct FontInfo *font = &gfx.font[font_nr];
   boolean print_inverse = FALSE;
 
-  if (font_size != FS_BIG && font_size != FS_MEDIUM && font_size != FS_SMALL)
-    font_size = FS_INITIAL;
-  if (font_type < FC_RED || font_type > FC_SPECIAL3)
-    font_type = FC_RED;
-
-  font_width = getFontWidth(font_size, font_type);
-  font_height = getFontHeight(font_size, font_type);
-
-  font_bitmap = (font_type == FC_SPECIAL2      ? font.bitmap_tile      :
-                font_size == FS_BIG            ? font.bitmap_big       :
-                font_size == FS_MEDIUM         ? font.bitmap_medium    :
-                font_size == FS_SMALL          ? font.bitmap_small     :
-                font.bitmap_initial);
-
-  if (font_bitmap == NULL)
+  if (font->bitmap == NULL)
     return;
 
-  if (font_type == FC_SPECIAL2)
-    font_starty = (font_size == FS_BIG ? 0 : FONT1_YSIZE) * 5;
-  else
-    font_starty = (font_type * (font_size == FS_BIG ? FONT1_YSIZE :
-                               font_size == FS_MEDIUM ? FONT6_YSIZE :
-                               font_size == FS_SMALL ? FONT2_YSIZE :
-                               FONT2_YSIZE) *
-                  FONT_LINES_PER_FONT);
-
-  if (font_type == FC_SPECIAL3)
-    font_starty -= FONT2_YSIZE * FONT_LINES_PER_FONT;
+  /* add offset for drawing font characters */
+  dst_x += font->draw_x;
+  dst_y += font->draw_y;
 
   while (*text)
   {
     char c = *text++;
 
-    if (c == '~' && font_size == FS_SMALL)
+    if (c == '~')
     {
       print_inverse = TRUE;
       continue;
@@ -258,74 +224,59 @@ void DrawTextExt(DrawBuffer *bitmap, int x, int y, char *text,
 
     if ((c >= 32 && c <= 95) || c == '°' || c == '´' || c == '|')
     {
-      int src_x = ((c - 32) % FONT_CHARS_PER_LINE) * font_width;
-      int src_y = ((c - 32) / FONT_CHARS_PER_LINE) * font_height + font_starty;
-      int dest_x = x, dest_y = y;
+      int src_x= font->src_x + ((c - 32) % FONT_CHARS_PER_LINE) * font->width;
+      int src_y= font->src_y + ((c - 32) / FONT_CHARS_PER_LINE) * font->height;
 
       if (c == '°' || c == '´' || c == '|')    /* map '°' and 'TM' signs */
       {
-       if (font_type == FC_SPECIAL2)
-       {
-         src_x = (c == '°' ? 1 : c == '´' ? 2 : 3) * font_width;
-         src_y = 4 * font_height;
-       }
-       else
-       {
-         src_x = FONT_CHARS_PER_LINE * font_width;
-         src_y = (c == '°' ? 1 : c == '´' ? 2 : 3) * font_height +font_starty;
-       }
+       src_x = font->src_x + FONT_CHARS_PER_LINE * font->width;
+       src_y = font->src_y + (c == '°' ? 1 : c == '´' ? 2 : 3) * font->height;
       }
 
       if (print_inverse)       /* special mode for text gadgets */
       {
        /* first step: draw solid colored rectangle (use "cursor" character) */
-       BlitBitmap(font_bitmap, bitmap, FONT_CHARS_PER_LINE * font_width,
-                  3 * font_height + font_starty,
-                  font_width, font_height, x, y);
+       BlitBitmap(font->bitmap, dst_bitmap,
+                  font->src_x + FONT_CHARS_PER_LINE * font->width,
+                  font->src_y + 3 * font->height,
+                  font->width, font->height, dst_x, dst_y);
 
        /* second step: draw masked black rectangle (use "space" character) */
-       SetClipOrigin(font_bitmap, font_bitmap->stored_clip_gc,
-                     dest_x - src_x, dest_y - src_y);
-       BlitBitmapMasked(font_bitmap, bitmap,
-                        0, 0, font_width, font_height, dest_x, dest_y);
+       SetClipOrigin(font->bitmap, font->bitmap->stored_clip_gc,
+                     dst_x - src_x, dst_y - src_y);
+       BlitBitmapMasked(font->bitmap, dst_bitmap,
+                        0, 0, font->width, font->height, dst_x, dst_y);
       }
       else if (mask_mode == FONT_MASKED)
       {
        /* clear font character background */
-       ClearRectangleOnBackground(bitmap, dest_x, dest_y,
-                                  font_width, font_height);
+       ClearRectangleOnBackground(dst_bitmap, dst_x, dst_y,
+                                  font->width, font->height);
 
 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
-       /* use special font tile clipmasks, if available */
-       if (font_size == FS_BIG || font_size == FS_MEDIUM)
+       /* use special font tile clipmasks */
        {
-         int font_nr = (font_size == FS_BIG ? 0 : 1);
          int font_char = (c >= 32 && c <= 95 ? c - 32 : 0);
 
-         SetClipMask(font_bitmap, tile_clip_gc,
-                     tile_clipmask[font_nr][font_type][font_char]);
-         SetClipOrigin(font_bitmap, tile_clip_gc, dest_x, dest_y);
-       }
-       else
-       {
-         SetClipOrigin(font_bitmap, font_bitmap->stored_clip_gc,
-                       dest_x - src_x, dest_y - src_y);
+         SetClipMask(font->bitmap, font_clip_gc,
+                     font->clip_mask[font_char]);
+         SetClipOrigin(font->bitmap, font_clip_gc, dst_x, dst_y);
        }
 #else
-       SetClipOrigin(font_bitmap, font_bitmap->stored_clip_gc,
-                     dest_x - src_x, dest_y - src_y);
+       SetClipOrigin(font->bitmap, font->bitmap->stored_clip_gc,
+                     dst_x - src_x, dst_y - src_y);
 #endif
 
-       BlitBitmapMasked(font_bitmap, bitmap, src_x, src_y,
-                        font_width, font_height, dest_x, dest_y);
+       BlitBitmapMasked(font->bitmap, dst_bitmap, src_x, src_y,
+                        font->width, font->height, dst_x, dst_y);
       }
       else     /* normal, non-masked font blitting */
       {
-       BlitBitmap(font_bitmap, bitmap, src_x, src_y,
-                  font_width, font_height, dest_x, dest_y);
+       BlitBitmap(font->bitmap, dst_bitmap, src_x, src_y,
+                  font->width, font->height, dst_x, dst_y);
       }
     }
 
-    x += font_width;
+    dst_x += font->width;
   }
 }