summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/bitfont.inl.c1
-rwxr-xr-xexamples/gravity.c (renamed from examples/phys.c)4
-rwxr-xr-xexamples/landscape.c12
-rwxr-xr-xexamples/ui.c708
-rwxr-xr-xreduced_system_layer.c10
5 files changed, 722 insertions, 13 deletions
diff --git a/examples/bitfont.inl.c b/examples/bitfont.inl.c
new file mode 100644
index 0000000..16ddabd
--- /dev/null
+++ b/examples/bitfont.inl.c
@@ -0,0 +1 @@
+0x1f111111f111111f, 0x111f111111f11111, 0x11111f111111f111, 0xf111111f111111f1, 0x11f111111f111111, 0x1111f111111f1111, 0x111111f111111f11, 0x1f111111f111111f, 0x111f111111f11111, 0x11111f111111f111, 0xf111111f111111f1, 0x11f111111f111111, 0x1111f111111f1111, 0x111111f111111f11, 0x1f01011110000000, 0x111f111111f11111, 0x11111f111111f111, 0xf111111f111111f1, 0x11f111111f111111, 0x1111f12000001111, 0x111111f010000011, 0x1f111111f111111f, 0x111f111111f11111, 0x11111f111111f111, 0xf111111f111111f1, 0x11f111111f111111, 0x1111f111111f1111, 0x111111f111111f11, 0x1f111111f111111f, 0x111f111111f11111, 0x11111f111111f111, 0xf0999f99111111f1, 0x11f111111f111111, 0x1111f111111f1111, 0x111111f111111f11, 0x1f111111f111111f, 0x111f069861611111, 0x11111f111111f111, 0xf111111f111111f1, 0x11f111111f111111, 0x1111f111111f1111, 0x111111f111111f11, 0x1f069f860111111f, 0x111f111111f11111, 0x11111f061f960111, 0x111111f111111f1, 0x11f111111f072302, 0x1111f02111111111, 0x699960111111f11, 0x50111111f111111f, 0x111f111111f01113, 0x11111f111111f111, 0xf111111f111111f1, 0x11f111111f111111, 0x1111f111111f1111, 0x111111f111111f11,
diff --git a/examples/phys.c b/examples/gravity.c
index 19db4c8..824558b 100755
--- a/examples/phys.c
+++ b/examples/gravity.c
@@ -1,7 +1,7 @@
#if 0 /*
#/ ================================================================
#/
-#/ phys.c
+#/ gravity.c
#/
#/ ================================================================
#/
@@ -126,7 +126,7 @@ i32 main(i32 argc, c8 **argv) {
u32 background = u32_from_rgb(.0f, .0f, .08f);
platform = (Platform) {
- .title = "Game",
+ .title = "Gravity",
.frame_width = 960,
.frame_height = 720,
};
diff --git a/examples/landscape.c b/examples/landscape.c
index 018242b..a3de2cf 100755
--- a/examples/landscape.c
+++ b/examples/landscape.c
@@ -87,9 +87,6 @@ enum {
IPv4 = 1,
IPv6 = 2,
- BUTTON_LEFT = 256,
- BUTTON_MIDDLE,
- BUTTON_RIGHT,
KEY_LEFT,
KEY_RIGHT,
KEY_UP,
@@ -109,8 +106,11 @@ enum {
KEY_END,
KEY_PAGEUP,
KEY_PAGEDOWN,
- KEY_F_ = 256 * 2,
- KEY_KP_ = 256 * 3,
+ KEY_KP_ = 128,
+ KEY_F_ = 256,
+ BUTTON_LEFT = KEY_F_ + 64,
+ BUTTON_MIDDLE,
+ BUTTON_RIGHT,
};
typedef struct {
@@ -388,7 +388,7 @@ i32 main(i32 argc, c8 **argv) {
u32 background = u32_from_rgb(.03f, .08f, .01f);
platform = (Platform) {
- .title = "Game",
+ .title = "Landscape",
.frame_width = 960,
.frame_height = 720,
};
diff --git a/examples/ui.c b/examples/ui.c
new file mode 100755
index 0000000..a116074
--- /dev/null
+++ b/examples/ui.c
@@ -0,0 +1,708 @@
+#if 0 /*
+#/ ================================================================
+#/
+#/ ui.c
+#/
+#/ This is a reduced system layer.
+#/ It allows you to create a window, draw graphics in it, handle
+#/ input events.
+#/
+#/ ----------------------------------------------------------------
+#/
+#/ DESIGN PRINCIPLES
+#/
+#/ - Minimalistic feature set. For graphics, you have access to the
+#/ pixel buffer, and that's it.
+#/
+#/ - No implicit control flow. No callbacks. You write your own
+#/ main and call everything explicitly. But the number of things
+#/ you have to call to do something is as little as possible.
+#/
+#/ - Optimized to use in a single source file.
+#/ Installation process? Ctrl+C, Ctrl+V, done.
+#/
+#/ If you have an idea how to reduce the feature set further,
+#/ let me know!
+#/
+#/ ----------------------------------------------------------------
+#/
+#/ (C) 2024 Mitya Selivanov <guattari.tech>, MIT License
+#/
+#/ ================================================================
+#/
+#/ Self-compilation shell script
+#/
+SRC=${0##*./}
+BIN=${SRC%.*}
+gcc \
+ -Wall -Wextra -Werror -pedantic \
+ -Wno-old-style-declaration \
+ -Wno-missing-braces \
+ -Wno-unused-variable \
+ -Wno-unused-but-set-variable \
+ -Wno-unused-parameter \
+ -Wno-overlength-strings \
+ -O3 \
+ -fsanitize=undefined,address,leak -mshstk \
+ -lX11 -lm \
+ -o $BIN $SRC && \
+ ./$BIN $@ && rm $BIN
+exit $? # */
+#endif
+// ================================================================
+//
+// Basic declarations
+//
+// ================================================================
+
+#define _GNU_SOURCE
+
+typedef signed char i8;
+typedef signed short i16;
+typedef signed i32;
+typedef signed long long i64;
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned u32;
+typedef unsigned long long u64;
+typedef char c8;
+typedef signed char b8;
+typedef float f32;
+typedef double f64;
+
+// ================================================================
+//
+// PLATFORM API
+//
+// ================================================================
+
+enum {
+ MAX_NUM_PIXELS = 4 * 1024 * 1024,
+ MAX_CLIPBOARD_SIZE = 0,
+ MAX_NUM_AUDIO_SAMPLES = 0,
+ MAX_NUM_SOCKETS = 0,
+
+ AUDIO_NUM_CHANNELS = 2,
+ AUDIO_SAMPLE_RATE = 44100,
+
+ IPv4 = 1,
+ IPv6 = 2,
+
+ KEY_LEFT,
+ KEY_RIGHT,
+ KEY_UP,
+ KEY_DOWN,
+ KEY_LCTRL,
+ KEY_RCTRL,
+ KEY_LSHIFT,
+ KEY_RSHIFT,
+ KEY_LALT,
+ KEY_RALT,
+ KEY_ESCAPE,
+ KEY_PRINTSCREEN,
+ KEY_DELETE,
+ KEY_PAUSE,
+ KEY_INSERT,
+ KEY_HOME,
+ KEY_END,
+ KEY_PAGEUP,
+ KEY_PAGEDOWN,
+ KEY_KP_ = 128,
+ KEY_F_ = 256,
+ BUTTON_LEFT = KEY_F_ + 64,
+ BUTTON_MIDDLE,
+ BUTTON_RIGHT,
+};
+
+typedef struct {
+ c8 *title;
+ i32 frame_width;
+ i32 frame_height;
+ u32 *pixels;
+ i64 clipboard_size;
+ c8 *clipboard; // TODO
+ b8 done;
+ b8 has_focus;
+ b8 has_cursor;
+ i32 cursor_x;
+ i32 cursor_y;
+ i32 cursor_dx;
+ i32 cursor_dy;
+ i64 wheel_dy;
+ b8 key_down[512];
+ b8 key_pressed[512];
+} Platform;
+
+typedef struct {
+ u16 type;
+ u16 port;
+ union {
+ u8 v4_address[4];
+ u8 v6_address[16];
+ };
+} IP_Address;
+
+typedef i64 (*Thread_Proc)(void *user_data);
+
+// Window
+void p_init(void);
+void p_cleanup(void);
+i32 p_handle_events(void);
+i32 p_wait_events(void);
+void p_render_frame(void);
+
+// Sound
+void p_handle_audio(i64 time_elapsed);
+void p_queue_sound(i64 delay, i64 num_samples, f32 *samples);
+
+// UDP sockets
+i64 p_recv(u16 slot, IP_Address address, i64 size, u8 *data, IP_Address *remote_address);
+i64 p_send(u16 slot, IP_Address address, i64 size, u8 *data);
+
+Platform platform = {0};
+
+// ================================================================
+//
+// UI
+//
+// ================================================================
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <assert.h>
+
+i64 char_num_bits_x = 4;
+i64 char_num_bits_y = 7;
+u64 bitfont[] = {
+#include "bitfont.inl.c"
+};
+
+void print_text(u32 color, i32 x, i32 y, f64 width, f64 height, i64 num_chars, c8 *text) {
+ assert(text != NULL);
+
+ f64 dx = x;
+ i64 w = (i64) floor(width + .5);
+
+ for (i64 n = 0; n < num_chars; ++n) {
+ i64 x0 = (i64) floor(dx + .5);
+ i64 y1 = (i64) floor(y + height + .5);
+
+ i64 num_cols = 0;
+
+ for (i64 i = x0; i < x0 + w; ++i, ++num_cols) {
+ b8 empty_col = 1;
+
+ for (i64 j = y; j < y1; ++j) {
+ if (i < 0 || i >= platform.frame_width || j < 0 || j >= platform.frame_height)
+ continue;
+ i64 char_x = ((i - x0) * (char_num_bits_x + 1)) / w;
+ if (char_x >= char_num_bits_x)
+ continue;
+ i64 char_y = ((j - y ) * char_num_bits_y ) / (y1 - y );
+ i64 bit_index = text[n] * char_num_bits_x * char_num_bits_y + char_y * char_num_bits_x + char_x;
+ i64 qword_index = bit_index / 64;
+ if (qword_index >= (i64) (sizeof bitfont / sizeof *bitfont))
+ continue;
+ u64 mask = 1ull << (bit_index % 64);
+ if (!!(bitfont[qword_index] & mask)) {
+ platform.pixels[j * platform.frame_width + i] = color;
+ empty_col = 0;
+ }
+ }
+
+ if (empty_col)
+ break;
+ }
+
+ if (text[n] == ' ')
+ dx += width;
+ else
+ dx += num_cols + width / char_num_bits_x;
+ }
+}
+
+i32 main(i32 argc, c8 **argv) {
+ c8 static data[] =
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "x x x x x x x x x x x x x x x x "
+ "x x x x x x x x x x x x x x x x "
+ "x x x x x x x x x x x x x x x x "
+ "x x x x x x x x x x x x x x x x "
+ "x x x x x x x x x x x x x x x x "
+ "x x x x x x x x x x x x x x x x "
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "x x x x x x x x x x x x x x x x "
+ "x x x x x x x x x x x x x x x x "
+ "x x x x x x x x x x x x x x x x "
+ "x x x x x x x x x x x x x x x x "
+ "x x x x x x x x x x x x x x x x "
+ "x x x x x x x x x x x x x x x x "
+ " ! xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxx xxxx"
+ " ! x x x x x x x x x x x x "
+ " ! x x x x x x x x x x x x "
+ " ! x x x x x x x x x x x x "
+ " x x x x x x x x x x x x "
+ " ! x x x x x x x x x x , x . x "
+ " x x x x x x x x x x , x x "
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "x x x x x x x x x x x x x x x x "
+ "x x x x x x x x x x x x x x x x "
+ "x x x x x x x x x x x x x x x x "
+ "x x x x x x x x x x x x x x x x "
+ "x x x x x x x x x x x x x x x x "
+ "x x x x x x x x x x x x x x x x "
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxH Hxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "x x x x x x x x H Hx x x x x x x "
+ "x x x x x x x x HHHHx x x x x x x "
+ "x x x x x x x x H Hx x x x x x x "
+ "x x x x x x x x H Hx x x x x x x "
+ "x x x x x x x x H Hx x x x x x x "
+ "x x x x x x x x x x x x x x x "
+ "xxxxxxxxxxxx SS xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "x x x S x x x x x x x x x x x x "
+ "x x x SS x x x x x x x x x x x x "
+ "x x x Sx x x x x x x x x x x x "
+ "x x x S Sx x x x x x x x x x x x "
+ "x x x SS x x x x x x x x x x x x "
+ "x x x x x x x x x x x x x x x "
+ "xxxx xxxxxxxxxxxx xxxxxxxxxxxx xxxxxxxxl xxxxxxxx "
+ "x aa x x x ee x x x i x x l x x oo "
+ "x ax x x e ex x x x x l x x o o"
+ "x aaaax x x eeeex x x ii x x l x x o o"
+ "x a ax x x e x x x i x x l x x o o"
+ "x aa x x x ee x x x iii x x l x x oo "
+ "x x x x x x x x x x x "
+ "xxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "x x r r x x x x x x x x x x x x x "
+ "x x rr x x x x x x x x x x x x x "
+ "x x r x x x x x x x x x x x x x "
+ "x x r x x x x x x x x x x x x x "
+ "x x r x x x x x x x x x x x x x "
+ "x x x x x x x x x x x x x x x "
+ ;
+
+ u64 bits[(16 * 8 * 7 * 4) / 64] = {0};
+
+ for (i64 j = 0; j < 8; ++j)
+ for (i64 i = 0; i < 16; ++i)
+ for (i64 y = 0; y < char_num_bits_y; ++y)
+ for (i64 x = 0; x < char_num_bits_x; ++x) {
+ i64 num_char = j * 16 + i;
+ i64 num_bit = y * char_num_bits_x + x;
+ i64 bit_index = num_char * char_num_bits_x * char_num_bits_y + num_bit;
+ i64 qword_index = bit_index / 64;
+ u64 mask = 1ull << (bit_index % 64);
+ i64 dx = i * char_num_bits_x + x;
+ i64 dy = j * char_num_bits_y + y;
+ i64 index = dy * char_num_bits_x * 16 + dx;
+ if (index < (i64) (sizeof data / sizeof *data) && data[index] != ' ')
+ bits[qword_index] |= mask;
+ }
+
+ FILE *f = fopen("bitfont.inl.c", "wb");
+ for (i64 i = 0; i < (i64) (sizeof bits / sizeof *bits); ++i)
+ fprintf(f, "0x%llx,%s", bits[i], i + 1 < (i64) (sizeof bits / sizeof *bits) ? " " : "\n");
+ fclose(f);
+
+ (void) argc;
+ (void) argv;
+
+ platform = (Platform) {
+ .title = "UI",
+ .frame_width = 960,
+ .frame_height = 720,
+ };
+
+ p_init();
+
+ while (!platform.done) {
+ p_wait_events();
+
+ for (i32 j = 0; j < platform.frame_height; ++j)
+ for (i32 i = 0; i < platform.frame_width; ++i)
+ platform.pixels[j * platform.frame_width + i] = 0x302000;
+
+ i64 color = 0xff7f7f;
+
+ if (platform.cursor_x >= 80 && platform.cursor_x < 800 &&
+ platform.cursor_y >= 80 && platform.cursor_y < 180)
+ color = 0xffffff;
+
+ print_text(color, 80, 80, 60., 100., 14, "Hello, Sailor!");
+
+ p_render_frame();
+ }
+
+ p_cleanup();
+ return 0;
+}
+
+// ================================================================
+//
+// PLATFORM IMPLEMENTATION
+//
+// ----------------------------------------------------------------
+//
+// TODO
+// - Clipboard
+// - Sound
+// - Sockets
+//
+// X11 clipboard
+// https://handmade.network/forums/articles/t/8544-implementing_copy_paste_in_x11
+//
+// ALSA
+// https://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2pcm_min_8c-example.html
+//
+// ================================================================
+
+#include <assert.h>
+#include <string.h>
+
+// ================================================================
+//
+// UDP sockets
+//
+// ================================================================
+
+i64 p_recv(u16 slot, IP_Address address, i64 size, u8 *data, IP_Address *remote_address) {
+ (void) slot;
+ (void) address;
+ (void) size;
+ (void) data;
+ (void) remote_address;
+ assert(0);
+ return 0;
+}
+
+i64 p_send(u16 slot, IP_Address address, i64 size, u8 *data) {
+ (void) slot;
+ (void) address;
+ (void) size;
+ (void) data;
+ assert(0);
+ return 0;
+}
+
+// ================================================================
+//
+// X11
+//
+// ================================================================
+
+#ifdef __linux__
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <sched.h>
+#include <time.h>
+
+static i16 _key_table[512];
+static u32 _buffer[MAX_NUM_PIXELS];
+static XImage _image;
+static Display *_display;
+static GC _gc;
+static Window _window;
+static Atom _wm_delete_window;
+
+void p_init(void) {
+ _display = XOpenDisplay(NULL);
+ assert(_display != NULL);
+
+ _key_table[XKeysymToKeycode(_display, XK_Left)] = KEY_LEFT;
+ _key_table[XKeysymToKeycode(_display, XK_Right)] = KEY_RIGHT;
+ _key_table[XKeysymToKeycode(_display, XK_Up)] = KEY_UP;
+ _key_table[XKeysymToKeycode(_display, XK_Down)] = KEY_DOWN;
+ _key_table[XKeysymToKeycode(_display, XK_1)] = '1';
+ _key_table[XKeysymToKeycode(_display, XK_2)] = '2';
+ _key_table[XKeysymToKeycode(_display, XK_3)] = '3';
+ _key_table[XKeysymToKeycode(_display, XK_4)] = '4';
+ _key_table[XKeysymToKeycode(_display, XK_5)] = '5';
+ _key_table[XKeysymToKeycode(_display, XK_6)] = '6';
+ _key_table[XKeysymToKeycode(_display, XK_7)] = '7';
+ _key_table[XKeysymToKeycode(_display, XK_8)] = '8';
+ _key_table[XKeysymToKeycode(_display, XK_9)] = '9';
+ _key_table[XKeysymToKeycode(_display, XK_0)] = '0';
+ _key_table[XKeysymToKeycode(_display, XK_A)] = 'a';
+ _key_table[XKeysymToKeycode(_display, XK_B)] = 'b';
+ _key_table[XKeysymToKeycode(_display, XK_C)] = 'c';
+ _key_table[XKeysymToKeycode(_display, XK_D)] = 'd';
+ _key_table[XKeysymToKeycode(_display, XK_E)] = 'e';
+ _key_table[XKeysymToKeycode(_display, XK_F)] = 'f';
+ _key_table[XKeysymToKeycode(_display, XK_G)] = 'g';
+ _key_table[XKeysymToKeycode(_display, XK_H)] = 'h';
+ _key_table[XKeysymToKeycode(_display, XK_I)] = 'i';
+ _key_table[XKeysymToKeycode(_display, XK_J)] = 'j';
+ _key_table[XKeysymToKeycode(_display, XK_K)] = 'k';
+ _key_table[XKeysymToKeycode(_display, XK_L)] = 'l';
+ _key_table[XKeysymToKeycode(_display, XK_M)] = 'm';
+ _key_table[XKeysymToKeycode(_display, XK_N)] = 'n';
+ _key_table[XKeysymToKeycode(_display, XK_O)] = 'o';
+ _key_table[XKeysymToKeycode(_display, XK_P)] = 'p';
+ _key_table[XKeysymToKeycode(_display, XK_Q)] = 'q';
+ _key_table[XKeysymToKeycode(_display, XK_R)] = 'r';
+ _key_table[XKeysymToKeycode(_display, XK_S)] = 's';
+ _key_table[XKeysymToKeycode(_display, XK_T)] = 't';
+ _key_table[XKeysymToKeycode(_display, XK_U)] = 'u';
+ _key_table[XKeysymToKeycode(_display, XK_V)] = 'v';
+ _key_table[XKeysymToKeycode(_display, XK_W)] = 'w';
+ _key_table[XKeysymToKeycode(_display, XK_X)] = 'x';
+ _key_table[XKeysymToKeycode(_display, XK_Y)] = 'y';
+ _key_table[XKeysymToKeycode(_display, XK_Z)] = 'z';
+ _key_table[XKeysymToKeycode(_display, XK_space)] = ' ';
+ _key_table[XKeysymToKeycode(_display, XK_braceleft)] = '[';
+ _key_table[XKeysymToKeycode(_display, XK_braceright)] = ']';
+ _key_table[XKeysymToKeycode(_display, XK_colon)] = ';';
+ _key_table[XKeysymToKeycode(_display, XK_quotedbl)] = '\'';
+ _key_table[XKeysymToKeycode(_display, XK_asciitilde)] = '`';
+ _key_table[XKeysymToKeycode(_display, XK_backslash)] = '\\';
+ _key_table[XKeysymToKeycode(_display, XK_comma)] = ',';
+ _key_table[XKeysymToKeycode(_display, XK_greater)] = '.';
+ _key_table[XKeysymToKeycode(_display, XK_question)] = '/';
+ _key_table[XKeysymToKeycode(_display, XK_F1)] = KEY_F_ + 1;
+ _key_table[XKeysymToKeycode(_display, XK_F2)] = KEY_F_ + 2;
+ _key_table[XKeysymToKeycode(_display, XK_F3)] = KEY_F_ + 3;
+ _key_table[XKeysymToKeycode(_display, XK_F4)] = KEY_F_ + 4;
+ _key_table[XKeysymToKeycode(_display, XK_F5)] = KEY_F_ + 5;
+ _key_table[XKeysymToKeycode(_display, XK_F6)] = KEY_F_ + 6;
+ _key_table[XKeysymToKeycode(_display, XK_F7)] = KEY_F_ + 7;
+ _key_table[XKeysymToKeycode(_display, XK_F8)] = KEY_F_ + 8;
+ _key_table[XKeysymToKeycode(_display, XK_F9)] = KEY_F_ + 9;
+ _key_table[XKeysymToKeycode(_display, XK_F10)] = KEY_F_ + 10;
+ _key_table[XKeysymToKeycode(_display, XK_F11)] = KEY_F_ + 11;
+ _key_table[XKeysymToKeycode(_display, XK_F12)] = KEY_F_ + 12;
+ _key_table[XKeysymToKeycode(_display, XK_Control_L)] = KEY_LCTRL;
+ _key_table[XKeysymToKeycode(_display, XK_Control_R)] = KEY_RCTRL;
+ _key_table[XKeysymToKeycode(_display, XK_Shift_L)] = KEY_LSHIFT;
+ _key_table[XKeysymToKeycode(_display, XK_Shift_R)] = KEY_RSHIFT;
+ _key_table[XKeysymToKeycode(_display, XK_Alt_L)] = KEY_LALT;
+ _key_table[XKeysymToKeycode(_display, XK_Alt_R)] = KEY_RALT;
+ _key_table[XKeysymToKeycode(_display, XK_Escape)] = KEY_ESCAPE;
+ _key_table[XKeysymToKeycode(_display, XK_BackSpace)] = '\b';
+ _key_table[XKeysymToKeycode(_display, XK_Tab)] = '\t';
+ _key_table[XKeysymToKeycode(_display, XK_Return)] = '\n';
+ _key_table[XKeysymToKeycode(_display, XK_Print)] = KEY_PRINTSCREEN;
+ _key_table[XKeysymToKeycode(_display, XK_Delete)] = KEY_DELETE;
+ _key_table[XKeysymToKeycode(_display, XK_Pause)] = KEY_PAUSE;
+ _key_table[XKeysymToKeycode(_display, XK_Insert)] = KEY_INSERT;
+ _key_table[XKeysymToKeycode(_display, XK_Home)] = KEY_HOME;
+ _key_table[XKeysymToKeycode(_display, XK_End)] = KEY_END;
+ _key_table[XKeysymToKeycode(_display, XK_Page_Up)] = KEY_PAGEUP;
+ _key_table[XKeysymToKeycode(_display, XK_Page_Down)] = KEY_PAGEDOWN;
+ _key_table[XKeysymToKeycode(_display, XK_KP_0)] = KEY_KP_ + '0';
+ _key_table[XKeysymToKeycode(_display, XK_KP_1)] = KEY_KP_ + '1';
+ _key_table[XKeysymToKeycode(_display, XK_KP_2)] = KEY_KP_ + '2';
+ _key_table[XKeysymToKeycode(_display, XK_KP_3)] = KEY_KP_ + '3';
+ _key_table[XKeysymToKeycode(_display, XK_KP_4)] = KEY_KP_ + '4';
+ _key_table[XKeysymToKeycode(_display, XK_KP_5)] = KEY_KP_ + '5';
+ _key_table[XKeysymToKeycode(_display, XK_KP_6)] = KEY_KP_ + '6';
+ _key_table[XKeysymToKeycode(_display, XK_KP_7)] = KEY_KP_ + '7';
+ _key_table[XKeysymToKeycode(_display, XK_KP_8)] = KEY_KP_ + '8';
+ _key_table[XKeysymToKeycode(_display, XK_KP_9)] = KEY_KP_ + '9';
+ _key_table[XKeysymToKeycode(_display, XK_KP_Enter)] = KEY_KP_ + '\n';
+ _key_table[XKeysymToKeycode(_display, XK_KP_Divide)] = KEY_KP_ + '/';
+ _key_table[XKeysymToKeycode(_display, XK_KP_Multiply)] = KEY_KP_ + '*';
+ _key_table[XKeysymToKeycode(_display, XK_KP_Add)] = KEY_KP_ + '+';
+ _key_table[XKeysymToKeycode(_display, XK_KP_Subtract)] = KEY_KP_ + '-';
+ _key_table[XKeysymToKeycode(_display, XK_KP_Decimal)] = KEY_KP_ + '.';
+ _key_table[XKeysymToKeycode(_display, XK_KP_Separator)] = KEY_KP_ + ',';
+
+ i32 screen = DefaultScreen(_display);
+ i32 depth = DefaultDepth (_display, screen);
+ Visual *visual = DefaultVisual(_display, screen);
+
+ _gc = DefaultGC(_display, screen);
+
+ XSetGraphicsExposures(_display, _gc, False);
+
+ i32 _display_width = DisplayWidth (_display, screen);
+ i32 _display_height = DisplayHeight(_display, screen);
+
+ i32 x = (_display_width - platform.frame_width) / 2;
+ i32 y = (_display_height - platform.frame_height) / 2;
+
+ _window = XCreateWindow(_display, XDefaultRootWindow(_display), x, y, platform.frame_width, platform.frame_height, 0, depth, InputOutput, visual, CWEventMask, &(XSetWindowAttributes) { .event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | VisibilityChangeMask | FocusChangeMask | StructureNotifyMask | SubstructureNotifyMask, });
+
+ platform.pixels = _buffer;
+
+ _image = (XImage) {
+ .width = platform.frame_width,
+ .height = platform.frame_height,
+ .depth = depth,
+ .xoffset = 0,
+ .format = ZPixmap,
+ .data = (c8 *) _buffer,
+ .byte_order = LSBFirst,
+ .bitmap_unit = 32,
+ .bitmap_bit_order = LSBFirst,
+ .bitmap_pad = 32,
+ .bits_per_pixel = 32,
+ .bytes_per_line = 4 * platform.frame_width,
+ .red_mask = 0xff0000,
+ .green_mask = 0x00ff00,
+ .blue_mask = 0x0000ff,
+ };
+
+
+ XInitImage(&_image);
+
+ _wm_delete_window = XInternAtom(_display, "WM_DELETE_WINDOW", False);
+
+ XSetWMProtocols(_display, _window, &_wm_delete_window, 1);
+
+ XStoreName(_display, _window, platform.title);
+ XMapWindow(_display, _window);
+}
+
+void p_cleanup(void) {
+ XDestroyWindow(_display, _window);
+ XCloseDisplay (_display);
+}
+
+i32 p_handle_events(void) {
+ i32 num_events = XEventsQueued(_display, QueuedAlready);
+
+ memset(platform.key_pressed, 0, sizeof platform.key_pressed);
+
+ platform.cursor_dx = 0;
+ platform.cursor_dy = 0;
+ platform.wheel_dy = 0;
+
+ XEvent ev;
+
+ for (i32 i = 0; i < num_events; ++i) {
+ XNextEvent(_display, &ev);
+
+ switch (ev.type) {
+ case DestroyNotify:
+ platform.done = 1;
+ break;
+
+ case MotionNotify:
+ platform.cursor_dx += ev.xmotion.x - platform.cursor_x;
+ platform.cursor_dy += ev.xmotion.y - platform.cursor_y;
+ platform.cursor_x = ev.xmotion.x;
+ platform.cursor_y = ev.xmotion.y;
+ break;
+
+ case ButtonPress:
+ platform.cursor_x = ev.xbutton.x;
+ platform.cursor_y = ev.xbutton.y;
+ switch (ev.xbutton.button) {
+ case Button1:
+ platform.key_down[BUTTON_LEFT] = 1;
+ ++platform.key_pressed[BUTTON_LEFT];
+ break;
+ case Button2:
+ platform.key_down[BUTTON_MIDDLE] = 1;
+ ++platform.key_pressed[BUTTON_MIDDLE];
+ break;
+ case Button3:
+ platform.key_down[BUTTON_RIGHT] = 1;
+ ++platform.key_pressed[BUTTON_RIGHT];
+ break;
+ case Button4: ++platform.wheel_dy; break;
+ case Button5: --platform.wheel_dy; break;
+ default:;
+ }
+ break;
+
+ case ButtonRelease:
+ platform.cursor_x = ev.xbutton.x;
+ platform.cursor_y = ev.xbutton.y;
+ switch (ev.xbutton.button) {
+ case Button1: platform.key_down[BUTTON_LEFT] = 0; break;
+ case Button2: platform.key_down[BUTTON_MIDDLE] = 0; break;
+ case Button3: platform.key_down[BUTTON_RIGHT] = 0; break;
+ default:;
+ }
+ break;
+
+ case KeyPress:
+ platform.cursor_x = ev.xkey.x;
+ platform.cursor_y = ev.xkey.y;
+ platform.key_down [_key_table[ev.xkey.keycode]] = 1;
+ platform.key_pressed[_key_table[ev.xkey.keycode]]++;
+ break;
+
+ case KeyRelease:
+ platform.cursor_x = ev.xkey.x;
+ platform.cursor_y = ev.xkey.y;
+ platform.key_down [_key_table[ev.xkey.keycode]] = 0;
+ platform.key_pressed[_key_table[ev.xkey.keycode]]--;
+ break;
+
+ case EnterNotify: platform.has_cursor = 1; break;
+ case LeaveNotify: platform.has_cursor = 0; break;
+ case FocusIn: platform.has_focus = 1; break;
+ case FocusOut: platform.has_focus = 0; break;
+
+ case ClientMessage:
+ if ((Atom) ev.xclient.data.l[0] == _wm_delete_window)
+ platform.done = 1;
+ break;
+
+ default:;
+ }
+ }
+
+ XWindowAttributes attrs;
+ XGetWindowAttributes(_display, _window, &attrs);
+
+ if ((platform.frame_width != attrs.width || platform.frame_height != attrs.height) && attrs.width * attrs.height * 4 <= (i32) sizeof _buffer) {
+ if (attrs.width > 0 && attrs.height > 0) {
+ _image.width = attrs.width;
+ _image.height = attrs.height;
+ _image.bytes_per_line = 4 * attrs.width;
+ }
+
+ platform.frame_width = attrs.width;
+ platform.frame_height = attrs.height;
+ }
+
+ return num_events;
+}
+
+i32 p_wait_events(void) {
+ i32 num_events = 0;
+
+ do {
+ num_events = p_handle_events();
+ sched_yield();
+ } while (num_events == 0);
+
+ return num_events;
+}
+
+void p_render_frame(void) {
+ if (platform.done)
+ return;
+
+ XPutImage(_display, _window, _gc, &_image, 0, 0, 0, 0, platform.frame_width, platform.frame_height);
+ XFlush(_display);
+}
+
+#endif
+
+// ================================================================
+//
+// ALSA
+//
+// ================================================================
+
+#ifdef __linux__
+
+void p_handle_audio(i64 time_elapsed) {
+ (void) time_elapsed;
+ assert(0);
+}
+
+void p_queue_sound(i64 delay, i64 num_samples, f32 *samples) {
+ (void) delay;
+ (void) num_samples;
+ (void) samples;
+ assert(0);
+}
+
+#endif
diff --git a/reduced_system_layer.c b/reduced_system_layer.c
index 01a39e5..6eb5144 100755
--- a/reduced_system_layer.c
+++ b/reduced_system_layer.c
@@ -87,9 +87,6 @@ enum {
IPv4 = 1,
IPv6 = 2,
- BUTTON_LEFT = 256,
- BUTTON_MIDDLE,
- BUTTON_RIGHT,
KEY_LEFT,
KEY_RIGHT,
KEY_UP,
@@ -109,8 +106,11 @@ enum {
KEY_END,
KEY_PAGEUP,
KEY_PAGEDOWN,
- KEY_F_ = 256 * 2,
- KEY_KP_ = 256 * 3,
+ KEY_KP_ = 128,
+ KEY_F_ = 256,
+ BUTTON_LEFT = KEY_F_ + 64,
+ BUTTON_MIDDLE,
+ BUTTON_RIGHT,
};
typedef struct {