1578 lines · 46.2 KB · C
RawDownload
/***********************************************************************\
*
* Level 9 interpreter
* Version 5.1
* Copyright (c) 1996-2011 Glen Summers and contributors.
* Contributions from David Kinder, Alan Staniforth, Simon Baldwin,
* Dieter Baron and Andreas Scherrer.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
*
\***********************************************************************/

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

#include "level9.h"

extern Bitmap* bitmap;

L9UINT32 filelength(FILE *f);
void L9Allocate(L9BYTE **ptr,L9UINT32 Size);

L9BOOL bitmap_exists(char* file)
{
	FILE* f = fopen(file,"rb");
	if (f != NULL)
	{
		fclose(f);
		return TRUE;
	}
	return FALSE;
}

L9BYTE* bitmap_load(char* file, L9UINT32* size)
{
	L9BYTE* data = NULL;
	FILE* f = fopen(file,"rb");
	if (f)
	{
		*size = filelength(f);
		L9Allocate(&data,*size);
		if (fread(data,1,*size,f) != *size)
		{
			free(data);
			data = NULL;
		}
		fclose(f);
	}
	return data;
}

Bitmap* bitmap_alloc(int x, int y)
{
	Bitmap* bitmap = NULL;
	L9Allocate((L9BYTE**)&bitmap,sizeof(Bitmap)+(x*y));

	bitmap->width = x;
	bitmap->height = y;
	bitmap->bitmap = ((L9BYTE*)bitmap)+sizeof(Bitmap);
	bitmap->npalette = 0;
	return bitmap;
}

/*
	A PC or ST palette colour is a sixteen bit value in which the low three nybbles
	hold the rgb colour values. The lowest nybble holds the blue value, the 
	second nybble the blue value and the third nybble the red value. (The high
	nybble is ignored). Within each nybble, only the low three bits are used
	IE the value can only be 0-7 not the full possible 0-15 and so the MSbit in
	each nybble is always 0.
*/
Colour bitmap_pcst_colour(int big, int small)
{
	Colour col;
	L9UINT32 r = big & 0xF;
	L9UINT32 g = (small >> 4) & 0xF;
	L9UINT32 b = small & 0xF;

	r *= 0x49; r >>= 1;
	g *= 0x49; g >>= 1;
	b *= 0x49; b >>= 1;

	col.red = (L9BYTE)(r&0xFF);
	col.green = (L9BYTE)(g&0xFF);
	col.blue = (L9BYTE)(b&0xFF);
	return col;
}

/*
	ST Bitmaps

	On the ST different graphics file formats were used for the early V4
	games (Knight Orc, Gnome Ranger) and the later V4 games (Lancelot,
	Ingrid's Back, Time & Magik and Scapeghost).
*/

/*
	Extracts the number of pixels requested from an eight-byte data block (4 bit-
	planes) passed to it.

	Note:	On entry each one of four pointers is set to point to the start of each
			bit-plane in the block. The function then indexes through each byte in
			each bit plane. and uses shift and mask operations to extract each four
			bit pixel into an L9PIXEL.

			The bit belonging to the pixel in the current byte of the current bit-
			plane is moved to its position in an eight-bit pixel. The byte is then
			masked by a value to select only that bit and added to the final pixel
			value.
*/
L9UINT32 bitmap_st1_decode_pixels(L9BYTE* bitmap, L9BYTE* data, L9UINT32 count, L9UINT32 pixels)
{
	L9UINT32 bitplane_length = count / 4; /* length of each bitplane */
	L9BYTE *bitplane0 = data; /* address of bit0 bitplane */
	L9BYTE *bitplane1 = data + (bitplane_length); /* address of bit1 bitplane */
	L9BYTE *bitplane2 = data + (bitplane_length * 2); /* address of bit2 bitplane */
	L9BYTE *bitplane3 = data + (bitplane_length * 3); /* address of bit3 bitplane */
	L9UINT32 bitplane_index, pixel_index = 0; /* index variables */

	for (bitplane_index = 0; bitplane_index < bitplane_length; bitplane_index++)
	{
		/* build the eight pixels from the current bitplane bytes, high bit to low */

		/* bit7 byte */
		bitmap[pixel_index] = ((bitplane3[bitplane_index] >> 4) & 0x08) 
			+ ((bitplane2[bitplane_index] >> 5) & 0x04)
			+ ((bitplane1[bitplane_index] >> 6) & 0x02) 
			+ ((bitplane0[bitplane_index] >> 7) & 0x01);
		if (pixels == ++pixel_index)
			break;

		/* bit6 byte */
		bitmap[pixel_index] = ((bitplane3[bitplane_index] >> 3) & 0x08) 
			+ ((bitplane2[bitplane_index] >> 4) & 0x04)
			+ ((bitplane1[bitplane_index] >> 5) & 0x02) 
			+ ((bitplane0[bitplane_index] >> 6) & 0x01);
		if (pixels == ++pixel_index)
			break;

		/* bit5 byte */
		bitmap[pixel_index] = ((bitplane3[bitplane_index] >> 2) & 0x08) 
			+ ((bitplane2[bitplane_index] >> 3) & 0x04)
			+ ((bitplane1[bitplane_index] >> 4) & 0x02) 
			+ ((bitplane0[bitplane_index] >> 5) & 0x01);
		if (pixels == ++pixel_index)
			break;

		/* bit4 byte */
		bitmap[pixel_index] = ((bitplane3[bitplane_index] >> 1) & 0x08) 
			+ ((bitplane2[bitplane_index] >> 2) & 0x04)
			+ ((bitplane1[bitplane_index] >> 3) & 0x02) 
			+ ((bitplane0[bitplane_index] >> 4) & 0x01);
		if (pixels == ++pixel_index)
			break;

		/* bit3 byte */
		bitmap[pixel_index] = ((bitplane3[bitplane_index]) & 0x08) 
			+ ((bitplane2[bitplane_index] >> 1) & 0x04)
			+ ((bitplane1[bitplane_index] >> 2) & 0x02) 
			+ ((bitplane0[bitplane_index] >> 3) & 0x01);
		if (pixels == ++pixel_index)
			break;

		/* bit2 byte */
		bitmap[pixel_index] = ((bitplane3[bitplane_index] << 1) & 0x08) 
			+ ((bitplane2[bitplane_index]) & 0x04)
			+ ((bitplane1[bitplane_index] >> 1) & 0x02) 
			+ ((bitplane0[bitplane_index] >> 2) & 0x01);
		if (pixels == ++pixel_index)
			break;

		/* bit1 byte */
		bitmap[pixel_index] = ((bitplane3[bitplane_index] << 2) & 0x08) 
			+ ((bitplane2[bitplane_index] << 1) & 0x04)
			+ ((bitplane1[bitplane_index]) & 0x02) 
			+ ((bitplane0[bitplane_index] >> 1) & 0x01);
		if (pixels == ++pixel_index)
			break;

		/* bit0 byte */
		bitmap[pixel_index] = ((bitplane3[bitplane_index] << 3) & 0x08) 
			+ ((bitplane2[bitplane_index] << 2) & 0x04)
			+ ((bitplane1[bitplane_index] << 1) & 0x02) 
			+ ((bitplane0[bitplane_index]) & 0x01);
		if (pixels == ++pixel_index)
			break;
	}

	return pixel_index;
}

/*
	The ST image file has the following format. It consists of a 44 byte header
	followed by the image data. 

	The header has the following format:
	Bytes 0-31:		sixteen entry ST palette
	Bytes 32-33:	padding
	Bytes 34-35:	big-endian word holding number of bitplanes needed to make
				up a row of pixels*
	Bytes 36-37:	padding
	Bytes 38-39:	big-endian word holding number of rows in the image*
	Bytes 40-41:	padding**
	Bytes 42-43:	mask for pixels to show in last 16 pixel block. Again, this 
				is big endian

	[*]		these are probably big-endian unsigned longs but I have designated
			the upper two bytes as padding because (a) Level 9 does not need
			them as longs and (b) using unsigned shorts reduces byte sex induced
			byte order juggling.
	[**]	not certain what this is for but I suspect that, like bytes 42-43
			it is a mask to indicate which pixels to show, in this case in the 
			first 16 pixel block 

	The image data is essentially a memory dump of the video RAM representing
	the image in lo-res mode. In lo-res mode each row is 320 pixels wide
	and each pixel can be any one of sixteen colours - needs 4 bits to store. 

	In the ST video memory (in lo-res mode which we are dealing with here)
	is organised as follows. The lowest point in memory in the frame buffer 
	represents the top-left of the screen, the highest the bottom-right. 
	Each row of pixels is stored in sequence. 

	Within each pixel row the pixels are stored as follows. Each row is
	divided into groups of 16 pixels. Each sixteen pixel group is stored
	in 8 bytes, logically four groups of two. Each two byte pair 
	is a bit-plane for that sixteen pixel group - that is it stores the
	same bit of each pixel in that group. The first two bytes store the 
	lowest bit, the second pair the second bit &c. 

	The word at bytes 34-35 of the header stores the number of bitplanes
	that make up each pixel row in the image. Multplying this number by
	four gives the number of pixels in the row***. For title and frame 
	images that will be 320, for sub-images it will be less. 

	[***]	Not always exactly. For GnomeRanger sub-images this value is 60 
			- implying there are 240 pixels per row. In fact there are only 
			225 pixels in each row. To identify this situation look at the 
			big-endian word in bytes 42-43 of the header. This is a mask 
			telling you the pixels to use. Each bit represents one pixel in 
			the block, with the MSBit representing the first pixel and the 
			LSbit the last.

			In this situation, the file does contain the entire sixteen
			pixel block (it has to with the bitplane arrangement) but
			the pixels which are not part of the image are just noise. When
			decoding the image, the L9BITMAP produced has the actual pixel 
			dimensions - the surplus pixels are discarded.

			I suspect, though I have not found an instance, that in theory
			the same situation could apply at the start of a pixel row and that
			in this case the big-endian word at bytes 40-41 is the mask.

	Having obtained the pixel dimensions of the image the function uses
	them to allocate memory for the bitmap and then extracts the pixel
	information from the bitmap row by row. For each row eight byte blocks
	are read from the image data and passed to UnpackSTv1Pixels along with
	the number of pixels to extract (usually 16, possibly less for the last
	block in a row.)
*/
L9BOOL bitmap_st1_decode(char* file, int x, int y)
{
	L9BYTE* data = NULL;
	int i, xi, yi, max_x, max_y, last_block;
	int bitplanes_row, bitmaps_row, pixel_count, get_pixels;

	L9UINT32 size;
	data = bitmap_load(file,&size);
	if (data == NULL)
		return FALSE;

	bitplanes_row = data[35]+data[34]*256;
	bitmaps_row = bitplanes_row/4;
	max_x = bitplanes_row*4;
	max_y = data[39]+data[38]*256;
	last_block = data[43]+data[42]*256;

	/* Check if sub-image with rows shorter than max_x */
	if (last_block != 0xFFFF)
	{
		/* use last_block to adjust max_x */
		int i = 0;
		while ((0x0001 & last_block) == 0) /* test for ls bit set */
		{
			last_block >>= 1; /* if not, shift right one bit */
			i++;
		}
		max_x = max_x - i;
	}

	if (max_x > MAX_BITMAP_WIDTH || max_y > MAX_BITMAP_HEIGHT)
	{
		free(data);
		return FALSE;
	}

	if ((x == 0) && (y == 0))
	{
		if (bitmap)
			free(bitmap);
		bitmap = bitmap_alloc(max_x,max_y);
	}
	if (bitmap == NULL)
	{
		free(data);
		return FALSE;
	}

	if (x+max_x > bitmap->width)
		max_x = bitmap->width-x;
	if (y+max_y > bitmap->height)
		max_y = bitmap->height-y;

	for (yi = 0; yi < max_y; yi++)
	{
		pixel_count = 0;
		for (xi = 0; xi < bitmaps_row; xi++)
		{
			if ((max_x - pixel_count) < 16)
				get_pixels = max_x - pixel_count;
			else
				get_pixels = 16;

			pixel_count += bitmap_st1_decode_pixels(
				bitmap->bitmap+((y+yi)*bitmap->width)+x+(xi*16),
				data+44+(yi*bitplanes_row*2)+(xi*8),8,get_pixels);
		}
	}

	bitmap->npalette = 16;
	for (i = 0; i < 16; i++)
		bitmap->palette[i] = bitmap_pcst_colour(data[(i*2)],data[1+(i*2)]);

	free(data);
	return TRUE;
}

void bitmap_st2_name(int num, char* dir, char* out)
{
	/* title picture is #30 */
	if (num == 0)
		num = 30;
	sprintf(out,"%s%d.squ",dir,num);
}

/*
	PC Bitmaps

	On the PC different graphics file formats were used for the early V4
	games (Knight Orc, Gnome Ranger) and the later V4 games (Lancelot,
	Ingrid's Back, Time & Magik and Scapeghost).

	The ST and the PC both use the same image file format for the later 
	V4 games (Lancelot, Ingrid's Back, Time & Magik and Scapeghost.)
*/

void bitmap_pc_name(int num, char* dir, char* out)
{
	/* title picture is #30 */
	if (num == 0)
		num = 30;
	sprintf(out,"%s%d.pic",dir,num);
}

/*
	The EGA standard for the IBM PCs and compatibles defines 64 colors, any
	16 of which can be mapped to the usable palette at any given time. If
	you display these 64 colors in numerical order, 16 at a time, you get a
	hodgepodge of colors in no logical order. The 64 EGA color numbers are
	assigned in a way that the numbers can easily be converted to a relative
	intensity of each of the three phosphor colors R,G,B. If the number is
	converted to six bit binary, the most significant three bits represent
	the 25% level of R,G,B in that order and the least significant three
	bits represent the 75% level of R,G,B in that order. Take EGA color 53
	for example. In binary, 53 is 110101. Since both R bits are on, R = 1.0.
	Of the G bits only the 25% bit is on so G = 0.25. Of the B bits only the
	75% bit is on so B = 0.75.
*/
Colour bitmap_pc1_colour(int i)
{
	Colour col;
	col.red = (((i&4)>>1) | ((i&0x20)>>5)) * 0x55;
	col.green = ((i&2) | ((i&0x10)>>4)) * 0x55;
	col.blue = (((i&1)<<1) | ((i&8)>>3)) * 0x55;
	return col;
}

/*
	The PC (v1) image file has the following format. It consists of a 22
	byte header organised like this: 

	Byte 0:     probably a file type flag
	Byte 1:     the MSB of the file's length as a word
	Bytes 2-3:  little-endian word with picture width in pixels
	Bytes 4-5:  little-endian word with picture height in pixel rows
	Bytes 6-21: the image colour table. One EGA colour in each byte

	The image data is extremely simple. The entire block is packed array
	of 4-bit pixels - IE each byte holds two pixels - the first in the high
	nybble, the second in the low. The pixel value is an index into the 
	image colour table. The pixels are organised with the top left first and 
	bottom left last, each row in turn.
*/
L9BOOL bitmap_pc1_decode(char* file, int x, int y)
{
	L9BYTE* data = NULL;
	int i, xi, yi, max_x, max_y;

	L9UINT32 size;
	data = bitmap_load(file,&size);
	if (data == NULL)
		return FALSE;

	max_x = data[2]+data[3]*256;
	max_y = data[4]+data[5]*256;
	if (max_x > MAX_BITMAP_WIDTH || max_y > MAX_BITMAP_HEIGHT)
	{
		free(data);
		return FALSE;
	}

	if ((x == 0) && (y == 0))
	{
		if (bitmap)
			free(bitmap);
		bitmap = bitmap_alloc(max_x,max_y);
	}
	if (bitmap == NULL)
	{
		free(data);
		return FALSE;
	}

	if (x+max_x > bitmap->width)
		max_x = bitmap->width-x;
	if (y+max_y > bitmap->height)
		max_y = bitmap->height-y;

	for (yi = 0; yi < max_y; yi++)
	{
		for (xi = 0; xi < max_x; xi++)
		{
			bitmap->bitmap[(bitmap->width*(y+yi))+(x+xi)] =
				(data[23+((yi*max_x)/2)+(xi/2)]>>((1-(xi&1))*4)) & 0x0f;
		}
	}

	bitmap->npalette = 16;
	for (i = 0; i < 16; i++)
		bitmap->palette[i] = bitmap_pc1_colour(data[6+i]);

	free(data);
	return TRUE;
}

/*
	The PC (v2) image file has the following format. It consists of a 44
	byte header followed by the image data. 

	The header has the following format:
	Bytes 0-1: "datalen": 	length of file -1 as a big-endian word*
	Bytes 2-3: "flagbyte1 & flagbyte2": unknown, possibly type identifiers. 
		Usually 0xFF or 0xFE followed by 0x84, 0x72, 0xFF, 0xFE or
		some other (of a fairly small range of possibles) byte.
	Bytes 4-35: "colour_index[]": sixteen entry palette. Basically an ST 
		palette (even if in a PC image file. Each entry is a sixteen
		bit value in which the low three nybbles hold the rgb colour
		values. The lowest nybble holds the blue value, the second
		nybble the blue value and the third nybble the red value. (The
		high nybble is ignored). Within each nybble, only the low
		three bits are used IE the value can only be 0-7 not the full
		possible 0-15 and so the MSbit in each nybble is always 0.**,
	Bytes 36-37: "width": image width in pixels as a big-endian word
	Bytes 38-39: "numrows": image height in pixel rows as a big-endian word
	Byte 40: "seedByte": seed byte to start picture decoding.
	Byte 41: "padByte": unknown. Possibly padding to word align the next 
		element?
	Bytes 42-297: "pixelTable": an array of 0x100 bytes used as a lookup table 
		for pixel values
	Bytes 298-313: "bitStripTable": an array of 0x10 bytes used as a lookup table 
		for the number of bytes to strip from the bit stream for the pixel being
		decoded
	Bytes 314-569:	"indexByteTable": an array of 0x100 bytes used as a lookup 
		table to index into bitStripTable and pixelTable****

	The encoded image data then follows ending in a 0x00 at the file length stored
	in the first two bytes of the file. there is then one extra byte holding a 

Lines 1–500 of 1578.