Complete.Org: Mailing Lists: Archives: freeciv-dev: February 2005:
[Freeciv-Dev] (PR#12108) generation of fog sprites
Home

[Freeciv-Dev] (PR#12108) generation of fog sprites

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] (PR#12108) generation of fog sprites
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Thu, 3 Feb 2005 23:37:26 -0800
Reply-to: bugs@xxxxxxxxxxx

<URL: http://bugs.freeciv.org/Ticket/Display.html?id=12108 >

Attached is:

- Code to generate civ3-style fog graphics.

- A set of civ3-style fog graphics at 64x32.

The fog graphics included with civ3 can't be used by freeciv (even with 
civ3gfx) because freeciv does not draw unknown tiles at all.  In these 
generated fog graphics the dark tiles are entirely covered by darkness.

Each sprite sits on top of the corner of 4 tiles.  Each of these 4 tiles 
may be known, fogged, or unknown.  Thus there are 3^4 = 81 combinations.

-jason

PNG image

/* By Jason Dorje Short.  Distributed under the GPL. */

/* Compile as
      gcc -Wall -g `pkg-config --cflags --libs gtk+-2.0` fog.c -o fog
 */

#include <assert.h>
#include <stdlib.h>

#include <gtk/gtk.h>

enum fogtype {
  UNKNOWN,
  FOG,
  KNOWN
};

int main(int argc, char **argv)
{
  GdkPixbuf *fog;
  int W, H, WH, i, j;
  char *filename;
  long long alpha_levels[3] = {255, 255 * 0.6, 0};

  /* This changes the ordering of the sprites so that it matches that in
   * civ3gfx. */
  const long long transform[4] = {0, 2, 1, 3};

  if (argc < 4) {
    printf("Usage: %s <width> <height> <output PNG>\n", argv[0]);
    printf("\n");
    printf("Give this program a tile size and filename and it will create\n");
    printf("a set of 81 known/fog/darkness sprites.  The ordering\n");
    printf("is the same as the ones used by civ3gfx; the utilities there\n");
    printf("can be used to generate a specfile.\n");
    exit(1);
  }

  W = atoi(argv[1]);
  H = atoi(argv[2]);
  WH = W * H;
  filename = argv[3];

  printf("Converting %d x %d sprites in %s.\n", W, H, filename);

  gtk_init(&argc, &argv);

  fog = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, W * 9, H * 9);

  for (i = 0; i < 81; i++) {
    enum fogtype values[4];
    int k = i, x, y;
    const int x0 = (i % 9) * W;
    const int y0 = (i / 9) * H;
    const int NUM = 2;
    long long alpha_points[NUM + 1][NUM + 1];
#define idx(x, y) (transform[(x) + (y) * 2])
#define value(x, y) (values[idx((x), (y))])
#define level(x, y) (alpha_levels[value((x), (y))])

    for (j = 0; j < 4; j++) {
      values[j] = k % 3;
      k /= 3;
    }
    assert(k == 0);

    /*

    Our transformed tile gets 9 vertices:

    X  X  X
    
    X  X  X
    
    X  X  X
    
    Each corner vertex takes an alpha value based on the tile that it covers.
    Each center vertex gets an alpha value that is the MAX of all the tiles
    that it touches.  We have to use MAX because unknown tiles must be
    entirely covered by 100% alpha.  Probably for fog-known borders we
    shouldn't use MAX here but should use the average instead.

    Then an interior pixel gets an alpha value that's the weighted average
    of the 4 nearest vertices.
    */
    alpha_points[0][0] = level(0, 0);
    alpha_points[2][0] = level(1, 0);
    alpha_points[0][2] = level(0, 1);
    alpha_points[2][2] = level(1, 1);

    alpha_points[1][0] = MAX(level(0, 0), level(1, 0));
    alpha_points[0][1] = MAX(level(0, 0), level(0, 1));
    alpha_points[1][2] = MAX(level(0, 1), level(1, 1));
    alpha_points[2][1] = MAX(level(1, 0), level(1, 1));

    alpha_points[1][1] = MAX(MAX(level(0, 0), level(0, 1)),
                             MAX(level(1, 0), level(1, 1)));

    for (x = 0; x < W; x++) {
      for (y = 0; y < H; y++) {
        const long long tx = x - W / 2;
        const long long ty = y;

        /* Transformed X/Y values. */
        const long long mx = tx * H + ty * W;
        const long long my = ty * W - tx * H;

        /* Pixbuf X/Y values. */
        const int px = x + x0;
        const int py = y + y0;
        guchar *pixel = gdk_pixbuf_get_pixels(fog)
          + py * gdk_pixbuf_get_rowstride(fog)
          + px * gdk_pixbuf_get_n_channels(fog);

        //      int idx;
        long long alpha;

        const long WHN = WH / NUM;
        const long long idx_x = mx / WHN, idx_y = my / WHN;
        const long long fx = mx - idx_x * WHN;
        const long long fy = my - idx_y * WHN;

        pixel[0] = pixel[1] = pixel[2] = 0;

        if (mx < 0 || my < 0 || mx >= W * H || my >= W * H) {
          pixel[3] = 0;
          continue;
        }

        assert(idx_x >= 0 && idx_x < NUM);
        assert(idx_y >= 0 && idx_y < NUM);
        assert(fx >= 0 && fx < WHN);
        assert(fy >= 0 && fy < WHN);

        alpha = (alpha_points[idx_x][idx_y] * (WHN - fx) * (WHN - fy)
                 + alpha_points[idx_x + 1][idx_y] * fx * (WHN - fy)
                 + alpha_points[idx_x][idx_y + 1] * (WHN - fx) * fy
                 + alpha_points[idx_x + 1][idx_y + 1] * fx * fy) / (WHN * WHN);
        assert(alpha >= 0 && alpha < 256);
        pixel[3] = alpha;
      }
    }
  }

  

  gdk_pixbuf_save(fog, filename, "png", NULL, NULL);
  return 0;
}

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