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