diff --git a/ports/quake2/build.sh b/ports/quake2/build.sh new file mode 100755 index 00000000..515fe0db --- /dev/null +++ b/ports/quake2/build.sh @@ -0,0 +1,36 @@ +#!/bin/bash ../install.sh + +NAME='quake2' +VERSION='git' +DOWNLOAD_URL="https://github.com/ozkl/quake2generic.git#a967e4f567a98941326fc7fe76eee5e52a04a633" + +configure() { + : +} + +build() { + baseq2_tar=../baseq2.tar.gz + baseq2_hash=9660c306d9440ff7d534f165ae4a7f550b9e879d5190830953034ebda10e873a + + if [ -f $baseq2_tar ]; then + if ! echo "$baseq2_hash $baseq2_tar" | sha256sum --check >/dev/null; then + rm $baseq2_tar + fi + fi + if [ ! -f $baseq2_tar ]; then + wget https://bananymous.com/files/baseq2.tar.gz -O $baseq2_tar || exit 1 + fi + if ! echo "$baseq2_hash $baseq2_tar" | sha256sum --check >/dev/null; then + echo "File hash does not match" >&2 + exit 1 + fi + make -j$(nproc) || exit 1 +} + +install() { + cp build/quake2 "${BANAN_SYSROOT}/bin/" || exit 1 + + baseq2_tar=$(realpath ../baseq2.tar.gz || exit 1) + cd "$BANAN_SYSROOT/home/user/" + tar xf $baseq2_tar +} diff --git a/ports/quake2/patches/0001-Add-support-for-banan-os.patch b/ports/quake2/patches/0001-Add-support-for-banan-os.patch new file mode 100644 index 00000000..1889b41f --- /dev/null +++ b/ports/quake2/patches/0001-Add-support-for-banan-os.patch @@ -0,0 +1,481 @@ +From f900c2967edc684334b663e522aeec79e8fee10d Mon Sep 17 00:00:00 2001 +From: Bananymous +Date: Thu, 14 Nov 2024 12:33:39 +0200 +Subject: [PATCH] Add support for banan-os + +--- + Makefile | 106 +++------------- + port_soft_banan_os.cpp | 277 +++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 295 insertions(+), 88 deletions(-) + create mode 100644 port_soft_banan_os.cpp + +diff --git a/Makefile b/Makefile +index 46142df..4437418 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,3 @@ +- +-SDL_CFLAGS = `sdl2-config --cflags` +-SDL_LIBS = `sdl2-config --cflags --libs` -lSDL2_mixer +- + MOUNT_DIR=. + + BUILDDIR=build +@@ -18,21 +14,19 @@ GAME_DIR=$(MOUNT_DIR)/game + CTF_DIR=$(MOUNT_DIR)/ctf + XATRIX_DIR=$(MOUNT_DIR)/xatrix + +-CC=clang #emcc ++CC=$(BANAN_ARCH)-banan_os-gcc + BASE_CFLAGS=-Dstricmp=strcasecmp + ++CXX=$(BANAN_ARCH)-banan_os-g++ ++CXXFLAGS=--std=c++20 + + RELEASE_CFLAGS=$(BASE_CFLAGS) -O6 -ffast-math -funroll-loops \ + -fomit-frame-pointer -fexpensive-optimizations -malign-loops=2 \ + -malign-jumps=2 -malign-functions=2 + + DEBUG_CFLAGS=$(BASE_CFLAGS) -g +-LDFLAGS=-ldl -lm +-XCFLAGS=-I/opt/X11/include +- +-GLLDFLAGS=-L/usr/X11/lib -L/usr/local/lib \ +- $(SDL_LIBS) -lGL +-GLCFLAGS=$(SDL_CFLAGS) ++LDFLAGS=-lgui -linput ++XCFLAGS= + + SHLIBEXT=so + +@@ -43,6 +37,10 @@ DO_CC=$(CC) $(CFLAGS) -o $@ -c $< + DO_SHLIB_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $< + DO_GL_SHLIB_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) $(GLCFLAGS) $(XCFLAGS) -o $@ -c $< + ++DO_CXX=$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $< ++DO_SHLIB_CXX=$(CXX) $(CFLAGS) $(CXXFLAGS) $(SHLIBCFLAGS) -o $@ -c $< ++DO_GL_SHLIB_CXX=$(CXX) $(CFLAGS) $(CXXFLAGS) $(SHLIBCFLAGS) $(GLCFLAGS) $(XCFLAGS) -o $@ -c $< ++ + ############################################################################# + # SETUP AND BUILD + ############################################################################# +@@ -61,14 +59,12 @@ createdirs: + @-mkdir -p $(BUILDDIR) \ + $(BUILDDIR)/client \ + $(BUILDDIR)/ref_soft \ +- $(BUILDDIR)/ref_softsdl \ +- $(BUILDDIR)/ref_gl \ + $(BUILDDIR)/net \ + $(BUILDDIR)/sound \ + $(BUILDDIR)/game + + +-TARGETS: $(BUILDDIR)/quake2-soft $(BUILDDIR)/quake2-gl ++TARGETS: $(BUILDDIR)/quake2 + + ############################################################################# + # CLIENT/SERVER +@@ -122,7 +118,7 @@ QUAKE2_OBJS = \ + \ + $(BUILDDIR)/client/pmove.o \ + \ +- $(BUILDDIR)/net/net_unix.o \ ++ $(BUILDDIR)/net/net_loopback.o \ + \ + $(BUILDDIR)/sound/snddma_null.o \ + \ +@@ -200,38 +196,11 @@ REF_SOFT_OBJS = \ + $(BUILDDIR)/ref_soft/r_rast.o \ + $(BUILDDIR)/ref_soft/r_scan.o \ + $(BUILDDIR)/ref_soft/r_sprite.o \ +- $(BUILDDIR)/ref_soft/r_surf.o +- +- +-REF_SOFT_SDL_OBJS = \ +- $(BUILDDIR)/ref_soft/port_soft_sdl.o +- +- +-############################################################################# +-# REF_GL +-############################################################################# +- +-REF_GL_OBJS = \ +- $(BUILDDIR)/ref_gl/gl_draw.o \ +- $(BUILDDIR)/ref_gl/gl_image.o \ +- $(BUILDDIR)/ref_gl/gl_light.o \ +- $(BUILDDIR)/ref_gl/gl_mesh.o \ +- $(BUILDDIR)/ref_gl/gl_model.o \ +- $(BUILDDIR)/ref_gl/gl_rmain.o \ +- $(BUILDDIR)/ref_gl/gl_rmisc.o \ +- $(BUILDDIR)/ref_gl/gl_rsurf.o \ +- $(BUILDDIR)/ref_gl/gl_warp.o \ +- \ +- $(BUILDDIR)/ref_gl/qgl_system.o \ +- $(BUILDDIR)/ref_gl/port_gl_sdl.o +- +- +-$(BUILDDIR)/quake2-soft : $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_SOFT_OBJS) $(REF_SOFT_SDL_OBJS) +- $(CC) $(CFLAGS) -o $@ $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_SOFT_OBJS) $(REF_SOFT_SDL_OBJS) $(LDFLAGS) $(GLLDFLAGS) +- +-$(BUILDDIR)/quake2-gl : $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_GL_OBJS) +- $(CC) $(CFLAGS) -o $@ $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_GL_OBJS) $(LDFLAGS) $(GLLDFLAGS) ++ $(BUILDDIR)/ref_soft/r_surf.o \ ++ $(BUILDDIR)/ref_soft/port_soft_banan_os.o + ++$(BUILDDIR)/quake2 : $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_SOFT_OBJS) ++ $(CC) $(CFLAGS) -o $@ $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_SOFT_OBJS) $(LDFLAGS) + + $(BUILDDIR)/client/cl_cin.o : $(CLIENT_DIR)/cl_cin.c + $(DO_CC) +@@ -362,7 +331,7 @@ $(BUILDDIR)/client/q_system.o : $(OTHER_DIR)/q_system.c + $(BUILDDIR)/client/glob.o : $(OTHER_DIR)/glob.c + $(DO_CC) + +-$(BUILDDIR)/net/net_unix.o : $(NET_DIR)/net_unix.c ++$(BUILDDIR)/net/net_loopback.o : $(NET_DIR)/net_loopback.c + $(DO_CC) + + $(BUILDDIR)/port_platform_unix.o : $(MOUNT_DIR)/port_platform_unix.c +@@ -689,45 +658,8 @@ $(BUILDDIR)/ref_soft/r_sprite.o : $(REF_SOFT_DIR)/r_sprite.c + $(BUILDDIR)/ref_soft/r_surf.o : $(REF_SOFT_DIR)/r_surf.c + $(DO_GL_SHLIB_CC) + +-$(BUILDDIR)/ref_soft/port_soft_sdl.o : $(MOUNT_DIR)/port_soft_sdl.c +- $(DO_GL_SHLIB_CC) +- +-############################################################################# +-# REF_GL +-############################################################################# +- +-$(BUILDDIR)/ref_gl/gl_draw.o : $(REF_GL_DIR)/gl_draw.c +- $(DO_GL_SHLIB_CC) +- +-$(BUILDDIR)/ref_gl/gl_image.o : $(REF_GL_DIR)/gl_image.c +- $(DO_GL_SHLIB_CC) +- +-$(BUILDDIR)/ref_gl/gl_light.o : $(REF_GL_DIR)/gl_light.c +- $(DO_GL_SHLIB_CC) +- +-$(BUILDDIR)/ref_gl/gl_mesh.o : $(REF_GL_DIR)/gl_mesh.c +- $(DO_GL_SHLIB_CC) +- +-$(BUILDDIR)/ref_gl/gl_model.o : $(REF_GL_DIR)/gl_model.c +- $(DO_GL_SHLIB_CC) +- +-$(BUILDDIR)/ref_gl/gl_rmain.o : $(REF_GL_DIR)/gl_rmain.c +- $(DO_GL_SHLIB_CC) +- +-$(BUILDDIR)/ref_gl/gl_rmisc.o : $(REF_GL_DIR)/gl_rmisc.c +- $(DO_GL_SHLIB_CC) +- +-$(BUILDDIR)/ref_gl/gl_rsurf.o : $(REF_GL_DIR)/gl_rsurf.c +- $(DO_GL_SHLIB_CC) +- +-$(BUILDDIR)/ref_gl/gl_warp.o : $(REF_GL_DIR)/gl_warp.c +- $(DO_GL_SHLIB_CC) +- +-$(BUILDDIR)/ref_gl/qgl_system.o : $(REF_GL_DIR)/qgl_system.c +- $(DO_GL_SHLIB_CC) +- +-$(BUILDDIR)/ref_gl/port_gl_sdl.o : $(MOUNT_DIR)/port_gl_sdl.c +- $(DO_GL_SHLIB_CC) ++$(BUILDDIR)/ref_soft/port_soft_banan_os.o : $(MOUNT_DIR)/port_soft_banan_os.cpp ++ $(DO_GL_SHLIB_CXX) + + + ############################################################################# +@@ -738,8 +670,6 @@ clean: + -rm -rf \ + $(BUILDDIR)/client \ + $(BUILDDIR)/ref_soft \ +- $(BUILDDIR)/ref_softsdl \ +- $(BUILDDIR)/ref_gl \ + $(BUILDDIR)/game \ + $(BUILDDIR)/net \ + $(BUILDDIR)/sound \ +diff --git a/port_soft_banan_os.cpp b/port_soft_banan_os.cpp +new file mode 100644 +index 0000000..c7d7e16 +--- /dev/null ++++ b/port_soft_banan_os.cpp +@@ -0,0 +1,277 @@ ++#include ++#include ++#include ++#include ++ ++#include ++ ++extern "C" { ++ ++#include "ref_soft/r_local.h" ++#include "client/keys.h" ++ ++#include "quake2.h" ++ ++static LibImage::Image::Color s_palette[256]; ++ ++static int s_mouse_dx { 0 }; ++static int s_mouse_dy { 0 }; ++static bool s_relative_mouse { false }; ++ ++static BAN::Vector s_buffer; ++static BAN::UniqPtr s_window; ++static bool s_is_fullscreen { false }; ++ ++static int key_to_quake_key(LibInput::Key key) ++{ ++ using namespace LibInput; ++ ++ switch (key) ++ { ++ case Key::PageUp: return K_PGUP; ++ case Key::PageDown: return K_PGDN; ++ case Key::Home: return K_HOME; ++ case Key::End: return K_END; ++ case Key::ArrowLeft: return K_LEFTARROW; ++ case Key::ArrowRight: return K_RIGHTARROW; ++ case Key::ArrowDown: return K_DOWNARROW; ++ case Key::ArrowUp: return K_UPARROW; ++ case Key::Escape: return K_ESCAPE; ++ case Key::Enter: return K_ENTER; ++ case Key::Tab: return K_TAB; ++ case Key::F1: return K_F1; ++ case Key::F2: return K_F2; ++ case Key::F3: return K_F3; ++ case Key::F4: return K_F4; ++ case Key::F5: return K_F5; ++ case Key::F6: return K_F6; ++ case Key::F7: return K_F7; ++ case Key::F8: return K_F8; ++ case Key::F9: return K_F9; ++ case Key::F10: return K_F10; ++ case Key::F11: return K_F11; ++ case Key::F12: return K_F12; ++ case Key::Backspace: return K_BACKSPACE; ++ case Key::Delete: return K_DEL; ++ case Key::LeftShift: ++ case Key::RightShift: return K_SHIFT; ++ case Key::LeftCtrl: ++ case Key::RightCtrl: return K_CTRL; ++ case Key::LeftAlt: ++ case Key::RightAlt: return K_ALT; ++ case Key::Insert: return K_INS; ++ default: ++ if (const char* ascii = key_to_utf8(key, 0); ascii && strlen(ascii) == 1) ++ return *ascii; ++ break; ++ } ++ ++ return 0; ++} ++ ++static int button_to_quake_button(LibInput::MouseButton button) ++{ ++ using namespace LibInput; ++ ++ switch (button) ++ { ++ case LibInput::MouseButton::Left: return K_MOUSE1; ++ case LibInput::MouseButton::Right: return K_MOUSE2; ++ case LibInput::MouseButton::Middle: return K_MOUSE3; ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++static void create_window(uint32_t width, uint32_t height) ++{ ++ ASSERT(!s_window); ++ s_window = MUST(LibGUI::Window::create(width, height, "Quake2"_sv)); ++ ++ s_window->set_mouse_move_event_callback( ++ [](auto event) ++ { ++ if (!s_relative_mouse) ++ return; ++ s_mouse_dx += event.x; ++ s_mouse_dy += event.y; ++ } ++ ); ++ ++ s_window->set_mouse_button_event_callback( ++ [](auto event) ++ { ++ if (int button = button_to_quake_button(event.button)) ++ Quake2_SendKey(button, event.pressed); ++ } ++ ); ++ ++ s_window->set_key_event_callback( ++ [](auto event) ++ { ++ if (int key = key_to_quake_key(event.key)) ++ Quake2_SendKey(key, event.pressed()); ++ } ++ ); ++ ++ s_window->set_close_window_event_callback( ++ []() ++ { ++ char command[] = "quit"; ++ ri.Cmd_ExecuteText(EXEC_NOW, command); ++ } ++ ); ++} ++ ++rserr_t SWimp_SetMode(int* pwidth, int* pheight, int mode, qboolean fullscreen) ++{ ++ int width, height; ++ ++ if (!ri.Vid_GetModeInfo(&width, &height, mode)) ++ return rserr_invalid_mode; ++ ++ if (!s_window) ++ create_window(width, height); ++ else if (s_window->width() != width || s_window->height() != height) ++ { ++ s_window->request_resize(width, height); ++ ++ bool resized { false }; ++ s_window->set_resize_window_event_callback([&]() { resized = true; }); ++ while (!resized) ++ s_window->poll_events(); ++ s_window->set_resize_window_event_callback({}); ++ ++ ASSERT(s_window->width() == width && s_window->height() == height); ++ } ++ ++ if (s_is_fullscreen != fullscreen) ++ { ++ s_is_fullscreen = fullscreen; ++ s_window->set_fullscreen(fullscreen); ++ } ++ ++ MUST(s_buffer.resize(s_window->width() * s_window->height())); ++ vid.rowbytes = s_window->width(); ++ vid.buffer = s_buffer.data(); ++ ++ *pwidth = s_window->width(); ++ *pheight = s_window->height(); ++ ++ ri.Vid_NewWindow(s_window->width(), s_window->height()); ++ ++ return rserr_ok; ++} ++ ++void SWimp_Shutdown(void) ++{ ++} ++ ++int SWimp_Init(void* hInstance, void* wndProc) ++{ ++ return true; ++} ++ ++static qboolean SWimp_InitGraphics(qboolean fullscreen) ++{ ++ return rserr_ok; ++} ++ ++void SWimp_SetPalette(const unsigned char* palette) ++{ ++ for (int i = 0; i < 256; i++) ++ { ++ s_palette[i].r = *palette++; ++ s_palette[i].g = *palette++; ++ s_palette[i].b = *palette++; ++ s_palette[i].a = *palette++; ++ } ++} ++ ++void SWimp_BeginFrame(float camera_seperation) ++{ ++} ++ ++void SWimp_EndFrame(void) ++{ ++ const uint32_t width = s_window->width(); ++ const uint32_t height = s_window->height(); ++ for (int y = 0; y < height; y++) ++ for (int x = 0; x < width; x++) ++ s_window->set_pixel(x, y, s_palette[s_buffer[y * width + x]].as_argb()); ++ s_window->invalidate(); ++} ++ ++void SWimp_AppActivate(qboolean active) ++{ ++} ++ ++int QG_Milliseconds(void) ++{ ++ struct timespec ts; ++ clock_gettime(CLOCK_MONOTONIC, &ts); ++ return (ts.tv_sec * 1'000) + (ts.tv_nsec / 1'000'000); ++} ++ ++void QG_GetMouseDiff(int* dx, int* dy) ++{ ++ *dx = s_mouse_dx; ++ s_mouse_dx = 0; ++ ++ *dy = s_mouse_dy; ++ s_mouse_dy = 0; ++} ++ ++void QG_CaptureMouse(void) ++{ ++ s_relative_mouse = true; ++ s_window->set_mouse_capture(true); ++} ++ ++void QG_ReleaseMouse(void) ++{ ++ s_relative_mouse = false; ++ s_window->set_mouse_capture(false); ++} ++ ++static uint64_t get_current_ns() ++{ ++ timespec last_ts; ++ clock_gettime(CLOCK_MONOTONIC, &last_ts); ++ return (uint64_t)last_ts.tv_sec * 1'000'000'000 + last_ts.tv_nsec; ++} ++ ++int main(int argc, char** argv) ++{ ++ Quake2_Init(argc, argv); ++ ++ uint64_t last_ns = get_current_ns(); ++ for (;;) ++ { ++ s_window->poll_events(); ++ ++ const uint64_t current_ns = get_current_ns(); ++ uint64_t duration_ns = current_ns - last_ns; ++ ++ if (duration_ns < 1'000'000) ++ { ++ timespec sleep_ts { ++ .tv_sec = 0, ++ .tv_nsec = (long)(1'000'000 - duration_ns) ++ }; ++ while (nanosleep(&sleep_ts, &sleep_ts)) ++ continue; ++ duration_ns = get_current_ns() - last_ns; ++ } ++ ++ Quake2_Frame(duration_ns / 1'000'000); ++ ++ last_ns = current_ns; ++ } ++ ++ return 0; ++} ++ ++} +-- +2.47.0 +