|
|
@@ -0,0 +1,418 @@ |
|
|
/* |
|
|
* The ToAru Sample Game |
|
|
*/ |
|
|
|
|
|
#include <stdio.h> |
|
|
#include <stdint.h> |
|
|
#include <syscall.h> |
|
|
#include <string.h> |
|
|
#include <stdlib.h> |
|
|
#include <time.h> |
|
|
|
|
|
DEFN_SYSCALL1(kbd_mode, 12, int); |
|
|
DEFN_SYSCALL0(kbd_get, 13); |
|
|
DEFN_SYSCALL2(shm_obtain, 35, char *, int) |
|
|
DEFN_SYSCALL1(shm_release, 36, char *) |
|
|
|
|
|
typedef struct sprite { |
|
|
uint16_t width; |
|
|
uint16_t height; |
|
|
uint32_t * bitmap; |
|
|
uint32_t * masks; |
|
|
uint32_t blank; |
|
|
uint8_t alpha; |
|
|
} sprite_t; |
|
|
|
|
|
uint16_t graphics_width = 0; |
|
|
uint16_t graphics_height = 0; |
|
|
uint16_t graphics_depth = 0; |
|
|
|
|
|
#define GFX_W graphics_width |
|
|
#define GFX_H graphics_height |
|
|
#define GFX_B (graphics_depth / 8) /* Display byte depth */ |
|
|
#define GFX(x,y) *((uint32_t *)&frame_mem[(GFX_W * (y) + (x)) * GFX_B]) |
|
|
#define SPRITE(sprite,x,y) sprite->bitmap[sprite->width * (y) + (x)] |
|
|
#define SMASKS(sprite,x,y) sprite->masks[sprite->width * (y) + (x)] |
|
|
|
|
|
uint8_t * gfx_mem; |
|
|
uint8_t * frame_mem; |
|
|
uint32_t gfx_size; |
|
|
sprite_t * sprites[128]; |
|
|
|
|
|
|
|
|
void * malloc_(size_t size) |
|
|
{ |
|
|
void * ret = malloc(size); |
|
|
if (!ret) { |
|
|
printf("[WARNING!] malloc_(%d) returned NULL!\n", size); |
|
|
while ((ret = malloc(size)) == NULL) { |
|
|
printf("."); |
|
|
} |
|
|
} |
|
|
return ret; |
|
|
} |
|
|
|
|
|
|
|
|
uint32_t rgb(uint8_t r, uint8_t g, uint8_t b) { |
|
|
return (r * 0x10000) + (g * 0x100) + (b * 0x1); |
|
|
} |
|
|
|
|
|
uint32_t flip_offset; |
|
|
|
|
|
void flip() { |
|
|
memcpy(gfx_mem, frame_mem, gfx_size); |
|
|
memset(frame_mem, 0, GFX_H * GFX_W * GFX_B); |
|
|
} |
|
|
|
|
|
void |
|
|
load_sprite(sprite_t * sprite, char * filename) { |
|
|
/* Open the requested binary */ |
|
|
FILE * image = fopen(filename, "r"); |
|
|
size_t image_size= 0; |
|
|
|
|
|
fseek(image, 0, SEEK_END); |
|
|
image_size = ftell(image); |
|
|
fseek(image, 0, SEEK_SET); |
|
|
|
|
|
/* Alright, we have the length */ |
|
|
char * bufferb = malloc_(image_size); |
|
|
fread(bufferb, image_size, 1, image); |
|
|
uint16_t x = 0; /* -> 212 */ |
|
|
uint16_t y = 0; /* -> 68 */ |
|
|
/* Get the width / height of the image */ |
|
|
signed int *bufferi = (signed int *)((uintptr_t)bufferb + 2); |
|
|
uint32_t width = bufferi[4]; |
|
|
uint32_t height = bufferi[5]; |
|
|
uint16_t bpp = bufferi[6] / 0x10000; |
|
|
uint32_t row_width = (bpp * width + 31) / 32 * 4; |
|
|
/* Skip right to the important part */ |
|
|
size_t i = bufferi[2]; |
|
|
|
|
|
sprite->width = width; |
|
|
sprite->height = height; |
|
|
sprite->bitmap = malloc_(sizeof(uint32_t) * width * height); |
|
|
|
|
|
for (y = 0; y < height; ++y) { |
|
|
for (x = 0; x < width; ++x) { |
|
|
if (i > image_size) return; |
|
|
/* Extract the color */ |
|
|
uint32_t color; |
|
|
if (bpp == 24) { |
|
|
color = bufferb[i + 3 * x] + |
|
|
bufferb[i+1 + 3 * x] * 0x100 + |
|
|
bufferb[i+2 + 3 * x] * 0x10000; |
|
|
} else if (bpp == 32) { |
|
|
color = bufferb[i + 4 * x] * 0x1000000 + |
|
|
bufferb[i+1 + 4 * x] * 0x100 + |
|
|
bufferb[i+2 + 4 * x] * 0x10000 + |
|
|
bufferb[i+3 + 4 * x] * 0x1; |
|
|
} |
|
|
/* Set our point */ |
|
|
sprite->bitmap[(height - y - 1) * width + x] = color; |
|
|
} |
|
|
i += row_width; |
|
|
} |
|
|
free(bufferb); |
|
|
} |
|
|
|
|
|
#define _RED(color) ((color & 0x00FF0000) / 0x10000) |
|
|
#define _GRE(color) ((color & 0x0000FF00) / 0x100) |
|
|
#define _BLU(color) ((color & 0x000000FF) / 0x1) |
|
|
|
|
|
uint32_t alpha_blend(uint32_t bottom, uint32_t top, uint32_t mask) { |
|
|
float a = _RED(mask) / 256.0; |
|
|
uint8_t red = _RED(bottom) * (1.0 - a) + _RED(top) * a; |
|
|
uint8_t gre = _GRE(bottom) * (1.0 - a) + _GRE(top) * a; |
|
|
uint8_t blu = _BLU(bottom) * (1.0 - a) + _BLU(top) * a; |
|
|
return rgb(red,gre,blu); |
|
|
} |
|
|
|
|
|
void draw_sprite(sprite_t * sprite, uint16_t x, uint16_t y) { |
|
|
for (uint16_t _y = 0; _y < sprite->height; ++_y) { |
|
|
for (uint16_t _x = 0; _x < sprite->width; ++_x) { |
|
|
if (sprite->alpha) { |
|
|
GFX(x + _x, y + _y) = alpha_blend(GFX(x + _x, y + _y), SPRITE(sprite, _x, _y), SMASKS(sprite, _x, _y)); |
|
|
} else { |
|
|
if (SPRITE(sprite,_x,_y) != sprite->blank) { |
|
|
GFX(x + _x, y + _y) = SPRITE(sprite, _x, _y); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
void waitabit() { |
|
|
int x = time(NULL); |
|
|
while (time(NULL) < x + 1) { |
|
|
// Do nothing. |
|
|
} |
|
|
} |
|
|
|
|
|
void draw_line(uint16_t x0, uint16_t x1, uint16_t y0, uint16_t y1, uint32_t color) { |
|
|
int deltax = abs(x1 - x0); |
|
|
int deltay = abs(y1 - y0); |
|
|
int sx = (x0 < x1) ? 1 : -1; |
|
|
int sy = (y0 < y1) ? 1 : -1; |
|
|
int error = deltax - deltay; |
|
|
while (1) { |
|
|
GFX(x0, y0) = color; |
|
|
if (x0 == x1 && y0 == y1) break; |
|
|
int e2 = 2 * error; |
|
|
if (e2 > -deltay) { |
|
|
error -= deltay; |
|
|
x0 += sx; |
|
|
} |
|
|
if (e2 < deltax) { |
|
|
error += deltax; |
|
|
y0 += sy; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
/* RPG Mapping Bits */ |
|
|
struct { |
|
|
int width; |
|
|
int height; |
|
|
char * buffer; |
|
|
int size; |
|
|
} map; |
|
|
|
|
|
void load_map(char * filename) { |
|
|
FILE * f = fopen(filename, "r"); |
|
|
char tmp[256]; |
|
|
fgets(tmp, 255, f); |
|
|
map.width = atoi(tmp); |
|
|
fgets(tmp, 256, f); |
|
|
map.height = atoi(tmp); |
|
|
map.size = map.height * map.width; |
|
|
map.buffer = malloc_(map.size); |
|
|
fread(map.buffer, map.size, 1, f); |
|
|
fclose(f); |
|
|
} |
|
|
|
|
|
char cell(int x, int y) { |
|
|
if (x < 0 || y < 0 || x >= map.width || y >= map.height) { |
|
|
return 'A'; /* The abyss is trees! */ |
|
|
} |
|
|
return (map.buffer[y * map.width + x]); |
|
|
} |
|
|
|
|
|
#define VIEW_SIZE 4 |
|
|
#define CELL_SIZE 64 |
|
|
|
|
|
int my_x = 2; |
|
|
int my_y = 2; |
|
|
int direction = 0; |
|
|
int offset_x = 0; |
|
|
int offset_y = 0; |
|
|
int offset_iter = 0; |
|
|
int map_x; |
|
|
int map_y; |
|
|
|
|
|
void render_map(int x, int y) { |
|
|
int i = 0; |
|
|
for (int _y = y - VIEW_SIZE; _y <= y + VIEW_SIZE; ++_y) { |
|
|
int j = 0; |
|
|
for (int _x = x - VIEW_SIZE; _x <= x + VIEW_SIZE; ++_x) { |
|
|
char c = cell(_x,_y); |
|
|
int sprite; |
|
|
switch (c) { |
|
|
case '\n': |
|
|
case 'A': |
|
|
sprite = 1; |
|
|
break; |
|
|
case '.': |
|
|
sprite = 2; |
|
|
break; |
|
|
case 'W': |
|
|
sprite = 3; |
|
|
break; |
|
|
default: |
|
|
sprite = 0; |
|
|
break; |
|
|
} |
|
|
draw_sprite(sprites[sprite], |
|
|
map_x + offset_x * offset_iter + j * CELL_SIZE, |
|
|
map_y + offset_y * offset_iter + i * CELL_SIZE); |
|
|
++j; |
|
|
} |
|
|
++i; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void display() { |
|
|
render_map(my_x,my_y); |
|
|
draw_sprite(sprites[124 + direction], map_x + CELL_SIZE * 4, map_y + CELL_SIZE * 4); |
|
|
flip(); |
|
|
} |
|
|
|
|
|
void transition(int nx, int ny) { |
|
|
if (nx < my_x) { |
|
|
offset_x = 1; |
|
|
offset_y = 0; |
|
|
} else if (ny < my_y) { |
|
|
offset_x = 0; |
|
|
offset_y = 1; |
|
|
} else if (nx > my_x) { |
|
|
offset_x = -1; |
|
|
offset_y = 0; |
|
|
} else if (ny > my_y) { |
|
|
offset_x = 0; |
|
|
offset_y = -1; |
|
|
} |
|
|
for (int i = 0; i < 64; i += 1) { |
|
|
offset_iter = i; |
|
|
display(); |
|
|
} |
|
|
offset_iter = 0; |
|
|
offset_x = 0; |
|
|
offset_y = 0; |
|
|
my_x = nx; |
|
|
my_y = ny; |
|
|
} |
|
|
|
|
|
void move(int cx, int cy) { |
|
|
int nx = my_x + cx; |
|
|
int ny = my_y + cy; |
|
|
|
|
|
if (cx == 1) { |
|
|
if (direction != 1) { |
|
|
direction = 1; |
|
|
return; |
|
|
} |
|
|
} else if (cx == -1) { |
|
|
if (direction != 2) { |
|
|
direction = 2; |
|
|
return; |
|
|
} |
|
|
} else if (cy == 1) { |
|
|
if (direction != 0) { |
|
|
direction = 0; |
|
|
return; |
|
|
} |
|
|
} else if (cy == -1) { |
|
|
if (direction != 3) { |
|
|
direction = 3; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
switch (cell(nx,ny)) { |
|
|
case '_': |
|
|
case '.': |
|
|
transition(nx,ny); |
|
|
break; |
|
|
default: |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
/* woah */ |
|
|
char font_buffer[400000]; |
|
|
sprite_t alpha_tmp; |
|
|
|
|
|
void init_sprite(int i, char * filename, char * alpha) { |
|
|
sprites[i] = malloc_(sizeof(sprite_t)); |
|
|
load_sprite(sprites[i], filename); |
|
|
if (alpha) { |
|
|
sprites[i]->alpha = 1; |
|
|
load_sprite(&alpha_tmp, alpha); |
|
|
sprites[i]->masks = alpha_tmp.bitmap; |
|
|
} else { |
|
|
sprites[i]->alpha = 0; |
|
|
} |
|
|
sprites[i]->blank = 0x0; |
|
|
} |
|
|
|
|
|
int main(int argc, char ** argv) { |
|
|
if (argc < 5) { |
|
|
return -1; |
|
|
} |
|
|
|
|
|
graphics_width = atoi(argv[1]); |
|
|
graphics_height = atoi(argv[2]); |
|
|
graphics_depth = atoi(argv[3]); |
|
|
if (!graphics_width || !graphics_height || !graphics_depth) { |
|
|
return -2; |
|
|
} |
|
|
|
|
|
int buf_size = (graphics_width * graphics_depth * graphics_depth); |
|
|
gfx_mem = (void *)syscall_shm_obtain(argv[4], buf_size); |
|
|
if (!gfx_mem) { |
|
|
return 1; |
|
|
} |
|
|
|
|
|
map_x = GFX_W / 2 - (64 * 9) / 2; |
|
|
map_y = GFX_H / 2 - (64 * 9) / 2; |
|
|
flip_offset = GFX_H; |
|
|
gfx_size = GFX_H * GFX_W * GFX_B; |
|
|
|
|
|
printf("game: w=%d, h=%d, d=%d, buf=0x%x\n", GFX_W, GFX_H, graphics_depth, gfx_mem); |
|
|
|
|
|
frame_mem = malloc_(gfx_size); |
|
|
|
|
|
printf("Graphics memory is at %p, backbuffer is at %p.\n", gfx_mem, frame_mem); |
|
|
|
|
|
if (!frame_mem) { |
|
|
return 1; |
|
|
} |
|
|
|
|
|
printf("Loading sprites...\n"); |
|
|
init_sprite(0, "/etc/game/0.bmp", NULL); |
|
|
init_sprite(1, "/etc/game/1.bmp", NULL); |
|
|
init_sprite(2, "/etc/game/2.bmp", NULL); |
|
|
init_sprite(3, "/etc/game/3.bmp", NULL); |
|
|
init_sprite(4, "/etc/game/4.bmp", NULL); |
|
|
init_sprite(5, "/etc/game/5.bmp", NULL); |
|
|
init_sprite(6, "/etc/game/6.bmp", NULL); |
|
|
init_sprite(7, "/etc/game/7.bmp", NULL); |
|
|
init_sprite(124, "/etc/game/remilia.bmp", NULL); |
|
|
init_sprite(125, "/etc/game/remilia_r.bmp", NULL); |
|
|
init_sprite(126, "/etc/game/remilia_l.bmp", NULL); |
|
|
init_sprite(127, "/etc/game/remilia_f.bmp", NULL); |
|
|
load_map("/etc/game/map"); |
|
|
printf("%d x %d\n", map.width, map.height); |
|
|
|
|
|
printf("\033[J\n"); |
|
|
|
|
|
syscall_kbd_mode(1); |
|
|
|
|
|
int playing = 1; |
|
|
while (playing) { |
|
|
|
|
|
display(); |
|
|
|
|
|
char ch = 0; |
|
|
ch = syscall_kbd_get(); |
|
|
switch (ch) { |
|
|
case 16: |
|
|
playing = 0; |
|
|
break; |
|
|
case 30: |
|
|
move(-1,0); |
|
|
/* left */ |
|
|
break; |
|
|
case 32: |
|
|
move(1,0); |
|
|
/* right */ |
|
|
break; |
|
|
case 31: |
|
|
move(0,1); |
|
|
/* Down */ |
|
|
break; |
|
|
case 17: |
|
|
move(0,-1); |
|
|
/* Up */ |
|
|
break; |
|
|
case 18: |
|
|
break; |
|
|
default: |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
syscall_kbd_mode(0); |
|
|
|
|
|
return 0; |
|
|
} |