From c923c07747f334b3eab70078a26f2d6b3df0cc8d Mon Sep 17 00:00:00 2001 From: lemon-sherbet Date: Fri, 16 Nov 2018 17:11:57 +0100 Subject: [PATCH] aoi --- .gitignore | 1 + aoi.c | 319 +++++++++++++++++++++++++++++++++++++++++++++++++++++ aoi.h | 39 +++++++ 3 files changed, 359 insertions(+) create mode 100644 .gitignore create mode 100644 aoi.c create mode 100644 aoi.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5761abc --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.o diff --git a/aoi.c b/aoi.c new file mode 100644 index 0000000..3ee48e0 --- /dev/null +++ b/aoi.c @@ -0,0 +1,319 @@ +#include +#include +#include +#include +#include + +#include "aoi.h" + +/********** + * macros * + **********/ + +#define aoi_log(...) do {\ + fprintf(stderr,"[%s:%i] ",__FILE__,__LINE__);\ + fprintf(stderr,__VA_ARGS__);\ + fputc('\n',stderr);\ +} while (0) + +#define aoi_error(...) do {\ + aoi_log(__VA_ARGS__);\ + exit(1);\ +} while (0) + +#define aoi_assert(x) if (!(x)) aoi_error("assertion failed '%s'", #x) + +/********* + * state * + *********/ + +ALLEGRO_DISPLAY* display = NULL; +ALLEGRO_BITMAP* sheet = NULL; + +/******************* + * input functions * + *******************/ + +//bitmask for input (current frame and previous frame) +uint16_t buttons = 0, buttonsprev = 0; + +int aoi_btn(uint8_t btn) { + return !!(buttons & (1 << btn)); +} + +typedef struct { + int kb_keycode; + int js_button; +} aoi_input_keymap_t; + +struct { + uint8_t n; //how many input buttons defined, max 16 (16 bit bitmask) + ALLEGRO_JOYSTICK* js; //joystick + aoi_input_keymap_t keymaps[16]; //keymaps for each input button +} aoi_input_config; + + +//init input config variable +void aoi_input_init(int n, ALLEGRO_JOYSTICK* js, aoi_input_keymap_t* keymaps) { + for (int i = 0; i < n; i++) { + aoi_input_config.keymaps[i] = keymaps[i]; + } + aoi_input_config.n = n; + aoi_input_config.js = js; +} + + +//parse input config string and init input config +void aoi_input_load(char* cfg) { + /*cfg of the format: + (@joystick name;)kKEY_CODE,jJOYSTICK_BUTTON;...; + */ + char js_name[200]; + int js_name_idx = 0; + char c; + aoi_input_keymap_t keymaps[16]; + uint8_t keymap = 0; + + while ((c = *cfg++)) { + switch (c) { + case '@': { + while (((c = *cfg++) != ';') && c) + js_name[js_name_idx++] = c; + js_name[js_name_idx] = 0; + } break; + case 'k': + case 'j': { + char t = c; + int n = -1; + char s[10]; + int i = 0; + c = *cfg++; + while (c && c != ';' && c != ',') { + s[i++] = c; + c = *cfg++; + } + //aoi_log("END %c", c); + sscanf(s, "%d", &n); + if (t == 'k') + keymaps[keymap].kb_keycode = n; + else + keymaps[keymap].js_button = n; + if (c == ';' || !c) keymap++; + } break; + } + } + + int max = al_get_num_joysticks(); + ALLEGRO_JOYSTICK* js = NULL; + for (int i = 0; i < max; i++) { + js = al_get_joystick(i); + if (js) { + const char* name = al_get_joystick_name(js); + if (strcmp(name,js_name) == 0) { + aoi_log("loaded joystick '%s' (index %i)", name, i); + break; + } + al_release_joystick(js); + js = NULL; + } + } + + aoi_input_init(keymap, js, keymaps); +} + +void aoi_input_update() { + buttonsprev = buttons; + buttons = 0; + + ALLEGRO_JOYSTICK_STATE jst; + if (aoi_input_config.js) al_get_joystick_state(aoi_input_config.js, &jst); + + ALLEGRO_KEYBOARD_STATE kst; + al_get_keyboard_state(&kst); + + for (int i = 0; i < aoi_input_config.n; i++) { + aoi_input_keymap_t map = aoi_input_config.keymaps[i]; + if (al_key_down(&kst, map.kb_keycode) || (aoi_input_config.js && jst.button[i])) + buttons |= 1 << i; + } +} + +/********************** + * graphics functions * + **********************/ + +void aoi_cls(aoi_color_t color) { + al_clear_to_color((ALLEGRO_COLOR) color); +} + +const int TW_ = AOI_TILE_WIDTH; +const int TH_ = AOI_TILE_HEIGHT; + +//draw sprite from spritesheet +void aoi_spr(uint8_t spr, int x, int y, uint8_t flip) { + al_draw_bitmap_region(sheet, TW_*(spr&0xF), TH_*(spr>>4), TW_, TH_, x, y, flip); +} + +//same but with extra options +void aoi_sprEX(uint8_t spr, int x, int y, uint8_t flip, float scale, float rot, int w, int h) { + al_draw_tinted_scaled_rotated_bitmap_region( + sheet, + TW_*(spr&0xF), + TH_*(spr>>4), + TW_*w, + TH_*h, + al_map_rgb(255,255,255), + 0, + 0, + x, + y, + scale, + scale, + rot, + flip + ); +} + +void aoi_line(int x0, int y0, int x1, int y1, aoi_color_t color) { + al_draw_line(x0, y0, x1, y1, (ALLEGRO_COLOR) color, -1); +} + +void aoi_rect(int x, int y, int w, int h, uint8_t filled, aoi_color_t color) { + if (filled) + al_draw_filled_rectangle(x, y, x+w, y+h, (ALLEGRO_COLOR) color); + else + al_draw_rectangle(x, y, x+w, y+h, (ALLEGRO_COLOR) color, -1); +} + +/***************** + * map functions * + *****************/ + +typedef struct { + uint8_t width, height; //dimensions in tiles + uint8_t* data; +} aoi_map_t; + +aoi_map_t* map = NULL; + +#define mget(x,y) (map->data[x+y*map->width]) +uint8_t aoi_mget(uint8_t x, uint8_t y) { + return (map && x < map->width && y < map->height && x > 0 && y > 0) ? mget(x,y) : 0; +} + +#define mset(x,y,t) (map->data[x+y*map->width] = t) +void aoi_mset(uint8_t x, uint8_t y, uint8_t tile) { + if (map && x < map->width && y < map->height && x >= 0 && y >= 0) + mset(x, y, tile); +} + +//draws map +void aoi_map(int x, int y) { + uint16_t siz = map->width*map->height; + for (int i = 0; i <= siz; i++) + aoi_spr(map->data[i], TW_*(i%map->width) + x, TH_*((int)i/map->height) + y, 0); +} + +/********************* + * loading functions * + *********************/ + +int aoi_load_spritesheet(char* path) { + return (sheet = al_load_bitmap(path)) != NULL; +} + +int aoi_load_map(char* path) { + ALLEGRO_FILE* f = al_fopen(path, "r"); + if (!f) return 0; + + //read once to get dimensions + int rows = 0, columns = 1; + int c = 0; + while ((c = al_fgetc(f)) != EOF) { + if (!rows && c == ',') columns++; + else if (c == '\n') rows++; + } + //aoi_log("%ix%i", columns, rows); + map = malloc(sizeof(aoi_map_t)); + map->width = columns, map->height = rows; + map->data = malloc(map->width*map->height); + + //read again to get data + al_fseek(f, 0, ALLEGRO_SEEK_SET); + int n = 0; + char s[6]; + int s_idx = 0; + int i = 0; + while ((c = al_fgetc(f)) != EOF) { + if (c == ',') { + s[s_idx] = 0; + s_idx = 0; + sscanf(s, "%d", &n); + map->data[i++] = (n < 0 ? 0 : n); + n = 0; + } else if (c == '\n'); + else if (s_idx < sizeof(s)) + s[s_idx++] = c; + } + + al_fclose(f); + return 1; +} + +void aoi_destroy_maps() { + free(map->data); + free(map); +} + +/***************** + * main function * + *****************/ + +int aoi_loop(void); + +int main(int argc, char** argv) { + aoi_log("starting up"); + al_init(); + al_init_image_addon(); + al_install_keyboard(); + al_install_joystick(); + + aoi_assert(display = al_create_display(AOI_INTERNAL_WIDTH, AOI_INTERNAL_HEIGHT)); + aoi_assert(aoi_load_spritesheet(AOI_SPRITESHEET_PATH)); + + //TODO load from run-time/compile-time(for defaults) config file + aoi_input_load("@mayflash limited MAYFLASH GameCube Controller Adapter;k26,j0;"); + + aoi_load_map("map.csv"); + + int running = 1; + unsigned int frames = 0; + double init_time = al_get_time(); + + while (running) { + double t0 = al_get_time(); + + aoi_input_update(); + + running = !aoi_loop(); + al_flip_display(); + + double delta = al_get_time() - t0; + if (delta < 1/AOI_FPS) { + al_rest(1/AOI_FPS-delta); + } //else aoi_log("lag frame (%u)", frames); + + frames++; + } + + double t = al_get_time(); + aoi_log("%i frames in %f seconds: avg = %fFPS", frames, init_time, frames/(t-init_time)); + aoi_log("quitting"); + + al_destroy_display(display); + al_destroy_bitmap(sheet); + + aoi_destroy_maps(); + + return 0; +} diff --git a/aoi.h b/aoi.h new file mode 100644 index 0000000..2f9ed86 --- /dev/null +++ b/aoi.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include + +#ifdef AOI_USE_CONFIG_FILE +#include "../aoi_config.h" +#endif + +#ifndef AOI_INTERNAL_WIDTH +#define AOI_INTERNAL_WIDTH 640 +#endif +#ifndef AOI_INTERNAL_HEIGHT +#define AOI_INTERNAL_HEIGHT 360 +#endif +#ifndef AOI_TILE_WIDTH +#define AOI_TILE_WIDTH 16 +#endif +#ifndef AOI_TILE_HEIGHT +#define AOI_TILE_HEIGHT 16 +#endif +#ifndef AOI_SPRITESHEET_PATH +#define AOI_SPRITESHEET_PATH "spritesheet.png" +#endif +#ifndef AOI_FPS +#define AOI_FPS 60.0 +#endif + +typedef ALLEGRO_COLOR aoi_color_t; + +#define aoi_color(r,g,b) ((aoi_color_t){r,g,b,0.0}) + +int aoi_btn(uint8_t btn); +void aoi_cls(aoi_color_t color); +void aoi_spr(uint8_t spr, int x, int y, uint8_t flip); +void aoi_sprEX(uint8_t spr, int x, int y, uint8_t flip, float scale, float rot, int w, int h); +void aoi_line(int x0, int y0, int x1, int y1, aoi_color_t color); +void aoi_rect(int x, int y, int w, int h, uint8_t filled, aoi_color_t color); +void aoi_map(int x, int y);