├── LICENSE ├── README.md ├── allegro_framework.c └── allegro_framework.h /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) arvidsson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | allegro_framework 2 | =========== 3 | 4 | Tiny Allegro 5 C framework. 5 | 6 | > Quickly prototype ideas or get acquainted with Allegro 5 without having to reinvent the game loop! 7 | 8 | Features 9 | -------- 10 | 11 | * easy setup of allegro and addons 12 | * game loop 13 | * simplified input 14 | * error handling and logging 15 | * random number generation 16 | * basic collision detection 17 | 18 | Install 19 | ------------ 20 | 21 | Include ```allegro_framework.c``` and ```allegro_framework.h``` in your project. 22 | 23 | Example 24 | ------- 25 | 26 | ```c 27 | #include "allegro_framework.h" 28 | 29 | Rectangle r = { 50, 50, 50, 50 }; 30 | Velocity v = { 3, 3 }; 31 | 32 | void update() 33 | { 34 | if (is_key_down(ALLEGRO_KEY_ESCAPE)) { 35 | quit(); 36 | } 37 | 38 | r.x += v.dx; 39 | r.y += v.dy; 40 | 41 | if (r.x < 0 || r.x + r.w > get_window_width()) { 42 | v.dx = -v.dx; 43 | } 44 | 45 | if (r.y < 0 || r.y + r.h > get_window_height()) { 46 | v.dy = -v.dy; 47 | } 48 | } 49 | 50 | void render() 51 | { 52 | al_draw_filled_rectangle(r.x, r.y, r.x + r.w, r.y + r.h, red_color); 53 | } 54 | 55 | int main(int argc, char *argv[]) 56 | { 57 | // must be called first! 58 | init_framework("example", 640, 480, false); 59 | 60 | // the game loop runs until we call quit() 61 | run_game_loop(update, render); 62 | 63 | return 0; 64 | } 65 | ``` 66 | 67 | License 68 | ------- 69 | MIT (c) arvidsson 70 | -------------------------------------------------------------------------------- /allegro_framework.c: -------------------------------------------------------------------------------- 1 | #include "allegro_framework.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static ALLEGRO_EVENT_QUEUE *event_queue = NULL; 10 | static ALLEGRO_DISPLAY *display = NULL; 11 | static ALLEGRO_TIMER *timer = NULL; 12 | static ALLEGRO_FILE *logfile = NULL; 13 | static ALLEGRO_FONT *default_font = NULL; 14 | 15 | static bool is_done = false; 16 | static bool is_paused = false; 17 | static bool should_alt_tab_pause = true; 18 | 19 | static bool keys[ALLEGRO_KEY_MAX] = { false }; 20 | static bool keys_pressed[ALLEGRO_KEY_MAX] = { false }; 21 | static bool keys_released[ALLEGRO_KEY_MAX] = { false }; 22 | 23 | static int mouse_x = 0, mouse_y = 0; 24 | static int mouse_old_x = 0, mouse_old_y = 0; 25 | static bool mouse_buttons[MAX_MOUSE_BUTTONS] = { false }; 26 | static bool mouse_buttons_pressed[MAX_MOUSE_BUTTONS] = { false }; 27 | static bool mouse_buttons_released[MAX_MOUSE_BUTTONS] = { false }; 28 | 29 | ALLEGRO_COLOR black_color; 30 | ALLEGRO_COLOR white_color; 31 | ALLEGRO_COLOR dark_grey_color; 32 | ALLEGRO_COLOR grey_color; 33 | ALLEGRO_COLOR light_grey_color; 34 | ALLEGRO_COLOR red_color; 35 | ALLEGRO_COLOR green_color; 36 | ALLEGRO_COLOR dark_green_color; 37 | ALLEGRO_COLOR blue_color; 38 | ALLEGRO_COLOR yellow_color; 39 | ALLEGRO_COLOR cyan_color; 40 | ALLEGRO_COLOR magenta_color; 41 | ALLEGRO_COLOR maroon_color; 42 | ALLEGRO_COLOR purple_color; 43 | ALLEGRO_COLOR lime_color; 44 | ALLEGRO_COLOR olive_color; 45 | ALLEGRO_COLOR navy_color; 46 | ALLEGRO_COLOR teal_color; 47 | ALLEGRO_COLOR brown_color; 48 | 49 | void write_logfile(int log_level, const char *format, ...) 50 | { 51 | char buffer[4096]; 52 | 53 | if (!logfile) { 54 | logfile = al_fopen("log.txt", "w"); 55 | } 56 | 57 | if (log_level == LOG_WARNING) { 58 | al_fputs(logfile, "WARNING: "); 59 | } 60 | else if (log_level == LOG_ERROR) { 61 | al_fputs(logfile, "ERROR: "); 62 | } 63 | 64 | va_list args; 65 | va_start(args, format); 66 | vsnprintf(buffer, sizeof(buffer), format, args); 67 | va_end(args); 68 | 69 | al_fputs(logfile, buffer); 70 | al_fputs(logfile, "\n"); 71 | 72 | if (log_level == LOG_ERROR) { 73 | exit(1); 74 | } 75 | } 76 | 77 | void init_framework(const char *title, int window_width, int window_height, bool fullscreen) 78 | { 79 | if (!al_init()) { 80 | log_error("Failed to initialize allegro"); 81 | } 82 | 83 | atexit(destroy_framework); 84 | 85 | al_set_exe_name(title); 86 | al_set_app_name(title); 87 | 88 | // set correct resource directory 89 | ALLEGRO_PATH *path = al_get_standard_path(ALLEGRO_RESOURCES_PATH); 90 | al_change_directory(al_path_cstr(path, '/')); 91 | al_destroy_path(path); 92 | 93 | if (!al_install_keyboard()) { 94 | log_error("Failed to install keyboard"); 95 | } 96 | 97 | if (!al_install_mouse()) { 98 | log_error("Failed to install mouse"); 99 | } 100 | 101 | if (!al_init_primitives_addon()) { 102 | log_error("Failed to init primitives addon"); 103 | } 104 | 105 | if (!al_init_image_addon()) { 106 | log_error("Failed to init image addon"); 107 | } 108 | 109 | al_init_font_addon(); 110 | default_font = al_create_builtin_font(); 111 | if (!default_font) { 112 | log_error("Failed to create builtin font"); 113 | } 114 | 115 | event_queue = al_create_event_queue(); 116 | if (!event_queue) { 117 | log_error("Failed to create event queue"); 118 | } 119 | 120 | if (fullscreen) { 121 | al_set_new_display_flags(ALLEGRO_FULLSCREEN_WINDOW); 122 | } 123 | else { 124 | al_set_new_display_flags(ALLEGRO_WINDOWED); 125 | } 126 | 127 | display = al_create_display(window_width, window_height); 128 | if (!display) { 129 | log_error("Failed to create display @ %dx%d", window_width, window_height); 130 | } 131 | al_set_window_title(display, title); 132 | 133 | timer = al_create_timer(1.0 / 60); 134 | if (!timer) { 135 | log_error("Failed to create timer"); 136 | } 137 | 138 | al_register_event_source(event_queue, al_get_keyboard_event_source()); 139 | al_register_event_source(event_queue, al_get_mouse_event_source()); 140 | al_register_event_source(event_queue, al_get_display_event_source(display)); 141 | al_register_event_source(event_queue, al_get_timer_event_source(timer)); 142 | 143 | srand(time(NULL)); 144 | 145 | // initialize default colors 146 | black_color = al_map_rgb(0, 0, 0); 147 | white_color = al_map_rgb(255, 255, 255); 148 | dark_grey_color = al_map_rgb(64, 64, 64); 149 | grey_color = al_map_rgb(128, 128, 128); 150 | light_grey_color = al_map_rgb(192, 192, 192); 151 | red_color = al_map_rgb(255, 0, 0); 152 | green_color = al_map_rgb(0, 255, 0); 153 | dark_green_color = al_map_rgb(0, 100, 0); 154 | blue_color = al_map_rgb(0, 0, 255); 155 | yellow_color = al_map_rgb(255, 255, 0); 156 | cyan_color = al_map_rgb(0, 255, 255); 157 | magenta_color = al_map_rgb(255, 0, 255); 158 | maroon_color = al_map_rgb(128, 0, 0); 159 | purple_color = al_map_rgb(128, 0, 128); 160 | lime_color = al_map_rgb(191, 255, 0); 161 | olive_color = al_map_rgb(128, 128, 0); 162 | navy_color = al_map_rgb(0, 0, 128); 163 | teal_color = al_map_rgb(0, 128, 128); 164 | brown_color = al_map_rgb(101, 55, 0); 165 | } 166 | 167 | void destroy_framework() 168 | { 169 | if (default_font) { 170 | al_destroy_font(default_font); 171 | default_font = NULL; 172 | } 173 | 174 | if (timer) { 175 | al_destroy_timer(timer); 176 | timer = NULL; 177 | } 178 | 179 | if (display) { 180 | al_destroy_display(display); 181 | display = NULL; 182 | } 183 | 184 | if (event_queue) { 185 | al_destroy_event_queue(event_queue); 186 | event_queue = NULL; 187 | } 188 | 189 | if (logfile) { 190 | al_fclose(logfile); 191 | logfile = NULL; 192 | } 193 | } 194 | 195 | void run_game_loop(void (*update_proc)(), void (*render_proc)()) 196 | { 197 | bool should_redraw = true; 198 | al_start_timer(timer); 199 | 200 | while (!is_done) { 201 | ALLEGRO_EVENT event; 202 | al_wait_for_event(event_queue, &event); 203 | 204 | switch (event.type) { 205 | case ALLEGRO_EVENT_TIMER: 206 | should_redraw = true; 207 | if (!is_paused) { 208 | update_proc(); 209 | } 210 | 211 | // clear input state 212 | memset(keys_pressed, false, sizeof(keys_pressed)); 213 | memset(keys_released, false, sizeof(keys_pressed)); 214 | memset(mouse_buttons_pressed, false, sizeof(mouse_buttons_pressed)); 215 | memset(mouse_buttons_released, false, sizeof(mouse_buttons_released)); 216 | mouse_old_x = mouse_x; 217 | mouse_old_y = mouse_y; 218 | break; 219 | 220 | case ALLEGRO_EVENT_KEY_DOWN: 221 | keys[event.keyboard.keycode] = true; 222 | keys_pressed[event.keyboard.keycode] = true; 223 | break; 224 | 225 | case ALLEGRO_EVENT_KEY_UP: 226 | keys[event.keyboard.keycode] = false; 227 | keys_released[event.keyboard.keycode] = true; 228 | break; 229 | 230 | case ALLEGRO_EVENT_KEY_CHAR: 231 | // handle alt-tab 232 | if ((event.keyboard.modifiers & ALLEGRO_KEYMOD_ALT) && 233 | event.keyboard.keycode == ALLEGRO_KEY_ENTER) { 234 | al_set_display_flag(display, ALLEGRO_FULLSCREEN_WINDOW, !(al_get_display_flags(display) & ALLEGRO_FULLSCREEN_WINDOW)); 235 | } 236 | break; 237 | 238 | case ALLEGRO_EVENT_MOUSE_AXES: 239 | mouse_x = event.mouse.x; 240 | mouse_y = event.mouse.y; 241 | break; 242 | 243 | case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN: 244 | mouse_buttons[event.mouse.button] = true; 245 | mouse_buttons_pressed[event.mouse.button] = true; 246 | break; 247 | 248 | case ALLEGRO_EVENT_MOUSE_BUTTON_UP: 249 | mouse_buttons[event.mouse.button] = false; 250 | mouse_buttons_released[event.mouse.button] = true; 251 | break; 252 | 253 | case ALLEGRO_EVENT_DISPLAY_CLOSE: 254 | is_done = true; 255 | break; 256 | 257 | case ALLEGRO_EVENT_DISPLAY_SWITCH_OUT: 258 | if (should_alt_tab_pause) { 259 | is_paused = true; 260 | } 261 | break; 262 | 263 | case ALLEGRO_EVENT_DISPLAY_SWITCH_IN: 264 | if (should_alt_tab_pause) { 265 | is_paused = false; 266 | } 267 | break; 268 | } 269 | 270 | if (should_redraw && al_is_event_queue_empty(event_queue) && !is_paused) { 271 | should_redraw = false; 272 | al_set_target_bitmap(al_get_backbuffer(display)); 273 | al_clear_to_color(al_map_rgb(0, 0, 0)); 274 | render_proc(); 275 | al_flip_display(); 276 | } 277 | } 278 | } 279 | 280 | void quit() 281 | { 282 | is_done = true; 283 | } 284 | 285 | void alt_tab_should_pause(bool true_or_false) 286 | { 287 | should_alt_tab_pause = true_or_false; 288 | } 289 | 290 | int get_window_width() 291 | { 292 | assert(display != NULL); 293 | return al_get_display_width(display); 294 | } 295 | 296 | int get_window_height() 297 | { 298 | assert(display != NULL); 299 | return al_get_display_height(display); 300 | } 301 | 302 | bool is_key_down(int keycode) 303 | { 304 | assert(keycode >= 0 && keycode < ALLEGRO_KEY_MAX); 305 | return keys[keycode]; 306 | } 307 | 308 | bool is_key_pressed(int keycode) 309 | { 310 | assert(keycode >= 0 && keycode < ALLEGRO_KEY_MAX); 311 | return keys_pressed[keycode]; 312 | } 313 | 314 | bool is_key_released(int keycode) 315 | { 316 | assert(keycode >= 0 && keycode < ALLEGRO_KEY_MAX); 317 | return keys_released[keycode]; 318 | } 319 | 320 | int get_mouse_x() 321 | { 322 | return mouse_x; 323 | } 324 | 325 | int get_mouse_y() 326 | { 327 | return mouse_y; 328 | } 329 | 330 | int get_mouse_dx() 331 | { 332 | return mouse_x - mouse_old_x; 333 | } 334 | 335 | int get_mouse_dy() 336 | { 337 | return mouse_y - mouse_old_y; 338 | } 339 | 340 | bool is_mouse_button_down(int mouse_button) 341 | { 342 | assert(mouse_button >= 0 && mouse_button < al_get_mouse_num_buttons()); 343 | return mouse_buttons[mouse_button]; 344 | } 345 | 346 | bool is_mouse_button_pressed(int mouse_button) 347 | { 348 | assert(mouse_button >= 0 && mouse_button < al_get_mouse_num_buttons()); 349 | return mouse_buttons_pressed[mouse_button]; 350 | } 351 | 352 | bool is_mouse_button_released(int mouse_button) 353 | { 354 | assert(mouse_button >= 0 && mouse_button < al_get_mouse_num_buttons()); 355 | return mouse_buttons_released[mouse_button]; 356 | } 357 | 358 | int wait_for_keypress() 359 | { 360 | ALLEGRO_EVENT event; 361 | do { 362 | al_wait_for_event(event_queue, &event); 363 | } while (event.type != ALLEGRO_EVENT_KEY_DOWN); 364 | return event.keyboard.keycode; 365 | } 366 | 367 | bool is_float_equal(float a, float b) 368 | { 369 | return fabs(a - b) < ALMOST_ZERO; 370 | } 371 | 372 | bool is_double_equal(double a, double b) 373 | { 374 | return fabs(a - b) < ALMOST_ZERO; 375 | } 376 | 377 | int lerpi(int a, int b, int alpha) 378 | { 379 | return a + alpha * (b - a); 380 | } 381 | 382 | float lerpf(float a, float b, float alpha) 383 | { 384 | return a + alpha * (b - a); 385 | } 386 | 387 | double lerpd(double a, double b, double alpha) 388 | { 389 | return a + alpha * (b - a); 390 | } 391 | 392 | int get_random_int(int min, int max) 393 | { 394 | return min + (rand() % (int)(max - min + 1)); 395 | } 396 | 397 | float get_random_float(float min, float max) 398 | { 399 | return min + ((float)rand() / ((float)RAND_MAX / (max - min))); 400 | } 401 | 402 | bool one_in(int chance) 403 | { 404 | if (get_random_int(0, chance - 1) == 0) 405 | return true; 406 | return false; 407 | } 408 | 409 | int roll_dice(int number, int sides) 410 | { 411 | int result = 0; 412 | for (int i = 0; i < number; i++) 413 | result += get_random_int(1, sides); 414 | return result; 415 | } 416 | 417 | ALLEGRO_FONT* get_default_font() 418 | { 419 | return default_font; 420 | } 421 | 422 | float angle_between_points(float x1, float y1, float x2, float y2) 423 | { 424 | return atan2(y2 - y1, x2 - x1); 425 | } 426 | 427 | float angle_between_points_ex(Point p1, Point p2) 428 | { 429 | return angle_between_points(p1.x, p1.y, p2.x, p2.y); 430 | } 431 | 432 | float distance_between_points(float x1, float y1, float x2, float y2) 433 | { 434 | float dx = x2 - x1; 435 | float dy = y2 - y1; 436 | return sqrt(dx * dx + dy * dy); 437 | } 438 | 439 | float distance_between_points_ex(Point p1, Point p2) 440 | { 441 | return distance_between_points(p1->x, p1->y, p2->x, p2->y); 442 | } 443 | 444 | bool rectangles_intersect(float l1, float t1, float r1, float b1, float l2, float t2, float r2, float b2) 445 | { 446 | return !(r1 < l2 || b1 < t2 || l1 > r2 || t1 > b2); 447 | } 448 | 449 | bool rectangles_intersect_ex(Rectangle r1, Rectangle r2) 450 | { 451 | return rectangles_intersect(r1->x, r1-y, r1->x + r1->w, r1->y + r1->h, r2->x, r2-y, r2->x + r2->w, r2->y + r2->h); 452 | } 453 | 454 | bool rectangle_contains_point(float l, float t, float r, float b, float x, float y) 455 | { 456 | return !(x < l || x > r || y < t || y > b); 457 | } 458 | 459 | bool rectangle_contains_point_ex(Rectangle r, Point p) 460 | { 461 | return rectangle_contains_point(r->x, r-y, r->x + r->w, r->y + r->h, p->x, p->y); 462 | } 463 | 464 | bool circles_intersect(float x1, float y1, float r1, float x2, float y2, float r2) 465 | { 466 | float radii = r1 + r2; 467 | float dx = x2 - x1; 468 | float dy = y2 - y1; 469 | return (radii * radii) > (dx * dx + dy * dy); 470 | } 471 | 472 | bool circles_intersect_ex(Circle c1, Circle c2) 473 | { 474 | return circles_intersect(c1->x, c1->y, c1->r, c2->x, c2->y, c2->r); 475 | } 476 | 477 | bool circle_contains_point(float x1, float y1, float r, float x2, float y2) 478 | { 479 | float dx = x2 - x1; 480 | float dy = y2 - y1; 481 | return (dx * dx + dy * dy) < (r * r); 482 | } 483 | 484 | bool circle_contains_point_ex(Circle c, Point p) 485 | { 486 | return circle_contains_point(c->x, c->y, c->r, p->x, p->y); 487 | } 488 | -------------------------------------------------------------------------------- /allegro_framework.h: -------------------------------------------------------------------------------- 1 | #ifndef INCLUDED_ALLEGRO_FRAMEWORK_H 2 | #define INCLUDED_ALLEGRO_FRAMEWORK_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | //============================================================================== 9 | 10 | // Includes. 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | //============================================================================== 17 | // UTIL 18 | //============================================================================== 19 | 20 | #define lengthof(x) (sizeof(x) / sizeof(x[0])) 21 | 22 | //============================================================================== 23 | // DEBUG 24 | //============================================================================== 25 | 26 | /* 27 | Logging macros. 28 | - log_message: for debug messages 29 | - log_warning: for non-fatal errors, i.e. continue program execution 30 | - log_error: for fatal errors, program will be forcefully terminated 31 | */ 32 | #define log_message(...) write_logfile(LOG_MESSAGE, __VA_ARGS__); 33 | #define log_warning(...) write_logfile(LOG_WARNING, __VA_ARGS__); 34 | #define log_error(...) write_logfile(LOG_ERROR, __VA_ARGS__); 35 | 36 | // logging levels (used in write_logfile) 37 | enum { LOG_MESSAGE, LOG_WARNING, LOG_ERROR }; 38 | 39 | /* 40 | Writes a message to the logfile. 41 | Use the logging macros above instead of using this function directly. 42 | */ 43 | void write_logfile(int log_level, const char *format, ...); 44 | 45 | //============================================================================== 46 | // FRAMEWORK 47 | //============================================================================== 48 | 49 | /* 50 | Initializes the framework. 51 | This must be called before you use anything else in this framework! 52 | 53 | title: the window title 54 | window_width: the width of the window 55 | window_height: the height of the window 56 | fullscreen: whether to start in fullscreen or not 57 | */ 58 | void init_framework(const char *title, int window_width, int window_height, bool fullscreen); 59 | 60 | /* 61 | Destroys everything we need to clean up when it is time to quit the program. 62 | This function is called automatically at program exit. 63 | */ 64 | void destroy_framework(); 65 | 66 | /* 67 | Runs the game loop; the heart of the game! 68 | 69 | update_proc() and draw_proc() are function pointers you need to define yourself. 70 | Will call update_proc() 60 times per second. 71 | Will call render_proc() 60 times a second if there is no other events to deal with. 72 | If there is nothing else to do, the game loop will sleep. 73 | */ 74 | void run_game_loop(void (*update_proc)(), void (*render_proc)()); 75 | 76 | // Stops the game loop. 77 | void quit(); 78 | 79 | /* 80 | Sets alt-tab behavior (switching out & in from an application). 81 | If enabled, the game logic and rendering will pause until the game 82 | becomes active again. This is enabled by default. 83 | */ 84 | void alt_tab_should_pause(bool true_or_false); 85 | 86 | //============================================================================== 87 | // GRAPHICS 88 | //============================================================================== 89 | 90 | // Returns the width of the window. 91 | int get_window_width(); 92 | 93 | // Returns the height of the window. 94 | int get_window_height(); 95 | 96 | // Returns a default font. Mainly used for debugging purposes. 97 | ALLEGRO_FONT* get_default_font(); 98 | 99 | // Default colors. 100 | extern ALLEGRO_COLOR black_color; 101 | extern ALLEGRO_COLOR white_color; 102 | extern ALLEGRO_COLOR dark_grey_color; 103 | extern ALLEGRO_COLOR grey_color; 104 | extern ALLEGRO_COLOR light_grey_color; 105 | extern ALLEGRO_COLOR red_color; 106 | extern ALLEGRO_COLOR green_color; 107 | extern ALLEGRO_COLOR dark_green_color; 108 | extern ALLEGRO_COLOR blue_color; 109 | extern ALLEGRO_COLOR yellow_color; 110 | extern ALLEGRO_COLOR cyan_color; 111 | extern ALLEGRO_COLOR magenta_color; 112 | extern ALLEGRO_COLOR maroon_color; 113 | extern ALLEGRO_COLOR purple_color; 114 | extern ALLEGRO_COLOR lime_color; 115 | extern ALLEGRO_COLOR olive_color; 116 | extern ALLEGRO_COLOR navy_color; 117 | extern ALLEGRO_COLOR teal_color; 118 | extern ALLEGRO_COLOR brown_color; 119 | 120 | //============================================================================== 121 | // INPUT 122 | //============================================================================== 123 | 124 | // Returns true if a key on the keyboard is held down. 125 | bool is_key_down(int keycode); 126 | 127 | // Returns true if a key on the keyboard was pressed. 128 | bool is_key_pressed(int keycode); 129 | 130 | // Returns true if a key on the keyboard was released. 131 | bool is_key_released(int keycode); 132 | 133 | // helper mouse input enum 134 | enum { 135 | MOUSE_LEFT_BUTTON, 136 | MOUSE_RIGHT_BUTTON, 137 | MOUSE_MIDDLE_BUTTON, 138 | MAX_MOUSE_BUTTONS 139 | }; 140 | 141 | // Returns mouse x coordinate. 142 | int get_mouse_x(); 143 | 144 | // Returns mouse y coordinate. 145 | int get_mouse_y(); 146 | 147 | // Returns mouse delta movement in x since last frame. 148 | int get_mouse_dx(); 149 | 150 | // Returns mouse delta movement in y since last frame. 151 | int get_mouse_dy(); 152 | 153 | // Returns true if a mouse button is held down. 154 | bool is_mouse_button_down(int mouse_button); 155 | 156 | // Returns true if a mouse button was pressed. 157 | bool is_mouse_button_pressed(int mouse_button); 158 | 159 | // Returns true if a mouse button was released. 160 | bool is_mouse_button_released(int mouse_button); 161 | 162 | /* 163 | Waits until a key is pressed on the keyboard. 164 | Returns the keycode of the key that was pressed. 165 | */ 166 | int wait_for_keypress(); 167 | 168 | //============================================================================== 169 | // MATH 170 | //============================================================================== 171 | 172 | // Math Constants. 173 | #define ALMOST_ZERO (0.001) 174 | #define PI (3.14159265358979323846) 175 | #define TWO_PI (PI * 2) 176 | #define HALF_PI (PI / 2) 177 | #define QUARTER_PI (PI / 4) 178 | #define EULER_NUMBER (2.718281828459045) 179 | 180 | // Convert to and from degrees and radians. 181 | #define DEG2RAD(DEG) ((DEG)*((PI)/(180.0))) 182 | #define RAD2DEG(RAD) ((RAD)*((180.0)/(PI))) 183 | 184 | bool is_float_equal(float a, float b); 185 | bool is_double_equal(double a, double b); 186 | int lerpi(int a, int b, int alpha); 187 | float lerpf(float a, float b, float alpha); 188 | double lerpd(double a, double b, double alpha); 189 | 190 | //============================================================================== 191 | // RANDOM 192 | //============================================================================== 193 | 194 | // Returns a random integer between [min, max]. 195 | int get_random_int(int min, int max); 196 | 197 | // Returns a random float between [min, max]. 198 | float get_random_float(float min, float max); 199 | 200 | // Returns true if the random number is one in [chance]. 201 | bool one_in(int chance); 202 | 203 | // Returns the result of rolling dice with a number of sides. 204 | int roll_dice(int number, int sides); 205 | 206 | //============================================================================== 207 | // COLLISION 208 | //============================================================================== 209 | 210 | // A point/vector. 211 | typedef struct { 212 | float x, y; 213 | } Point; 214 | 215 | // A rectangle. 216 | typedef struct { 217 | float x, y; 218 | float w, h; 219 | } Rectangle; 220 | 221 | // A circle. 222 | typedef struct { 223 | float x, y; 224 | float r; 225 | } Circle; 226 | 227 | // A velocity. 228 | typedef struct { 229 | float dx, dy; 230 | } Velocity; 231 | 232 | // Returns the angle between two points. 233 | float angle_between_points(float x1, float y1, float x2, float y2); 234 | 235 | // Returns the distance between two points. 236 | float distance_between_points(float x1, float y1, float x2, float y2); 237 | 238 | // Returns true if two rectangles overlap. 239 | bool rectangles_intersect(float l1, float t1, float r1, float b1, float l2, float t2, float r2, float b2); 240 | 241 | // Returns true if the point is inside the rectangle. 242 | bool rectangle_contains_point(float l, float t, float r, float b, float x, float y); 243 | 244 | // Returns true if two circles overlap. 245 | bool circles_intersect(float x1, float y1, float r1, float x2, float y2, float r2); 246 | 247 | // Returns true if the point is inside the circle. 248 | bool circle_contains_point(float x1, float y1, float r, float x2, float y2); 249 | 250 | // Variants of the functions using the structs defined above. 251 | float angle_between_points_ex(Point p1, Point p2); 252 | float distance_between_points_ex(Point p1, Point p2); 253 | bool rectangles_intersect_ex(Rectangle r1, Rectangle r2); 254 | bool rectangle_contains_point_ex(Rectangle r, Point p); 255 | bool circles_intersect_ex(Circle c1, Circle c2); 256 | bool circle_contains_point_ex(Circle c, Point p); 257 | 258 | //============================================================================== 259 | 260 | #ifdef __cplusplus 261 | } 262 | #endif 263 | 264 | #endif 265 | --------------------------------------------------------------------------------