diff --git a/apps/examples/circle-raster/CMakeLists.txt b/apps/examples/circle-raster/CMakeLists.txt new file mode 100644 index 0000000..b92f11b --- /dev/null +++ b/apps/examples/circle-raster/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.21) + +project(circle-raster LANGUAGES C) + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Debug) +endif() + +add_subdirectory($ENV{TWNROOT} $ENV{TWNROOT}/build) + +set(SOURCE_FILES + game.c + state.h +) + +use_townengine(${PROJECT_NAME} "${SOURCE_FILES}" ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/apps/examples/circle-raster/data/twn.toml b/apps/examples/circle-raster/data/twn.toml new file mode 100644 index 0000000..2752b58 --- /dev/null +++ b/apps/examples/circle-raster/data/twn.toml @@ -0,0 +1,26 @@ +# This file contains everything about the engine and your game that can be +# configured before it runs. +# +# Optional settings are commented out, with their default values shown. +# Invalid values in these settings will be ignored. + +# Data about your game as an application +[about] +title = "Template" +developer = "You" +app_id = "template" +dev_id = "you" + +# Game runtime details +[game] +resolution = [ 640, 480 ] +#debug = true + +# Engine tweaks. You probably don't need to change these +[engine] +#ticks_per_second = 60 # minimum of 8 +#keybind_slots = 3 # minimum of 1 +#texture_atlas_size = 2048 # minimum of 32 +#font_texture_size = 2048 # minimum of 1024 +#font_oversampling = 4 # minimum of 0 +#font_filtering = "linear" # possible values: "nearest", "linear" diff --git a/apps/examples/circle-raster/game.c b/apps/examples/circle-raster/game.c new file mode 100644 index 0000000..b5d7e62 --- /dev/null +++ b/apps/examples/circle-raster/game.c @@ -0,0 +1,54 @@ +#include "twn_game_api.h" +#include "state.h" + +#include +#include + + +/* Emits `x` and `y` for every intersecting cell */ +/* We snap position to the nearest corner, which means there's no aliasing */ +/* It works great for integer radii */ +#define m_iter_circle_pixels(p_center_x, p_center_y, p_radius) \ + for (float y = (p_center_y + ceilf(p_radius)) - 1; y > (p_center_y - ceilf(p_radius)) - 1; --y) \ + for (float x = p_center_x - ceilf(sqrtf(p_radius * p_radius - (y - p_center_y + (y <= p_center_y)) * (y - p_center_y + (y <= p_center_y)))); x < p_center_x + ceilf(sqrtf(p_radius * p_radius - (y - p_center_y + (y <= p_center_y)) * (y - p_center_y + (y <= p_center_y)))); ++x) + + +void game_tick(void) { + if (ctx.initialization_needed) { + if (!ctx.udata) { + ctx.udata = ccalloc(1, sizeof (struct state)); + struct state *state = ctx.udata; + state->r = 10; + } + } + + struct state *state = ctx.udata; + + Vec2 const mouse_snap = {floorf(ctx.mouse_position.x / 8) * 8, floorf(ctx.mouse_position.y / 8) * 8}; + + input_action("up", CONTROL_LEFT_MOUSE); + input_action("down", CONTROL_RIGHT_MOUSE); + + if (input_action_just_pressed("up")) + state->r += 1; + if (input_action_just_pressed("down")) + state->r -= 1; + + float const rs = state->r * state->r; + float const cr = ceilf(state->r); + for (float iy = cr - 1; iy > -cr - 1; --iy) { + float const dx = ceilf(sqrtf(rs - (iy + (iy <= 0)) * (iy + (iy <= 0)))); + for (float ix = -dx; ix < dx; ++ix) { + draw_box((Rect){mouse_snap.x + ix * 8, mouse_snap.y + iy * 8, 8, 8}, 1, (Color){255, 0, 0, 125}); + } + } + + draw_circle(mouse_snap, state->r * 8, (Color){125, 125, 125, 125}); +} + + +void game_end(void) { + /* do your deinitialization here */ + struct state *state = ctx.udata; + free(state); +} diff --git a/apps/examples/circle-raster/state.h b/apps/examples/circle-raster/state.h new file mode 100644 index 0000000..25ac5f9 --- /dev/null +++ b/apps/examples/circle-raster/state.h @@ -0,0 +1,11 @@ +#ifndef STATE_H +#define STATE_H + +#include "twn_game_api.h" + +struct state { + float r; +}; + + +#endif