eobish

changeset 4:ce0548d24918

mostly works
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 18 Jan 2015 13:30:30 +0200
parents e32bdd5fb622
children 0baf4e98315e
files src/fblib.c src/fblib.h src/fblibimp.h src/fblibsdl.c src/image.c src/image.h src/level.c src/level.h src/main.c src/player.c src/player.h src/rend.c src/rend.h src/tileset.c src/tileset.h
diffstat 15 files changed, 1032 insertions(+), 21 deletions(-) [+]
line diff
     1.1 --- a/src/fblib.c	Sun Jan 18 05:51:51 2015 +0200
     1.2 +++ b/src/fblib.c	Sun Jan 18 13:30:30 2015 +0200
     1.3 @@ -29,19 +29,19 @@
     1.4  	return 0;
     1.5  }
     1.6  
     1.7 -void fb_keyboard_callback(void (*func)(int, int, void*), void *cls)
     1.8 +void fb_keyboard_callback(int (*func)(int, int, void*), void *cls)
     1.9  {
    1.10  	fb_cb.keyb = func;
    1.11  	fb_cb.keyb_data = cls;
    1.12  }
    1.13  
    1.14 -void fb_mouse_button_callback(void (*func)(int, int, int, int, void*), void *cls)
    1.15 +void fb_mouse_button_callback(int (*func)(int, int, int, int, void*), void *cls)
    1.16  {
    1.17  	fb_cb.button = func;
    1.18  	fb_cb.button_data = cls;
    1.19  }
    1.20  
    1.21 -void fb_mouse_motion_callback(void (*func)(int, int, void*), void *cls)
    1.22 +void fb_mouse_motion_callback(int (*func)(int, int, void*), void *cls)
    1.23  {
    1.24  	fb_cb.motion = func;
    1.25  	fb_cb.motion_data = cls;
     2.1 --- a/src/fblib.h	Sun Jan 18 05:51:51 2015 +0200
     2.2 +++ b/src/fblib.h	Sun Jan 18 13:30:30 2015 +0200
     2.3 @@ -30,9 +30,9 @@
     2.4  int fb_key_state(int key);
     2.5  int fb_mouse_state(int bn, int *x, int *y);
     2.6  
     2.7 -void fb_keyboard_callback(void (*func)(int, int, void*), void *cls);
     2.8 -void fb_mouse_button_callback(void (*func)(int, int, int, int, void*), void *cls);
     2.9 -void fb_mouse_motion_callback(void (*func)(int, int, void*), void *cls);
    2.10 +void fb_keyboard_callback(int (*func)(int, int, void*), void *cls);
    2.11 +void fb_mouse_button_callback(int (*func)(int, int, int, int, void*), void *cls);
    2.12 +void fb_mouse_motion_callback(int (*func)(int, int, void*), void *cls);
    2.13  
    2.14  int fb_process_events(void);
    2.15  
     3.1 --- a/src/fblibimp.h	Sun Jan 18 05:51:51 2015 +0200
     3.2 +++ b/src/fblibimp.h	Sun Jan 18 13:30:30 2015 +0200
     3.3 @@ -4,9 +4,9 @@
     3.4  #include "fblib.h"
     3.5  
     3.6  struct callbacks {
     3.7 -	void (*keyb)(int, int, void*);
     3.8 -	void (*button)(int, int, int, int, void*);
     3.9 -	void (*motion)(int, int, void*);
    3.10 +	int (*keyb)(int, int, void*);
    3.11 +	int (*button)(int, int, int, int, void*);
    3.12 +	int (*motion)(int, int, void*);
    3.13  
    3.14  	void *keyb_data, *button_data, *motion_data;
    3.15  } fb_cb;
     4.1 --- a/src/fblibsdl.c	Sun Jan 18 05:51:51 2015 +0200
     4.2 +++ b/src/fblibsdl.c	Sun Jan 18 13:30:30 2015 +0200
     4.3 @@ -155,7 +155,9 @@
     4.4  					fb_inp.key[key] = state;
     4.5  				}
     4.6  				if(fb_cb.keyb) {
     4.7 -					fb_cb.keyb(key, state, fb_cb.keyb_data);
     4.8 +					if(fb_cb.keyb(key, state, fb_cb.keyb_data) == -1) {
     4.9 +						return -1;
    4.10 +					}
    4.11  				} else {
    4.12  					if(key == SDLK_ESCAPE) {
    4.13  						return -1;
    4.14 @@ -173,7 +175,9 @@
    4.15  				fb_inp.mbutton[ev.button.which] = state;
    4.16  
    4.17  				if(fb_cb.button) {
    4.18 -					fb_cb.button(ev.button.which, state, fb_inp.mx, fb_inp.my, fb_cb.button_data);
    4.19 +					if(fb_cb.button(ev.button.which, state, fb_inp.mx, fb_inp.my, fb_cb.button_data) == -1) {
    4.20 +						return -1;
    4.21 +					}
    4.22  				}
    4.23  			}
    4.24  			break;
    4.25 @@ -182,7 +186,9 @@
    4.26  			fb_inp.mx = ev.motion.x / scale;
    4.27  			fb_inp.my = ev.motion.y / scale;
    4.28  			if(fb_cb.motion) {
    4.29 -				fb_cb.motion(fb_inp.mx, fb_inp.my, fb_cb.motion_data);
    4.30 +				if(fb_cb.motion(fb_inp.mx, fb_inp.my, fb_cb.motion_data) == -1) {
    4.31 +					return -1;
    4.32 +				}
    4.33  			}
    4.34  			break;
    4.35  		}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/image.c	Sun Jan 18 13:30:30 2015 +0200
     5.3 @@ -0,0 +1,138 @@
     5.4 +#include <stdio.h>
     5.5 +#include <stdlib.h>
     5.6 +#include <string.h>
     5.7 +#include <errno.h>
     5.8 +#include "image.h"
     5.9 +
    5.10 +#define LOADFAIL(f, m)	fprintf(stderr, "failed to load image: %s: %s\n", f, m)
    5.11 +
    5.12 +int load_image(struct image *img, const char *fname)
    5.13 +{
    5.14 +	static const char *magic = "TILEIMAG";
    5.15 +	FILE *fp;
    5.16 +	char sig[8];
    5.17 +
    5.18 +	if(!(fp = fopen(fname, "rb"))) {
    5.19 +		LOADFAIL(fname, strerror(errno));
    5.20 +		return -1;
    5.21 +	}
    5.22 +	if(fread(sig, sizeof sig, 1, fp) <= 0 || memcmp(sig, magic, 8) != 0) {
    5.23 +		LOADFAIL(fname, "corrupted or empty file");
    5.24 +		fclose(fp);
    5.25 +		return -1;
    5.26 +	}
    5.27 +	if(fread(&img->xsz, 4, 1, fp) <= 0 || fread(&img->ysz, 4, 1, fp) <= 0) {
    5.28 +		LOADFAIL(fname, "failed to read file header");
    5.29 +		fclose(fp);
    5.30 +		return -1;
    5.31 +	}
    5.32 +
    5.33 +	if(!(img->pixels = malloc(img->xsz * img->ysz))) {
    5.34 +		LOADFAIL(fname, "failed to allocate pixel buffer");
    5.35 +		fclose(fp);
    5.36 +		return -1;
    5.37 +	}
    5.38 +	if(fread(img->pixels, 1, img->xsz * img->ysz, fp) < img->xsz * img->ysz) {
    5.39 +		LOADFAIL(fname, "unexpected end of file while reading pixels");
    5.40 +		fclose(fp);
    5.41 +		return -1;
    5.42 +	}
    5.43 +	fclose(fp);
    5.44 +	return 0;
    5.45 +}
    5.46 +
    5.47 +void destroy_image(struct image *img)
    5.48 +{
    5.49 +	if(img) {
    5.50 +		free(img->pixels);
    5.51 +		img->pixels = 0;
    5.52 +	}
    5.53 +}
    5.54 +
    5.55 +int load_palette(struct color *col, const char *fname)
    5.56 +{
    5.57 +	FILE *fp;
    5.58 +	char buf[128];
    5.59 +	int nent = 0;
    5.60 +
    5.61 +	if(!(fp = fopen(fname, "r"))) {
    5.62 +		fprintf(stderr, "failed to open palette file: %s: %s\n", fname, strerror(errno));
    5.63 +		return -1;
    5.64 +	}
    5.65 +
    5.66 +	while(fgets(buf, sizeof buf, fp)) {
    5.67 +		char *endp, *line = buf;
    5.68 +		int r, g, b;
    5.69 +
    5.70 +		if(!line || !*line) continue;
    5.71 +
    5.72 +		if(*line == '#') {	/* hex html-like values */
    5.73 +			unsigned int val = strtol(line + 1, &endp, 16);
    5.74 +			if(endp == line) {
    5.75 +				fprintf(stderr, "unrecognized line \"%s\" in palette file: %s\n", line, fname);
    5.76 +				fclose(fp);
    5.77 +				return -1;
    5.78 +			}
    5.79 +
    5.80 +			r = (val >> 16) & 0xff;
    5.81 +			g = (val >> 8) & 0xff;
    5.82 +			b = val & 0xff;
    5.83 +		} else {
    5.84 +			fprintf(stderr, "unrecognized line \"%s\" in palette file: %s\n", line, fname);
    5.85 +			fclose(fp);
    5.86 +			return -1;
    5.87 +		}
    5.88 +
    5.89 +		if(nent >= 256) {
    5.90 +			fprintf(stderr, "palette file %s contains more than 256 entries ... skipping the rest\n", fname);
    5.91 +			break;
    5.92 +		}
    5.93 +
    5.94 +		col[nent].r = r;
    5.95 +		col[nent].g = g;
    5.96 +		col[nent].b = b;
    5.97 +		nent++;
    5.98 +	}
    5.99 +
   5.100 +	printf("loaded palette: %s (%d colors)\n", fname, nent);
   5.101 +
   5.102 +	fclose(fp);
   5.103 +	return nent;
   5.104 +}
   5.105 +
   5.106 +#define MIN(a, b)	((a) < (b) ? (a) : (b))
   5.107 +#define MAX(a, b)	((a) > (b) ? (a) : (b))
   5.108 +
   5.109 +void blitkey(struct image *destimg, int dstx, int dsty, struct image *srcimg, int key)
   5.110 +{
   5.111 +	int srcx = 0, srcy = 0;
   5.112 +	int i, j, width, height;
   5.113 +	unsigned char *src, *dst;
   5.114 +
   5.115 +	if(dstx < 0) {
   5.116 +		srcx += -dstx;
   5.117 +		dstx = 0;
   5.118 +	}
   5.119 +	if(dsty < 0) {
   5.120 +		srcy += -dsty;
   5.121 +		dsty = 0;
   5.122 +	}
   5.123 +
   5.124 +	width = MIN(destimg->xsz - dstx, srcimg->xsz - srcx);
   5.125 +	height = MIN(destimg->ysz - dsty, srcimg->ysz - srcy);
   5.126 +
   5.127 +	if(width <= 0 || height <= 0) return;	/* ended up with a zero-area blit */
   5.128 +
   5.129 +	src = srcimg->pixels + srcy * srcimg->xsz + srcx;
   5.130 +	dst = destimg->pixels + dsty * destimg->xsz + dstx;
   5.131 +
   5.132 +	for(i=0; i<height; i++) {
   5.133 +		for(j=0; j<width; j++) {
   5.134 +			if(src[j] != key) {
   5.135 +				dst[j] = src[j];
   5.136 +			}
   5.137 +		}
   5.138 +		src += srcimg->xsz;
   5.139 +		dst += destimg->xsz;
   5.140 +	}
   5.141 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/image.h	Sun Jan 18 13:30:30 2015 +0200
     6.3 @@ -0,0 +1,21 @@
     6.4 +#ifndef IMAGE_H_
     6.5 +#define IMAGE_H_
     6.6 +
     6.7 +struct color {
     6.8 +	int r, g, b;
     6.9 +};
    6.10 +
    6.11 +struct image {
    6.12 +	int xsz, ysz;
    6.13 +	unsigned char *pixels;
    6.14 +};
    6.15 +
    6.16 +int load_image(struct image *img, const char *fname);
    6.17 +void destroy_image(struct image *img);
    6.18 +
    6.19 +/* returns the number of palette entries loaded */
    6.20 +int load_palette(struct color *col, const char *fname);
    6.21 +
    6.22 +void blitkey(struct image *img, int x, int y, struct image *src, int key);
    6.23 +
    6.24 +#endif	/* IMAGE_H_ */
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/level.c	Sun Jan 18 13:30:30 2015 +0200
     7.3 @@ -0,0 +1,138 @@
     7.4 +#include <stdio.h>
     7.5 +#include <stdlib.h>
     7.6 +#include <string.h>
     7.7 +#include <ctype.h>
     7.8 +#include <math.h>
     7.9 +#include "level.h"
    7.10 +
    7.11 +#define C_WALL		'#'
    7.12 +#define C_START		's'
    7.13 +#define C_GOAL		'x'
    7.14 +
    7.15 +#define IS_SOLID(x)	((x) == C_WALL)
    7.16 +
    7.17 +static void clean_line(char *buf);
    7.18 +
    7.19 +
    7.20 +void level_init(struct level *lvl)
    7.21 +{
    7.22 +	memset(lvl, 0, sizeof *lvl);
    7.23 +}
    7.24 +
    7.25 +void level_destroy(struct level *lvl)
    7.26 +{
    7.27 +	if(lvl) {
    7.28 +		destroy_tileset(&lvl->tileset);
    7.29 +	}
    7.30 +}
    7.31 +
    7.32 +int level_load(struct level *lvl, const char *fname)
    7.33 +{
    7.34 +	FILE *fp;
    7.35 +	char buf[256], *dir, *slash;
    7.36 +	int i, size[2], nlines;
    7.37 +
    7.38 +	dir = alloca(strlen(fname) + 1);
    7.39 +	strcpy(dir, fname);
    7.40 +	if((slash = strrchr(dir, '/'))) {
    7.41 +		slash[1] = 0;
    7.42 +	} else {
    7.43 +		*dir = 0;
    7.44 +	}
    7.45 +
    7.46 +	if(!(fp = fopen(fname, "r"))) {
    7.47 +		fprintf(stderr, "failed to open file: %s\n", fname);
    7.48 +		return -1;
    7.49 +	}
    7.50 +
    7.51 +	nlines = 0;
    7.52 +	while(fgets(buf, sizeof buf, fp)) {
    7.53 +		clean_line(buf);
    7.54 +
    7.55 +		if(memcmp(buf, "@s", 2) == 0) {
    7.56 +			if(sscanf(buf, "@s %dx%d", size, size + 1) != 2) {
    7.57 +				fprintf(stderr, "level file %s doesn't start with size definition\n", fname);
    7.58 +				fclose(fp);
    7.59 +				return -1;
    7.60 +			}
    7.61 +			if(size[0] > MAX_LEVEL_SIZE || size[1] > MAX_LEVEL_SIZE) {
    7.62 +				fprintf(stderr, "level size %dx%d is larger than compile-time maximum (%d)\n", size[0], size[1], MAX_LEVEL_SIZE);
    7.63 +				fclose(fp);
    7.64 +				return -1;
    7.65 +			}
    7.66 +
    7.67 +			lvl->num_cells[0] = size[0];
    7.68 +			lvl->num_cells[1] = size[1];
    7.69 +			continue;
    7.70 +
    7.71 +		} else if(memcmp(buf, "@t", 2) == 0) {
    7.72 +			char *path, *tname = buf + 3;
    7.73 +
    7.74 +			while(*tname && isspace(*tname)) ++tname;
    7.75 +
    7.76 +			path = alloca(strlen(tname) + strlen(dir) + 2);
    7.77 +			sprintf(path, "%s%s", dir, tname);
    7.78 +
    7.79 +			if(load_tileset(&lvl->tileset, path) == -1) {
    7.80 +				fprintf(stderr, "failed to load tileset for level %s\n", fname);
    7.81 +				fclose(fp);
    7.82 +				return -1;
    7.83 +			}
    7.84 +			continue;
    7.85 +		}
    7.86 +
    7.87 +		if(nlines >= size[0]) {
    7.88 +			fprintf(stderr, "warning: level contains more lines than specified, ignoring the rest\n");
    7.89 +			break;
    7.90 +		}
    7.91 +
    7.92 +		for(i=0; buf[i]; i++) {
    7.93 +			if(i >= size[1]) {
    7.94 +				fprintf(stderr, "warning: line %d is longer than the level size definition says. Skipping the rest.\n", nlines + 1);
    7.95 +				break;
    7.96 +			}
    7.97 +			lvl->cells[nlines][i] = buf[i];
    7.98 +
    7.99 +			if(buf[i] == C_START) {
   7.100 +				lvl->start_pos[0] = i;
   7.101 +				lvl->start_pos[1] = nlines;
   7.102 +				printf("start cell found (%d,%d)\n", lvl->start_pos[0], lvl->start_pos[1]);
   7.103 +			}
   7.104 +			if(buf[i] == C_GOAL) {
   7.105 +				lvl->goal_pos[0] = i;
   7.106 +				lvl->goal_pos[1] = nlines;
   7.107 +				printf("gold cell found (%d, %d)\n", i, nlines);
   7.108 +			}
   7.109 +		}
   7.110 +		nlines++;
   7.111 +	}
   7.112 +
   7.113 +	fclose(fp);
   7.114 +	return 0;
   7.115 +}
   7.116 +
   7.117 +static int clamp(int x, int low, int high)
   7.118 +{
   7.119 +	return x < low ? low : (x > high ? high : x);
   7.120 +}
   7.121 +
   7.122 +int level_cell(struct level *lvl, int cx, int cy)
   7.123 +{
   7.124 +	cx = clamp(cx, 0, lvl->num_cells[1] - 1);
   7.125 +	cy = clamp(cy, 0, lvl->num_cells[0] - 1);
   7.126 +
   7.127 +	return lvl->cells[cy][cx];
   7.128 +}
   7.129 +
   7.130 +
   7.131 +static void clean_line(char *buf)
   7.132 +{
   7.133 +	char *end = buf + strlen(buf) - 1;
   7.134 +
   7.135 +	if(end <= buf) return;
   7.136 +
   7.137 +	while(end >= buf && !isprint(*end)) {
   7.138 +		*end-- = 0;
   7.139 +	}
   7.140 +}
   7.141 +
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/level.h	Sun Jan 18 13:30:30 2015 +0200
     8.3 @@ -0,0 +1,24 @@
     8.4 +#ifndef LEVEL_H_
     8.5 +#define LEVEL_H_
     8.6 +
     8.7 +#include "tileset.h"
     8.8 +
     8.9 +#define MAX_LEVEL_SIZE	64
    8.10 +
    8.11 +struct level {
    8.12 +	int cells[MAX_LEVEL_SIZE][MAX_LEVEL_SIZE];
    8.13 +	int num_cells[2];
    8.14 +	int start_pos[2];
    8.15 +	int goal_pos[2];
    8.16 +
    8.17 +	struct tileset tileset;
    8.18 +};
    8.19 +
    8.20 +void level_init(struct level *lvl);
    8.21 +void level_destroy(struct level *lvl);
    8.22 +
    8.23 +int level_load(struct level *lvl, const char *fname);
    8.24 +
    8.25 +int level_cell(struct level *lvl, int cx, int cy);
    8.26 +
    8.27 +#endif	/* LEVEL_H_ */
     9.1 --- a/src/main.c	Sun Jan 18 05:51:51 2015 +0200
     9.2 +++ b/src/main.c	Sun Jan 18 13:30:30 2015 +0200
     9.3 @@ -1,14 +1,22 @@
     9.4  #include <stdio.h>
     9.5  #include "fblib.h"
     9.6 +#include "rend.h"
     9.7 +#include "level.h"
     9.8 +#include "player.h"
     9.9  
    9.10 -static void display();
    9.11 +static int init(void);
    9.12 +static void cleanup(void);
    9.13 +static void display(void);
    9.14 +static int keyb(int key, int state, void *cls);
    9.15 +
    9.16 +static struct player player;
    9.17 +static struct level level;
    9.18  
    9.19  int main(int argc, char **argv)
    9.20  {
    9.21 -	if(fb_init(320, 240, 8) == -1) {
    9.22 +	if(init() == -1) {
    9.23  		return 1;
    9.24  	}
    9.25 -	fb_set_palette_entry(1, 255, 0, 0);
    9.26  
    9.27  	for(;;) {
    9.28  		if(fb_process_events() == -1) {
    9.29 @@ -17,21 +25,95 @@
    9.30  		display();
    9.31  	}
    9.32  
    9.33 -done:
    9.34 -	fb_shutdown();
    9.35 +	cleanup();
    9.36  	return 0;
    9.37  }
    9.38  
    9.39 -void display()
    9.40 +static int init(void)
    9.41  {
    9.42  	int i;
    9.43 +
    9.44 +	if(fb_init(320, 240, 8) == -1) {
    9.45 +		return -1;
    9.46 +	}
    9.47 +	fb_keyboard_callback(keyb, 0);
    9.48 +
    9.49 +	level_init(&level);
    9.50 +	if(level_load(&level, "data/0.lvl") == -1) {
    9.51 +		return -1;
    9.52 +	}
    9.53 +
    9.54 +	if(init_renderer() == -1) {
    9.55 +		return -1;
    9.56 +	}
    9.57 +
    9.58 +	player_init(&player, &level);
    9.59 +
    9.60 +	/* setup the level tileset palette
    9.61 +	 * TODO: do it properly
    9.62 +	 */
    9.63 +	for(i=0; i<level.tileset.pal_size; i++) {
    9.64 +		struct color *col = level.tileset.pal + i;
    9.65 +		fb_set_palette_entry(i, col->r, col->g, col->b);
    9.66 +	}
    9.67 +
    9.68 +	return 0;
    9.69 +}
    9.70 +
    9.71 +static void cleanup(void)
    9.72 +{
    9.73 +	shutdown_renderer();
    9.74 +	level_destroy(&level);
    9.75 +	fb_shutdown();
    9.76 +}
    9.77 +
    9.78 +static void display(void)
    9.79 +{
    9.80  	int width = fb_get_width();
    9.81  	int height = fb_get_height();
    9.82  	unsigned char *pixels = (unsigned char*)fb_begin_frame();
    9.83  
    9.84 -	for(i=0; i<width * height; i++) {
    9.85 -		*pixels++ = 1;
    9.86 -	}
    9.87 +	setup_renderer(pixels, width, height);
    9.88 +	render_level(&level, player.x, player.y, player.dir);
    9.89  
    9.90  	fb_end_frame();
    9.91  }
    9.92 +
    9.93 +static int keyb(int key, int state, void *cls)
    9.94 +{
    9.95 +	if(!state) return 0;
    9.96 +
    9.97 +	switch(key) {
    9.98 +	case 27:
    9.99 +		return -1;
   9.100 +
   9.101 +	case 'w':
   9.102 +		player_move(&player, 1, 0);
   9.103 +		break;
   9.104 +
   9.105 +	case 's':
   9.106 +		player_move(&player, -1, 0);
   9.107 +		break;
   9.108 +
   9.109 +	case 'q':
   9.110 +		player_move(&player, 0, -1);
   9.111 +		break;
   9.112 +
   9.113 +	case 'e':
   9.114 +		player_move(&player, 0, 1);
   9.115 +		break;
   9.116 +
   9.117 +	case 'a':
   9.118 +		player_turn(&player, -1);
   9.119 +		break;
   9.120 +
   9.121 +	case 'd':
   9.122 +		player_turn(&player, 1);
   9.123 +		break;
   9.124 +
   9.125 +	default:
   9.126 +		break;
   9.127 +	}
   9.128 +
   9.129 +	return 0;
   9.130 +}
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/player.c	Sun Jan 18 13:30:30 2015 +0200
    10.3 @@ -0,0 +1,47 @@
    10.4 +#include <stdio.h>
    10.5 +#include "player.h"
    10.6 +#include "level.h"
    10.7 +
    10.8 +static char *dirnames[] = {
    10.9 +	"north", "east", "south", "west"
   10.10 +};
   10.11 +
   10.12 +void player_init(struct player *p, struct level *lvl)
   10.13 +{
   10.14 +	p->x = lvl->start_pos[0];
   10.15 +	p->y = lvl->start_pos[1];
   10.16 +	p->lvl = lvl;
   10.17 +	p->dir = DIR_NORTH;
   10.18 +}
   10.19 +
   10.20 +int player_move(struct player *p, int dfwd, int dside)
   10.21 +{
   10.22 +	int nx, ny;
   10.23 +	int dx, dy;
   10.24 +
   10.25 +	player_dir_vec(p, &dx, &dy);
   10.26 +	nx = p->x + dx * dfwd - dy * dside;
   10.27 +	ny = p->y + dy * dfwd + dx * dside;
   10.28 +
   10.29 +	if(level_cell(p->lvl, nx, ny) == '#') {
   10.30 +		return -1;
   10.31 +	}
   10.32 +	p->x = nx;
   10.33 +	p->y = ny;
   10.34 +	return 0;
   10.35 +}
   10.36 +
   10.37 +void player_turn(struct player *p, int angle)
   10.38 +{
   10.39 +	int dir = (p->dir + angle) % 4;
   10.40 +	if(dir < 0) dir += 4;
   10.41 +
   10.42 +	printf("turn(%d): %s -> %s\n", angle, dirnames[p->dir], dirnames[dir]);
   10.43 +	p->dir = dir;
   10.44 +}
   10.45 +
   10.46 +void player_dir_vec(struct player *p, int *dx, int *dy)
   10.47 +{
   10.48 +	*dx = p->dir == DIR_EAST ? 1 : (p->dir == DIR_WEST ? -1 : 0);
   10.49 +	*dy = p->dir == DIR_NORTH ? -1 : (p->dir == DIR_SOUTH ? 1 : 0);
   10.50 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/src/player.h	Sun Jan 18 13:30:30 2015 +0200
    11.3 @@ -0,0 +1,23 @@
    11.4 +#ifndef PLAYER_H_
    11.5 +#define PLAYER_H_
    11.6 +
    11.7 +enum { DIR_NORTH, DIR_EAST, DIR_SOUTH, DIR_WEST };
    11.8 +
    11.9 +struct level;
   11.10 +
   11.11 +struct player {
   11.12 +	int x, y;
   11.13 +	int dir;
   11.14 +
   11.15 +	struct level *lvl;
   11.16 +};
   11.17 +
   11.18 +void player_init(struct player *p, struct level *lvl);
   11.19 +
   11.20 +int player_move(struct player *p, int dfwd, int dside);
   11.21 +void player_turn(struct player *p, int angle);
   11.22 +
   11.23 +void player_dir_vec(struct player *p, int *dx, int *dy);
   11.24 +
   11.25 +
   11.26 +#endif	/* PLAYER_H_ */
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/src/rend.c	Sun Jan 18 13:30:30 2015 +0200
    12.3 @@ -0,0 +1,119 @@
    12.4 +#include <stdlib.h>
    12.5 +#include <string.h>
    12.6 +#include "rend.h"
    12.7 +#include "player.h"
    12.8 +
    12.9 +static void draw_tile(struct tile *tile);
   12.10 +
   12.11 +static struct image fb;
   12.12 +
   12.13 +
   12.14 +int init_renderer(void)
   12.15 +{
   12.16 +	return 0;
   12.17 +}
   12.18 +
   12.19 +void shutdown_renderer(void)
   12.20 +{
   12.21 +}
   12.22 +
   12.23 +void setup_renderer(unsigned char *pixels, int xsz, int ysz)
   12.24 +{
   12.25 +	fb.xsz = xsz;
   12.26 +	fb.ysz = ysz;
   12.27 +	fb.pixels = pixels;
   12.28 +}
   12.29 +
   12.30 +#define MAX_Z	5
   12.31 +#define LEFT	0
   12.32 +#define CENTER	1
   12.33 +#define RIGHT	2
   12.34 +
   12.35 +#define CHR_TYPE	0
   12.36 +#define CHR_SIDE	1
   12.37 +#define CHR_STATE	2
   12.38 +#define CHR_Z		3
   12.39 +
   12.40 +void render_level(struct level *lvl, int px, int py, int pdir)
   12.41 +{
   12.42 +	int i, j, dx, dy, backz, clear_start, clear_end;
   12.43 +	char cells[3][MAX_Z + 1];
   12.44 +	struct tileset *ts = &lvl->tileset;
   12.45 +	struct tile *tile_ceil, *tile_floor;
   12.46 +
   12.47 +	dx = pdir == DIR_EAST ? 1 : (pdir == DIR_WEST ? -1 : 0);
   12.48 +	dy = pdir == DIR_NORTH ? -1 : (pdir == DIR_SOUTH ? 1 : 0);
   12.49 +
   12.50 +	for(i=0; i<3; i++) {	/* get 3 abreast cells ... */
   12.51 +		int xoffs = (1 - i) * dy;
   12.52 +		int yoffs = (i - 1) * dx;
   12.53 +
   12.54 +		for(j=0; j<MAX_Z + 1; j++) {	/* ... for each depth */
   12.55 +			int x = px + xoffs + dx * j;
   12.56 +			int y = py + yoffs + dy * j;
   12.57 +
   12.58 +			cells[i][j] = level_cell(lvl, x, y);
   12.59 +		}
   12.60 +	}
   12.61 +
   12.62 +	/* draw floor and ceiling */
   12.63 +	tile_ceil = get_tile(ts, "ceil");
   12.64 +	tile_floor = get_tile(ts, "floor");
   12.65 +
   12.66 +	clear_start = tile_ceil ? tile_ceil->orig_y + tile_ceil->img.ysz : 0;
   12.67 +	clear_end = tile_floor ? tile_floor->orig_y : fb.ysz;
   12.68 +
   12.69 +	draw_tile(tile_ceil);
   12.70 +	draw_tile(tile_floor);
   12.71 +	memset(fb.pixels + clear_start * fb.xsz, 0, (clear_end - clear_start) * fb.xsz);
   12.72 +
   12.73 +	/* find where the back wall should go if it is within visual range
   12.74 +	 * and draw it ...
   12.75 +	 */
   12.76 +	backz = -1;
   12.77 +	for(i=1; i<MAX_Z + 1; i++) {
   12.78 +		if(cells[CENTER][i] == '#') {
   12.79 +			char name[] = "wcs ";	/* wall-center-solid */
   12.80 +			backz = i;
   12.81 +			name[CHR_Z] = backz + '0' - 1;
   12.82 +			draw_tile(get_tile(ts, name));
   12.83 +			break;
   12.84 +		}
   12.85 +	}
   12.86 +	if(backz == -1) {
   12.87 +		char name[] = "wco ";	/* wall-center-open */
   12.88 +		backz = MAX_Z;
   12.89 +		name[CHR_Z] = backz + '0' - 1;
   12.90 +		draw_tile(get_tile(ts, name));
   12.91 +	}
   12.92 +
   12.93 +	/* now render back to front */
   12.94 +	for(i=0; i<backz; i++) {
   12.95 +		int z = backz - i - 1;
   12.96 +		char name[] = "w---";	/* wall-<side>-<state>-<z> */
   12.97 +
   12.98 +		for(j=0; j<3; j++) {
   12.99 +			int state = 's';
  12.100 +
  12.101 +			if(j == CENTER) continue;	/* no walls in the center */
  12.102 +
  12.103 +			if(cells[j][z] != '#') {
  12.104 +				state = 'o';
  12.105 +				/* if it's an open cell, then skip drawing if the next z is also open */
  12.106 +				if(z >= MAX_Z || cells[j][z + 1] != '#') continue;
  12.107 +			}
  12.108 +
  12.109 +			name[CHR_SIDE] = j == LEFT ? 'l' : 'r';
  12.110 +			name[CHR_STATE] = state;
  12.111 +			name[CHR_Z] = z + '0';
  12.112 +			draw_tile(get_tile(ts, name));
  12.113 +		}
  12.114 +	}
  12.115 +}
  12.116 +
  12.117 +static void draw_tile(struct tile *tile)
  12.118 +{
  12.119 +	if(!tile) return;
  12.120 +
  12.121 +	blitkey(&fb, tile->orig_x, tile->orig_y, &tile->img, 31);	/* TODO unhardcode key */
  12.122 +}
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/src/rend.h	Sun Jan 18 13:30:30 2015 +0200
    13.3 @@ -0,0 +1,14 @@
    13.4 +#ifndef REND_H_
    13.5 +#define REND_H_
    13.6 +
    13.7 +#include "level.h"
    13.8 +
    13.9 +int init_renderer(void);
   13.10 +void shutdown_renderer(void);
   13.11 +
   13.12 +void setup_renderer(unsigned char *pixels, int xsz, int ysz);
   13.13 +
   13.14 +void render_level(struct level *lvl, int px, int py, int pdir);
   13.15 +
   13.16 +
   13.17 +#endif	/* REND_H_ */
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/src/tileset.c	Sun Jan 18 13:30:30 2015 +0200
    14.3 @@ -0,0 +1,374 @@
    14.4 +#include <stdio.h>
    14.5 +#include <stdlib.h>
    14.6 +#include <string.h>
    14.7 +#include <errno.h>
    14.8 +#include <ctype.h>
    14.9 +#include <assert.h>
   14.10 +#include "tileset.h"
   14.11 +#include "image.h"
   14.12 +
   14.13 +struct orig_node {
   14.14 +	char *prefix;
   14.15 +	struct { int x, y; } *orig;
   14.16 +	int count;
   14.17 +	struct orig_node *next;
   14.18 +};
   14.19 +
   14.20 +struct tile_node {
   14.21 +	struct tile tile;
   14.22 +	struct tile_node *next;
   14.23 +};
   14.24 +
   14.25 +enum { OPT_IMGDIR, OPT_MAXDIST, OPT_ORIGINS, OPT_PALETTE };
   14.26 +static struct option {
   14.27 +	int id;
   14.28 +	char *name, *val;
   14.29 +	int ival;
   14.30 +} opt[] = {
   14.31 +	/* maintain the same order as with the enum above */
   14.32 +	{ OPT_IMGDIR, "imagedir", 0, 0 },
   14.33 +	{ OPT_MAXDIST, "maxdist", 0, 0 },
   14.34 +	{ OPT_ORIGINS, "origins", 0, 0 },
   14.35 +	{ OPT_PALETTE, "palette", 0, 0 },
   14.36 +	{ 0, 0, 0 }
   14.37 +};
   14.38 +
   14.39 +static struct orig_node *load_origin_list(const char *fname);
   14.40 +static struct orig_node *find_origin(struct orig_node *list, const char *name);
   14.41 +static char *clean_line(char *buf);
   14.42 +static struct option *get_option(const char *name);
   14.43 +static int tilecmp(const void *a, const void *b);
   14.44 +
   14.45 +int load_tileset(struct tileset *ts, const char *fname)
   14.46 +{
   14.47 +	FILE *fp;
   14.48 +	char buf[256];
   14.49 +	int i, nline = 0, ntiles = 0;
   14.50 +	struct orig_node *origlist = 0;
   14.51 +	struct tile_node *tlist = 0;
   14.52 +	char *slash, *dir, *imgdir = "";
   14.53 +
   14.54 +	dir = alloca(strlen(fname) + 1);
   14.55 +	strcpy(dir, fname);
   14.56 +	if((slash = strrchr(dir, '/'))) {
   14.57 +		slash[1] = 0;
   14.58 +	} else {
   14.59 +		*dir = 0;
   14.60 +	}
   14.61 +
   14.62 +	if(!(fp = fopen(fname, "r"))) {
   14.63 +		fprintf(stderr, "failed to load tileset: %s: %s\n", fname, strerror(errno));
   14.64 +		return -1;
   14.65 +	}
   14.66 +
   14.67 +	while(fgets(buf, sizeof buf, fp)) {
   14.68 +		char *line, *name, *valstr;
   14.69 +		struct option *opt;
   14.70 +
   14.71 +		++nline;
   14.72 +
   14.73 +		line = clean_line(buf);
   14.74 +		if(!*line) continue;
   14.75 +
   14.76 +		name = line;
   14.77 +		if(!(valstr = strchr(line, '='))) {
   14.78 +			fprintf(stderr, "tileset: %s line %d: invalid syntax: %s\n", fname, nline, line);
   14.79 +			goto fail;
   14.80 +		}
   14.81 +		*valstr++ = 0;
   14.82 +
   14.83 +		name = clean_line(name);
   14.84 +		valstr = clean_line(valstr);
   14.85 +
   14.86 +		if(!*name || !*valstr) {
   14.87 +			fprintf(stderr, "tileset: %s line %d: malformed line\n", fname, nline);
   14.88 +			goto fail;
   14.89 +		}
   14.90 +
   14.91 +		/* first check to see if it's an option */
   14.92 +		if((opt = get_option(name))) {
   14.93 +			opt->val = strdup(valstr);
   14.94 +			opt->ival = atoi(valstr);
   14.95 +
   14.96 +			switch(opt->id) {
   14.97 +			case OPT_IMGDIR:
   14.98 +				{
   14.99 +					int len = strlen(opt->val);
  14.100 +					imgdir = alloca(len + 2);
  14.101 +					strcpy(imgdir, opt->val);
  14.102 +
  14.103 +					if(imgdir[len - 1] != '/') {
  14.104 +						imgdir[len] = '/';
  14.105 +						imgdir[len + 1] = 0;
  14.106 +					}
  14.107 +					printf("imgdir: \"%s\"\n", imgdir);
  14.108 +				}
  14.109 +				break;
  14.110 +
  14.111 +			case OPT_ORIGINS:
  14.112 +				{
  14.113 +					char *path = alloca(strlen(dir) + strlen(opt->val) + 1);
  14.114 +					sprintf(path, "%s%s", dir, opt->val);
  14.115 +
  14.116 +					if(!(origlist = load_origin_list(path))) {
  14.117 +						goto failmsg;
  14.118 +					}
  14.119 +				}
  14.120 +			default:
  14.121 +				break;
  14.122 +			}
  14.123 +
  14.124 +		} else {
  14.125 +			/* otherwise it's just a tile... add it to the list */
  14.126 +			char *path;
  14.127 +			struct tile_node *tnode;
  14.128 +
  14.129 +			if(!(tnode = malloc(sizeof *tnode))) {
  14.130 +				goto failmsg;
  14.131 +			}
  14.132 +			if(!(tnode->tile.name = strdup(name))) {
  14.133 +				free(tnode);
  14.134 +				goto failmsg;
  14.135 +			}
  14.136 +
  14.137 +			if(!(path = malloc(strlen(dir) + strlen(imgdir) + strlen(valstr) + 1))) {
  14.138 +				free(tnode->tile.name);
  14.139 +				free(tnode);
  14.140 +				goto failmsg;
  14.141 +			}
  14.142 +
  14.143 +			sprintf(path, "%s%s%s", dir, imgdir, valstr);
  14.144 +			if(load_image(&tnode->tile.img, path) == -1) {
  14.145 +				free(tnode->tile.name);
  14.146 +				free(tnode);
  14.147 +				free(path);
  14.148 +				goto failmsg;
  14.149 +			}
  14.150 +			free(path);
  14.151 +			tnode->next = tlist;
  14.152 +			tlist = tnode;
  14.153 +			++ntiles;
  14.154 +		}
  14.155 +	}
  14.156 +	fclose(fp), fp = 0;
  14.157 +
  14.158 +	/* if there is a palette, load it */
  14.159 +	if(opt[OPT_PALETTE].val) {
  14.160 +		const char *fname = opt[OPT_PALETTE].val;
  14.161 +		char *path = alloca(strlen(dir) + strlen(fname) + 1);
  14.162 +		sprintf(path, "%s%s", dir, fname);
  14.163 +
  14.164 +		if((ts->pal_size = load_palette(ts->pal, path)) == -1) {
  14.165 +			goto failmsg;
  14.166 +		}
  14.167 +	}
  14.168 +
  14.169 +	/* allocate the array of tiles and copy all the tiles from the list */
  14.170 +	if(!(ts->tile = calloc(ntiles, sizeof *ts->tile))) {
  14.171 +		goto failmsg;
  14.172 +	}
  14.173 +	ts->num_tiles = ntiles;
  14.174 +
  14.175 +	i = 0;
  14.176 +	while(tlist) {
  14.177 +		int idx;
  14.178 +		struct orig_node *onode;
  14.179 +		struct tile_node *tnode = tlist;
  14.180 +		tlist = tlist->next;
  14.181 +
  14.182 +		ts->tile[i] = tnode->tile;
  14.183 +		free(tnode);
  14.184 +
  14.185 +		/* determine the origin index by the tile z number,
  14.186 +		 * which if it exists, it starts at name[3]
  14.187 +		 */
  14.188 +		idx = atoi(ts->tile[i].name + 3);
  14.189 +
  14.190 +		/* retrieve the origin for this tile */
  14.191 +		if((onode = find_origin(origlist, ts->tile[i].name))) {
  14.192 +			if(idx >= onode->count) idx = onode->count - 1;
  14.193 +			ts->tile[i].orig_x = onode->orig[idx].x;
  14.194 +			ts->tile[i].orig_y = onode->orig[idx].y;
  14.195 +		}
  14.196 +		++i;
  14.197 +	}
  14.198 +
  14.199 +	/* now we need to sort them so that we can binary-search tiles later in real-time */
  14.200 +	qsort(ts->tile, ntiles, sizeof *ts->tile, tilecmp);
  14.201 +
  14.202 +	printf("loaded tileset %s\n", fname);
  14.203 +	for(i=0; i<ntiles; i++) {
  14.204 +		printf("  tile: %s\n", ts->tile[i].name);
  14.205 +	}
  14.206 +
  14.207 +	return 0;
  14.208 +
  14.209 +failmsg:
  14.210 +	fprintf(stderr, "failed to load tileset: %s\n", fname);
  14.211 +fail:
  14.212 +	if(fp) fclose(fp);
  14.213 +	while(tlist) {
  14.214 +		struct tile_node *n = tlist;
  14.215 +		tlist = tlist->next;
  14.216 +		free(n->tile.name);
  14.217 +		destroy_image(&n->tile.img);
  14.218 +		free(n);
  14.219 +	}
  14.220 +	return -1;
  14.221 +}
  14.222 +
  14.223 +void destroy_tileset(struct tileset *ts)
  14.224 +{
  14.225 +	int i;
  14.226 +
  14.227 +	if(!ts) return;
  14.228 +
  14.229 +	if(ts->tile) {
  14.230 +		for(i=0; i<ts->num_tiles; i++) {
  14.231 +			free(ts->tile[i].name);
  14.232 +			destroy_image(&ts->tile[i].img);
  14.233 +		}
  14.234 +		free(ts->tile);
  14.235 +		ts->tile = 0;
  14.236 +	}
  14.237 +}
  14.238 +
  14.239 +struct tile *get_tile(struct tileset *ts, const char *name)
  14.240 +{
  14.241 +	struct tile key;
  14.242 +	key.name = (char*)name;
  14.243 +	return bsearch(&key, ts->tile, ts->num_tiles, sizeof *ts->tile, tilecmp);
  14.244 +}
  14.245 +
  14.246 +static struct orig_node *load_origin_list(const char *fname)
  14.247 +{
  14.248 +	FILE *fp;
  14.249 +	char buf[256];
  14.250 +	int i, valbuf[2][64], num, nline = 0;
  14.251 +	struct orig_node *head = 0;
  14.252 +
  14.253 +	if(!(fp = fopen(fname, "r"))) {
  14.254 +		fprintf(stderr, "failed to load origins file: %s: %s\n", fname, strerror(errno));
  14.255 +		return 0;
  14.256 +	}
  14.257 +
  14.258 +	while(fgets(buf, sizeof buf, fp)) {
  14.259 +		char *tok, *name, *line;
  14.260 +		struct orig_node *onode;
  14.261 +
  14.262 +		++nline;
  14.263 +
  14.264 +		line = clean_line(buf);
  14.265 +		if(!*line) continue;
  14.266 +
  14.267 +		if(!(name = strtok(line, " \t\n\r"))) {
  14.268 +			continue;
  14.269 +		}
  14.270 +		num = 0;
  14.271 +		while(num < 64 && (tok = strtok(0, " \t\n\r"))) {
  14.272 +			if(sscanf(tok, "%dx%d", valbuf[0] + num, valbuf[1] + num) != 2) {
  14.273 +				fprintf(stderr, "failed to load origins file: %s: ", fname);
  14.274 +				fprintf(stderr, "invalid token \"%s\" on line %d (%s)\n", tok, nline, name);
  14.275 +				goto fail;
  14.276 +			}
  14.277 +			++num;
  14.278 +		}
  14.279 +		if(num >= 64) {
  14.280 +			fprintf(stderr, "warning: origins file %s: excessive number of %s origins on line %d\n", fname, name, nline);
  14.281 +		}
  14.282 +
  14.283 +		if(!(onode = malloc(sizeof *onode))) {
  14.284 +			fprintf(stderr, "failed to allocate origins node\n");
  14.285 +			goto fail;
  14.286 +		}
  14.287 +		if(!(onode->prefix = malloc(strlen(name) + 1))) {
  14.288 +			fprintf(stderr, "failed to allocate origins name\n");
  14.289 +			free(onode);
  14.290 +			goto fail;
  14.291 +		}
  14.292 +		if(!(onode->orig = malloc(num * sizeof *onode->orig))) {
  14.293 +			fprintf(stderr, "failed to allocate origins array\n");
  14.294 +			free(onode);
  14.295 +			goto fail;
  14.296 +		}
  14.297 +
  14.298 +		strcpy(onode->prefix, name);
  14.299 +		onode->count = num;
  14.300 +		onode->next = head;
  14.301 +		head = onode;
  14.302 +
  14.303 +		for(i=0; i<num; i++) {
  14.304 +			onode->orig[i].x = valbuf[0][i];
  14.305 +			onode->orig[i].y = valbuf[1][i];
  14.306 +		}
  14.307 +	}
  14.308 +	fclose(fp);
  14.309 +	return head;
  14.310 +
  14.311 +fail:
  14.312 +	fclose(fp);
  14.313 +	while(head) {
  14.314 +		struct orig_node *tmp = head;
  14.315 +		head = head->next;
  14.316 +		free(tmp->prefix);
  14.317 +		free(tmp->orig);
  14.318 +	}
  14.319 +	return 0;
  14.320 +}
  14.321 +
  14.322 +static struct orig_node *find_origin(struct orig_node *list, const char *name)
  14.323 +{
  14.324 +	struct orig_node *node = list;
  14.325 +	struct orig_node *best = 0;
  14.326 +	int best_len = 0;
  14.327 +
  14.328 +	while(node) {
  14.329 +		const char *nmptr = name;
  14.330 +		const char *pptr = node->prefix;
  14.331 +		int len;
  14.332 +
  14.333 +		while(*pptr && *nmptr && *pptr == *nmptr) ++pptr, ++nmptr;
  14.334 +		if((len = nmptr - name) > best_len) {
  14.335 +			best = node;
  14.336 +			best_len = len;
  14.337 +		}
  14.338 +		node = node->next;
  14.339 +	}
  14.340 +	return best;
  14.341 +}
  14.342 +
  14.343 +static char *clean_line(char *buf)
  14.344 +{
  14.345 +	char *end = buf + strlen(buf);
  14.346 +
  14.347 +	while(*buf && isspace(*buf)) ++buf;
  14.348 +	while(end > buf && (!*end || isspace(*end))) {
  14.349 +		*end-- = 0;
  14.350 +	}
  14.351 +
  14.352 +	/* also remove comments */
  14.353 +	if((end = strchr(buf, '#'))) {
  14.354 +		*end = 0;
  14.355 +	}
  14.356 +	return buf;
  14.357 +}
  14.358 +
  14.359 +static struct option *get_option(const char *name)
  14.360 +{
  14.361 +	int i;
  14.362 +	for(i=0; opt[i].name; i++) {
  14.363 +		if(strcmp(name, opt[i].name) == 0) {
  14.364 +			assert(i == opt[i].id);
  14.365 +			return opt + i;
  14.366 +		}
  14.367 +	}
  14.368 +	return 0;
  14.369 +}
  14.370 +
  14.371 +/* tile comparison for sorting the array of tiles by name */
  14.372 +static int tilecmp(const void *a, const void *b)
  14.373 +{
  14.374 +	const struct tile *ta = a;
  14.375 +	const struct tile *tb = b;
  14.376 +	return strcmp(ta->name, tb->name);
  14.377 +}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/src/tileset.h	Sun Jan 18 13:30:30 2015 +0200
    15.3 @@ -0,0 +1,25 @@
    15.4 +#ifndef TILESET_H_
    15.5 +#define TILESET_H_
    15.6 +
    15.7 +#include "image.h"
    15.8 +
    15.9 +struct tile {
   15.10 +	char *name;
   15.11 +	struct image img;
   15.12 +	int orig_x, orig_y;
   15.13 +};
   15.14 +
   15.15 +struct tileset {
   15.16 +	struct tile *tile;
   15.17 +	int num_tiles;
   15.18 +
   15.19 +	struct color pal[256];
   15.20 +	int pal_size;
   15.21 +};
   15.22 +
   15.23 +int load_tileset(struct tileset *ts, const char *fname);
   15.24 +void destroy_tileset(struct tileset *ts);
   15.25 +
   15.26 +struct tile *get_tile(struct tileset *ts, const char *name);
   15.27 +
   15.28 +#endif	/* TILESET_H_ */