summaryrefslogtreecommitdiff
path: root/plat.c
diff options
context:
space:
mode:
authorquou <quou@disroot.org>2024-06-01 12:19:16 +1000
committerquou <quou@disroot.org>2024-06-01 12:20:17 +1000
commitea7cd94f7aeb177618db3907a6c86b7252e018f0 (patch)
treee972f9cf590ef756c2e41f3eac5b03e16db08300 /plat.c
Initial commit.
Diffstat (limited to 'plat.c')
-rw-r--r--plat.c462
1 files changed, 462 insertions, 0 deletions
diff --git a/plat.c b/plat.c
new file mode 100644
index 0000000..e9c71ba
--- /dev/null
+++ b/plat.c
@@ -0,0 +1,462 @@
+#include "plat.h"
+#include "config.h"
+
+extern void prog_init(void*);
+extern void prog_update(void);
+extern void prog_deinit(void);
+
+#ifdef plat_posix
+#define _POSIX_SOURCE
+#define _GNU_SOURCE
+#include "std_printers.c"
+#include <dirent.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+static clockid_t global_clock;
+static unsigned long global_freq;
+
+void init_timer(void) {
+ struct timespec ts;
+
+ global_clock = CLOCK_REALTIME;
+ global_freq = 1000000000;
+
+#if defined(_POSIX_MONOTONIC_CLOCK)
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+ global_clock = CLOCK_MONOTONIC;
+ }
+#endif
+}
+
+static unsigned long get_timer() {
+ struct timespec ts;
+
+ clock_gettime(global_clock, &ts);
+ return
+ (unsigned long)ts.tv_sec * global_freq +
+ (unsigned long)ts.tv_nsec;
+}
+
+unsigned long get_current_time() {
+ return get_timer();
+}
+
+void sleep_ns(unsigned long ns) {
+ struct timespec t = { 0 };
+ t.tv_nsec = ns;
+ nanosleep(&t, &t);
+}
+
+unsigned char* load_binary(const char* n, int* size) {
+ FILE* f;
+ int s;
+ void* b;
+ f = fopen(n, "r");
+ if (!f) {
+ print_err("Failed to open %s.\n", n);
+ pbreak(error_file_not_found);
+ return 0;
+ }
+ fseek(f, 0, SEEK_END);
+ s = ftell(f);
+ rewind(f);
+ b = malloc(s);
+ s = fread(b, 1, s, f);
+ if (size) *size = s;
+ return b;
+}
+
+void free_file(void* p) {
+ free(p);
+}
+
+void iter_dir(const char* path, Dir_Iter fn, void* u) {
+ struct dirent* de;
+ int l;
+ DIR* di;
+ char buf[256];
+ char* p;
+ di = opendir(path);
+ if (!di) return;
+ strcpy(buf, path);
+ l = strlen(buf);
+ if (!l) return;
+ if (buf[l - 1] != '/') {
+ strcat(buf, "/");
+ l++;
+ }
+ p = buf + l;
+ while ((de = readdir(di))) {
+ if (de->d_name[0] == '.')
+ continue;
+ strcpy(p, de->d_name);
+ if (de->d_type == DT_DIR)
+ iter_dir(buf, fn, u);
+ else
+ fn(u, buf);
+ }
+}
+
+#endif
+
+#ifdef plat_x11
+
+#define Font RX11Font
+#include <stdlib.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#undef RX11Font
+
+#include "rcache.h"
+
+#define txt_buf_max 32
+
+struct {
+ int w, h, run;
+ Display* d;
+ Window wi;
+ GC gc;
+ XImage* bb;
+ Colour* bp, * fb;
+ Atom wm_p, wm_d;
+ char txt_buf[txt_buf_max];
+ char raw_buf[txt_buf_max];
+ int txt_len;
+ int mx, my, scrx, scry;
+} app;
+static MBtn mheld_btns[mbtn_count];
+static MBtn mpressed_btns[mbtn_count];
+static MBtn mreleased_btns[mbtn_count];
+
+static void reset_keys(void) {
+ int i;
+ for (i = 0; i < mbtn_count; i++) {
+ mpressed_btns[i] = 0;
+ mreleased_btns[i] = 0;
+ }
+}
+
+void init_app_render(const XWindowAttributes* wa) {
+ Colour* p, * fb;
+ Display* d;
+ XImage* bb;
+ int w, h;
+ d = app.d;
+ w = app.w;
+ h = app.h;
+ p = (Colour*)malloc(sizeof *p * w * h);
+ fb = (Colour*)malloc(sizeof *fb * w * h);
+ bb = app.bb;
+ if (bb) {
+ XDestroyImage(bb);
+ }
+ if (!p) {
+ print_err("Out of memory.\n");
+ pbreak(error_out_of_memory);
+ }
+ bb = XCreateImage(
+ d,
+ wa->visual,
+ wa->depth,
+ ZPixmap,
+ 0,
+ (char*)p,
+ w,
+ h,
+ 32,
+ w * sizeof *p
+ );
+ if (!bb) {
+ print_err("Failed to create X11 backbuffer.\n");
+ pbreak(error_platform_error);
+ }
+ app.bp = p;
+ app.fb = fb;
+ app.bb = bb;
+}
+
+void init_app(void) {
+ Window w, r;
+ Display* d;
+ GC gc;
+ unsigned rm, bm;
+ XWindowAttributes wa;
+ app.run = 0;
+ d = XOpenDisplay(0);
+ if (!d) {
+ print_err("Failed to open X11 display.\n");
+ pbreak(error_platform_error);
+ return;
+ }
+ r = DefaultRootWindow(d);
+ app.wm_p = XInternAtom(
+ d,
+ "WM_PROTOCOLS",
+ 0
+ );
+ app.wm_d = XInternAtom(
+ d,
+ "WM_DELETE_WINDOW",
+ 0
+ );
+ w = XCreateSimpleWindow(
+ d,
+ r,
+ 0,
+ 0,
+ default_window_w,
+ default_window_h,
+ 0,
+ WhitePixel(d, 0),
+ BlackPixel(d, 0)
+ );
+ XSetWMProtocols(d, w, &app.wm_d, 1);
+ XStoreName(d, w, app_name);
+ XSelectInput(
+ d,
+ w,
+ ExposureMask |
+ KeyPressMask |
+ KeyReleaseMask |
+ PointerMotionMask |
+ ButtonPressMask |
+ ButtonReleaseMask
+ );
+ XClearWindow(d, w);
+ XMapRaised(d, w);
+ gc = XCreateGC(d, w, 0, 0);
+ if (!gc) {
+ print_err("Failed to create graphics context.\n");
+ pbreak(error_platform_error);
+ return;
+ }
+ XGetWindowAttributes(d, w, &wa);
+ if (wa.depth != 24 && wa.depth != 32) {
+ print_err("Only true colour displays are supported.\n");
+ pbreak(error_platform_error);
+ }
+ rm = wa.visual->red_mask & 0x1000000;
+ bm = wa.visual->blue_mask & 0xffffff;
+ if ((rm == 0xff && bm == 0xff0000)) {
+ print_war("Detected BGR. Colours will look fucked.\n");
+ }
+ app.d = d;
+ app.gc = gc;
+ app.w = wa.width;
+ app.h = wa.height;
+ app.run = 1;
+ app.wi = w;
+ app.bb = 0;
+ init_app_render(&wa);
+}
+
+void deinit_app(void) {
+ XDestroyWindow(app.d, app.wi);
+ XDestroyImage(app.bb);
+ XCloseDisplay(app.d);
+}
+
+void update_events(void) {
+ XWindowAttributes wa;
+ Display* d;
+ Window w;
+ XEvent e;
+ Rectangle r;
+ int mb;
+ d = app.d;
+ w = app.wi;
+ reset_keys();
+ app.scrx = app.scry = 0;
+ while (XPending(d)) {
+ XNextEvent(d, &e);
+ switch (e.type) {
+ case ClientMessage:
+ if (
+ (Atom)e.xclient.data.l[0] ==
+ app.wm_d
+ ) {
+ app.run = 0;
+ }
+ break;
+ case Expose:
+ XGetWindowAttributes(d, w, &wa);
+ if (
+ wa.width != app.w ||
+ wa.height != app.h
+ ) {
+ app.w = wa.width;
+ app.h = wa.height;
+ init_app_render(&wa);
+ }
+ r.x = 0;
+ r.y = 0;
+ r.w = app.w;
+ r.h = app.h;
+ rc_invalidate(&r);
+ 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:
+ mb = e.xbutton.button - 1;
+ mheld_btns[mb] = 1;
+ mpressed_btns[mb] = 1;
+ break;
+ }
+ break;
+ case ButtonRelease:
+ switch (e.xbutton.button) {
+ case 1:
+ case 2:
+ case 3:
+ mb = e.xbutton.button - 1;
+ mheld_btns[mb] = 0;
+ mreleased_btns[mb] = 1;
+ break;
+ case 4:
+ app.scry--;
+ break;
+ case 5:
+ app.scry++;
+ break;
+ case 6:
+ app.scrx--;
+ break;
+ case 7:
+ app.scrx++;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+int main(int argc, const char** argv) {
+ void* mem;
+ unsigned long now, next;
+ long ts;
+ (void)argc;
+ (void)argv;
+ init_timer();
+ mem = malloc(memory_size);
+ if (!mem) {
+ print_err("Out of memory.\n");
+ return error_out_of_memory;
+ }
+ init_app();
+ next = get_current_time();
+ prog_init(mem);
+ while (app.run) {
+ now = get_current_time();
+ while (now >= next) {
+ update_events();
+ prog_update();
+ next += ms_per_frame * 1000000;
+ }
+ ts = next - now;
+ if (ts > 0)
+ sleep_ns(ts);
+ }
+ prog_deinit();
+ deinit_app();
+ free(mem);
+ return 0;
+}
+
+void plat_present(
+ int x,
+ int y,
+ int w,
+ int h
+) {
+ const Colour* src;
+ Colour* dst;
+ int i, j;
+ int ex, ey;
+ int s;
+ ex = x + w;
+ ey = y + h;
+ dst = app.bp + x + y * app.w;
+ src = app.fb + x + y * app.w;
+ s = app.w - w;
+ for (j = y; j < ey; j++) {
+ for (i = x; i < ex; i++) {
+ dst->r = src->b;
+ dst->g = src->g;
+ dst->b = src->r;
+ dst->a = src->a;
+ dst++;
+ src++;
+ }
+ dst += s;
+ src += s;
+ }
+ XPutImage(
+ app.d,
+ app.wi,
+ app.gc,
+ app.bb,
+ x, y,
+ x, y,
+ w, h
+ );
+}
+
+Colour* get_fb(void) {
+ return app.fb;
+}
+
+int get_render_w(void) {
+ return app.w;
+}
+
+int get_render_h(void) {
+ return app.h;
+}
+
+int get_mouse_x(void) {
+ return app.mx;
+}
+
+int get_mouse_y(void) {
+ return app.my;
+}
+
+int get_mscroll_x(void) {
+ return app.scrx;
+}
+
+int get_mscroll_y(void) {
+ return app.scry;
+}
+
+int mbtn_pressed(MBtn btn) {
+ return mheld_btns[btn];
+}
+
+int mbtn_just_pressed(MBtn btn) {
+ return mpressed_btns[btn];
+}
+
+int mbtn_just_released(MBtn btn) {
+ return mreleased_btns[btn];
+}
+
+#endif
+