From f7a24f2aa14b83a7a861c8f5dec5d90ae805276f Mon Sep 17 00:00:00 2001 From: Miloslav Ciz Date: Thu, 29 May 2025 22:27:28 +0200 Subject: [PATCH] Add X11 frontend --- TODO.txt | 10 +-- data | 2 +- frontend_x11.c | 183 +++++++++++++++++++++++++++++++++++++++++++++++++ make.sh | 24 ++++--- 4 files changed, 204 insertions(+), 15 deletions(-) create mode 100644 frontend_x11.c diff --git a/TODO.txt b/TODO.txt index 841a8a1..c8bfc83 100644 --- a/TODO.txt +++ b/TODO.txt @@ -11,13 +11,8 @@ fuck issue trackers :D - Nibble, should hopefully be powerful enough. - ESPboy? - linux framebuffer? -- make car turned on its back behave nicer? but how? - press forward map??? :-D only when physics is frozen - make some kinda repo for world record runs? how will they submit it? -- Try doing the bouncy car body? Just keep a point and its velocity, change - its velocity by a proportion of car's velocity change (this minus prev. - frame), then offset car body by this. However we'll also have to transform - inbetween world space and model space. - final tests: - very long replay - different resolutions @@ -43,6 +38,11 @@ fuck issue trackers :D =========== HANDLED ============== - should drifting make a sound? NO NEED +- make car turned on its back behave nicer? but how? PROLLY NOT +- Try doing the bouncy car body? Just keep a point and its velocity, change + its velocity by a proportion of car's velocity change (this minus prev. + frame), then offset car body by this. However we'll also have to transform + inbetween world space and model space. LEAVE FOR A MOD - add display of inputs on the screen (option in setting? arg?) - viewing replay during countdown bugs! - sometimes after restart the timer shows not 0:0:0, but something like 0:0:033 diff --git a/data b/data index a347563..9f32ce3 100644 --- a/data +++ b/data @@ -135,4 +135,4 @@ details #RLC2 00'24'948;00LC2;3c5ba5dd 0000756:0001:0143:0021:01a9:0051:00b5:0031:01d9:0041:0069:0031:00c9:0041:0079:0021:01d3:0061:0063:0031:0073:0072:0043:0041:0033:0061:0243:0041:0189:0021:0129:0021:0133:0021:0085:0031:0053:0041:0033:0041:0043:00d1:02f9:0031:00c9:0031:00a3:0051:00f9:0061:00d9:0031:01d3:0101:0043:0041:0059:00a1:0093:0031:00b9:0031:00a3:00e7:0046:0092:0043:00d1:00f9:0031:0033:0031:0033:0051:0093:0051:00a9:0031:00a9:0041 #RLC5 00'25'971;00LC5;90f26004 0000787:0001:0023:0071:0063:0031:0155:0031:0139:0031:01d9:0021:0179:0031:0064:006c:0038:0029:0171:0063:0091:0033:0061:00e9:0041:0029:0031:0093:0081:0079:0091:00a9:0051:0019:0061:0039:0031:0099:0031:0029:0041:0089:0041:0029:0031:0049:0031:0019:0071:0029:0031:0193:0031:00a3:0021:00d3:0051:0063:0021:0139:0068:001c:0070:0028:0059:00b1:0033:00d1:0043:0041:0043:0051:0319:00d1:0043:0051:0189:0061:0029:0031:0099:0031:00b5:0051:00c9:0051:0039:0051:0049:0061:0039:0041:0169:0051:0105:0031:01f3:0031:0053:0012:0076:0062:0043:0101:00b9:0021 #RLCtiny2 00'05'181;00LCtiny2;833ee4b2 0000157:0011:0320:0034:00a0:00d4:00f0 -#RLCtiny3 00'12'342;00LCtiny3;df0bd8ce +#RLCtiny1 00'12'276;00LCtiny1;ae1ab677 0000372:0001:02e9:0021:01e9:0051:00c9:0151:0073:0091:0059:0051:0073:0041:00a9:0031:0033:0031:0063:0031:0063:0021:0023:0087:0073:0131:0023:00a1:0069:0091:0103:0031:0205:0021:00b3:0091:0113:0021:00b9:0031:0053:0051:0039 diff --git a/frontend_x11.c b/frontend_x11.c new file mode 100644 index 0000000..fc68419 --- /dev/null +++ b/frontend_x11.c @@ -0,0 +1,183 @@ +/** @file frontend_sdl.c + X11 frontend for Licar. +*/ + +#include +#include +#include +#include +#include +#include +#include // for usleep + +#define LCR_SETTING_LOG_LEVEL 2 +#define LCR_SETTING_RESOLUTION_X 320 +#define LCR_SETTING_RESOLUTION_Y 240 +#define LCR_SETTING_MUSIC 0 + +#define DATA_FILE_NAME "data" + +#include "game.h" + +char framebuffer[LCR_SETTING_RESOLUTION_X * LCR_SETTING_RESOLUTION_Y * 4]; +FILE *dataFile = 0; +uint8_t buttonStates[8]; + +void LCR_drawPixel(unsigned long index, uint16_t color) +{ + char *p = framebuffer + 4 * index; + + *p = (color << 3) & 0xff; + p++; + *p = (color >> 3) & 0xfc; + p++; + *p = (color >> 8) & 0xf8; +} + +char LCR_getNextDataFileChar(void) +{ + if (!dataFile) + return 0; + + int c = fgetc(dataFile); + + if (c == EOF) + { + rewind(dataFile); + return 0; + } + + return c; +} + +void LCR_appendDataStr(const char *str) +{ + if (!dataFile) + return; + + if (str == 0 || *str == 0) + rewind(dataFile); + else + { + fclose(dataFile); + + dataFile = fopen(DATA_FILE_NAME,"a"); + + if (dataFile) + { + fprintf(dataFile,"%s",str); + fclose(dataFile); + dataFile = fopen(DATA_FILE_NAME,"r"); + } + } +} + +uint8_t LCR_keyPressed(uint8_t key) +{ + return buttonStates[key % 8]; +} + +void LCR_sleep(uint16_t timeMs) +{ + usleep(timeMs * 1000); +} + +void LCR_log(const char *str) +{ + printf("LOG: %s\n",str); +} + +int main(int argc, char **argv) +{ + int running = 1; + struct timeval now; + + LCR_gameInit(argc,(const char **) argv); + + Display *display = XOpenDisplay(0); + int screen = DefaultScreen(display); + + dataFile = fopen(DATA_FILE_NAME,"r"); + + if (!dataFile) + LCR_log("couldn't open data file"); + + Window window = XCreateSimpleWindow(display,RootWindow(display,screen),10,10, + LCR_SETTING_RESOLUTION_X,LCR_SETTING_RESOLUTION_Y,1, + BlackPixel(display,screen),WhitePixel(display,screen)); + + XSizeHints *sizeHints = XAllocSizeHints(); + sizeHints->flags = PMaxSize | PMinSize; + sizeHints->max_width = LCR_SETTING_RESOLUTION_X; + sizeHints->min_width = LCR_SETTING_RESOLUTION_X; + sizeHints->max_height = LCR_SETTING_RESOLUTION_Y; + sizeHints->min_height = LCR_SETTING_RESOLUTION_Y; + XSetWMNormalHints(display,window,sizeHints); + XFree(sizeHints); + + XMapWindow(display,window); + + XSelectInput(display,window,KeyPressMask | KeyReleaseMask); + + GC context = DefaultGC(display,screen); + + XStoreName(display,window,"Licar"); + + /* + Hardcoded constants here may perhaps cause trouble on some platforms, but + doing X11 "the right way" would mean 1 billion lines of code, so fuck it. + */ + XImage *image = XCreateImage(display,DefaultVisual(display,screen), + /*DefaultDepth(display,screen)*/24,ZPixmap,0,framebuffer, + LCR_SETTING_RESOLUTION_X,LCR_SETTING_RESOLUTION_Y,8,0); + + while (running) // main loop + { + XEvent event; + + gettimeofday(&now,NULL); + running &= LCR_gameStep(now.tv_sec * 1000 + now.tv_usec / 1000); + + XPutImage(display,window,context,image,0,0,0,0,LCR_SETTING_RESOLUTION_X, + LCR_SETTING_RESOLUTION_Y); + + while (XCheckWindowEvent(display,window,KeyPressMask | + KeyReleaseMask,&event) != False) + { + uint8_t state = event.xkey.type == KeyPress; + + switch (XKeycodeToKeysym(display,event.xkey.keycode,0)) + { + case XK_Up: case XK_w: + buttonStates[LCR_KEY_UP % 8] = state; break; + + case XK_Left: case XK_a: + buttonStates[LCR_KEY_LEFT % 8] = state; break; + + case XK_Right: case XK_d: + buttonStates[LCR_KEY_RIGHT % 8] = state; break; + + case XK_Down: case XK_s: + buttonStates[LCR_KEY_DOWN % 8] = state; break; + + case XK_j: case XK_Return: + buttonStates[LCR_KEY_A % 8] = state; break; + + case XK_k: case XK_Escape: + buttonStates[LCR_KEY_B % 8] = state; break; + + default: break; + } + } + } + + XDestroyImage(image); + XCloseDisplay(display); + + if (dataFile) + fclose(dataFile); + + LCR_gameEnd(); + + return 0; +} diff --git a/make.sh b/make.sh index 67c8cb4..b1208d4 100755 --- a/make.sh +++ b/make.sh @@ -30,30 +30,36 @@ if [ $# -gt 0 ]; then fi if [ $PLATFORM = "sdl" ]; then - # PC SDL build, requires: - # - SDL2 (dev) package + # PC SDL build, requires: SDL2 (dev) package + # preferred, should support all features SDL_FLAGS=`sdl2-config --cflags --libs` COMMAND="${COMPILER} ${C_FLAGS} frontend_sdl.c -I/usr/local/include ${SDL_FLAGS}" elif [ $PLATFORM = "csfml" ]; then - # PC CMFML build, requires: - # - csfml (dev) package + # PC CMFML build, requires: csfml (dev) package + # similar to SDL, should support all features COMMAND="${COMPILER} ${C_FLAGS} frontend_csfml.c -lcsfml-graphics -lcsfml-window -lcsfml-system -lcsfml-audio" elif [ $PLATFORM = "saf" ]; then - # SAF build, requires: - # - saf.h - # - backend libraries (SDL2 by default) + # SAF build, requires: saf.h, backend libraries (SDL2 by default) + # limited by SAF (low resoulution, few colors, no files, simple sound, ...) SDL_FLAGS=`sdl2-config --cflags --libs` COMMAND="${COMPILER} ${C_FLAGS} frontend_saf.c -lcsfml-graphics -I/use/local/include ${SDL_FLAGS}" elif [ $PLATFORM = "test" ]; then # autotest build + # unplayable, only serves for development COMMAND="${COMPILER} ${C_FLAGS} frontend_test.c" +elif [ $PLATFORM = "x11" ]; then + # X11 build, requires: xlib + # has no sound + + COMMAND="${COMPILER} ${C_FLAGS} -lX11 frontend_x11.c" elif [ $PLATFORM = "emscripten" ]; then - # emscripten (browser Javascript) build, requires: - # - emscripten + # emscripten (browser Javascript) build, requires: emscripten + # limited, low quality, no files + COMMAND="../emsdk/upstream/emscripten/emcc ./frontend_sdl.c -s USE_SDL=2 -O3 -lopenal --shell-file HTMLshell.html -o licar.html -s EXPORTED_FUNCTIONS='[\"_main\"]' -s EXPORTED_RUNTIME_METHODS='[\"ccall\",\"cwrap\"]'" else echo "unknown frontend"