#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) static int32_t ceil_sqrt(int32_t const n) { int32_t res = 1; #pragma clang loop unroll_count(8) while(res * res < n) res++; return res; } static void benchmark(struct state *state) { volatile float x, y; profile_start("float"); for (int i = 0; i < 1000; ++i) { float const rs = state->r * state->r; float const cr = ceilf(state->r); for (float iy = -cr; iy <= cr - 1; ++iy) { float const dx = ceilf(sqrtf(rs - (iy + (iy <= 0)) * (iy + (iy <= 0)))); for (float ix = -dx; ix < dx; ++ix) { x = ix; y = iy; } } } profile_end("float"); profile_start("int32_t"); for (int i = 0; i < 1000; ++i) { int32_t const rsi = (int32_t)state->r * (int32_t)state->r; for (int32_t iy = -(int32_t)state->r; iy <= (int32_t)state->r - 1; ++iy) { int32_t const dx = ceil_sqrt(rsi - (iy + (iy <= 0)) * (iy + (iy <= 0))); for (int32_t ix = -dx; ix < dx; ++ix) { x = (float)ix; y = (float)iy; } } } profile_end("int32_t"); (void)x; (void)y; } 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; int32_t const rsi = (int32_t)state->r * (int32_t)state->r; for (int32_t iy = -(int32_t)state->r; iy <= (int32_t)state->r - 1; ++iy) { int32_t const dx = ceil_sqrt(rsi - (iy + (iy <= 0)) * (iy + (iy <= 0))); for (int32_t ix = -dx; ix < dx; ++ix) { draw_box((Rect){mouse_snap.x + (float)ix * 8, mouse_snap.y + (float)iy * 8, 8, 8}, 1, (Color){125, 125, 0, 255}); } } draw_circle(mouse_snap, state->r * 8, (Color){125, 125, 125, 125}); benchmark(state); } void game_end(void) { /* do your deinitialization here */ struct state *state = ctx.udata; free(state); }