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: Fri, 4 Feb 2005 09:47:56 -0800
Reply-to: bugs@xxxxxxxxxxx

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

Here is a new version.  This one can make non-iso fog too.

-jason

/* 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>

/* Alpha levels. */
#define A_UNKNOWN 255
#define A_FOG 255 * 0.45
#define A_KNOWN 0

enum fogtype {
  UNKNOWN,
  FOG,
  KNOWN
};

const long long mmax(long long a, long long b)
{
  if (a == A_UNKNOWN || b == A_UNKNOWN) {
    return A_UNKNOWN;
  }

  return (a + b + 1) / 2;
}

int main(int argc, char **argv)
{
  GdkPixbuf *fog;
  int W, H, WH, i, j;
  char *filename;
  long long alpha_levels[3] = {A_UNKNOWN, A_FOG, A_KNOWN};
  int iso;

  /* 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);

  if (W != H) {
    iso = 1;
    assert(W == 2 * H);
  } else {
    iso = 0;
  }

  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] = mmax(level(0, 0), level(1, 0));
    alpha_points[0][1] = mmax(level(0, 0), level(0, 1));
    alpha_points[1][2] = mmax(level(0, 1), level(1, 1));
    alpha_points[2][1] = mmax(level(1, 0), level(1, 1));

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

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

        /* Transformed X/Y values. */
        const long long mx = iso ? (tx * H + ty * W) : tx * H;
        const long long my = iso ? (ty * W - tx * H) : ty * W;

        /* 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]