summaryrefslogtreecommitdiff
path: root/reduced_system_layer.c
diff options
context:
space:
mode:
Diffstat (limited to 'reduced_system_layer.c')
-rw-r--r--reduced_system_layer.c184
1 files changed, 101 insertions, 83 deletions
diff --git a/reduced_system_layer.c b/reduced_system_layer.c
index b828781..8853166 100644
--- a/reduced_system_layer.c
+++ b/reduced_system_layer.c
@@ -5,7 +5,7 @@
// This is a reduced system layer.
// It allows you to create a window, draw graphics in it, handle
// input events, write samples to audio output, send and receive
-// UDP packets.
+// UDP packets, etc. All code is single-threaded.
//
// Primary target platforms: Linux (X11), Windows, Web.
//
@@ -49,8 +49,10 @@
// - Sound
// - Windows audio
// - Recording
+// - Device selection
// - Networking
// - Windows sockets
+// - TCP
// - Long term
// - Allocator
// - Parsing
@@ -84,7 +86,7 @@
// - WebAssembly
// - Sound
// - ALSA
-// - WebAssembly audio
+// - Web audio
// - Networking
// - Unix UDP sockets
// - UTF-8
@@ -154,7 +156,7 @@ extern "C" {
//
// ================================================================
-// NOTE: This procedure is required for the WebAssembly compatibility.
+// NOTE: This procedure is required for the Web compatibility.
void update_and_render_frame(void);
#if defined(__wasm__)
@@ -493,6 +495,21 @@ typedef struct {
} Drop_File;
typedef struct {
+ c32 code;
+ i8 len;
+} UTF8_Char;
+
+typedef struct {
+ u16 protocol;
+ u16 port;
+ union {
+ u32 v4_address_as_u32;
+ u8 v4_address[4];
+ u8 v6_address[16];
+ };
+} IP_Address;
+
+typedef struct {
c8 *title;
i32 frame_width;
i32 frame_height;
@@ -514,40 +531,23 @@ typedef struct {
i32 cursor_dy;
i64 wheel_dx;
i64 wheel_dy;
- i64 sound_clock_time;
- i64 sound_clock_carry;
i64 num_sound_samples_elapsed;
- i64 sound_position;
i64 num_drop_files;
Drop_File *drop_files;
vec4_f32 pixels [MAX_NUM_PIXELS];
- f32 sound_ring [MAX_NUM_SOUND_FRAMES];
Input_Key input [MAX_INPUT_SIZE];
c8 clipboard [MAX_CLIPBOARD_SIZE];
b8 key_down [MAX_NUM_KEYS];
b8 key_pressed [MAX_NUM_KEYS];
-
- // TODO: Allocator for big buffers
- u8 drop_files_buffer[DROP_FILES_BUFFER_SIZE];
} Platform;
-typedef struct {
- u16 protocol;
- u16 port;
- union {
- u32 v4_address_as_u32;
- u8 v4_address[4];
- u8 v6_address[16];
- };
-} IP_Address;
-
// UTF-8
// NOTE: We need UTF-8 because we use Xutf8LookupString on Xlib.
-i32 utf8_size(c32 c);
-c32 utf8_read(i64 len, c8 *s);
-i32 utf8_write(c32 c, c8 *buffer);
+i8 utf8_size (c32 c);
+UTF8_Char utf8_read (i64 len, c8 *s);
+i8 utf8_write(c32 c, c8 *buffer);
// Time and sleep
i64 p_time(void);
@@ -575,7 +575,9 @@ void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames);
i64 p_recv(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port, IP_Address *remote_address);
i64 p_send(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port);
+#ifdef REDUCED_SYSTEM_LAYER_HEADER
extern Platform g_platform;
+#endif
// ================================================================
@@ -597,6 +599,13 @@ extern Platform g_platform;
Platform g_platform = {0};
+static i64 _sound_clock_time = 0;
+static i64 _sound_clock_carry = 0;
+static i64 _sound_position = 0;
+
+static f32 _sound_ring [MAX_NUM_SOUND_FRAMES] = {0};
+static u8 _drop_files_buffer [DROP_FILES_BUFFER_SIZE] = {0};
+
void p_event_loop(void) {
p_init();
#if !defined(__wasm__)
@@ -624,43 +633,55 @@ void p_event_loop(void) {
} while (0)
#endif
-c32 utf8_read(i64 len, c8 *s) {
+i8 utf8_size(c32 c) {
+ if ((c & 0x00007f) == c) return 1;
+ if ((c & 0x0007ff) == c) return 2;
+ if ((c & 0x00ffff) == c) return 3;
+ if ((c & 0x1fffff) == c) return 4;
+ return 0;
+}
+
+UTF8_Char utf8_read(i64 len, c8 *s) {
if (len >= 1 &&
(s[0] & 0x80) == 0)
- return s[0];
+ return (UTF8_Char) {
+ .code = s[0],
+ .len = 1,
+ };
if (len >= 2 &&
(s[0] & 0xe0) == 0xc0 &&
(s[1] & 0xc0) == 0x80)
- return (s[1] & 0x3f)
- | ((s[0] & 0x1f) << 6);
+ return (UTF8_Char) {
+ .code = (s[1] & 0x3f)
+ | ((s[0] & 0x1f) << 6),
+ .len = 2,
+ };
if (len >= 3 &&
(s[0] & 0xf0) == 0xe0 &&
(s[1] & 0xc0) == 0x80 &&
(s[2] & 0xc0) == 0x80)
- return (s[2] & 0x3f)
- | ((s[1] & 0x3f) << 6)
- | ((s[0] & 0x0f) << 12);
+ return (UTF8_Char) {
+ .code = (s[2] & 0x3f)
+ | ((s[1] & 0x3f) << 6)
+ | ((s[0] & 0x0f) << 12),
+ .len = 3,
+ };
if (len >= 4 &&
(s[0] & 0xf8) == 0xf0 &&
(s[1] & 0xc0) == 0x80 &&
(s[2] & 0xc0) == 0x80 &&
(s[3] & 0xc0) == 0x80)
- return (s[3] & 0x3f)
- | ((s[2] & 0x3f) << 6)
- | ((s[1] & 0x3f) << 12)
- | ((s[0] & 0x07) << 18);
- return 0;
-}
-
-i32 utf8_size(c32 c) {
- if ((c & 0x00007f) == c) return 1;
- if ((c & 0x0007ff) == c) return 2;
- if ((c & 0x00ffff) == c) return 3;
- if ((c & 0x1fffff) == c) return 4;
- return 0;
+ return (UTF8_Char) {
+ .code = (s[3] & 0x3f)
+ | ((s[2] & 0x3f) << 6)
+ | ((s[1] & 0x3f) << 12)
+ | ((s[0] & 0x07) << 18),
+ .len = 4,
+ };
+ return (UTF8_Char) {0};
}
-i32 utf8_write(c32 c, c8 *buffer) {
+i8 utf8_write(c32 c, c8 *buffer) {
if ((c & 0x7f) == c) {
buffer[0] = (c8) c;
return 1;
@@ -703,18 +724,18 @@ u32 rgb_u32_from_f32_(vec3_f32 c) {
}
static i64 sound_samples_elapsed_(void) {
- if (g_platform.sound_clock_time == 0) {
- g_platform.sound_clock_time = p_time();
- g_platform.sound_clock_carry = 0;
+ if (_sound_clock_time == 0) {
+ _sound_clock_time = p_time();
+ _sound_clock_carry = 0;
return 0;
}
- i64 time_elapsed = p_time() - g_platform.sound_clock_time;
- i64 delta = time_elapsed * SOUND_SAMPLE_RATE + g_platform.sound_clock_carry;
+ i64 time_elapsed = p_time() - _sound_clock_time;
+ i64 delta = time_elapsed * SOUND_SAMPLE_RATE + _sound_clock_carry;
i64 num_samples = delta / 1000;
- g_platform.sound_clock_time += time_elapsed;
- g_platform.sound_clock_carry = delta % 1000;
+ _sound_clock_time += time_elapsed;
+ _sound_clock_carry = delta % 1000;
return num_samples;
}
@@ -763,8 +784,8 @@ static void drop_files_set_num_(i64 num) {
i64 src_size = (i64) sizeof(Drop_File) * g_platform.num_drop_files;
i64 dst_size = (i64) sizeof(Drop_File) * num;
- u8 *src = g_platform.drop_files_buffer + (DROP_FILES_BUFFER_SIZE - src_size);
- u8 *dst = g_platform.drop_files_buffer + (DROP_FILES_BUFFER_SIZE - num * (i64) sizeof(Drop_File));
+ u8 *src = _drop_files_buffer + (DROP_FILES_BUFFER_SIZE - src_size);
+ u8 *dst = _drop_files_buffer + (DROP_FILES_BUFFER_SIZE - num * (i64) sizeof(Drop_File));
for (i64 i = 0; i < src_size; ++i)
dst[i] = src[i];
@@ -825,7 +846,7 @@ static void drop_files_set_name_(i64 index, i64 name_size, c8 *name) {
}
g_platform.drop_files[index].name_size = name_size + 1;
- g_platform.drop_files[index].name = (c8 *) g_platform.drop_files_buffer + offset;
+ g_platform.drop_files[index].name = (c8 *) _drop_files_buffer + offset;
for (i64 i = 0; i < name_size; ++i)
g_platform.drop_files[index].name[i] = name[i];
@@ -851,7 +872,7 @@ static void drop_files_set_data_(i64 index, i64 data_size) {
}
g_platform.drop_files[index].data_size = data_size;
- g_platform.drop_files[index].data = g_platform.drop_files_buffer + offset;
+ g_platform.drop_files[index].data = _drop_files_buffer + offset;
}
// ================================================================
@@ -966,7 +987,7 @@ static b8 sockets_open(u16 slot, IP_Address address, u16 *local_port) {
_sockets[slot].socket = socket(address.protocol == IPv4_UDP ? AF_INET : AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if (_sockets[slot].socket == -1) {
- LOG_ERROR("socket failed (errno %d)", errno);
+ LOG_ERROR("socket failed (errno %d).", errno);
return 0;
}
@@ -983,14 +1004,14 @@ static b8 sockets_open(u16 slot, IP_Address address, u16 *local_port) {
if (bind(_sockets[slot].socket, p, p_len) == -1) {
close(_sockets[slot].socket);
- LOG_ERROR("bind failed (errno %d)", errno);
+ LOG_ERROR("bind failed (errno %d).", errno);
return 0;
}
if (getsockname(_sockets[slot].socket, p, &(socklen_t) {p_len}) == -1) {
close(_sockets[slot].socket);
- LOG_ERROR("getsockname failed (errno %d)", errno);
+ LOG_ERROR("getsockname failed (errno %d).", errno);
return 0;
}
@@ -1152,8 +1173,6 @@ static void sound_init(void) {
if (_sound_ready)
return;
- g_platform.sound_position = 0;
-
i32 s;
s = snd_pcm_open(&_sound_out, "default", SND_PCM_STREAM_PLAYBACK, 0);
@@ -1246,29 +1265,29 @@ void p_handle_sound(void) {
i32 s;
- if (num_frames <= MAX_NUM_SOUND_FRAMES - g_platform.sound_position) {
- s = snd_pcm_writei(_sound_out, g_platform.sound_ring + g_platform.sound_position, num_frames / NUM_SOUND_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)
LOG_ERROR("snd_pcm_writei failed: %s", snd_strerror(s));
- memset(g_platform.sound_ring + g_platform.sound_position, 0, num_frames * sizeof *g_platform.sound_ring);
+ memset(_sound_ring + _sound_position, 0, num_frames * sizeof *_sound_ring);
} else {
- i64 part_one = MAX_NUM_SOUND_FRAMES - g_platform.sound_position;
+ i64 part_one = MAX_NUM_SOUND_FRAMES - _sound_position;
i64 part_two = num_frames - part_one;
- s = snd_pcm_writei(_sound_out, g_platform.sound_ring + g_platform.sound_position, part_one / NUM_SOUND_CHANNELS);
+ s = snd_pcm_writei(_sound_out, _sound_ring + _sound_position, part_one / NUM_SOUND_CHANNELS);
if (s < 0)
LOG_ERROR("snd_pcm_writei failed: %s", snd_strerror(s));
- s = snd_pcm_writei(_sound_out, g_platform.sound_ring, part_two / NUM_SOUND_CHANNELS);
+ s = snd_pcm_writei(_sound_out, _sound_ring, part_two / NUM_SOUND_CHANNELS);
if (s < 0)
LOG_ERROR("snd_pcm_writei failed: %s", snd_strerror(s));
- memset(g_platform.sound_ring + g_platform.sound_position, 0, part_one * sizeof *g_platform.sound_ring);
- memset(g_platform.sound_ring, 0, part_two * sizeof *g_platform.sound_ring);
+ memset(_sound_ring + _sound_position, 0, part_one * sizeof *_sound_ring);
+ memset(_sound_ring, 0, part_two * sizeof *_sound_ring);
}
- g_platform.sound_position = (g_platform.sound_position + num_frames) % MAX_NUM_SOUND_FRAMES;
+ _sound_position = (_sound_position + num_frames) % MAX_NUM_SOUND_FRAMES;
}
void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) {
@@ -1295,19 +1314,19 @@ void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) {
sound_init();
- i64 begin = (g_platform.sound_position + delay_in_samples) % MAX_NUM_SOUND_FRAMES;
+ i64 begin = (_sound_position + delay_in_samples) % MAX_NUM_SOUND_FRAMES;
if (num_frames <= MAX_NUM_SOUND_FRAMES - begin)
for (i64 i = 0; i < num_frames; ++i)
- g_platform.sound_ring[begin + i] += frames[i];
+ _sound_ring[begin + i] += frames[i];
else {
i64 part_one = MAX_NUM_SOUND_FRAMES - begin;
i64 part_two = num_frames - part_one;
for (i64 i = 0; i < part_one; ++i)
- g_platform.sound_ring[begin + i] += frames[i];
+ _sound_ring[begin + i] += frames[i];
for (i64 i = 0; i < part_two; ++i)
- g_platform.sound_ring[i] += frames[part_one + i];
+ _sound_ring[i] += frames[part_one + i];
}
}
@@ -1726,7 +1745,7 @@ i32 p_handle_events(void) {
.scroll = !!(ev.xkey.state & Mod3Mask),
.meta = !!(ev.xkey.state & Mod4Mask),
.key = k,
- .c = utf8_read(len, buf),
+ .c = utf8_read(len, buf).code,
};
}
}
@@ -2251,8 +2270,7 @@ void p_sleep_for(i64 duration) {
void p_init(void) {
++_num_events;
- g_platform.done = 1;
- g_platform.sound_position = 0;
+ g_platform.done = 1;
_sound_read = (MAX_NUM_SOUND_FRAMES + ((-SOUND_AVAIL_MIN) % MAX_NUM_SOUND_FRAMES)) % MAX_NUM_SOUND_FRAMES;
}
@@ -2314,7 +2332,7 @@ void p_clipboard_write(i64 size, c8 *data) {
void p_handle_sound(void) {
g_platform.num_sound_samples_elapsed = sound_samples_elapsed_();
- g_platform.sound_position = (g_platform.sound_position + g_platform.num_sound_samples_elapsed * NUM_SOUND_CHANNELS) % MAX_NUM_SOUND_FRAMES;
+ _sound_position = (_sound_position + g_platform.num_sound_samples_elapsed * NUM_SOUND_CHANNELS) % MAX_NUM_SOUND_FRAMES;
}
void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) {
@@ -2334,19 +2352,19 @@ void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) {
if (num_frames > MAX_NUM_SOUND_FRAMES)
return;
- i64 begin = (g_platform.sound_position + delay_in_samples * NUM_SOUND_CHANNELS) % MAX_NUM_SOUND_FRAMES;
+ i64 begin = (_sound_position + delay_in_samples * NUM_SOUND_CHANNELS) % MAX_NUM_SOUND_FRAMES;
if (num_frames <= MAX_NUM_SOUND_FRAMES - begin)
for (i64 i = 0; i < num_frames; ++i)
- g_platform.sound_ring[begin + i] += frames[i];
+ _sound_ring[begin + i] += frames[i];
else {
i64 part_one = MAX_NUM_SOUND_FRAMES - begin;
i64 part_two = num_frames - part_one;
for (i64 i = 0; i < part_one; ++i)
- g_platform.sound_ring[begin + i] += frames[i];
+ _sound_ring[begin + i] += frames[i];
for (i64 i = 0; i < part_two; ++i)
- g_platform.sound_ring[i] += frames[part_one + i];
+ _sound_ring[i] += frames[part_one + i];
}
}
@@ -2545,8 +2563,8 @@ __attribute__((export_name("js_frame"))) void js_frame(i32 frame_width, i32 fram
for (i64 j = 0; j < NUM_SOUND_CHANNELS; ++j)
for (i64 i = 0; i < num_samples; ++i) {
i64 n = (_sound_read + i * NUM_SOUND_CHANNELS + j) % MAX_NUM_SOUND_FRAMES;
- _sound_buffer[j * num_samples + i] = g_platform.sound_ring[n];
- g_platform.sound_ring[n] = 0.f;
+ _sound_buffer[j * num_samples + i] = _sound_ring[n];
+ _sound_ring[n] = 0.f;
}
_sound_read = (_sound_read + num_samples * NUM_SOUND_CHANNELS) % MAX_NUM_SOUND_FRAMES;