/apps/examples/circle-raster: simple code for grid-centered circle rasterization

This commit is contained in:
veclavtalica 2025-01-24 23:26:32 +03:00
parent cb5f207761
commit 37cd8cf2cf
4 changed files with 107 additions and 0 deletions

View File

@ -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})

View File

@ -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"

View File

@ -0,0 +1,54 @@
#include "twn_game_api.h"
#include "state.h"
#include <malloc.h>
#include <math.h>
/* 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);
}

View File

@ -0,0 +1,11 @@
#ifndef STATE_H
#define STATE_H
#include "twn_game_api.h"
struct state {
float r;
};
#endif