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, 4 Nov 2002 12:26:16 -0800
Reply-to: rt@xxxxxxxxxxxxxx

Raimar Falke via RT wrote:
> On Mon, Nov 04, 2002 at 03:04:06AM -0800, Jason Short via RT wrote:
> 
>>Attached is an update of Vasco's patch for PNG under XAW.  See 
>>http://lists.complete.org/freeciv-dev@xxxxxxxxxxx/2001/10/msg00797.html.gz.
>>
>>I've added minimal autoconf support, but we will need real support 
>>before we go further.  A patch would be welcome.
>>
>>Now, this patch *replaces* XPM support with (limited) PNG support. 
>>There's nothing wrong with that (IMO), but it means when the patch is 
>>applied the xaw client will no longer be able to use XPMs.
> 
> 
> So what does Xaw+this patch support and what is missing? Do all images
> have to have the same palette (as mentioned before)?

Well, I can't answer this definitively; perhaps Vasco can.  I don't even 
know if PNG has the concept of the "same palette"; if all images use the 
same 32 colors it might all just work out.

I suspect that in Trident's case there will be no problem anyway - since 
trident uses so few colors.  For tilesets with more colors I don't know.

> Also the patch violates a lot of the coding style guide points.

Fixed; new patch attached.

jason

Index: client/gui-xaw/graphics.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-xaw/graphics.c,v
retrieving revision 1.39
diff -u -r1.39 graphics.c
--- client/gui-xaw/graphics.c   2002/08/07 11:21:43     1.39
+++ client/gui-xaw/graphics.c   2002/11/04 20:22:23
@@ -17,15 +17,13 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
+#include <limits.h>
 
 #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"
@@ -62,6 +60,7 @@
 Cursor nuke_cursor;
 Cursor patrol_cursor;
 
+static struct Sprite *ctor_sprite(Pixmap mypixmap, int width, int height);
 static struct Sprite *ctor_sprite_mask(Pixmap mypixmap, Pixmap mask, 
                                       int width, int height);
 
@@ -167,22 +166,27 @@
 struct Sprite *crop_sprite(struct Sprite *source,
                           int x, int y, int width, int height)
 {
-  GC plane_gc;
-  Pixmap mypixmap, mask;
+  Pixmap mypixmap;
 
   mypixmap = XCreatePixmap(display, root_window,
                           width, height, display_depth);
   XCopyArea(display, source->pixmap, mypixmap, civ_gc, 
            x, y, width, height, 0, 0);
-
-  mask = XCreatePixmap(display, root_window, width, height, 1);
 
-  plane_gc = XCreateGC(display, mask, 0, NULL);
-  XCopyArea(display, source->mask, mask, plane_gc, 
-           x, y, width, height, 0, 0);
-  XFreeGC(display, plane_gc);
-
-  return ctor_sprite_mask(mypixmap, mask, width, height);
+  if (source->has_mask) {
+    GC plane_gc;
+    Pixmap mask;
+
+    mask = XCreatePixmap(display, root_window, width, height, 1);
+
+    plane_gc = XCreateGC(display, mask, 0, NULL);
+    XCopyArea(display, source->mask, mask, plane_gc, 
+             x, y, width, height, 0, 0);
+    XFreeGC(display, plane_gc);
+    return ctor_sprite_mask(mypixmap, mask, width, height);
+  } else {
+    return ctor_sprite(mypixmap, width, height);
+  }
 }
 
 /***************************************************************************
@@ -257,7 +261,6 @@
   XFreePixmap(display, mask);
 }
 
-#ifdef UNUSED
 /***************************************************************************
 ...
 ***************************************************************************/
@@ -270,7 +273,6 @@
   mysprite->has_mask=0;
   return mysprite;
 }
-#endif
 
 /***************************************************************************
 ...
@@ -290,23 +292,7 @@
 
 
 
-#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.
 ***************************************************************************/
@@ -314,60 +300,231 @@
 {
   static char *ext[] =
   {
-    "xpm",
+    "png",
     NULL
   };
 
   return ext;
 }
 
+
+
 /***************************************************************************
 ...
 ***************************************************************************/
+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;
+}
+
+/***************************************************************************
+...
+***************************************************************************/
+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;
+
+  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);
+  }
 
-again:
+  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 {
+       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);
 }
 
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/04 20:22:31
@@ -351,6 +351,9 @@
     dnl Checks for X:
     AC_PATH_XTRA
 
+    # FIXME: check for libpng, and make sure we have libz
+    LDFLAGS="$LDFLAGS -lpng"
+
     dnl Determine the Xfuncproto control definitions:
     FC_CHECK_X_PROTO_DEFINE(FUNCPROTO)
     if test -n "$fc_x_proto_value"; then

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