From 1b8008c41a04ceeb3ac4970f469ce9420ec29241 Mon Sep 17 00:00:00 2001 From: quou Date: Sun, 15 Dec 2024 22:48:12 +1100 Subject: Windowing + keyboard and mouse input --- .gitignore | 1 + Makefile | 23 ++++- app.cpp | 300 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ app.hpp | 123 +++++++++++++++++++++++++ c2.cpp | 16 ++++ debug_env | 2 + todo.txt | 2 +- 7 files changed, 465 insertions(+), 2 deletions(-) create mode 100644 app.cpp create mode 100644 app.hpp create mode 100644 c2.cpp create mode 100644 debug_env diff --git a/.gitignore b/.gitignore index 6e6f69f..337b226 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ tags /cfg/libcfg.a /qstd/libqstd.a /sc/sc +/c2 diff --git a/Makefile b/Makefile index e506470..b9f2151 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,18 @@ .POSIX: +target = c2 data_dir = data shaders = data/triangle.csh tools = qstd cfg sc +objects = app.o c2.o +includes = -Iqstd +defines = -Dplat_x86 -Dplat_posix -Dplat_x11 -Dallocation_default_alignment=8 +cflags = $(includes) $(defines) $(DEBUG_COMPILE_FLAG) +libs = -lX11 -lm +lflags = $(libs) $(DEBUG_LINK_FLAG) .PHONY: all clean $(tools) -all: $(shaders) $(tools) +all: $(target) $(shaders) $(tools) $(objects) qstd: $(MAKE) -C qstd @@ -19,11 +26,25 @@ sc: qstd cfg data/triangle.csh: intermediate/triangle.glsl | $(data_dir) sc ./sc/sc intermediate/triangle.glsl data/triangle.csh +app.o: app.cpp app.hpp + $(CXX) -c $(cflags) app.cpp -o app.o + +c2.o: c2.cpp app.hpp + $(CXX) -c $(cflags) c2.cpp -o c2.o + +$(target): $(objects) qstd/libqstd.a + $(CXX) $(objects) $(lflags) -o $(target) -Lqstd -lqstd + +qstd/libqstd.a: + $(MAKE) -C qstd + $(data_dir): mkdir -p $(data_dir) clean: rm -rf $(data_dir) + rm -f $(objects) + rm -f $(targets) make -C qstd clean make -C cfg clean make -C sc clean diff --git a/app.cpp b/app.cpp new file mode 100644 index 0000000..9c6c458 --- /dev/null +++ b/app.cpp @@ -0,0 +1,300 @@ +#include "app.hpp" + +extern "C" { +#include "memory.h" +} + +#ifdef plat_x11 +#include +#include + +#include + +Key key_from_xkey(unsigned key) { + switch (key) { + case 0x61: return key_A; + case 0x62: return key_B; + case 0x63: return key_C; + case 0x64: return key_D; + case 0x65: return key_E; + case 0x66: return key_F; + case 0x67: return key_G; + case 0x68: return key_H; + case 0x69: return key_I; + case 0x6A: return key_J; + case 0x6B: return key_K; + case 0x6C: return key_L; + case 0x6D: return key_M; + case 0x6E: return key_N; + case 0x6F: return key_O; + case 0x70: return key_P; + case 0x71: return key_Q; + case 0x72: return key_R; + case 0x73: return key_S; + case 0x74: return key_T; + case 0x75: return key_U; + case 0x76: return key_V; + case 0x77: return key_W; + case 0x78: return key_X; + case 0x79: return key_Y; + case 0x7A: return key_Z; + case XK_F1: return key_f1; + case XK_F2: return key_f2; + case XK_F3: return key_f3; + case XK_F4: return key_f4; + case XK_F5: return key_f5; + case XK_F6: return key_f6; + case XK_F7: return key_f7; + case XK_F8: return key_f8; + case XK_F9: return key_f9; + case XK_F10: return key_f10; + case XK_F11: return key_f11; + case XK_F12: return key_f12; + case XK_Down: return key_down; + case XK_Left: return key_left; + case XK_Right: return key_right; + case XK_Up: return key_up; + case XK_Escape: return key_escape; + case XK_Return: return key_return; + case XK_BackSpace: return key_backspace; + case XK_Linefeed: return key_return; + case XK_Tab: return key_tab; + case XK_Delete: return key_delete; + case XK_Home: return key_home; + case XK_End: return key_end; + case XK_Page_Up: return key_page_up; + case XK_Page_Down: return key_page_down; + case XK_Insert: return key_insert; + case XK_Shift_L: return key_shift; + case XK_Shift_R: return key_shift; + case XK_Control_L: return key_control; + case XK_Control_R: return key_control; + case XK_Super_L: return key_super; + case XK_Super_R: return key_super; + case XK_Alt_L: return key_alt; + case XK_Alt_R: return key_alt; + case XK_space: return key_space; + case XK_period: return key_period; + case XK_0: return key_0; + case XK_1: return key_1; + case XK_2: return key_2; + case XK_3: return key_3; + case XK_4: return key_4; + case XK_5: return key_5; + case XK_6: return key_6; + case XK_7: return key_7; + case XK_8: return key_8; + case XK_9: return key_9; + default: return key_unknown; + } +} + +struct App_Internal { + Display* d; + Window wi; + Atom wm_delete; + + void init(App* app, const char* name) { + const int default_w = 1920; + const int default_h = 1080; + XWindowAttributes wa; + XSetWindowAttributes attribs = { + .event_mask = + ExposureMask | + KeyPressMask | + KeyReleaseMask | + ButtonPressMask | + ButtonReleaseMask | + PointerMotionMask + }; + Window root; + Visual* v; + d = XOpenDisplay(0); + wm_delete = XInternAtom( + d, + "WM_DELETE_WINDOW", + 0 + ); + root = DefaultRootWindow(d); + v = XDefaultVisual(d, 0); + wi = XCreateWindow( + d, + root, + 0, + 0, + default_w, + default_h, + 0, + 0, + InputOutput, + v, + CWEventMask, + &attribs + ); + XSetWMProtocols(d, wi, &wm_delete, 1); + XStoreName(d, wi, name); + XMapRaised(d, wi); + XGetWindowAttributes(d, wi, &wa); + app->w = wa.width; + app->h = wa.height; + } + + void begin(App* app) { + while (XPending(d)) { + XEvent e; + KeySym sym; + Key key; + int btn; + XNextEvent(d, &e); + switch (e.type) { + case ClientMessage: + if ( + (Atom)e.xclient.data.l[0] == + wm_delete + ) { + app->running = 0; + } + break; + case MotionNotify: + app->mx = e.xmotion.x; + app->my = e.xmotion.y; + break; + case ButtonPress: + switch (e.xbutton.button) { + case 1: + case 2: + case 3: + app->mbtn_states[e.xbutton.button - 1] |= + key_state_pressed | + key_state_just_pressed; + break; + case 4: + app->scrolly++; + break; + case 5: + app->scrolly--; + break; + case 6: + app->scrollx++; + break; + case 7: + app->scrollx--; + break; + } + break; + case ButtonRelease: + switch (e.xbutton.button) { + case 1: + case 2: + case 3: + btn = e.xbutton.button - 1; + app->mbtn_states[btn] &= ~key_state_pressed; + app->mbtn_states[btn] |= key_state_just_released; + break; + case 4: + app->scrolly++; + break; + case 5: + app->scrolly--; + break; + case 6: + app->scrollx++; + break; + case 7: + app->scrollx--; + break; + } + break; + case KeyPress: + sym = XLookupKeysym(&e.xkey, 0); + key = key_from_xkey(sym); + app->key_states[key] |= + key_state_pressed | + key_state_just_pressed; + break; + case KeyRelease: + sym = XLookupKeysym(&e.xkey, 0); + key = key_from_xkey(sym); + app->key_states[key] &= ~key_state_pressed; + app->key_states[key] |= key_state_just_released; + break; + } + } + } + + void end(App* app) { + (void)app; + } +}; + +#endif + +App* App::create(const char* name) { + App* app; + App_Internal* i; + char* mem = (char*)malloc(app_memory_size); + Arena* a = (Arena*)mem; + mem += sizeof *a; + init_arena(a, mem, app_memory_size - sizeof *a); + app = (App*)arena_alloc(a, sizeof *app + sizeof *i); + app->running = 0; + app->arena = a; + i = (App_Internal*)&app[1]; + i->init(app, name); + return app; +} + +void App::destroy() { + free(arena); +} + +void App::begin() { + int j; + App_Internal* i = (App_Internal*)&this[1]; + for (j = 0; j < key_count; j++) + key_states[j] &= ~( + key_state_just_pressed | key_state_just_released + ); + for (j = 0; j < mbtn_count; j++) + mbtn_states[j] &= ~( + key_state_just_pressed | key_state_just_released + ); + i->begin(this); +} + +void App::end() { + App_Internal* i = (App_Internal*)&this[1]; + i->end(this); +} + +Key_State App::ks(Key k) { + return (Key_State)key_states[k]; +} + +Key_State App::ms(Mbtn k) { + return (Key_State)mbtn_states[k]; +} + +bool App::kp(Key k) { + return key_states[k] & key_state_pressed; +} + +bool App::kjp(Key k) { + return key_states[k] & key_state_just_pressed; +} + +bool App::kjr(Key k) { + return key_states[k] & key_state_just_released; +} + +bool App::mp(Mbtn b) { + return mbtn_states[b] & key_state_pressed; +} + +bool App::mjp(Mbtn b) { + return mbtn_states[b] & key_state_just_pressed; +} + +bool App::mjr(Mbtn b) { + return mbtn_states[b] & key_state_just_released; +} diff --git a/app.hpp b/app.hpp new file mode 100644 index 0000000..80d6cb0 --- /dev/null +++ b/app.hpp @@ -0,0 +1,123 @@ +#ifndef app_hpp +#define app_hpp + +#define app_memory_size (4096 * 16) + +struct Arena; + +#define key_xmacro() \ + x(key_unknown) \ + x(key_A) \ + x(key_B) \ + x(key_C) \ + x(key_D) \ + x(key_E) \ + x(key_F) \ + x(key_G) \ + x(key_H) \ + x(key_I) \ + x(key_J) \ + x(key_K) \ + x(key_L) \ + x(key_M) \ + x(key_N) \ + x(key_O) \ + x(key_P) \ + x(key_Q) \ + x(key_R) \ + x(key_S) \ + x(key_T) \ + x(key_U) \ + x(key_V) \ + x(key_W) \ + x(key_X) \ + x(key_Y) \ + x(key_Z) \ + x(key_f1) \ + x(key_f2) \ + x(key_f3) \ + x(key_f4) \ + x(key_f5) \ + x(key_f6) \ + x(key_f7) \ + x(key_f8) \ + x(key_f9) \ + x(key_f10) \ + x(key_f11) \ + x(key_f12) \ + x(key_down) \ + x(key_left) \ + x(key_right) \ + x(key_up) \ + x(key_escape) \ + x(key_return) \ + x(key_backspace) \ + x(key_tab) \ + x(key_delete) \ + x(key_home) \ + x(key_end) \ + x(key_page_up) \ + x(key_page_down) \ + x(key_insert) \ + x(key_shift) \ + x(key_control) \ + x(key_super) \ + x(key_alt) \ + x(key_space) \ + x(key_period) \ + x(key_0) \ + x(key_1) \ + x(key_2) \ + x(key_3) \ + x(key_4) \ + x(key_5) \ + x(key_6) \ + x(key_7) \ + x(key_8) \ + x(key_9) \ + +enum Key { +#define x(name) name, + key_xmacro() +#undef x + key_count +}; + +enum Mbtn { + mbtn_left, + mbtn_middle, + mbtn_right, + mbtn_count +}; + +enum Key_State { + key_state_pressed = 1 << 0, + key_state_just_pressed = 1 << 1, + key_state_just_released = 1 << 2 +}; + +struct App { + Arena* arena; + int running, w, h; + int mx, my; + int scrollx, scrolly; + unsigned char key_states[key_count]; + unsigned char mbtn_states[mbtn_count]; + + static App* create(const char* name); + void destroy(); + + void begin(); + void end(); + + Key_State ks(Key k); + Key_State ms(Mbtn k); + bool kp(Key k); + bool kjp(Key k); + bool kjr(Key k); + bool mp(Mbtn k); + bool mjp(Mbtn k); + bool mjr(Mbtn k); +}; + +#endif diff --git a/c2.cpp b/c2.cpp new file mode 100644 index 0000000..f6ad356 --- /dev/null +++ b/c2.cpp @@ -0,0 +1,16 @@ +#include "app.hpp" +extern "C" { +#include "plat.h" +} + +int main() { + App* app = App::create("c2"); + app->running = 1; + while (app->running) { + app->begin(); + if (app->mp(mbtn_left)) + print("%d, %d, %d\n", app->mx, app->my, app->scrolly); + app->end(); + } + app->destroy(); +} diff --git a/debug_env b/debug_env new file mode 100644 index 0000000..589d7ba --- /dev/null +++ b/debug_env @@ -0,0 +1,2 @@ +export DEBUG_COMPILE_FLAG="-O0 -g -DDEBUG" +export DEBUG_LINK_FLAG="-g" diff --git a/todo.txt b/todo.txt index d85fe76..bb854a8 100644 --- a/todo.txt +++ b/todo.txt @@ -1,6 +1,6 @@ todo list - [x] shader compiling - - [ ] windowing + input + - [x] windowing + input - [ ] vulkan device and swapchain, etc - [ ] draw a triangle - [ ] texture conversion + compression, etc -- cgit v1.2.3-54-g00ecf