From c9208089c6074575342d529f494295c13269a1aa Mon Sep 17 00:00:00 2001 From: Mitya Selivanov Date: Tue, 14 Jan 2025 04:13:45 +0100 Subject: Rectangle anti-aliasing --- reduced_system_layer.c | 186 +++++++++++++++++++++++++++++++------------------ 1 file changed, 120 insertions(+), 66 deletions(-) (limited to 'reduced_system_layer.c') diff --git a/reduced_system_layer.c b/reduced_system_layer.c index 9eabca9..3d020bd 100755 --- a/reduced_system_layer.c +++ b/reduced_system_layer.c @@ -75,6 +75,7 @@ #/ - Graphics #/ - Font #/ - Adaptive resolution +#/ - Oklab color #/ #/ ---------------------------------------------------------------- #/ @@ -124,7 +125,7 @@ typedef unsigned u32; typedef unsigned long long u64; typedef char c8; typedef int c32; -typedef signed char b8; +typedef unsigned char b8; typedef float f32; typedef double f64; @@ -170,23 +171,59 @@ typedef struct { f64 v[16]; } mat4; extern "C" { #endif -enum { - MAX_NUM_PIXELS = 10 * 1024 * 1024, - MAX_INPUT_SIZE = 256, - MAX_CLIPBOARD_SIZE = 10 * 1024 * 1024, - MAX_NUM_SOCKETS = 64, - MAX_NUM_KEYS = 512, - MAX_PIXEL_SIZE = 16, +#ifndef MAX_NUM_PIXELS +#define MAX_NUM_PIXELS (10 * 1024 * 1024) +#endif - MIN_FRAME_DURATION = 9, - MAX_FRAME_DURATION = 38, +#ifndef MAX_INPUT_SIZE +#define MAX_INPUT_SIZE 256 +#endif - AUDIO_NUM_CHANNELS = 2, - AUDIO_SAMPLE_RATE = 44100, - AUDIO_AVAIL_MIN = 512, +#ifndef MAX_CLIPBOARD_SIZE +#define MAX_CLIPBOARD_SIZE (10 * 1024 * 1024) +#endif - MAX_NUM_AUDIO_FRAMES = 10 * AUDIO_SAMPLE_RATE * AUDIO_NUM_CHANNELS, // 10 seconds +#ifndef MAX_NUM_SOCKETS +#define MAX_NUM_SOCKETS 64 +#endif + +#ifndef MAX_NUM_KEYS +#define MAX_NUM_KEYS 512 +#endif + +#ifndef MIN_PIXEL_SIZE +#define MIN_PIXEL_SIZE 1 +#endif + +#ifndef MAX_PIXEL_SIZE +#define MAX_PIXEL_SIZE 16 +#endif + +#ifndef MIN_FRAME_DURATION +#define MIN_FRAME_DURATION 9 +#endif + +#ifndef MAX_FRAME_DURATION +#define MAX_FRAME_DURATION 38 +#endif + +#ifndef NUM_SOUND_CHANNELS +#define NUM_SOUND_CHANNELS 2 +#endif +#ifndef SOUND_SAMPLE_RATE +#define SOUND_SAMPLE_RATE 44100 +#endif + +#ifndef SOUND_AVAIL_MIN +#define SOUND_AVAIL_MIN 512 +#endif + +#ifndef MAX_NUM_SOUND_FRAMES +#define MAX_NUM_SOUND_FRAMES (10 * SOUND_SAMPLE_RATE * NUM_SOUND_CHANNELS) +#endif + +enum { IPv4_UDP = 1, IPv6_UDP = 2, @@ -329,15 +366,17 @@ typedef struct { typedef struct { c8 * title; + i32 real_width; + i32 real_height; i32 frame_width; i32 frame_height; - vec3_f32 * pixels; + vec4_f32 * pixels; i64 input_size; Input_Key *input; i64 clipboard_size; c8 * clipboard; b8 done; - b8 exact_resolution; // TODO + b8 exact_resolution; b8 graceful_exit; b8 has_focus; b8 has_cursor; @@ -408,6 +447,7 @@ i32 main(i32 argc, c8 **argv); f64 floor(f64 x); f64 ceil(f64 x); f64 sqrt(f64 x); +f64 cbrt(f64 x); f64 pow(f64 x, f64 y); f64 log(f64 x); f64 log2(f64 x); @@ -457,9 +497,9 @@ void update_and_render_frame(void) { for (i64 j = 0; j < g_platform.frame_height; ++j) for (i64 i = 0; i < g_platform.frame_width; ++i) if (i < x || i >= x + w || j < y || j >= y + h) - g_platform.pixels[j * g_platform.frame_width + i] = (vec3_f32) { .8f, .8f, .8f }; + g_platform.pixels[j * g_platform.frame_width + i] = (vec4_f32) { .8f, .8f, .8f, 1.f }; else - g_platform.pixels[j * g_platform.frame_width + i] = (vec3_f32) { .27f, .21f, .24f }; + g_platform.pixels[j * g_platform.frame_width + i] = (vec4_f32) { .27f, .21f, .24f, 1.f }; p_render_frame(); p_sleep_for(0); @@ -888,7 +928,7 @@ i64 p_send(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port) { static b8 _sound_ready = 0; static i64 _sound_position = 0; -static f32 _sound_ring[MAX_NUM_AUDIO_FRAMES] = {0}; +static f32 _sound_ring[MAX_NUM_SOUND_FRAMES] = {0}; static snd_pcm_t *_sound_out = NULL; static void sound_init(void) { @@ -922,11 +962,11 @@ static void sound_init(void) { if (s < 0) fprintf(stderr, "%s:%d, %s: snd_pcm_hw_params_set_format failed: %s\n", __FILE__, __LINE__, __func__, snd_strerror(s)); - s = snd_pcm_hw_params_set_rate(_sound_out, hw_params, AUDIO_SAMPLE_RATE, 0); + s = snd_pcm_hw_params_set_rate(_sound_out, hw_params, SOUND_SAMPLE_RATE, 0); if (s < 0) fprintf(stderr, "%s:%d, %s: snd_pcm_hw_params_set_rate failed: %s\n", __FILE__, __LINE__, __func__, snd_strerror(s)); - s = snd_pcm_hw_params_set_channels(_sound_out, hw_params, AUDIO_NUM_CHANNELS); + s = snd_pcm_hw_params_set_channels(_sound_out, hw_params, NUM_SOUND_CHANNELS); if (s < 0) fprintf(stderr, "%s:%d, %s: snd_pcm_hw_params_set_channels failed: %s\n", __FILE__, __LINE__, __func__, snd_strerror(s)); @@ -940,7 +980,7 @@ static void sound_init(void) { if (s < 0) fprintf(stderr, "%s:%d, %s: snd_pcm_sw_params_current failed: %s\n", __FILE__, __LINE__, __func__, snd_strerror(s)); - s = snd_pcm_sw_params_set_avail_min(_sound_out, sw_params, AUDIO_AVAIL_MIN); + s = snd_pcm_sw_params_set_avail_min(_sound_out, sw_params, SOUND_AVAIL_MIN); if (s < 0) fprintf(stderr, "%s:%d, %s: snd_pcm_sw_params_set_avail_min failed: %s\n", __FILE__, __LINE__, __func__, snd_strerror(s)); @@ -979,30 +1019,30 @@ static void sound_cleanup(void) { void p_handle_audio(i64 samples_elapsed) { sound_init(); - i64 num_frames = samples_elapsed * AUDIO_NUM_CHANNELS; + i64 num_frames = samples_elapsed * NUM_SOUND_CHANNELS; - if (num_frames > MAX_NUM_AUDIO_FRAMES) { + if (num_frames > MAX_NUM_SOUND_FRAMES) { fprintf(stderr, "%s:%d, %s: Sound buffer overflow.\n", __FILE__, __LINE__, __func__); - num_frames = MAX_NUM_AUDIO_FRAMES; + num_frames = MAX_NUM_SOUND_FRAMES; } i32 s; - if (num_frames <= MAX_NUM_AUDIO_FRAMES - _sound_position) { - s = snd_pcm_writei(_sound_out, _sound_ring + _sound_position, num_frames / AUDIO_NUM_CHANNELS); + if (num_frames <= MAX_NUM_SOUND_FRAMES - _sound_position) { + s = snd_pcm_writei(_sound_out, _sound_ring + _sound_position, num_frames / NUM_SOUND_CHANNELS); if (s < 0) fprintf(stderr, "%s:%d, %s: snd_pcm_writei failed: %s\n", __FILE__, __LINE__, __func__, snd_strerror(s)); memset(_sound_ring + _sound_position, 0, num_frames * sizeof *_sound_ring); } else { - i64 part_one = MAX_NUM_AUDIO_FRAMES - _sound_position; + i64 part_one = MAX_NUM_SOUND_FRAMES - _sound_position; i64 part_two = num_frames - part_one; - s = snd_pcm_writei(_sound_out, _sound_ring + _sound_position, part_one / AUDIO_NUM_CHANNELS); + s = snd_pcm_writei(_sound_out, _sound_ring + _sound_position, part_one / NUM_SOUND_CHANNELS); if (s < 0) fprintf(stderr, "%s:%d, %s: snd_pcm_writei failed: %s\n", __FILE__, __LINE__, __func__, snd_strerror(s)); - s = snd_pcm_writei(_sound_out, _sound_ring, part_two / AUDIO_NUM_CHANNELS); + s = snd_pcm_writei(_sound_out, _sound_ring, part_two / NUM_SOUND_CHANNELS); if (s < 0) fprintf(stderr, "%s:%d, %s: snd_pcm_writei failed: %s\n", __FILE__, __LINE__, __func__, snd_strerror(s)); @@ -1010,7 +1050,7 @@ void p_handle_audio(i64 samples_elapsed) { memset(_sound_ring, 0, part_two * sizeof *_sound_ring); } - _sound_position = (_sound_position + num_frames) % MAX_NUM_AUDIO_FRAMES; + _sound_position = (_sound_position + num_frames) % MAX_NUM_SOUND_FRAMES; } void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) { @@ -1020,7 +1060,7 @@ void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) { return; if (delay_in_samples < 0) { - frames += -delay_in_samples * AUDIO_NUM_CHANNELS; + frames += -delay_in_samples * NUM_SOUND_CHANNELS; num_samples -= delay_in_samples; delay_in_samples = 0; } @@ -1028,22 +1068,22 @@ void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) { if (num_samples <= 0) return; - i64 num_frames = num_samples * AUDIO_NUM_CHANNELS; + i64 num_frames = num_samples * NUM_SOUND_CHANNELS; - if (num_frames > MAX_NUM_AUDIO_FRAMES) { + if (num_frames > MAX_NUM_SOUND_FRAMES) { fprintf(stderr, "%s:%d, %s: Sound buffer overflow.\n", __FILE__, __LINE__, __func__); return; } sound_init(); - i64 begin = (_sound_position + delay_in_samples) % MAX_NUM_AUDIO_FRAMES; + i64 begin = (_sound_position + delay_in_samples) % MAX_NUM_SOUND_FRAMES; - if (num_frames <= MAX_NUM_AUDIO_FRAMES - begin) + if (num_frames <= MAX_NUM_SOUND_FRAMES - begin) for (i64 i = 0; i < num_frames; ++i) _sound_ring[begin + i] += frames[i]; else { - i64 part_one = MAX_NUM_AUDIO_FRAMES - begin; + i64 part_one = MAX_NUM_SOUND_FRAMES - begin; i64 part_two = num_frames - part_one; for (i64 i = 0; i < part_one; ++i) @@ -1070,7 +1110,7 @@ void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) { static i16 _key_table[MAX_NUM_KEYS] = {0}; static b8 _key_repeat[MAX_NUM_KEYS] = {0}; static i64 _frame_time = 0; -static vec3_f32 _pixels[MAX_NUM_PIXELS] = {0}; +static vec4_f32 _pixels[MAX_NUM_PIXELS] = {0}; static i32 _pixel_size = 0; static u32 _pixels_scaled[MAX_NUM_PIXELS] = {0}; static u32 _pixels_internal[MAX_NUM_PIXELS] = {0}; @@ -1568,13 +1608,20 @@ i32 p_handle_events(void) { i32 width = _image.width; i32 height = _image.height; - if (_pixel_size <= 1) - _pixel_size = 1; - else { + if (_pixel_size <= MIN_PIXEL_SIZE) + _pixel_size = MIN_PIXEL_SIZE; + + if (_pixel_size > 1) { width = (i32) floor(((f64) _image.width) / _pixel_size + .5); height = (i32) floor(((f64) _image.height) / _pixel_size + .5); } + if (g_platform.real_width != _image.width || g_platform.real_height != _image.height) { + ++num_events; + g_platform.real_width = _image.width; + g_platform.real_height = _image.height; + } + if (g_platform.frame_width != width || g_platform.frame_height != height) { ++num_events; g_platform.frame_width = width; @@ -1605,11 +1652,11 @@ void p_render_frame(void) { if (g_platform.frame_width == _image.width && g_platform.frame_height == _image.height) { i64 size = g_platform.frame_width * g_platform.frame_height; for (i64 i = 0; i < size; ++i) - _pixels_internal[i] = rgb_u32_from_f32(_pixels[i]); + _pixels_internal[i] = rgb_u32_from_f32((vec3_f32) { _pixels[i].x, _pixels[i].y, _pixels[i].z }); } else { i64 size = g_platform.frame_width * g_platform.frame_height; for (i64 i = 0; i < size; ++i) - _pixels_scaled[i] = rgb_u32_from_f32(_pixels[i]); + _pixels_scaled[i] = rgb_u32_from_f32((vec3_f32) { _pixels[i].x, _pixels[i].y, _pixels[i].z }); for (i64 j = 0; j < _image.height; ++j) { i64 j0 = (j * g_platform.frame_height) / _image.height; @@ -1628,7 +1675,7 @@ void p_render_frame(void) { if (_pixel_size < MAX_PIXEL_SIZE && frame_duration > MAX_FRAME_DURATION) ++_pixel_size; - else if (_pixel_size > 1 && frame_duration < MIN_FRAME_DURATION) + else if (_pixel_size > MIN_PIXEL_SIZE && frame_duration < MIN_FRAME_DURATION) --_pixel_size; } } @@ -1670,8 +1717,8 @@ static b8 _key_pressed[MAX_NUM_KEYS] = {0}; static b8 _wait_events = 0; i64 _sound_position = 0; i64 _sound_read = 0; -f32 _sound_ring[MAX_NUM_AUDIO_FRAMES] = {0}; -f32 _sound_buffer[MAX_NUM_AUDIO_FRAMES] = {0}; +f32 _sound_ring[MAX_NUM_SOUND_FRAMES] = {0}; +f32 _sound_buffer[MAX_NUM_SOUND_FRAMES] = {0}; i32 p_time_impl(void); @@ -1689,7 +1736,7 @@ void p_init(void) { g_platform.input = _input; g_platform.clipboard = _clipboard_buffer; g_platform.done = 1; - _sound_position = AUDIO_AVAIL_MIN % MAX_NUM_AUDIO_FRAMES; + _sound_position = SOUND_AVAIL_MIN % MAX_NUM_SOUND_FRAMES; _sound_read = 0; } @@ -1717,11 +1764,11 @@ void p_render_frame(void) { if (_frame_width == g_platform.frame_width && _frame_height == g_platform.frame_height) { i64 size = g_platform.frame_width * g_platform.frame_height; for (i64 i = 0; i < size; ++i) - _pixels_internal[i] = 0xff000000u | rgb_u32_from_f32(_pixels[i]); + _pixels_internal[i] = 0xff000000u | rgb_u32_from_f32((vec3_f32) { _pixels[i].x, _pixels[i].y, _pixels[i].z }); } else { i64 size = g_platform.frame_width * g_platform.frame_height; for (i64 i = 0; i < size; ++i) - _pixels_scaled[i] = rgb_u32_from_f32(_pixels[i]); + _pixels_scaled[i] = rgb_u32_from_f32((vec3_f32) { _pixels[i].x, _pixels[i].y, _pixels[i].z }); for (i64 j = 0; j < _frame_height; ++j) { i64 j0 = (j * g_platform.frame_height) / _frame_height; @@ -1752,7 +1799,7 @@ void p_handle_audio(i64 samples_elapsed) { if (samples_elapsed <= 0) return; - _sound_position = (_sound_position + samples_elapsed * AUDIO_NUM_CHANNELS) % MAX_NUM_AUDIO_FRAMES; + _sound_position = (_sound_position + samples_elapsed * NUM_SOUND_CHANNELS) % MAX_NUM_SOUND_FRAMES; } void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) { @@ -1760,7 +1807,7 @@ void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) { return; if (delay_in_samples < 0) { - frames += -delay_in_samples * AUDIO_NUM_CHANNELS; + frames += -delay_in_samples * NUM_SOUND_CHANNELS; num_samples -= delay_in_samples; delay_in_samples = 0; } @@ -1768,17 +1815,17 @@ void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) { if (num_samples <= 0) return; - i64 num_frames = num_samples * AUDIO_NUM_CHANNELS; - if (num_frames > MAX_NUM_AUDIO_FRAMES) + i64 num_frames = num_samples * NUM_SOUND_CHANNELS; + if (num_frames > MAX_NUM_SOUND_FRAMES) return; - i64 begin = (_sound_position + delay_in_samples * AUDIO_NUM_CHANNELS) % MAX_NUM_AUDIO_FRAMES; + i64 begin = (_sound_position + delay_in_samples * NUM_SOUND_CHANNELS) % MAX_NUM_SOUND_FRAMES; - if (num_frames <= MAX_NUM_AUDIO_FRAMES - begin) + if (num_frames <= MAX_NUM_SOUND_FRAMES - begin) for (i64 i = 0; i < num_frames; ++i) _sound_ring[begin + i] += frames[i]; else { - i64 part_one = MAX_NUM_AUDIO_FRAMES - begin; + i64 part_one = MAX_NUM_SOUND_FRAMES - begin; i64 part_two = num_frames - part_one; for (i64 i = 0; i < part_one; ++i) @@ -1810,13 +1857,20 @@ __attribute__((export_name("js_frame"))) void js_frame(i32 frame_width, i32 fram i32 width = _frame_width; i32 height = _frame_height; - if (_pixel_size <= 1) - _pixel_size = 1; - else { + if (_pixel_size <= MIN_PIXEL_SIZE) + _pixel_size = MIN_PIXEL_SIZE; + + if (_pixel_size > 1) { width = (i32) floor(((f64) _frame_width) / _pixel_size + .5); height = (i32) floor(((f64) _frame_height) / _pixel_size + .5); } + if (g_platform.real_width != _frame_width || g_platform.real_height != _frame_height) { + ++num_events; + g_platform.real_width = frame_width; + g_platform.real_height = frame_height; + } + if (g_platform.frame_width != width || g_platform.frame_height != height) { ++_num_events; g_platform.frame_width = width; @@ -1834,21 +1888,21 @@ __attribute__((export_name("js_frame"))) void js_frame(i32 frame_width, i32 fram } // Convert interleaved frames to non-interleaved. - for (i64 j = 0; j < AUDIO_NUM_CHANNELS; ++j) + for (i64 j = 0; j < NUM_SOUND_CHANNELS; ++j) for (i64 i = 0; i < num_samples; ++i) { - i64 n = (_sound_read + i * AUDIO_NUM_CHANNELS + j) % MAX_NUM_AUDIO_FRAMES; + i64 n = (_sound_read + i * NUM_SOUND_CHANNELS + j) % MAX_NUM_SOUND_FRAMES; _sound_buffer[j * num_samples + i] = _sound_ring[n]; _sound_ring [n] = 0.f; } - _sound_read = (_sound_read + num_samples * AUDIO_NUM_CHANNELS) % MAX_NUM_AUDIO_FRAMES; + _sound_read = (_sound_read + num_samples * NUM_SOUND_CHANNELS) % MAX_NUM_SOUND_FRAMES; if (!g_platform.exact_resolution && do_render) { i64 frame_duration = p_time() - frame_time; if (_pixel_size < MAX_PIXEL_SIZE && frame_duration > MAX_FRAME_DURATION) ++_pixel_size; - else if (_pixel_size > 1 && frame_duration < MIN_FRAME_DURATION) + else if (_pixel_size > MIN_PIXEL_SIZE && frame_duration < MIN_FRAME_DURATION) --_pixel_size; } } @@ -1907,15 +1961,15 @@ __attribute__((export_name("js_keyup"))) void js_keyup(u32 key, u32 mod) { } __attribute__((export_name("js_sample_rate"))) f64 js_sample_rate(void) { - return (f64) AUDIO_SAMPLE_RATE; + return (f64) SOUND_SAMPLE_RATE; } __attribute__((export_name("js_num_channels"))) i32 js_num_channels(void) { - return AUDIO_NUM_CHANNELS; + return NUM_SOUND_CHANNELS; } __attribute__((export_name("js_max_num_audio_frames"))) i32 js_max_num_audio_frames(void) { - return MAX_NUM_AUDIO_FRAMES; + return MAX_NUM_SOUND_FRAMES; } __attribute__((export_name("js_sound_buffer"))) void *js_sound_buffer(void) { -- cgit v1.2.3