Wed, 02 Jul 2025 23:21:17 +0200
resolve TODOs regarding input.h
a) mouse position must be integer, because it can be negative (though rarely)
b) we should not trade "access complexity" for space in the scancodes array
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * Copyright 2023 Mike Becker. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include <ascension/core.h> #include <ascension/ui.h> #include <ascension/sprite.h> #include <ascension/2d.h> #include <cx/printf.h> enum Textures2d { TEX_SHIP = 0, TEX_BACKDROP, TEX2D_COUNT }; static AscTexture tex2d[TEX2D_COUNT]; #define TEXTURE_SHIP &tex2d[TEX_SHIP] #define TEXTURE_BACKDROP &tex2d[TEX_BACKDROP] #define BACKDROP_SCENE asc_window_scene(0) #define MAIN_SCENE asc_window_scene(1) static void destroy_textures(void) { asc_texture_destroy(tex2d, TEX2D_COUNT); } static void init_textures(void) { asc_texture_init_2d(tex2d, TEX2D_COUNT); asc_texture_from_file(TEXTURE_SHIP, "ship.png"); asc_texture_from_file(TEXTURE_BACKDROP, "backdrop.png"); asc_gl_context_add_cleanup_func(asc_active_glctx, destroy_textures); } static void update_fps_counter(AscBehavior *behavior) { AscSceneNode *node = behavior->node; static float last_fps = 0.f; if (fabsf(asc_context.frame_rate - last_fps) > 1) { last_fps = asc_context.frame_rate; asc_text_printf(node, "%.2f FPS", asc_context.frame_rate); } } static void tie_fps_counter_to_corner(AscBehavior *behavior) { // TODO: this should be replaced with some sort of UI layout manager AscSceneNode *node = behavior->node; if (asc_test_flag(node->flags, ASC_SCENE_NODE_GRAPHICS_UPDATED) || asc_active_window->resized) { asc_vec2u bottom_right = asc_active_window->dimensions; asc_vec2u text_size = ((AscText*)node)->dimension; asc_set_position2d( node, (int)bottom_right.x - (int)text_size.width - 10, (int)bottom_right.y - (int)text_size.height - 10 ); } } static void scale_backdrop(AscBehavior *behavior) { // scale the backdrop to the size of the window if (asc_active_window->resized) { AscSceneNode *node = behavior->node; asc_vec2u window_size = asc_active_window->dimensions; asc_sprite_set_size(node, window_size.width, window_size.height); } } static void create_backdrop(void) { AscSceneNode *node = asc_sprite( .texture = TEXTURE_BACKDROP, .texture_scale_mode = ASC_TEXTURE_SCALE_REPEAT ); asc_behavior_add(node, .func = scale_backdrop); asc_scene_add_node(BACKDROP_SCENE, node); } static void create_fps_counter(void) { asc_font(ASC_FONT_REGULAR, 12); asc_ink_rgb(255, 255, 255); AscSceneNode *node = asc_text(.name = "FPS Counter"); asc_behavior_add(node, .func = update_fps_counter, .interval = asc_seconds(1)); asc_behavior_add(node, tie_fps_counter_to_corner); asc_ui_add_node(node); } static void create_score_counter(void) { asc_font(ASC_FONT_BOLD, 16); asc_ink_rgb(0, 255, 0); AscSceneNode *node = asc_text( .name = "Score Counter", .x = 10, .y = 10, .text = "Score: 0" ); asc_ui_add_node(node); } static void create_spaceship(void) { AscSceneNode *sprite = asc_sprite( .name = "Player", .texture = TEXTURE_SHIP, .x = 250, .y = 300, .width = 64, .height = 64 ); asc_scene_add_node(MAIN_SCENE, sprite); // TODO: return something } static asc_recti update_viewport_for_window_resize(asc_vec2u window_size) { // Compute scaling and offsets unsigned viewport_size, offset_x = 0, offset_y = 0; if (window_size.width > window_size.height) { // Wider window: letterbox (black bars on top/bottom) offset_x = (window_size.width - window_size.height) / 2; viewport_size = window_size.height; } else { // Taller window: pillarbox (black bars on sides) offset_y = (window_size.height - window_size.width) / 2; viewport_size = window_size.width; } // Set the viewport to the scaled and centered region return asc_recti_new(offset_x, offset_y, viewport_size, viewport_size); } int main(void) { asc_context_initialize(); if (asc_has_error()) { SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error",asc_get_error(), NULL); return 1; } #ifdef TEST_BUILD asc_set_font_path("../../fonts"); asc_set_shader_path("../../shader"); asc_set_texture_path("../../test/snake/textures"); #endif // create window AscWindowSettings settings; asc_window_settings_init_defaults(&settings); settings.title = "Snake"; asc_window_initialize(0, &settings); asc_ui_scale_auto(); // load textures init_textures(); // initialize the scenes const int game_field_size = 500; asc_scene_init(BACKDROP_SCENE, .type = ASC_CAMERA_ORTHO, .projection_update_func = asc_camera_ortho_update_size ); asc_ink_rgb(0, 128, 90); asc_scene_init(MAIN_SCENE, .type = ASC_CAMERA_ORTHO, .ortho.rect = asc_recti_new(0, 0, game_field_size, game_field_size), .viewport_clear = true, .viewport_update_func = update_viewport_for_window_resize ); // backdrop for letterbox/pillarbox create_backdrop(); // create UI elements create_fps_counter(); create_score_counter(); // create spaceship create_spaceship(); // Main Loop do { // quit application on any error if (asc_has_error()) { SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", asc_get_error(), asc_active_window->window); asc_clear_error(); asc_context_quit(); } // debug-key for clearing the shader registry if (asc_key_pressed(ASC_KEY(S))) { asc_shader_clear_registry(); asc_dprintf("Shader cache cleared."); } // quit application on ESC key press if (asc_key_pressed(ASC_KEY(ESCAPE))) { asc_context_quit(); } } while (asc_loop_next()); // cleanup asc_context_destroy(); return 0; }