2025-01-24 20:26:32 +00:00
|
|
|
#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)
|
|
|
|
|
|
|
|
|
2025-01-24 21:53:28 +00:00
|
|
|
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");
|
|
|
|
|
2025-01-24 23:28:40 +00:00
|
|
|
profile_start("int32_t acc");
|
|
|
|
|
|
|
|
for (int i = 0; i < 1000; ++i) {
|
|
|
|
int32_t const rsi = (int32_t)state->r * (int32_t)state->r;
|
|
|
|
int32_t acc = 1;
|
|
|
|
for (int32_t iy = (int32_t)state->r - 1; iy >= 0; --iy) {
|
|
|
|
while (acc * acc < rsi - iy * iy) acc++;
|
|
|
|
for (int32_t ix = -acc; ix < acc; ++ix) {
|
|
|
|
/* lower portion */
|
|
|
|
x = (float)ix;
|
|
|
|
y = (float)iy;
|
|
|
|
/* upper portion */
|
|
|
|
x = (float)ix;
|
|
|
|
y = (float)-iy - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
profile_end("int32_t acc");
|
|
|
|
|
2025-01-25 02:48:11 +00:00
|
|
|
profile_start("int32_t acc precalc");
|
|
|
|
|
|
|
|
for (int i = 0; i < 1000; ++i) {
|
|
|
|
int32_t const rsi = (int32_t)state->r * (int32_t)state->r;
|
|
|
|
int32_t acc = (int32_t)(sqrtf(state->r * state->r - (state->r - 1) * (state->r - 1)));
|
|
|
|
for (int32_t iy = (int32_t)state->r - 1; iy >= 0; --iy) {
|
|
|
|
while (acc * acc < rsi - iy * iy) acc++;
|
|
|
|
for (int32_t ix = -acc; ix < acc; ++ix) {
|
|
|
|
/* lower portion */
|
|
|
|
x = (float)ix;
|
|
|
|
y = (float)iy;
|
|
|
|
/* upper portion */
|
|
|
|
x = (float)ix;
|
|
|
|
y = (float)(int32_t)(~(uint32_t)iy);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
profile_end("int32_t acc precalc");
|
|
|
|
|
2025-01-24 21:53:28 +00:00
|
|
|
(void)x; (void)y;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-01-24 20:26:32 +00:00
|
|
|
void game_tick(void) {
|
|
|
|
if (ctx.initialization_needed) {
|
|
|
|
if (!ctx.udata) {
|
|
|
|
ctx.udata = ccalloc(1, sizeof (struct state));
|
|
|
|
struct state *state = ctx.udata;
|
2025-01-25 02:48:11 +00:00
|
|
|
state->r = 24;
|
2025-01-24 20:26:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2025-01-24 21:53:28 +00:00
|
|
|
int32_t const rsi = (int32_t)state->r * (int32_t)state->r;
|
2025-01-24 23:28:40 +00:00
|
|
|
int32_t acc = 1;
|
|
|
|
for (int32_t iy = (int32_t)state->r - 1; iy >= 0; --iy) {
|
|
|
|
while (acc * acc < rsi - iy * iy) acc++;
|
|
|
|
for (int32_t ix = -acc; ix < acc; ++ix) {
|
|
|
|
/* lower portion */
|
2025-01-24 21:53:28 +00:00
|
|
|
draw_box((Rect){mouse_snap.x + (float)ix * 8, mouse_snap.y + (float)iy * 8, 8, 8}, 1, (Color){125, 125, 0, 255});
|
2025-01-24 23:28:40 +00:00
|
|
|
/* upper portion */
|
|
|
|
draw_box((Rect){mouse_snap.x + (float)ix * 8, mouse_snap.y + (float)(-iy - 1) * 8, 8, 8}, 1, (Color){125, 125, 0, 255});
|
2025-01-24 20:26:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
draw_circle(mouse_snap, state->r * 8, (Color){125, 125, 125, 125});
|
2025-01-24 21:53:28 +00:00
|
|
|
|
|
|
|
benchmark(state);
|
2025-01-24 20:26:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void game_end(void) {
|
|
|
|
/* do your deinitialization here */
|
|
|
|
struct state *state = ctx.udata;
|
|
|
|
free(state);
|
|
|
|
}
|