aoi
This commit is contained in:
commit
c923c07747
3 changed files with 359 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
*.o
|
319
aoi.c
Normal file
319
aoi.c
Normal file
|
@ -0,0 +1,319 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <allegro5/allegro.h>
|
||||||
|
#include <allegro5/allegro_image.h>
|
||||||
|
#include <allegro5/allegro_primitives.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
39
aoi.h
Normal file
39
aoi.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <allegro5/allegro.h>
|
||||||
|
|
||||||
|
#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);
|
Loading…
Reference in a new issue