Miscellaneous Ramblings
-----------------------

Instead of duplicating data for each sprite from a global image as in
wmfishtime, we create a pointer in the sprite structure to individual images.
This allows more efficient use of memory.

The sprites are vertically stacked frames with the number of frames added to
the source. These were created in the the Gimp (well, the ufo was an animated
gif borrowed from a freebie site).

The RGBA sprites were transparent and saved as "C-source" files.
The CMAP sprites were indexed and saved as "Header" files.

Note that the CMAP sprites require the transparent background to be the first
value, eg 0 in the data which matches the first value in the colour map. I
used pure blue {  0,  0,255} in the source data which wasn't present in the
sprites.

The files created were modified, but contain the same basic data.

Note that the sprite routines are not complete. I have only included what I
required for wmufo; the colour mapped sprites do not include alpha-blending
and the rgba could handle rgb sprites alpha-blended or not. The following is
what I might use.

For rgb sprites (not rgba) there is no transparent background checking. You
could use a default colour but you would need to check every pixel for a
match - wasting cpu. Use rgb for small rectangles where it is less efficient
to use cmap sprites.

static void
draw_sprite_cmap(int x, int y, int f, sprite_cmap sp, int a)
{
	/* Sprite height */
	int sh = sp.h / sp.f;
	/* Bounding box of the clipped sprite */
	int dw, di, dh, ds;
	/* Loop counters */
	int w, h;
	/* Position in sprite data */
	int ps_sp_init;
	/* Postion in rgb buffer */
	int ps_bf_curr, ps_bf_row;
	/* Colour map reference */
	unsigned int c;

	/* Off screen */
	if ((y < -(sh)) || (y > YMAX) || (x > XMAX) || (x < -((int) sp.w)))
		return;

	/* Invalid frame */
	if (f >= sp.f)
		return;

	/* Clip top */
	ds = 0;
	if (y < 0)
		ds = -(y);

	/* Clip bottom */
	dh = sh;
	if ((y + sh) > YMAX)
		dh = YMAX - y;

	/* Clip right */
	dw = (int) sp.w;
	if (x > (XMAX - (int) sp.w))
		dw = XMAX - x;

	/* Clip left */
	di = 0;
	if (x < 0)
		di = -(x);

	/* Offset to current sprite frame */
	ps_sp_init = f * sh * (int) sp.w;

	/* Optimise if no alpha-blend */
	if (a) {
		for (h = ds; h < dh; h++) {
			/* Offset to beginning of current row */
			ps_bf_row = (h + y) * XMAX;
			for (w = di; w < dw; w++) {
				/* Background is transparent - skip */
				if ((c = 3 * sp.data[ps_sp_init + h * (int) sp.w + w]) != 0) {
					ps_bf_curr = (ps_bf_row + x + w) * 3;

					bm.rgb[ps_bf_curr] = (a * sp.cmap[c] + (256 - a) * bm.rgb[ps_bf_curr]) >> 8;
					bm.rgb[++ps_bf_curr] = (a * sp.cmap[c + 1] + (256 - a) * bm.rgb[ps_bf_curr]) >> 8;
					bm.rgb[++ps_bf_curr] = (a *sp.cmap[c + 2] + (256 - a) * bm.rgb[ps_bf_curr]) >> 8;
				}
			}
		}
	} else {
		for (h = ds; h < dh; h++) {
			/* Offset to beginning of current row */
			ps_bf_row = (h + y) * XMAX;
			for (w = di; w < dw; w++) {
				/* Background is transparent - skip */
				if ((c = 3 * sp.data[ps_sp_init + h * (int) sp.w + w]) != 0) {
					ps_bf_curr = (ps_bf_row + x + w) * 3;

					bm.rgb[ps_bf_curr] = sp.cmap[c];
					bm.rgb[++ps_bf_curr] = sp.cmap[c + 1];
					bm.rgb[++ps_bf_curr] = sp.cmap[c + 2];
			}
		}
	}
}

static void
draw_sprite_rgba(int x, int y, int f, sprite_rgba sp, int a)
{
	/* Sprite height */
	int sh = sp.h / sp.f;
	/* Bounding box of clipped sprite */
	int dw, di, dh, ds;
	/* Loop counters */
	int w, h;
	/* Postion in sprite data */
	int ps_sp_init, ps_sp_curr;
	/* Positon in rgb buffer */
	int ps_bf_row, ps_bf_curr;
	/* Alpha value */
	unsigned char a;

	/* Off screen */
	if ((y < -(sh)) || (y > YMAX) || (x > XMAX) || (x < -((int) sp.w)))
		return;

	/* Invalid frame */
	if (f >= sp.f)
		return;

	/* Clip top */
	ds = 0;
	if (y < 0)
		ds = -(y);

	/* Clip bottom */
	dh = sh;
	if ((y + sh) > YMAX)
		dh = YMAX - y;

	/* Clip right */
	dw = (int) sp.w;
	if (x > (XMAX - (int) sp.w))
		dw = XMAX - x;

	/* Clip left */
	di = 0;
	if (x < 0)
		di = -(x);

	/* Offset to current sprite frame */
	ps_sp_init = f * sh * (int) sp.w * (int) sp.b;

	/* Optimise for rgba, rgb, or rgb with alpha */
	if (sp.b = 4) {
		for (h = ds; h < dh; h++) {
			/* Offset to beginning of current row */
			ps_bf_row = (h + y) * XMAX;
			for (w = di; w < dw; w++) {
				ps_sp_curr = ps_sp_init + (h * (int) sp.w + w) * (int) sp.b;
				/* Alpha is fully transparent - skip */
				if ((a = sp.data[ps_sp_curr + 3]) != 0) {
					ps_bf_curr = (ps_bf_row + x + w) * 3;

					bm.rgb[ps_bf_curr] = (a * sp.data[ps_sp_curr] + (256 - a) * bm.rgb[ps_bf_curr]) >> 8;
					bm.rgb[++ps_bf_curr] = (a * sp.data[ps_sp_curr + 1] + (256 - a) * bm.rgb[ps_bf_curr]) >> 8;
					bm.rgb[++ps_bf_curr] = (a * sp.data[ps_sp_curr + 2] + (256 - a) * bm.rgb[ps_bf_curr]) >> 8;
				}
			}
		}
	} else if (sp.b = 3) {
		if (a) {
			for (h = ds; h < dh; h++) {
				/* Offset to beginning of current row */
				ps_bf_row = (h + y) * XMAX;
				for (w = di; w < dw; w++) {
					ps_sp_curr = ps_sp_init + (h * (int) sp.w + w) * (int) sp.b;
					ps_bf_curr = (ps_bf_row + x + w) * 3;

					bm.rgb[ps_bf_curr] = (a * sp.data[ps_sp_curr] + (256 - a) * bm.rgb[ps_bf_curr]) >> 8;
					bm.rgb[++ps_bf_curr] = (a * sp.data[ps_sp_curr + 1] + (256 - a) * bm.rgb[ps_bf_curr]) >> 8;
					bm.rgb[++ps_bf_curr] = (a * sp.data[ps_sp_curr + 2] + (256 - a) * bm.rgb[ps_bf_curr]) >> 8;
					}
				}
			}
		} else {
			for (h = ds; h < dh; h++) {
				/* Offset to beginning of current row */
				ps_bf_row = (h + y) * XMAX;
				for (w = di; w < dw; w++) {
					ps_sp_curr = ps_sp_init + (h * (int) sp.w + w) * (int) sp.b;
					ps_bf_curr = (ps_bf_row + x + w) * 3;

					memcpy(&bm.rgb[ps_bf_curr], &sp.data[ps_sp_curr], 3);
					}
				}
			}
		}
	}
}
