Complete.Org: Mailing Lists: Archives: freeciv-dev: November 2002:
[Freeciv-Dev] Re: (PR#2269) PNG for freeciv
Home

[Freeciv-Dev] Re: (PR#2269) PNG for freeciv

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Cc: freeciv-dev@xxxxxxxxxxx
Subject: [Freeciv-Dev] Re: (PR#2269) PNG for freeciv
From: "Jason Short via RT" <rt@xxxxxxxxxxxxxx>
Date: Mon, 11 Nov 2002 17:07:57 -0800
Reply-to: rt@xxxxxxxxxxxxxx

Attached is another update of Vasco's PNG for XAW patch.

Changes:

- Updated to current CVS (i.e., split from the parts that were already 
applied).
- A couple of comments.
- A couple more fixed style points.
- Autoconf support.

Per (or some autoconf person), could you look over the 
configure.in/configure.ac changes?

Anyone using XAW, please test it out.

If there are no problems, it should be ready to go in later this week.

jason

Index: configure.ac
===================================================================
RCS file: /home/freeciv/CVS/freeciv/configure.ac,v
retrieving revision 1.23
diff -u -r1.23 configure.ac
--- configure.ac        2002/10/11 23:45:46     1.23
+++ configure.ac        2002/11/12 01:03:06
@@ -361,6 +361,16 @@
       AC_DEFINE_UNQUOTED(NARROWPROTO, $fc_x_proto_value, [Narrowproto])
     fi
 
+    dnl Check for libpng
+    AC_CHECK_LIB(png, png_read_image, [X_LIBS="$X_LIBS -lpng"],
+       AC_MSG_ERROR([Could not find PNG library (libpng).]))
+    AC_CHECK_HEADER(png.h, ,
+       AC_MSG_ERROR([libpng found but not png.h.
+You may need to install a libpng \"development\" package.]))
+
+    dnl Force check for zlib (needed for PNG loading)
+    WITH_ZLIB="yes"
+
     dnl Try to get additional Xpm paths:
     FC_XPM_PATHS
 
@@ -524,10 +534,10 @@
 dnl contain their own libz which may be too old a version to have gzgets().
 if test "$WITH_ZLIB" = "yes"; then
     AC_CHECK_LIB(z, gzgets, , 
-        AC_MSG_ERROR([Specified --with-zlib but did not find zlib library.]), 
+        AC_MSG_ERROR([Could not find zlib library.]), 
         $CLIENT_LIBS)
     AC_CHECK_HEADER(zlib.h, , 
-        AC_MSG_ERROR([Specified --with-zlib; zlib found but not zlib.h.  
+        AC_MSG_ERROR([zlib found but not zlib.h.  
 You may need to install a zlib \"development\" package.]))
 
 elif test "$WITH_ZLIB" = "maybe"; then
Index: configure.in
===================================================================
RCS file: /home/freeciv/CVS/freeciv/configure.in,v
retrieving revision 1.202
diff -u -r1.202 configure.in
--- configure.in        2002/10/11 23:45:46     1.202
+++ configure.in        2002/11/12 01:03:06
@@ -355,6 +355,16 @@
       AC_DEFINE_UNQUOTED(NARROWPROTO, $fc_x_proto_value)
     fi
 
+    dnl Check for libpng
+    AC_CHECK_LIB(png, png_create_read_struct, [X_LIBS="$X_LIBS -lpng"],
+       AC_MSG_ERROR([Could not find PNG library (libpng).]))
+    AC_CHECK_HEADER(png.h, ,
+       AC_MSG_ERROR([libpng found but not png.h.
+You may need to install a libpng \"development\" package.]))
+
+    dnl Force check for zlib (needed for PNG loading)
+    WITH_ZLIB="yes"
+
     dnl Try to get additional Xpm paths:
     FC_XPM_PATHS
 
@@ -518,10 +528,10 @@
 dnl contain their own libz which may be too old a version to have gzgets().
 if test "$WITH_ZLIB" = "yes"; then
     AC_CHECK_LIB(z, gzgets, , 
-        AC_MSG_ERROR([Specified --with-zlib but did not find zlib library.]), 
+        AC_MSG_ERROR([Could not find zlib library.]), 
         $CLIENT_LIBS)
     AC_CHECK_HEADER(zlib.h, , 
-        AC_MSG_ERROR([Specified --with-zlib; zlib found but not zlib.h.  
+        AC_MSG_ERROR([zlib found but not zlib.h.  
 You may need to install a zlib \"development\" package.]))
 
 elif test "$WITH_ZLIB" = "maybe"; then
Index: client/gui-xaw/graphics.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-xaw/graphics.c,v
retrieving revision 1.42
diff -u -r1.42 graphics.c
--- client/gui-xaw/graphics.c   2002/11/07 19:36:28     1.42
+++ client/gui-xaw/graphics.c   2002/11/12 01:03:07
@@ -14,6 +14,8 @@
 #include <config.h>
 #endif
 
+#include <ctype.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -21,11 +23,7 @@
 #include <X11/Xlib.h>
 #include <X11/Intrinsic.h>
 
-#ifdef XPM_H_NO_X11
-#include <xpm.h>
-#else
-#include <X11/xpm.h>
-#endif
+#include <png.h>
 
 #include "fcintl.h"
 #include "game.h"
@@ -292,25 +290,7 @@
   return mysprite;
 }
 
-
-
-#ifdef UNUSED
 /***************************************************************************
-...
-***************************************************************************/
-void dtor_sprite(struct Sprite *mysprite)
-{
-  XFreePixmap(display, mysprite->pixmap);
-  if(mysprite->has_mask)
-    XFreePixmap(display, mysprite->mask);
-  free_colors(mysprite->pcolorarray, mysprite->ncols);
-  free(mysprite->pcolorarray);
-  free(mysprite);
-
-}
-#endif
-
-/***************************************************************************
  Returns the filename extensions the client supports
  Order is important.
 ***************************************************************************/
@@ -318,7 +298,7 @@
 {
   static const char *ext[] =
   {
-    "xpm",
+    "png",
     NULL
   };
 
@@ -326,52 +306,224 @@
 }
 
 /***************************************************************************
+  Return true iff the given pixel is transparent.  The 'trans' and
+  'ntrans' parameters provide an array of transparent colors.
+***************************************************************************/
+static bool is_transparent(png_byte index, png_bytep trans, int ntrans)
+{
+  int i;
+
+  for (i = 0; i < ntrans; i++) {
+    if (index == trans[i]) {
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+/***************************************************************************
+  Converts an image to a pixmap...
+***************************************************************************/
+static Pixmap image2pixmap(XImage *xi)
+{
+  Pixmap ret;
+  XGCValues values;
+  GC gc;
+  
+  ret = XCreatePixmap(display, root_window,
+                     xi->width, xi->height, xi->depth);
+
+  values.foreground = 1;
+  values.background = 0;
+  gc = XCreateGC(display, ret, GCForeground | GCBackground, &values);
+
+  XPutImage(display, ret, gc, xi, 0, 0, 0, 0, xi->width, xi->height);
+  XFreeGC(display, gc);
+  return ret;
+}
+
+/***************************************************************************
 ...
 ***************************************************************************/
 struct Sprite *load_gfxfile(const char *filename)
 {
+  png_structp pngp;
+  png_infop infop;
+  png_uint_32 sig_read = 0;
+  png_int_32 width, height, row, col;
+  int bit_depth, color_type, interlace_type;
+  FILE *fp;
+  int npalette, ntrans;
+  png_colorp palette;
+  png_bytep trans;
+  unsigned long *pcolorarray;
+  png_bytep *row_pointers;
   struct Sprite *mysprite;
-  Pixmap mypixmap, mask_bitmap;
-  int err;
-  XpmAttributes attributes;
-  
-  attributes.extensions = NULL;
-  attributes.valuemask = XpmCloseness|XpmColormap;
-  attributes.colormap = cmap;
-  attributes.closeness = 40000;
+  XImage *xi;
+  int has_mask;
 
-again:
+  fp = fopen(filename, "rb");
+  if (!fp) {
+    freelog(LOG_FATAL, _("Failed reading PNG file: %s"), filename);
+    exit(EXIT_FAILURE);
+  }
+
+  pngp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+  if (!pngp) {
+    freelog(LOG_FATAL, _("Failed creating PNG struct"));
+    exit(EXIT_FAILURE);
+  }
+
+  infop = png_create_info_struct(pngp);
+  if (!infop) {
+    freelog(LOG_FATAL, _("Failed creating PNG struct"));
+    exit(EXIT_FAILURE);
+  }
   
-  if((err=XpmReadFileToPixmap(display, root_window, (char*)filename, 
&mypixmap, 
-                             &mask_bitmap, &attributes))!=XpmSuccess) {
-    if(err==XpmColorError || err==XpmColorFailed) {
-      color_error();
-      goto again;
+  if (setjmp(pngp->jmpbuf)) {
+    freelog(LOG_FATAL, _("Failed while reading PNG file: %s"), filename);
+    exit(EXIT_FAILURE);
+  }
+
+  png_init_io(pngp, fp);
+  png_set_sig_bytes(pngp, sig_read);
+
+  png_read_info(pngp, infop);
+  png_get_IHDR(pngp, infop, &width, &height, &bit_depth, &color_type,
+              &interlace_type, NULL, NULL);
+
+  png_set_strip_16(pngp);
+  png_set_packing(pngp);
+
+  if (png_get_PLTE(pngp, infop, &palette, &npalette)) {
+    int i;
+
+    pcolorarray = fc_malloc(npalette * sizeof(unsigned long));
+
+    for (i = 0; i < npalette; i++) {
+      XColor mycolor;
+
+      mycolor.red  = palette[i].red << 8;
+      mycolor.green = palette[i].green << 8;
+      mycolor.blue = palette[i].blue << 8;
+
+      if (XAllocColor(display, cmap, &mycolor)) {
+       pcolorarray[i] = mycolor.pixel;
+      } else {
+       /* We're out of colors.  For the rest of the palette, just
+          find the closes match and use it. */
+       XColor *cols;
+       int ncols, j;
+
+       ncols = DefaultVisual(display, screen_number)->map_entries;
+       cols = fc_malloc(sizeof(XColor) * ncols);
+
+       for (j = 0; j < ncols; j++) {
+         cols[j].pixel = j;
+       }
+       XQueryColors(display, cmap, cols, ncols);
+
+       for (; i < npalette; i++) {
+         int best = INT_MAX;
+         unsigned long pixel=0;
+
+         for (j = 0; j < ncols; j++) {
+           int rd, gd, bd, dist;
+           
+           rd = (cols[j].red  >> 8) - palette[i].red;
+           gd = (cols[j].green >> 8) - palette[i].green;
+           bd = (cols[j].blue >> 8) - palette[i].blue;
+           dist = rd * rd + gd * gd + bd * bd;
+           
+           if (dist < best) {
+             best = dist;
+             pixel = j;
+           }
+         }
+         pcolorarray[i] = pixel;
+       }
+       free(cols);
+       break;
+      }
     }
-    freelog(LOG_FATAL, _("Failed reading XPM file: %s"), filename);
+  } else {
+    freelog(LOG_FATAL, _("PNG file has no palette: %s"), filename);
     exit(EXIT_FAILURE);
   }
 
+  png_read_update_info(pngp, infop);
+  has_mask = png_get_tRNS(pngp, infop, &trans, &ntrans, NULL);
+
+  row_pointers = fc_malloc(sizeof(png_bytep) * height);
+
+  for (row = 0; row < height; row++) {
+    row_pointers[row] = fc_malloc(png_get_rowbytes(pngp, infop));
+  }
+
+  png_read_image(pngp, row_pointers);
+  png_read_end(pngp, infop);
+  fclose(fp);
+
   mysprite=fc_malloc(sizeof(struct Sprite));
+  mysprite->pixmap = 0;
+  mysprite->mask = 0;
   
-  mysprite->pixmap=mypixmap;
-  mysprite->mask=mask_bitmap;
-  mysprite->has_mask=(mask_bitmap!=0);
-  mysprite->width=attributes.width;
-  mysprite->height=attributes.height;
+  xi = XCreateImage(display, DefaultVisual(display, screen_number),
+                   display_depth, ZPixmap, 0, NULL, width, height, 32, 0);
+  xi->data = fc_calloc(xi->bytes_per_line * xi->height, 1);
+
+  for (row = 0; row < height; row++) {
+    for (col = 0; col < width; col++) {
+      XPutPixel(xi, col, row, pcolorarray[row_pointers[row][col]]);
+    }
+  }
+  mysprite->pixmap = image2pixmap(xi);
+  XDestroyImage(xi);
+
+  if (has_mask) {
+    XImage *xm;
 
+    xm = XCreateImage(display, DefaultVisual(display, screen_number),
+                     1, XYBitmap, 0, NULL, width, height, 8, 0);
+    xm->data = fc_calloc(xm->bytes_per_line * xm->height, 1);
+
+    for (row = 0; row < height; row++) {
+      for (col = 0; col < width; col++) {
+       XPutPixel(xm, col, row,
+                 !is_transparent(row_pointers[row][col], trans, ntrans));
+      }
+    }
+    mysprite->mask = image2pixmap(xm);
+    XDestroyImage(xm);
+  }
+
+  mysprite->has_mask = has_mask;
+  mysprite->width = width;
+  mysprite->height = height;
+  mysprite->pcolorarray = pcolorarray;
+  mysprite->ncols = npalette;
+
+  for (row = 0; row < height; row++) {
+    free(row_pointers[row]);
+  }
+  free(row_pointers);
+  png_destroy_read_struct(&pngp, &infop, NULL);
   return mysprite;
 }
 
 /***************************************************************************
    Deletes a sprite.  These things can use a lot of memory.
-   
-   (How/why does this differ from dtor_sprite() ?  --dwp)
 ***************************************************************************/
 void free_sprite(struct Sprite *s)
 {
-  if(s->pixmap) XFreePixmap(display,s->pixmap);
-  if(s->has_mask) XFreePixmap(display,s->mask);
+  XFreePixmap(display, s->pixmap);
+  if (s->has_mask) {
+    XFreePixmap(display, s->mask);
+  }
+#if 0
+  free_colors(s->pcolorarray, s->ncols);
+#endif
+  free(s->pcolorarray);
   free(s);
 }
 

[Prev in Thread] Current Thread [Next in Thread]