diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..67e68a91 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,57 @@ +name: CI + +on: [push, pull_request] + +jobs: + build: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + backend: [sdl, sokol] + optimize: [Debug] + name: Zig Build + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - uses: mlugg/setup-zig@v1 + with: + version: 0.13.0 + + - if: ${{ matrix.os == 'ubuntu-latest' }} + run: | + sudo apt update + sudo apt install \ + build-essential \ + libasound2-dev \ + libpulse-dev \ + libaudio-dev \ + libjack-dev \ + libsndio-dev \ + libx11-dev \ + libxext-dev \ + libxrandr-dev \ + libxcursor-dev \ + libxfixes-dev \ + libxi-dev \ + libxss-dev \ + libxkbcommon-dev \ + libdrm-dev \ + libgbm-dev \ + libgl1-mesa-dev \ + libgles2-mesa-dev \ + libegl1-mesa-dev \ + libdbus-1-dev \ + libibus-1.0-dev \ + libudev-dev \ + fcitx-libs-dev + + - name: Build Linux + run: zig build -Dplatform_backend=${{ matrix.backend }} -Doptimize=${{ matrix.optimize }} + + - name: Build Windows + run: zig build -Dplatform_backend=${{ matrix.backend }} -Doptimize=${{ matrix.optimize }} -Dtarget=x86_64-windows + + - name: Build Wasm32 + run: zig build -Dplatform_backend=${{ matrix.backend }} -Doptimize=${{ matrix.optimize }} -Dtarget=wasm32-emscripten + diff --git a/.gitignore b/.gitignore index 303944fc..d5907909 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ zig-cache .zig-cache zig-out .DS_Store +*.sublime-workspace diff --git a/3rdparty/sdl/build.zig b/3rdparty/sdl/build.zig new file mode 100644 index 00000000..71758368 --- /dev/null +++ b/3rdparty/sdl/build.zig @@ -0,0 +1,1062 @@ +const std = @import("std"); + +const Build = std.Build; +const Step = std.Build.Step; + +pub fn build(b: *Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + const t = target.result; + + const lib = b.addStaticLibrary(.{ + .name = "SDL3", + .target = target, + .optimize = optimize, + }); + + const upstream = b.dependency("sdl_src", .{ + .target = target, + .optimize = optimize, + }); + + const upstream_root = .{ .dependency = .{ + .dependency = upstream, + .sub_path = "", + } }; + + lib.addIncludePath(upstream.path("include")); + lib.addIncludePath(upstream.path("src")); + lib.addIncludePath(upstream.path("src/hidapi/hidapi")); + + lib.addCSourceFiles(.{ + .root = upstream_root, + .files = &generic_src_files, + }); + lib.defineCMacro("SDL_USE_BUILTIN_OPENGL_DEFINITIONS", "1"); + lib.linkLibC(); + + switch (t.os.tag) { + .linux => { + lib.addIncludePath(upstream.path("src/hidapi/linux")); + lib.addCSourceFiles(.{ .root = upstream_root, .files = &linux_src_files }); + }, + .windows => { + lib.addIncludePath(upstream.path("src/hidapi/windows")); + lib.addCSourceFiles(.{ .root = upstream_root, .files = &windows_src_files }); + lib.linkSystemLibrary("setupapi"); + lib.linkSystemLibrary("winmm"); + lib.linkSystemLibrary("gdi32"); + lib.linkSystemLibrary("imm32"); + lib.linkSystemLibrary("version"); + lib.linkSystemLibrary("oleaut32"); + lib.linkSystemLibrary("ole32"); + }, + .macos => { + lib.addCSourceFiles(.{ .root = upstream_root, .files = &darwin_src_files }); + lib.addCSourceFiles(.{ + .root = upstream_root, + .files = &objective_c_src_files, + .flags = &.{"-fobjc-arc"}, + }); + lib.linkFramework("OpenGL"); + lib.linkFramework("Metal"); + lib.linkFramework("CoreVideo"); + lib.linkFramework("Cocoa"); + lib.linkFramework("IOKit"); + lib.linkFramework("ForceFeedback"); + lib.linkFramework("Carbon"); + lib.linkFramework("CoreAudio"); + lib.linkFramework("AudioToolbox"); + lib.linkFramework("AVFoundation"); + lib.linkFramework("Foundation"); + }, + .emscripten => { + // NOTE: Currently this include path is injected by the delve build. + // Previously we looked for the 'sysroot' property to be defined on our builder. + // But at the moment, there is a chicken and egg problem in that we get the emsdk + // from the sokol module rather than using it ourselves. + lib.defineCMacro("__EMSCRIPTEN_PTHREADS__ ", "1"); + lib.addCSourceFiles(.{ .root = upstream_root, .files = &emscripten_src_files }); + }, + else => {}, + } + + const use_pregenerated_config = switch (t.os.tag) { + .windows, .macos, .emscripten => true, + else => false, + }; + + if (use_pregenerated_config) { + lib.addIncludePath(upstream.path("include/build_config")); + lib.installHeadersDirectory(upstream.path("include/build_config"), "SDL3", .{}); + applyOptions(&global_options, b, lib, upstream_root); + } else { + // causes pregenerated SDL_config.h to assert an error + lib.defineCMacro("USING_GENERATED_CONFIG_H", ""); + + const config_header = b.addConfigHeader(.{ + .style = .{ .cmake = upstream.path("include/build_config/SDL_build_config.h.cmake") }, + .include_path = "SDL_build_config.h", + }, .{ + .HAVE_STDINT_H = 1, + .HAVE_SYS_TYPES_H = 1, + .HAVE_STDIO_H = 1, + .HAVE_STRING_H = 1, + .HAVE_ALLOCA_H = 1, + .HAVE_CTYPE_H = 1, + .HAVE_FLOAT_H = 1, + .HAVE_ICONV_H = 1, + .HAVE_INTTYPES_H = 1, + .HAVE_LIMITS_H = 1, + .HAVE_MALLOC_H = 1, + .HAVE_MATH_H = 1, + .HAVE_MEMORY_H = 1, + .HAVE_SIGNAL_H = 1, + .HAVE_STDARG_H = 1, + .HAVE_STDDEF_H = 1, + .HAVE_STDLIB_H = 1, + .HAVE_STRINGS_H = 1, + .HAVE_WCHAR_H = 1, + .HAVE_LIBUNWIND_H = 1, + .HAVE_LIBC = 1, + .STDC_HEADERS = 1, + .SDL_DEFAULT_ASSERT_LEVEL_CONFIGURED = 0, + .SDL_AUDIO_DISABLED = 1, + .SDL_AUDIO_DRIVER_DUMMY = 1, + .SDL_CAMERA_DISABLED = 1, + .SDL_CAMERA_DRIVER_DUMMY = 1, + .SDL_SENSOR_DUMMY = 1, + }); + switch (t.os.tag) { + .linux => { + config_header.addValues(.{ + .SDL_LOADSO_DLOPEN = 1, + .HAVE_DLOPEN = 1, + .HAVE_MALLOC = 1, + .HAVE_CALLOC = 1, + .HAVE_REALLOC = 1, + .HAVE_FREE = 1, + .HAVE_GETENV = 1, + .HAVE_SETENV = 1, + .HAVE_PUTENV = 1, + .HAVE_UNSETENV = 1, + .HAVE_ABS = 1, + .HAVE_BCOPY = 1, + .HAVE_MEMSET = 1, + .HAVE_MEMCPY = 1, + .HAVE_MEMMOVE = 1, + .HAVE_MEMCMP = 1, + .HAVE_WCSLEN = 1, + .HAVE_WCSNLEN = 1, + // Not on Ubuntu Jammy + // .HAVE_WCSLCPY = 1, + // .HAVE_WCSLCAT = 1, + .HAVE_WCSDUP = 1, + .HAVE_WCSSTR = 1, + .HAVE_WCSCMP = 1, + .HAVE_WCSNCMP = 1, + .HAVE_WCSTOL = 1, + .HAVE_STRLEN = 1, + .HAVE_STRNLEN = 1, + // Not on Ubuntu Jammy + // .HAVE_STRLCPY = 1, + // .HAVE_STRLCAT = 1, + .HAVE_STRPBRK = 1, + .HAVE_INDEX = 1, + .HAVE_RINDEX = 1, + .HAVE_STRCHR = 1, + .HAVE_STRRCHR = 1, + .HAVE_STRSTR = 1, + .HAVE_STRTOK_R = 1, + .HAVE_STRTOL = 1, + .HAVE_STRTOUL = 1, + .HAVE_STRTOLL = 1, + .HAVE_STRTOULL = 1, + .HAVE_STRTOD = 1, + .HAVE_ATOI = 1, + .HAVE_ATOF = 1, + .HAVE_STRCMP = 1, + .HAVE_STRNCMP = 1, + .HAVE_STRCASESTR = 1, + .HAVE_SSCANF = 1, + .HAVE_VSSCANF = 1, + .HAVE_VSNPRINTF = 1, + .HAVE_ACOS = 1, + .HAVE_ACOSF = 1, + .HAVE_ASIN = 1, + .HAVE_ASINF = 1, + .HAVE_ATAN = 1, + .HAVE_ATANF = 1, + .HAVE_ATAN2 = 1, + .HAVE_ATAN2F = 1, + .HAVE_CEIL = 1, + .HAVE_CEILF = 1, + .HAVE_COPYSIGN = 1, + .HAVE_COPYSIGNF = 1, + .HAVE_COS = 1, + .HAVE_COSF = 1, + .HAVE_EXP = 1, + .HAVE_EXPF = 1, + .HAVE_FABS = 1, + .HAVE_FABSF = 1, + .HAVE_FLOOR = 1, + .HAVE_FLOORF = 1, + .HAVE_FMOD = 1, + .HAVE_FMODF = 1, + .HAVE_ISINF = 1, + .HAVE_ISINFF = 1, + .HAVE_ISINF_FLOAT_MACRO = 1, + .HAVE_ISNAN = 1, + .HAVE_ISNANF = 1, + .HAVE_ISNAN_FLOAT_MACRO = 1, + .HAVE_LOG = 1, + .HAVE_LOGF = 1, + .HAVE_LOG10 = 1, + .HAVE_LOG10F = 1, + .HAVE_LROUND = 1, + .HAVE_LROUNDF = 1, + .HAVE_MODF = 1, + .HAVE_MODFF = 1, + .HAVE_POW = 1, + .HAVE_POWF = 1, + .HAVE_ROUND = 1, + .HAVE_ROUNDF = 1, + .HAVE_SCALBN = 1, + .HAVE_SCALBNF = 1, + .HAVE_SIN = 1, + .HAVE_SINF = 1, + .HAVE_SQRT = 1, + .HAVE_SQRTF = 1, + .HAVE_TAN = 1, + .HAVE_TANF = 1, + .HAVE_TRUNC = 1, + .HAVE_TRUNCF = 1, + .HAVE_FOPEN64 = 1, + .HAVE_FSEEKO = 1, + .HAVE_FSEEKO64 = 1, + .HAVE_MEMFD_CREATE = 1, + .HAVE_POSIX_FALLOCATE = 1, + .HAVE_SIGACTION = 1, + .HAVE_SA_SIGACTION = 1, + .HAVE_ST_MTIM = 1, + .HAVE_SETJMP = 1, + .HAVE_NANOSLEEP = 1, + .HAVE_GMTIME_R = 1, + .HAVE_LOCALTIME_R = 1, + .HAVE_NL_LANGINFO = 1, + .HAVE_SYSCONF = 1, + .HAVE_CLOCK_GETTIME = 1, + .HAVE_GETPAGESIZE = 1, + .HAVE_ICONV = 1, + .HAVE_PTHREAD_SETNAME_NP = 1, + .HAVE_SEM_TIMEDWAIT = 1, + .HAVE_GETAUXVAL = 1, + .HAVE_POLL = 1, + .HAVE__EXIT = 1, + .HAVE_SYS_INOTIFY_H = 1, + .HAVE_INOTIFY_INIT = 1, + .HAVE_INOTIFY_INIT1 = 1, + .HAVE_INOTIFY = 1, + .HAVE_O_CLOEXEC = 1, + .HAVE_LINUX_INPUT_H = 1, + .SDL_INPUT_LINUXEV = 1, + .SDL_INPUT_LINUXKD = 1, + .SDL_JOYSTICK_HIDAPI = 1, + .SDL_JOYSTICK_LINUX = 1, + .SDL_JOYSTICK_VIRTUAL = 1, + .SDL_HAPTIC_LINUX = 1, + .SDL_PROCESS_POSIX = 1, + .SDL_THREAD_PTHREAD = 1, + .SDL_THREAD_PTHREAD_RECURSIVE_MUTEX = 1, + .SDL_TIME_UNIX = 1, + .SDL_TIMER_UNIX = 1, + .SDL_VIDEO_DRIVER_DUMMY = 1, + .SDL_VIDEO_DRIVER_OFFSCREEN = 1, + .SDL_VIDEO_DRIVER_X11 = 1, + .SDL_VIDEO_DRIVER_X11_DYNAMIC = "\"libX11.so.6\"", + .SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR = "\"libXcursor.so.1\"", + .SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT = "\"libXext.so.6\"", + .SDL_VIDEO_DRIVER_X11_DYNAMIC_XFIXES = "\"libXfixes.so.3\"", + .SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 = "\"libXi.so.6\"", + .SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR = "\"libXrandr.so.2\"", + .SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS = "\"libXss.so.1\"", + .SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM = 1, + .SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS = 1, + .SDL_VIDEO_DRIVER_X11_XCURSOR = 1, + .SDL_VIDEO_DRIVER_X11_XDBE = 1, + .SDL_VIDEO_DRIVER_X11_XFIXES = 1, + .SDL_VIDEO_DRIVER_X11_XINPUT2 = 1, + .SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH = 1, + .SDL_VIDEO_DRIVER_X11_XRANDR = 1, + .SDL_VIDEO_DRIVER_X11_XSCRNSAVER = 1, + .SDL_VIDEO_DRIVER_X11_XSHAPE = 1, + .SDL_VIDEO_OPENGL = 1, + .SDL_VIDEO_OPENGL_GLX = 1, + .SDL_VIDEO_VULKAN = 1, + .SDL_GPU_VULKAN = 1, + .SDL_POWER_LINUX = 1, + .SDL_FILESYSTEM_UNIX = 1, + .SDL_STORAGE_GENERIC = 1, + .SDL_STORAGE_STEAM = 1, + .SDL_FSOPS_POSIX = 1, + //.SDL_CAMERA_DRIVER_V4L2 = 1, + .DYNAPI_NEEDS_DLOPEN = 1, + .SDL_DISABLE_LSX = 1, + .SDL_DISABLE_LASX = 1, + .SDL_DISABLE_NEON = 1, + }); + applyOptionsWithConfig(&linux_options, b, lib, upstream_root, config_header); + applyOptionsWithConfig(&global_options, b, lib, upstream_root, config_header); + }, + else => {}, + } + lib.addConfigHeader(config_header); + lib.installConfigHeader(config_header); + + const revision_header = b.addConfigHeader(.{ + .style = .{ .cmake = upstream.path("include/build_config/SDL_revision.h.cmake") }, + .include_path = "SDL_revision.h", + }, .{}); + lib.addConfigHeader(revision_header); + lib.installConfigHeader(revision_header); + } + lib.installHeadersDirectory(upstream.path("include/SDL3"), "SDL3", .{}); + b.installArtifact(lib); +} + +const generic_src_files = [_][]const u8{ + "src/SDL.c", + "src/SDL_assert.c", + "src/SDL_error.c", + "src/SDL_guid.c", + "src/SDL_hashtable.c", + "src/SDL_hints.c", + "src/SDL_list.c", + "src/SDL_log.c", + "src/SDL_properties.c", + "src/SDL_utils.c", + + "src/atomic/SDL_atomic.c", + "src/atomic/SDL_spinlock.c", + + "src/audio/SDL_audio.c", + "src/audio/SDL_audiocvt.c", + "src/audio/SDL_audiodev.c", + "src/audio/SDL_audioqueue.c", + "src/audio/SDL_audioresample.c", + "src/audio/SDL_audiotypecvt.c", + "src/audio/SDL_mixer.c", + "src/audio/SDL_wave.c", + "src/audio/disk/SDL_diskaudio.c", + "src/audio/dsp/SDL_dspaudio.c", + "src/audio/dummy/SDL_dummyaudio.c", + + "src/camera/SDL_camera.c", + "src/camera/dummy/SDL_camera_dummy.c", + + "src/core/SDL_core_unsupported.c", + + "src/cpuinfo/SDL_cpuinfo.c", + + "src/dialog/SDL_dialog_utils.c", + + "src/dynapi/SDL_dynapi.c", + + "src/events/SDL_categories.c", + "src/events/SDL_clipboardevents.c", + "src/events/SDL_displayevents.c", + "src/events/SDL_dropevents.c", + "src/events/SDL_events.c", + "src/events/SDL_keyboard.c", + "src/events/SDL_keymap.c", + "src/events/SDL_keysym_to_scancode.c", + "src/events/SDL_mouse.c", + "src/events/SDL_pen.c", + "src/events/SDL_quit.c", + "src/events/SDL_scancode_tables.c", + "src/events/SDL_touch.c", + "src/events/SDL_windowevents.c", + "src/events/imKStoUCS.c", + + "src/file/SDL_iostream.c", + + "src/filesystem/SDL_filesystem.c", + + "src/gpu/SDL_gpu.c", + "src/gpu/vulkan/SDL_gpu_vulkan.c", + + "src/haptic/SDL_haptic.c", + + "src/hidapi/SDL_hidapi.c", + + "src/joystick/SDL_gamepad.c", + "src/joystick/SDL_joystick.c", + "src/joystick/SDL_steam_virtual_gamepad.c", + "src/joystick/controller_type.c", + "src/joystick/steam/SDL_steamcontroller.c", + "src/joystick/virtual/SDL_virtualjoystick.c", + + "src/joystick/hidapi/SDL_hidapi_combined.c", + "src/joystick/hidapi/SDL_hidapi_gamecube.c", + "src/joystick/hidapi/SDL_hidapi_luna.c", + "src/joystick/hidapi/SDL_hidapi_ps3.c", + "src/joystick/hidapi/SDL_hidapi_ps4.c", + "src/joystick/hidapi/SDL_hidapi_ps5.c", + "src/joystick/hidapi/SDL_hidapi_rumble.c", + "src/joystick/hidapi/SDL_hidapi_shield.c", + "src/joystick/hidapi/SDL_hidapi_stadia.c", + "src/joystick/hidapi/SDL_hidapi_steam.c", + "src/joystick/hidapi/SDL_hidapi_steamdeck.c", + "src/joystick/hidapi/SDL_hidapi_steam_hori.c", + "src/joystick/hidapi/SDL_hidapi_switch.c", + "src/joystick/hidapi/SDL_hidapi_wii.c", + "src/joystick/hidapi/SDL_hidapi_xbox360.c", + "src/joystick/hidapi/SDL_hidapi_xbox360w.c", + "src/joystick/hidapi/SDL_hidapi_xboxone.c", + "src/joystick/hidapi/SDL_hidapijoystick.c", + + "src/libm/e_atan2.c", + "src/libm/e_exp.c", + "src/libm/e_fmod.c", + "src/libm/e_log.c", + "src/libm/e_log10.c", + "src/libm/e_pow.c", + "src/libm/e_rem_pio2.c", + "src/libm/e_sqrt.c", + "src/libm/k_cos.c", + "src/libm/k_rem_pio2.c", + "src/libm/k_sin.c", + "src/libm/k_tan.c", + "src/libm/s_atan.c", + "src/libm/s_copysign.c", + "src/libm/s_cos.c", + "src/libm/s_fabs.c", + "src/libm/s_floor.c", + "src/libm/s_isinf.c", + "src/libm/s_isinff.c", + "src/libm/s_isnan.c", + "src/libm/s_isnanf.c", + "src/libm/s_modf.c", + "src/libm/s_scalbn.c", + "src/libm/s_sin.c", + "src/libm/s_tan.c", + + "src/locale/SDL_locale.c", + + "src/main/SDL_main_callbacks.c", + "src/main/SDL_runapp.c", + "src/main/generic/SDL_sysmain_callbacks.c", + + "src/misc/SDL_url.c", + + "src/power/SDL_power.c", + + "src/process/SDL_process.c", + + "src/render/SDL_d3dmath.c", + "src/render/SDL_render.c", + "src/render/SDL_yuv_sw.c", + + "src/sensor/SDL_sensor.c", + "src/sensor/dummy/SDL_dummysensor.c", + + "src/stdlib/SDL_crc16.c", + "src/stdlib/SDL_crc32.c", + "src/stdlib/SDL_getenv.c", + "src/stdlib/SDL_iconv.c", + "src/stdlib/SDL_malloc.c", + "src/stdlib/SDL_memcpy.c", + "src/stdlib/SDL_memmove.c", + "src/stdlib/SDL_memset.c", + "src/stdlib/SDL_mslibc.c", + "src/stdlib/SDL_murmur3.c", + "src/stdlib/SDL_qsort.c", + "src/stdlib/SDL_random.c", + "src/stdlib/SDL_stdlib.c", + "src/stdlib/SDL_string.c", + "src/stdlib/SDL_strtokr.c", + + "src/storage/SDL_storage.c", + "src/storage/generic/SDL_genericstorage.c", + "src/storage/steam/SDL_steamstorage.c", + + "src/thread/SDL_thread.c", + + // "src/thread/generic/SDL_sysmutex.c", + + "src/time/SDL_time.c", + + "src/timer/SDL_timer.c", + + "src/video/SDL_RLEaccel.c", + "src/video/SDL_blit.c", + "src/video/SDL_blit_0.c", + "src/video/SDL_blit_1.c", + "src/video/SDL_blit_A.c", + "src/video/SDL_blit_N.c", + "src/video/SDL_blit_auto.c", + "src/video/SDL_blit_copy.c", + "src/video/SDL_blit_slow.c", + "src/video/SDL_bmp.c", + "src/video/SDL_clipboard.c", + "src/video/SDL_egl.c", + "src/video/SDL_fillrect.c", + "src/video/SDL_pixels.c", + "src/video/SDL_rect.c", + "src/video/SDL_stretch.c", + "src/video/SDL_surface.c", + "src/video/SDL_video.c", + "src/video/SDL_video_unsupported.c", + "src/video/SDL_vulkan_utils.c", + "src/video/SDL_yuv.c", + "src/video/yuv2rgb/yuv_rgb_lsx.c", + "src/video/yuv2rgb/yuv_rgb_sse.c", + "src/video/yuv2rgb/yuv_rgb_std.c", + + "src/video/dummy/SDL_nullevents.c", + "src/video/dummy/SDL_nullframebuffer.c", + "src/video/dummy/SDL_nullvideo.c", + + "src/video/offscreen/SDL_offscreenevents.c", + "src/video/offscreen/SDL_offscreenframebuffer.c", + "src/video/offscreen/SDL_offscreenvideo.c", + "src/video/offscreen/SDL_offscreenwindow.c", + "src/video/offscreen/SDL_offscreenopengles.c", + "src/video/offscreen/SDL_offscreenvulkan.c", +}; + +const windows_src_files = [_][]const u8{ + "src/audio/directsound/SDL_directsound.c", + "src/audio/wasapi/SDL_wasapi.c", + "src/audio/wasapi/SDL_wasapi_win32.c", + + "src/camera/mediafoundation/SDL_camera_mediafoundation.c", + + "src/core/windows/SDL_hid.c", + "src/core/windows/SDL_immdevice.c", + "src/core/windows/SDL_windows.c", + "src/core/windows/SDL_xinput.c", + "src/core/windows/pch.c", + "src/core/windows/pch_cpp.cpp", + // "src/core/gdk/SDL_gdk.cpp", + + "src/dialog/windows/SDL_windowsdialog.c", + + "src/filesystem/windows/SDL_sysfilesystem.c", + "src/filesystem/windows/SDL_sysfsops.c", + + "src/gpu/d3d11/SDL_gpu_d3d11.c", + "src/gpu/d3d12/SDL_gpu_d3d12.c", + + "src/haptic/windows/SDL_dinputhaptic.c", + "src/haptic/windows/SDL_windowshaptic.c", + + "src/hidapi/windows/hid.c", + "src/hidapi/windows/hidapi_descriptor_reconstruct.c", + "src/hidapi/windows/pp_data_dump/pp_data_dump.c", + + "src/joystick/windows/SDL_dinputjoystick.c", + "src/joystick/windows/SDL_rawinputjoystick.c", + "src/joystick/windows/SDL_windows_gaming_input.c", + "src/joystick/windows/SDL_windowsjoystick.c", + "src/joystick/windows/SDL_xinputjoystick.c", + + "src/loadso/windows/SDL_sysloadso.c", + + "src/locale/windows/SDL_syslocale.c", + + "src/main/windows/SDL_sysmain_runapp.c", + + "src/misc/windows/SDL_sysurl.c", + + "src/power/windows/SDL_syspower.c", + + "src/process/windows/SDL_windowsprocess.c", + + "src/render/direct3d/SDL_render_d3d.c", + "src/render/direct3d/SDL_shaders_d3d.c", + "src/render/direct3d11/SDL_render_d3d11.c", + "src/render/direct3d11/SDL_shaders_d3d11.c", + "src/render/direct3d12/SDL_render_d3d12.c", + "src/render/direct3d12/SDL_shaders_d3d12.c", + + "src/sensor/windows/SDL_windowssensor.c", + + "src/thread/windows/SDL_syscond_cv.c", + "src/thread/windows/SDL_sysmutex.c", + "src/thread/windows/SDL_sysrwlock_srw.c", + "src/thread/windows/SDL_syssem.c", + "src/thread/windows/SDL_systhread.c", + "src/thread/windows/SDL_systls.c", + + // NOTE: Looks like some platforms will require these, + // but they can't be globally used in the 'generic' + // source list because they'll conflict with their + // platform specific implementation. + "src/thread/generic/SDL_syscond.c", + "src/thread/generic/SDL_sysrwlock.c", + "src/thread/generic/SDL_syssem.c", + "src/thread/generic/SDL_systhread.c", + "src/thread/generic/SDL_systls.c", + + "src/time/windows/SDL_systime.c", + + "src/timer/windows/SDL_systimer.c", + + "src/video/windows/SDL_windowsclipboard.c", + "src/video/windows/SDL_windowsevents.c", + "src/video/windows/SDL_windowsframebuffer.c", + "src/video/windows/SDL_windowsgameinput.c", + "src/video/windows/SDL_windowskeyboard.c", + "src/video/windows/SDL_windowsmessagebox.c", + "src/video/windows/SDL_windowsmodes.c", + "src/video/windows/SDL_windowsmouse.c", + "src/video/windows/SDL_windowsopengl.c", + "src/video/windows/SDL_windowsopengles.c", + "src/video/windows/SDL_windowsrawinput.c", + "src/video/windows/SDL_windowsshape.c", + "src/video/windows/SDL_windowsvideo.c", + "src/video/windows/SDL_windowsvulkan.c", + "src/video/windows/SDL_windowswindow.c", +}; + +const linux_src_files = [_][]const u8{ + "src/camera/v4l2/SDL_camera_v4l2.c", + + "src/core/linux/SDL_evdev.c", + "src/core/linux/SDL_evdev_capabilities.c", + "src/core/linux/SDL_evdev_kbd.c", + "src/core/linux/SDL_sandbox.c", + "src/core/linux/SDL_threadprio.c", + "src/core/unix/SDL_appid.c", + "src/core/unix/SDL_poll.c", + + // Requires D-BUS development package + // "src/core/linux/SDL_dbus.c", + // "src/core/linux/SDL_fcitx.c", + // "src/core/linux/SDL_ibus.c", + // "src/core/linux/SDL_ime.c", + // "src/core/linux/SDL_system_theme.c", + // "src/core/linux/SDL_udev.c", + + "src/dialog/unix/SDL_portaldialog.c", + "src/dialog/unix/SDL_unixdialog.c", + "src/dialog/unix/SDL_zenitydialog.c", + + "src/filesystem/unix/SDL_sysfilesystem.c", + "src/filesystem/posix/SDL_sysfsops.c", + + "src/haptic/linux/SDL_syshaptic.c", + + // Requires libudev development package + // "src/hidapi/linux/hid.c", + + "src/joystick/linux/SDL_sysjoystick.c", + "src/joystick/dummy/SDL_sysjoystick.c", + + "src/loadso/dlopen/SDL_sysloadso.c", + + "src/locale/unix/SDL_syslocale.c", + + "src/misc/unix/SDL_sysurl.c", + + "src/power/linux/SDL_syspower.c", + + "src/process/posix/SDL_posixprocess.c", + + "src/thread/pthread/SDL_syscond.c", + "src/thread/pthread/SDL_sysmutex.c", + "src/thread/pthread/SDL_sysrwlock.c", + "src/thread/pthread/SDL_syssem.c", + "src/thread/pthread/SDL_systhread.c", + "src/thread/pthread/SDL_systls.c", + + "src/time/unix/SDL_systime.c", + + "src/timer/unix/SDL_systimer.c", + + "src/video/kmsdrm/SDL_kmsdrmdyn.c", + "src/video/kmsdrm/SDL_kmsdrmevents.c", + "src/video/kmsdrm/SDL_kmsdrmmouse.c", + "src/video/kmsdrm/SDL_kmsdrmopengles.c", + "src/video/kmsdrm/SDL_kmsdrmvideo.c", + "src/video/kmsdrm/SDL_kmsdrmvulkan.c", + "src/video/x11/SDL_x11clipboard.c", + "src/video/x11/SDL_x11dyn.c", + "src/video/x11/SDL_x11events.c", + "src/video/x11/SDL_x11framebuffer.c", + "src/video/x11/SDL_x11keyboard.c", + "src/video/x11/SDL_x11messagebox.c", + "src/video/x11/SDL_x11modes.c", + "src/video/x11/SDL_x11mouse.c", + "src/video/x11/SDL_x11opengl.c", + "src/video/x11/SDL_x11opengles.c", + "src/video/x11/SDL_x11pen.c", + "src/video/x11/SDL_x11settings.c", + "src/video/x11/SDL_x11shape.c", + "src/video/x11/SDL_x11touch.c", + "src/video/x11/SDL_x11video.c", + "src/video/x11/SDL_x11vulkan.c", + "src/video/x11/SDL_x11window.c", + "src/video/x11/SDL_x11xfixes.c", + "src/video/x11/SDL_x11xinput2.c", + "src/video/x11/edid-parse.c", + "src/video/x11/xsettings-client.c", +}; + +const darwin_src_files = [_][]const u8{ + "src/audio/aaudio/SDL_aaudio.c", + "src/haptic/darwin/SDL_syshaptic.c", + "src/hidapi/mac/hid.c", + "src/joystick/darwin/SDL_iokitjoystick.c", + "src/power/macos/SDL_syspower.c", + "src/thread/pthread/SDL_syscond.c", + "src/thread/pthread/SDL_sysmutex.c", + "src/thread/pthread/SDL_sysrwlock.c", + "src/thread/pthread/SDL_syssem.c", + "src/thread/pthread/SDL_systhread.c", + "src/thread/pthread/SDL_systls.c", + "src/time/unix/SDL_systime.c", + "src/timer/unix/SDL_systimer.c", + "src/process/posix/SDL_posixprocess.c", + "src/core/unix/SDL_appid.c", + "src/core/unix/SDL_poll.c", + "src/locale/unix/SDL_syslocale.c", + "src/misc/unix/SDL_sysurl.c", +}; + +const objective_c_src_files = [_][]const u8{ + "src/audio/coreaudio/SDL_coreaudio.m", + "src/camera/coremedia/SDL_camera_coremedia.m", + "src/dialog/cocoa/SDL_cocoadialog.m", + "src/filesystem/cocoa/SDL_sysfilesystem.m", + "src/gpu/metal/SDL_gpu_metal.m", + "src/hidapi/ios/hid.m", + // "src/hidapi/testgui/mac_support_cocoa.m", + "src/joystick/apple/SDL_mfijoystick.m", + "src/locale/macos/SDL_syslocale.m", + "src/main/ios/SDL_sysmain_callbacks.m", + "src/misc/ios/SDL_sysurl.m", + "src/misc/macos/SDL_sysurl.m", + "src/power/uikit/SDL_syspower.m", + "src/render/metal/SDL_render_metal.m", + "src/sensor/coremotion/SDL_coremotionsensor.m", + "src/video/cocoa/SDL_cocoaclipboard.m", + "src/video/cocoa/SDL_cocoaevents.m", + "src/video/cocoa/SDL_cocoakeyboard.m", + "src/video/cocoa/SDL_cocoamessagebox.m", + "src/video/cocoa/SDL_cocoametalview.m", + "src/video/cocoa/SDL_cocoamodes.m", + "src/video/cocoa/SDL_cocoamouse.m", + "src/video/cocoa/SDL_cocoaopengl.m", + "src/video/cocoa/SDL_cocoaopengles.m", + "src/video/cocoa/SDL_cocoapen.m", + "src/video/cocoa/SDL_cocoashape.m", + "src/video/cocoa/SDL_cocoavideo.m", + "src/video/cocoa/SDL_cocoavulkan.m", + "src/video/cocoa/SDL_cocoawindow.m", + "src/video/uikit/SDL_uikitappdelegate.m", + "src/video/uikit/SDL_uikitclipboard.m", + "src/video/uikit/SDL_uikitevents.m", + "src/video/uikit/SDL_uikitmessagebox.m", + "src/video/uikit/SDL_uikitmetalview.m", + "src/video/uikit/SDL_uikitmodes.m", + "src/video/uikit/SDL_uikitopengles.m", + "src/video/uikit/SDL_uikitopenglview.m", + "src/video/uikit/SDL_uikitvideo.m", + "src/video/uikit/SDL_uikitview.m", + "src/video/uikit/SDL_uikitviewcontroller.m", + "src/video/uikit/SDL_uikitvulkan.m", + "src/video/uikit/SDL_uikitwindow.m", +}; + +const ios_src_files = [_][]const u8{}; + +const emscripten_src_files = [_][]const u8{ + "src/audio/emscripten/SDL_emscriptenaudio.c", + "src/camera/emscripten/SDL_camera_emscripten.c", + "src/filesystem/emscripten/SDL_sysfilesystem.c", + "src/joystick/emscripten/SDL_sysjoystick.c", + "src/locale/emscripten/SDL_syslocale.c", + "src/main/emscripten/SDL_sysmain_callbacks.c", + "src/main/emscripten/SDL_sysmain_runapp.c", + "src/misc/emscripten/SDL_sysurl.c", + "src/power/emscripten/SDL_syspower.c", + "src/video/emscripten/SDL_emscriptenevents.c", + "src/video/emscripten/SDL_emscriptenframebuffer.c", + "src/video/emscripten/SDL_emscriptenmouse.c", + "src/video/emscripten/SDL_emscriptenopengles.c", + "src/video/emscripten/SDL_emscriptenvideo.c", + + "src/timer/unix/SDL_systimer.c", + "src/loadso/dlopen/SDL_sysloadso.c", + "src/audio/disk/SDL_diskaudio.c", + "src/render/opengles2/SDL_render_gles2.c", + "src/render/opengles2/SDL_shaders_gles2.c", + "src/sensor/dummy/SDL_dummysensor.c", + + "src/thread/pthread/SDL_syscond.c", + "src/thread/pthread/SDL_sysmutex.c", + "src/thread/pthread/SDL_sysrwlock.c", + "src/thread/pthread/SDL_syssem.c", + "src/thread/pthread/SDL_systhread.c", + "src/thread/pthread/SDL_systls.c", +}; + +const unknown_src_files = [_][]const u8{}; + +const static_headers = [_][]const u8{ + "SDL3/SDL.h", + "SDL3/SDL_assert.h", + "SDL3/SDL_atomic.h", + "SDL3/SDL_audio.h", + "SDL3/SDL_begin_code.h", + "SDL3/SDL_bits.h", + "SDL3/SDL_blendmode.h", + "SDL3/SDL_camera.h", + "SDL3/SDL_clipboard.h", + "SDL3/SDL_close_code.h", + "SDL3/SDL_copying.h", + "SDL3/SDL_cpuinfo.h", + "SDL3/SDL_dialog.h", + "SDL3/SDL_egl.h", + "SDL3/SDL_endian.h", + "SDL3/SDL_error.h", + "SDL3/SDL_events.h", + "SDL3/SDL_filesystem.h", + "SDL3/SDL_gamepad.h", + "SDL3/SDL_gpu.h", + "SDL3/SDL_guid.h", + "SDL3/SDL_haptic.h", + "SDL3/SDL_hidapi.h", + "SDL3/SDL_hints.h", + "SDL3/SDL_init.h", + "SDL3/SDL_intrin.h", + "SDL3/SDL_iostream.h", + "SDL3/SDL_joystick.h", + "SDL3/SDL_keyboard.h", + "SDL3/SDL_keycode.h", + "SDL3/SDL_loadso.h", + "SDL3/SDL_locale.h", + "SDL3/SDL_log.h", + "SDL3/SDL_main.h", + "SDL3/SDL_main_impl.h", + "SDL3/SDL_messagebox.h", + "SDL3/SDL_metal.h", + "SDL3/SDL_misc.h", + "SDL3/SDL_mouse.h", + "SDL3/SDL_mutex.h", + "SDL3/SDL_oldnames.h", + "SDL3/SDL_opengl.h", + "SDL3/SDL_opengl_glext.h", + "SDL3/SDL_opengles.h", + "SDL3/SDL_opengles2.h", + "SDL3/SDL_opengles2_gl2.h", + "SDL3/SDL_opengles2_gl2ext.h", + "SDL3/SDL_opengles2_gl2platform.h", + "SDL3/SDL_opengles2_khrplatform.h", + "SDL3/SDL_pen.h", + "SDL3/SDL_pixels.h", + "SDL3/SDL_platform.h", + "SDL3/SDL_platform_defines.h", + "SDL3/SDL_power.h", + "SDL3/SDL_process.h", + "SDL3/SDL_properties.h", + "SDL3/SDL_rect.h", + "SDL3/SDL_render.h", + "SDL3/SDL_revision.h", + "SDL3/SDL_scancode.h", + "SDL3/SDL_sensor.h", + "SDL3/SDL_stdinc.h", + "SDL3/SDL_storage.h", + "SDL3/SDL_surface.h", + "SDL3/SDL_system.h", + "SDL3/SDL_test.h", + "SDL3/SDL_test_assert.h", + "SDL3/SDL_test_common.h", + "SDL3/SDL_test_compare.h", + "SDL3/SDL_test_crc32.h", + "SDL3/SDL_test_font.h", + "SDL3/SDL_test_fuzzer.h", + "SDL3/SDL_test_harness.h", + "SDL3/SDL_test_log.h", + "SDL3/SDL_test_md5.h", + "SDL3/SDL_test_memory.h", + "SDL3/SDL_thread.h", + "SDL3/SDL_time.h", + "SDL3/SDL_timer.h", + "SDL3/SDL_touch.h", + "SDL3/SDL_version.h", + "SDL3/SDL_video.h", + "SDL3/SDL_vulkan.h", + "build_config/SDL_build_config.h", + "build_config/SDL_build_config_android.h", + "build_config/SDL_build_config_emscripten.h", + "build_config/SDL_build_config_ios.h", + "build_config/SDL_build_config_macos.h", + "build_config/SDL_build_config_minimal.h", + "build_config/SDL_build_config_ngage.h", + "build_config/SDL_build_config_windows.h", + "build_config/SDL_build_config_wingdk.h", + "build_config/SDL_build_config_xbox.h", +}; + +const SdlOption = struct { + name: []const u8, + desc: []const u8, + default: bool, + // SDL configs affect the public SDL_config.h header file. Any values + // should occur in a header file in the include directory. + sdl_configs: []const []const u8, + // C Macros are similar to SDL configs but aren't present in the public + // headers and only affect the SDL implementation. None of the values + // should occur in the include directory. + c_macros: []const []const u8 = &.{}, + src_files: []const []const u8, + system_libs: []const []const u8, +}; + +const global_options = [_]SdlOption{ + .{ + .name = "render_driver_software", + .desc = "enable the software render driver", + .default = true, + .sdl_configs = &.{}, + .c_macros = &.{"SDL_VIDEO_RENDER_SW"}, + .src_files = &.{ + "src/render/software/SDL_blendfillrect.c", + "src/render/software/SDL_blendline.c", + "src/render/software/SDL_blendpoint.c", + "src/render/software/SDL_drawline.c", + "src/render/software/SDL_drawpoint.c", + "src/render/software/SDL_render_sw.c", + "src/render/software/SDL_rotate.c", + "src/render/software/SDL_triangle.c", + }, + .system_libs = &.{}, + }, + .{ + .name = "render_driver_ogl", + .desc = "enable the opengl render driver", + .default = true, + .sdl_configs = &.{"SDL_VIDEO_RENDER_OGL"}, + .src_files = &.{ + "src/render/opengl/SDL_render_gl.c", + "src/render/opengl/SDL_shaders_gl.c", + }, + .system_libs = &.{}, + }, + .{ + .name = "render_driver_vulkan", + .desc = "enable the vulkan render driver", + .default = true, + .sdl_configs = &.{"SDL_VIDEO_RENDER_VULKAN"}, + .src_files = &.{ + "src/render/vulkan/SDL_render_vulkan.c", + "src/render/vulkan/SDL_shaders_vulkan.c", + }, + .system_libs = &.{}, + }, + .{ + .name = "render_driver_gpu", + .desc = "enable the opengl render driver", + .default = true, + .sdl_configs = &.{"SDL_VIDEO_RENDER_GPU"}, + .src_files = &.{ + "src/render/gpu/SDL_pipeline_gpu.c", + "src/render/gpu/SDL_render_gpu.c", + "src/render/gpu/SDL_shaders_gpu.c", + }, + .system_libs = &.{}, + }, + .{ + .name = "render_driver_ogl_es2", + .desc = "enable the opengl es2 render driver", + .default = true, + .sdl_configs = &.{"SDL_VIDEO_RENDER_OGL_ES2"}, + .src_files = &.{ + "src/render/opengles2/SDL_render_gles2.c", + "src/render/opengles2/SDL_shaders_gles2.c", + }, + .system_libs = &.{}, + }, +}; + +const linux_options = [_]SdlOption{ + .{ + .name = "video_driver_x11", + .desc = "enable the x11 video driver", + .default = true, + .sdl_configs = &.{ + "SDL_VIDEO_DRIVER_X11", + "SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS", + }, + .src_files = &.{}, + .system_libs = &.{ "x11", "xext" }, + }, + .{ + .name = "audio_driver_pulse", + .desc = "enable the pulse audio driver", + .default = false, + .sdl_configs = &.{"SDL_AUDIO_DRIVER_PULSEAUDIO"}, + .src_files = &.{"src/audio/pulseaudio/SDL_pulseaudio.c"}, + .system_libs = &.{"pulse"}, + }, + .{ + .name = "audio_driver_alsa", + .desc = "enable the alsa audio driver", + .default = false, + .sdl_configs = &.{"SDL_AUDIO_DRIVER_ALSA"}, + .src_files = &.{"src/audio/alsa/SDL_alsa_audio.c"}, + .system_libs = &.{"alsa"}, + }, +}; + +fn applyOption( + comptime option: *const SdlOption, + lib: *std.Build.Step.Compile, + upstream_root: std.Build.LazyPath, +) void { + lib.addCSourceFiles(.{ .root = upstream_root, .files = option.src_files }); + for (option.system_libs) |lib_name| { + lib.linkSystemLibrary(lib_name); + } +} + +fn applyOptions( + comptime options: []const SdlOption, + b: *std.Build, + lib: *std.Build.Step.Compile, + upstream_root: std.Build.LazyPath, +) void { + inline for (options) |option| { + const enabled = if (b.option(bool, option.name, option.desc)) |o| o else option.default; + for (option.c_macros) |name| { + lib.defineCMacro(name, if (enabled) "1" else "0"); + } + if (enabled) { + applyOption(&option, lib, upstream_root); + } + } +} + +fn applyOptionsWithConfig( + comptime options: []const SdlOption, + b: *std.Build, + lib: *std.Build.Step.Compile, + upstream_root: std.Build.LazyPath, + config_header: *std.Build.Step.ConfigHeader, +) void { + inline for (options) |option| { + const enabled = if (b.option(bool, option.name, option.desc)) |o| o else option.default; + for (option.c_macros) |name| { + lib.defineCMacro(name, if (enabled) "1" else "0"); + } + for (option.sdl_configs) |config| { + config_header.values.put(config, .{ .int = if (enabled) 1 else 0 }) catch @panic("OOM"); + } + if (enabled) { + applyOption(&option, lib, upstream_root); + } + } +} diff --git a/3rdparty/sdl/build.zig.zon b/3rdparty/sdl/build.zig.zon new file mode 100644 index 00000000..3252f910 --- /dev/null +++ b/3rdparty/sdl/build.zig.zon @@ -0,0 +1,14 @@ +.{ + .name = "SDL", + .minimum_zig_version = "0.13.0", + .version = "3.1.3-1", + .dependencies = .{ + .sdl_src = .{ + .url = "git+https://github.com/libsdl-org/SDL#afee27a5304b5dec9a8694cb408f877bf1c58d6a", + .hash = "1220e118f229f4e63568c548748d693df623891e0053d1d0630d4ae9e0d3971267cc", + }, + }, + .paths = .{ + "", + }, +} diff --git a/build.zig b/build.zig index fecd605d..37c56954 100644 --- a/build.zig +++ b/build.zig @@ -8,10 +8,16 @@ const system_sdk = @import("system-sdk"); var target: Build.ResolvedTarget = undefined; var optimize: std.builtin.OptimizeMode = undefined; +const PlatformBackend = enum { + sdl, + sokol, +}; + const ModuleImport = struct { module: *Build.Module, name: []const u8, }; + const BuildCollection = struct { add_imports: []const ModuleImport, link_libraries: []const *Build.Step.Compile, @@ -21,12 +27,22 @@ pub fn build(b: *std.Build) !void { target = b.standardTargetOptions(.{}); optimize = b.standardOptimizeOption(.{}); + const delve_config = b.addOptions(); + const platform_backend = b.option(PlatformBackend, "platform_backend", "(default: sokol)") orelse PlatformBackend.sokol; + delve_config.addOption(PlatformBackend, "platform_backend", platform_backend); + + // Set sokol up first because it brings in things like the emscripten sdk. const dep_sokol = b.dependency("sokol", .{ .target = target, .optimize = optimize, .with_sokol_imgui = true, }); + const dep_sdl = b.dependency("sdl", .{ + .target = target, + .optimize = optimize, + }); + const dep_ziglua = b.dependency("ziglua", .{ .target = target, .optimize = optimize, @@ -67,6 +83,9 @@ pub fn build(b: *std.Build) !void { // inject the cimgui header search path into the sokol C library compile step const cimgui_root = dep_cimgui.namedWriteFiles("cimgui").getDirectory(); dep_sokol.artifact("sokol_clib").addIncludePath(cimgui_root); + if (platform_backend == PlatformBackend.sdl) { + dep_sokol.artifact("sokol_clib").defineCMacro("SOKOL_IMGUI_NO_SOKOL_APP", ""); + } dep_stb_truetype.artifact("stb_truetype").addIncludePath(b.path("3rdparty/stb_truetype/libs")); @@ -110,6 +129,7 @@ pub fn build(b: *std.Build) !void { .target = target, .optimize = optimize, }); + delve_mod.addOptions("config", delve_config); for (build_collection.add_imports) |build_import| { delve_mod.addImport(build_import.name, build_import.module); @@ -124,6 +144,10 @@ pub fn build(b: *std.Build) !void { delve_mod.linkLibrary(lib); } + if (platform_backend == PlatformBackend.sdl) { + delve_mod.linkLibrary(dep_sdl.artifact("SDL3")); + } + // For web builds, add the Emscripten system headers so C libraries can find the stdlib headers if (target.result.isWasm()) { const emsdk_include_path = getEmsdkSystemIncludePath(dep_sokol); @@ -137,6 +161,10 @@ pub fn build(b: *std.Build) !void { for (build_collection.link_libraries) |lib| { lib.addSystemIncludePath(emsdk_include_path); } + + if (platform_backend == PlatformBackend.sdl) { + dep_sdl.artifact("SDL3").addIncludePath(emsdk_include_path); + } } // Delve Static Library artifact @@ -285,6 +313,11 @@ pub fn getEmsdkSystemIncludePath(dep_sokol: *Build.Dependency) Build.LazyPath { return dep_emsdk.path("upstream/emscripten/cache/sysroot/include"); } +pub fn getEmsdkSysroot(dep_sokol: *Build.Dependency) Build.LazyPath { + const dep_emsdk = dep_sokol.builder.dependency("emsdk", .{}); + return dep_emsdk.path("upstream/emscripten"); +} + pub fn emscriptenRunStep(b: *Build, name: []const u8, dep_sokol: *Build.Dependency) *Build.Step.Run { const emsdk = dep_sokol.builder.dependency("emsdk", .{}); return sokol.emRunStep(b, .{ .name = name, .emsdk = emsdk }); diff --git a/build.zig.zon b/build.zig.zon index b5c1b470..a465ff0b 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,6 +1,6 @@ .{ .name = "delve", - .version = "0.0.2", + .version = "0.1.1", .paths = .{ "src", "3rdparty", @@ -23,6 +23,9 @@ .url = "git+https://github.com/floooh/sokol-zig.git#d3e21f76498213d6d58179065756f5f2ed9b90cf", .hash = "122052a192829b377c637ce242ee8c9121e03d8cd10c889758dc6fb176368de7d67b", }, + .sdl = .{ + .path = "3rdparty/sdl", + }, .ymlz = .{ .url = "git+https://github.com/pwbh/ymlz#bd3ce82da20844117f3da76d0cd40453936b1b66", .hash = "122066bde791372e092cf04ccf2b827e9b1164a2ea23c7187d71d2d2f39252777f25", diff --git a/delve.sublime-project b/delve.sublime-project new file mode 100644 index 00000000..55a2e695 --- /dev/null +++ b/delve.sublime-project @@ -0,0 +1,97 @@ +{ + "folders": + [ + { + "path": ".", + "folder_exclude_patterns": [ + ".zig-cache", + "3rdparty/system-sdk/*", + "zig-out", + ], + } + ], + "build_systems": [ + { + "name": "Build", + "working_dir": "$project_path", + "cmd": ["zig", "build", "-Dplatform_backend=sdl"], + "file_regex": "^\\s*([^:]+):(\\d+):(\\d+):\\s*(.*)$", + "variants": [ + { + "name": "Sokol Backend", + "cmd": ["zig", "build"], + }, + { + "name": "Release", + "cmd": ["zig", "build", "-Doptimize=ReleaseFast", "-Dplatform_backend=sdl"], + }, + { + "name": "Release - Sokol App", + "cmd": ["zig", "build", "-Doptimize=ReleaseFast"], + }, + { + "name": "Windows x86_64", + "cmd": ["zig", "build", "-Dplatform_backend=sdl", "-Dtarget=x86_64-windows"] + }, + { + "name": "Windows x86_64 - Sokol App", + "cmd": ["zig", "build", "-Dplatform_backend=sokol", "-Dtarget=x86_64-windows"] + }, + { + "name": "wasm32", + "cmd": ["zig", "build", "-Dtarget=wasm32-emscripten", "--release=small", "-Dplatform_backend=sdl"] + }, + { + "name": "wasm32 - Sokol App", + "cmd": ["zig", "build", "-Dtarget=wasm32-emscripten", "--release=small"] + } + ], + "target": "terminus_exec", + "cancel": "terminus_cancel_build", + }, + { + "name": "Forest", + "working_dir": "$project_path", + "cmd": ["zig", "build", "run-forest", "-Dplatform_backend=sdl"], + "file_regex": "^\\s*([^:]+):(\\d+):(\\d+):\\s*(.*)$", + "variants": [ + { + "name": "Release", + "cmd": ["zig", "build", "run-forest", "-Doptimize=ReleaseFast", "-Dplatform_backend=sdl"], + }, + { + "name": "Windows x86_64", + "cmd": ["zig", "build", "run-forest", "-Dtarget=x86_64-windows", "-Dplatform_backend=sdl"] + }, + { + "name": "Windows x86_64 - Sokol App", + "cmd": ["zig", "build", "run-forest", "-Dtarget=x86_64-windows"] + }, + { + "name": "Sokol Backend", + "cmd": ["zig", "build", "run-forest"], + }, + { + "name": "wasm32", + "cmd": ["zig", "build", "run-forest", "-Dtarget=wasm32-emscripten", "--release=small", "-Dplatform_backend=sdl"] + }, + { + "name": "wasm32 - Sokol App", + "cmd": ["zig", "build", "run-forest", "-Dtarget=wasm32-emscripten", "--release=small"] + } + ], + "target": "terminus_exec", + "cancel": "terminus_cancel_build", + } + ], + "settings": + { + "LSP": + { + "zig": + { + "enabled": true + } + } + }, +} diff --git a/src/framework/api/graphics.zig b/src/framework/api/graphics.zig index d93c58b2..d1ce5c45 100644 --- a/src/framework/api/graphics.zig +++ b/src/framework/api/graphics.zig @@ -1,7 +1,6 @@ const std = @import("std"); const math = @import("../math.zig"); const ziglua = @import("ziglua"); -const papp = @import("../platform/app.zig"); const debug = @import("../debug.zig"); const colors = @import("../colors.zig"); const assets = @import("assets.zig"); diff --git a/src/framework/platform/app.zig b/src/framework/platform/app.zig index dce8908e..f267f8c3 100644 --- a/src/framework/platform/app.zig +++ b/src/framework/platform/app.zig @@ -1,19 +1,33 @@ const std = @import("std"); +const time = std.time; + const app = @import("../app.zig"); const debug = @import("../debug.zig"); -const gfx = @import("graphics.zig"); const mem = @import("../mem.zig"); const modules = @import("../modules.zig"); -const time = @import("std").time; -const sokol_app_backend = @import("backends/sokol/app.zig"); -// Actual app backend, implementation could be switched out here -const AppBackend = sokol_app_backend.App; +const graphics = @import("graphics.zig"); +const input = @import("input.zig"); +const audio = @import("audio.zig"); + +const build_config = @import("config"); + +const platform_backend = switch (build_config.platform_backend) { + .sdl => @import("backends/sdl3.zig"), + .sokol => @import("backends/sokol_app.zig"), +}; const NS_PER_SECOND: i64 = 1_000_000_000; const NS_PER_SECOND_F: f32 = 1_000_000_000.0; const NS_FPS_LIMIT_OVERHEAD = 1_250_000; // tuned to ensure consistent frame pacing +pub const PlatformHooks = struct { + on_init_fn: *const fn () void, + on_frame_fn: *const fn () void, + on_cleanup_fn: *const fn () void, + // maybe an on_event fn? +}; + const DeltaTime = struct { f_delta_time: f32, ns_delta_time: u64, @@ -59,7 +73,7 @@ const state = struct { pub fn init() !void { debug.log("App platform starting", .{}); - AppBackend.init(.{ + platform_backend.init(.{ .on_init_fn = on_init, .on_cleanup_fn = on_cleanup, .on_frame_fn = on_frame, @@ -71,30 +85,36 @@ pub fn init() !void { pub fn deinit() void { debug.log("App platform stopping", .{}); - AppBackend.deinit(); + platform_backend.deinit(); } pub fn startMainLoop(config: app.AppConfig) void { - if (config.target_fps) |target| + if (config.target_fps) |target| { setTargetFPS(target); + } - if (config.use_fixed_timestep) + if (config.use_fixed_timestep) { setFixedTimestep(config.fixed_timestep_delta); + } - AppBackend.startMainLoop(config); + platform_backend.startMainLoop(config); } pub fn getWidth() i32 { - return AppBackend.getWidth(); + return platform_backend.getWidth(); } pub fn getHeight() i32 { - return AppBackend.getHeight(); + return platform_backend.getHeight(); +} + +pub fn getDpiScale() f32 { + return platform_backend.getDpiScale(); } pub fn captureMouse(captured: bool) void { state.mouse_captured = captured; - AppBackend.captureMouse(captured); + platform_backend.captureMouse(captured); } pub fn isMouseCaptured() bool { @@ -107,7 +127,7 @@ pub fn getAspectRatio() f32 { fn on_init() void { // Start graphics first - gfx.init() catch { + graphics.init() catch { debug.log("Fatal error initializing graphics backend!\n", .{}); return; }; @@ -129,7 +149,7 @@ fn on_cleanup() void { modules.stopModules(); modules.cleanupModules(); app.stopSubsystems(); - gfx.deinit(); + graphics.deinit(); debug.deinit(); mem.deinit(); } @@ -162,9 +182,9 @@ fn on_frame() void { modules.preDrawModules(); // then draw! - gfx.startFrame(); + graphics.startFrame(); modules.drawModules(); - gfx.endFrame(); + graphics.endFrame(); // tell modules this frame is done modules.postDrawModules(); @@ -284,7 +304,7 @@ pub fn getFixedTimestepLerp(include_delta: bool) f32 { /// Exit cleanly pub fn exit() void { - sokol_app_backend.exit(); + platform_backend.exit(); } /// Exit with an error @@ -294,10 +314,10 @@ pub fn exitWithError() void { // Start a new Imgui frame pub fn startImguiFrame() void { - sokol_app_backend.startImguiFrame(); + platform_backend.startImguiFrame(); } // Render Imgui pub fn renderImgui() void { - sokol_app_backend.renderImgui(); + platform_backend.renderImgui(); } diff --git a/src/framework/platform/backends/sdl3.zig b/src/framework/platform/backends/sdl3.zig new file mode 100644 index 00000000..187ac82d --- /dev/null +++ b/src/framework/platform/backends/sdl3.zig @@ -0,0 +1,593 @@ +const std = @import("std"); +const assert = std.debug.assert; +const app = @import("../../app.zig"); +const debug = @import("../../debug.zig"); +const platform = @import("../app.zig"); +const input = @import("../input.zig"); +const cimgui = @import("cimgui"); + +const sokol = @import("sokol"); +const slog = sokol.log; +const sg = sokol.gfx; +const simgui = sokol.imgui; +const sglue = sokol.glue; + +const target = @import("builtin").target; + +const c = @cImport({ + @cInclude("SDL3/SDL.h"); + if (target.os.tag == .emscripten) @cInclude("emscripten.h"); +}); + +var window: *c.SDL_Window = undefined; +var gl_context: c.SDL_GLContext = undefined; +var app_config: app.AppConfig = undefined; +var hooks: platform.PlatformHooks = undefined; +var running: bool = false; + +pub fn init(cfg: platform.PlatformHooks) void { + debug.log("Initializing SDL Backend", .{}); + + if (!c.SDL_Init(c.SDL_INIT_VIDEO | c.SDL_INIT_GAMEPAD)) { + debug.log("ERROR: Failed to initialize SDL - {s}", .{c.SDL_GetError()}); + std.process.exit(1); + } + debug.log("SDL initialized", .{}); + + hooks = cfg; +} + +pub fn deinit() void { + debug.log("Deinitializing SDL App Backend", .{}); + window = undefined; + gl_context = undefined; + app_config = undefined; + hooks = undefined; + c.SDL_Quit(); +} + +fn sokol_init() void { + debug.log("Sokol graphics context initializing", .{}); + + // Leaving the OpenGL context initialization in "sokol" init, because it applies to the sokol case + // and not the SDL_gpu case. + + assert(c.SDL_GL_SetAttribute(c.SDL_GL_CONTEXT_FLAGS, c.SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG)); + assert(c.SDL_GL_SetAttribute(c.SDL_GL_CONTEXT_PROFILE_MASK, c.SDL_GL_CONTEXT_PROFILE_CORE)); + assert(c.SDL_GL_SetAttribute(c.SDL_GL_CONTEXT_MAJOR_VERSION, 3)); + assert(c.SDL_GL_SetAttribute(c.SDL_GL_CONTEXT_MINOR_VERSION, 3)); + assert(c.SDL_GL_SetAttribute(c.SDL_GL_DOUBLEBUFFER, 1)); + + gl_context = c.SDL_GL_CreateContext(window) orelse { + debug.err("Failed to create GL context: {s}", .{c.SDL_GetError()}); + std.process.exit(1); + }; + + if (!c.SDL_GL_MakeCurrent(window, gl_context)) { + debug.err("Failed to bind GL context: {s}", .{c.SDL_GetError()}); + std.process.exit(1); + } + + sg.setup(.{ + // TODO + .environment = if (target.os.tag == .emscripten) sglue.environment() else .{}, + .logger = .{ + .func = slog.func, + }, + .buffer_pool_size = app_config.buffer_pool_size, // sokol default is 128 + .shader_pool_size = app_config.shader_pool_size, // sokol default is 64 + .image_pool_size = app_config.image_pool_size, // sokol default is 128 + .pipeline_pool_size = app_config.pipeline_pool_size, // sokol default is 64 + .sampler_pool_size = app_config.sampler_pool_size, // sokol default is 64 + .attachments_pool_size = app_config.pass_pool_size, // sokol default is 16, + }); + + simgui.setup(.{ + .logger = .{ + .func = slog.func, + }, + }); + + const io = cimgui.igGetIO(); + // platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText; + // platform_io.Platform_GetClipboardTextFn = ImGui_ImplSDL3_GetClipboardText; + io.*.SetPlatformImeDataFn = imguiSetPlatformImeData; + + const viewport = cimgui.igGetMainViewport(); + viewport.*.PlatformHandleRaw = @ptrCast(window); + + debug.log("Sokol setup backend: {}", .{sg.queryBackend()}); + + // call the callback that will tell everything else to start up + hooks.on_init_fn(); +} + +fn cleanup() void { + hooks.on_cleanup_fn(); + sg.shutdown(); +} + +fn frame() void { + hooks.on_frame_fn(); +} + +pub fn startMainLoop(config: app.AppConfig) void { + app_config = config; + + debug.log("Creating SDL Window", .{}); + + // TODO: For SDL_gpu we'll want Vulkan instead (or Metal... others?) + const window_flags = c.SDL_WINDOW_OPENGL | c.SDL_WINDOW_HIGH_PIXEL_DENSITY; + + window = c.SDL_CreateWindow(config.title, config.width, config.height, window_flags) orelse { + debug.err("ERROR: Failed to create SDL window - {s}", .{c.SDL_GetError()}); + return; + }; + _ = c.SDL_ShowWindow(window); + _ = c.SDL_RaiseWindow(window); + + defer _ = c.SDL_DestroyWindow(window); + + sokol_init(); + defer _ = c.SDL_GL_DestroyContext(gl_context); + + debug.log("SDL app starting main loop", .{}); + + const tick = struct { + pub fn call() callconv(.C) void { + var event: c.SDL_Event = undefined; + while (c.SDL_PollEvent(&event)) { + if (imguiHandleEvent(&event)) { + continue; + } + switch (event.type) { + c.SDL_EVENT_QUIT => { + if (target.os.tag == .emscripten) { + c.emscripten_cancel_main_loop(); + } else { + running = false; + } + }, + c.SDL_EVENT_WINDOW_RESIZED => { + var w: c_int = 0; + var h: c_int = 0; + assert(c.SDL_GetWindowSize(window, &w, &h)); + //sg.create_offscreen_pass(w, h); + debug.log("Window size: {} x {}", .{ w, h }); + }, + c.SDL_EVENT_MOUSE_BUTTON_DOWN => { + input.onMouseDown(event.button.button); + }, + c.SDL_EVENT_MOUSE_BUTTON_UP => { + input.onMouseUp(event.button.button); + }, + c.SDL_EVENT_MOUSE_MOTION => { + input.onMouseMoved(event.motion.x, event.motion.y, event.motion.xrel, event.motion.yrel); + }, + c.SDL_EVENT_KEY_DOWN => { + if (!event.key.repeat) { + const code = sdlkToKeyCode(&event.key); + input.onKeyDown(@intFromEnum(code)); + } + }, + c.SDL_EVENT_KEY_UP => { + const code = sdlkToKeyCode(&event.key); + input.onKeyUp(@intFromEnum(code)); + }, + else => {}, + } + } + + frame(); + assert(c.SDL_GL_SwapWindow(window)); + } + }.call; + + if (target.os.tag == .emscripten) { + c.emscripten_set_main_loop(tick, 0, 1); + } else { + running = true; + while (running) { + tick(); + } + } + + cleanup(); +} + +pub fn getWidth() i32 { + var w: c_int = 0; + var _h: c_int = 0; + if (!c.SDL_GetWindowSize(window, &w, &_h)) { + debug.err("Unable to get SDL window size: {s}", .{c.SDL_GetError()}); + } + return w; +} + +pub fn getHeight() i32 { + var _w: c_int = 0; + var h: c_int = 0; + if (!c.SDL_GetWindowSize(window, &_w, &h)) { + debug.log("Unable to get SDL window size: {s}", .{c.SDL_GetError()}); + } + return h; +} + +pub fn captureMouse(captured: bool) void { + if (!c.SDL_SetWindowRelativeMouseMode(window, captured)) { + debug.log("Unable to capture mouse: {s}", .{c.SDL_GetError()}); + } + + if (captured) { + _ = c.SDL_HideCursor(); + } else { + _ = c.SDL_ShowCursor(); + } +} + +pub fn startImguiFrame() void { + var w: c_int = 0; + var h: c_int = 0; + if (!c.SDL_GetWindowSize(window, &w, &h)) { + debug.log("Unable to get SDL window size: {s}", .{c.SDL_GetError()}); + return; + } + + simgui.newFrame(.{ + .width = w, + .height = w, + .delta_time = platform.getCurrentDeltaTime(), + .dpi_scale = getDpiScale(), + }); +} + +pub fn renderImgui() void { + simgui.render(); +} + +pub fn exit() void { + var event: c.SDL_Event = .{ + .quit = .{ + .type = c.SDL_EVENT_QUIT, + .timestamp = c.SDL_GetTicksNS(), + }, + }; + _ = c.SDL_PushEvent(&event); +} + +pub fn getDpiScale() f32 { + const primary_display_id = c.SDL_GetPrimaryDisplay(); + return c.SDL_GetDisplayContentScale(primary_display_id); +} + +/////////////////////////////////////////////////////////////////////////////// + +fn imguiHandleEvent(event: *c.SDL_Event) bool { + const io = cimgui.igGetIO(); + switch (event.type) { + c.SDL_EVENT_WINDOW_FOCUS_GAINED => { + simgui.addFocusEvent(true); + }, + c.SDL_EVENT_WINDOW_FOCUS_LOST => { + simgui.addFocusEvent(false); + }, + // c.SDL_EVENT_WINDOW_MOUSE_ENTER => {}, + // c.SDL_EVENT_WINDOW_MOUSE_LEAVE => {}, + c.SDL_EVENT_MOUSE_BUTTON_DOWN => { + imguiAddMouseButtonEvent(&event.button, true); + }, + c.SDL_EVENT_MOUSE_BUTTON_UP => { + imguiAddMouseButtonEvent(&event.button, false); + }, + c.SDL_EVENT_MOUSE_MOTION => { + const dpi = getDpiScale(); + simgui.addMousePosEvent(event.motion.x / dpi, event.motion.y / dpi); + }, + c.SDL_EVENT_MOUSE_WHEEL => { + const dpi = getDpiScale(); + simgui.addMousePosEvent(event.wheel.mouse_x / dpi, event.wheel.mouse_y / dpi); + simgui.addMouseWheelEvent(event.wheel.x, event.wheel.y); + }, + c.SDL_EVENT_TEXT_INPUT => { + simgui.addInputCharactersUtf8(std.mem.span(event.text.text)); + }, + c.SDL_EVENT_KEY_DOWN => { + if (!event.key.repeat) { + imguiAddKeyEvent(&event.key); + } + }, + c.SDL_EVENT_KEY_UP => { + imguiAddKeyEvent(&event.key); + }, + else => {}, + } + return io.*.WantCaptureKeyboard or io.*.WantCaptureMouse; +} + +fn imguiSetPlatformImeData(_: [*c]cimgui.ImGuiViewport, data: [*c]cimgui.ImGuiPlatformImeData) callconv(.C) void { + if (data.*.WantVisible) { + if (!c.SDL_StartTextInput(window)) { + debug.err("Failed to initiate text input: {s}", .{c.SDL_GetError()}); + } + } else { + _ = c.SDL_StopTextInput(window); + } +} + +fn imguiAddMouseButtonEvent(ev: *c.SDL_MouseButtonEvent, pressed: bool) void { + const dpi = getDpiScale(); + const mouse_button: i32 = switch (ev.button) { + c.SDL_BUTTON_LEFT => 0, + c.SDL_BUTTON_RIGHT => 1, + c.SDL_BUTTON_MIDDLE => 2, + else => return, + }; + simgui.addMousePosEvent(ev.x / dpi, ev.y / dpi); + simgui.addMouseButtonEvent(mouse_button, pressed); +} + +fn imguiUpdateModifierKeys(ev: *c.SDL_KeyboardEvent) void { + const io = cimgui.igGetIO(); + cimgui.ImGuiIO_AddKeyEvent(io, cimgui.ImGuiMod_Ctrl, (ev.mod & c.SDL_KMOD_CTRL) != 0); + cimgui.ImGuiIO_AddKeyEvent(io, cimgui.ImGuiMod_Shift, (ev.mod & c.SDL_KMOD_SHIFT) != 0); + cimgui.ImGuiIO_AddKeyEvent(io, cimgui.ImGuiMod_Alt, (ev.mod & c.SDL_KMOD_ALT) != 0); + cimgui.ImGuiIO_AddKeyEvent(io, cimgui.ImGuiMod_Super, (ev.mod & c.SDL_KMOD_GUI) != 0); +} + +fn imguiAddKeyEvent(ev: *c.SDL_KeyboardEvent) void { + var keycode = cimgui.ImGuiKey_None; + keycode = switch (ev.key) { + c.SDLK_SPACE => cimgui.ImGuiKey_Space, + c.SDLK_APOSTROPHE => cimgui.ImGuiKey_Apostrophe, + c.SDLK_COMMA => cimgui.ImGuiKey_Comma, + c.SDLK_MINUS => cimgui.ImGuiKey_Minus, + c.SDLK_PERIOD => cimgui.ImGuiKey_Period, + c.SDLK_SLASH => cimgui.ImGuiKey_Slash, + c.SDLK_0 => cimgui.ImGuiKey_0, + c.SDLK_1 => cimgui.ImGuiKey_1, + c.SDLK_2 => cimgui.ImGuiKey_2, + c.SDLK_3 => cimgui.ImGuiKey_3, + c.SDLK_4 => cimgui.ImGuiKey_4, + c.SDLK_5 => cimgui.ImGuiKey_5, + c.SDLK_6 => cimgui.ImGuiKey_6, + c.SDLK_7 => cimgui.ImGuiKey_7, + c.SDLK_8 => cimgui.ImGuiKey_8, + c.SDLK_9 => cimgui.ImGuiKey_9, + c.SDLK_SEMICOLON => cimgui.ImGuiKey_Semicolon, + c.SDLK_EQUALS => cimgui.ImGuiKey_Equal, + c.SDLK_A => cimgui.ImGuiKey_A, + c.SDLK_B => cimgui.ImGuiKey_B, + c.SDLK_C => cimgui.ImGuiKey_C, + c.SDLK_D => cimgui.ImGuiKey_D, + c.SDLK_E => cimgui.ImGuiKey_E, + c.SDLK_F => cimgui.ImGuiKey_F, + c.SDLK_G => cimgui.ImGuiKey_G, + c.SDLK_H => cimgui.ImGuiKey_H, + c.SDLK_I => cimgui.ImGuiKey_I, + c.SDLK_J => cimgui.ImGuiKey_J, + c.SDLK_K => cimgui.ImGuiKey_K, + c.SDLK_L => cimgui.ImGuiKey_L, + c.SDLK_M => cimgui.ImGuiKey_M, + c.SDLK_N => cimgui.ImGuiKey_N, + c.SDLK_O => cimgui.ImGuiKey_O, + c.SDLK_P => cimgui.ImGuiKey_P, + c.SDLK_Q => cimgui.ImGuiKey_Q, + c.SDLK_R => cimgui.ImGuiKey_R, + c.SDLK_S => cimgui.ImGuiKey_S, + c.SDLK_T => cimgui.ImGuiKey_T, + c.SDLK_U => cimgui.ImGuiKey_U, + c.SDLK_V => cimgui.ImGuiKey_V, + c.SDLK_W => cimgui.ImGuiKey_W, + c.SDLK_X => cimgui.ImGuiKey_X, + c.SDLK_Y => cimgui.ImGuiKey_Y, + c.SDLK_Z => cimgui.ImGuiKey_Z, + c.SDLK_LEFTBRACKET => cimgui.ImGuiKey_LeftBracket, + c.SDLK_BACKSLASH => cimgui.ImGuiKey_Backslash, + c.SDLK_RIGHTBRACKET => cimgui.ImGuiKey_RightBracket, + c.SDLK_GRAVE => cimgui.ImGuiKey_GraveAccent, + // c.SDLK_WORLD_1 => cimgui.ImGuiKey_WORLD_1, + // c.SDLK_WORLD_2 => cimgui.ImGuiKey_WORLD_2, + c.SDLK_ESCAPE => cimgui.ImGuiKey_Escape, + c.SDLK_RETURN => cimgui.ImGuiKey_Enter, + c.SDLK_TAB => cimgui.ImGuiKey_Tab, + c.SDLK_BACKSPACE => cimgui.ImGuiKey_Backspace, + c.SDLK_INSERT => cimgui.ImGuiKey_Insert, + c.SDLK_DELETE => cimgui.ImGuiKey_Delete, + c.SDLK_RIGHT => cimgui.ImGuiKey_RightArrow, + c.SDLK_LEFT => cimgui.ImGuiKey_LeftArrow, + c.SDLK_DOWN => cimgui.ImGuiKey_DownArrow, + c.SDLK_UP => cimgui.ImGuiKey_UpArrow, + c.SDLK_PAGEUP => cimgui.ImGuiKey_PageUp, + c.SDLK_PAGEDOWN => cimgui.ImGuiKey_PageDown, + c.SDLK_HOME => cimgui.ImGuiKey_Home, + c.SDLK_END => cimgui.ImGuiKey_End, + c.SDLK_CAPSLOCK => cimgui.ImGuiKey_CapsLock, + c.SDLK_SCROLLLOCK => cimgui.ImGuiKey_ScrollLock, + c.SDLK_NUMLOCKCLEAR => cimgui.ImGuiKey_NumLock, + c.SDLK_PRINTSCREEN => cimgui.ImGuiKey_PrintScreen, + c.SDLK_PAUSE => cimgui.ImGuiKey_Pause, + c.SDLK_F1 => cimgui.ImGuiKey_F1, + c.SDLK_F2 => cimgui.ImGuiKey_F2, + c.SDLK_F3 => cimgui.ImGuiKey_F3, + c.SDLK_F4 => cimgui.ImGuiKey_F4, + c.SDLK_F5 => cimgui.ImGuiKey_F5, + c.SDLK_F6 => cimgui.ImGuiKey_F6, + c.SDLK_F7 => cimgui.ImGuiKey_F7, + c.SDLK_F8 => cimgui.ImGuiKey_F8, + c.SDLK_F9 => cimgui.ImGuiKey_F9, + c.SDLK_F10 => cimgui.ImGuiKey_F10, + c.SDLK_F11 => cimgui.ImGuiKey_F11, + c.SDLK_F12 => cimgui.ImGuiKey_F12, + c.SDLK_F13 => cimgui.ImGuiKey_F13, + c.SDLK_F14 => cimgui.ImGuiKey_F14, + c.SDLK_F15 => cimgui.ImGuiKey_F15, + c.SDLK_F16 => cimgui.ImGuiKey_F16, + c.SDLK_F17 => cimgui.ImGuiKey_F17, + c.SDLK_F18 => cimgui.ImGuiKey_F18, + c.SDLK_F19 => cimgui.ImGuiKey_F19, + c.SDLK_F20 => cimgui.ImGuiKey_F20, + c.SDLK_F21 => cimgui.ImGuiKey_F21, + c.SDLK_F22 => cimgui.ImGuiKey_F22, + c.SDLK_F23 => cimgui.ImGuiKey_F23, + c.SDLK_F24 => cimgui.ImGuiKey_F24, + // c.SDLK_F25 => cimgui.ImGuiKey_F25, + c.SDLK_KP_0 => cimgui.ImGuiKey_Keypad0, + c.SDLK_KP_1 => cimgui.ImGuiKey_Keypad1, + c.SDLK_KP_2 => cimgui.ImGuiKey_Keypad2, + c.SDLK_KP_3 => cimgui.ImGuiKey_Keypad3, + c.SDLK_KP_4 => cimgui.ImGuiKey_Keypad4, + c.SDLK_KP_5 => cimgui.ImGuiKey_Keypad5, + c.SDLK_KP_6 => cimgui.ImGuiKey_Keypad6, + c.SDLK_KP_7 => cimgui.ImGuiKey_Keypad7, + c.SDLK_KP_8 => cimgui.ImGuiKey_Keypad8, + c.SDLK_KP_9 => cimgui.ImGuiKey_Keypad9, + c.SDLK_KP_DECIMAL => cimgui.ImGuiKey_KeypadDecimal, + c.SDLK_KP_DIVIDE => cimgui.ImGuiKey_KeypadDivide, + c.SDLK_KP_MULTIPLY => cimgui.ImGuiKey_KeypadMultiply, + c.SDLK_KP_MINUS => cimgui.ImGuiKey_KeypadSubtract, + c.SDLK_KP_PLUS => cimgui.ImGuiKey_KeypadAdd, + c.SDLK_KP_ENTER => cimgui.ImGuiKey_KeypadEnter, + c.SDLK_KP_EQUALS => cimgui.ImGuiKey_KeypadEqual, + c.SDLK_LSHIFT => cimgui.ImGuiKey_LeftShift, + c.SDLK_LCTRL => cimgui.ImGuiKey_LeftCtrl, + c.SDLK_LALT => cimgui.ImGuiKey_LeftAlt, + c.SDLK_LGUI => cimgui.ImGuiKey_LeftSuper, + c.SDLK_RSHIFT => cimgui.ImGuiKey_RightShift, + c.SDLK_RCTRL => cimgui.ImGuiKey_RightCtrl, + c.SDLK_RALT => cimgui.ImGuiKey_RightAlt, + c.SDLK_RGUI => cimgui.ImGuiKey_RightSuper, + c.SDLK_MENU => cimgui.ImGuiKey_Menu, + else => cimgui.ImGuiKey_None, + }; + imguiUpdateModifierKeys(ev); + simgui.addKeyEvent(keycode, ev.down); +} + +fn sdlkToKeyCode(ev: *c.SDL_KeyboardEvent) input.KeyCodes { + var keycode = input.KeyCodes.INVALID; + keycode = switch (ev.key) { + c.SDLK_SPACE => .SPACE, + c.SDLK_APOSTROPHE => .APOSTROPHE, + c.SDLK_COMMA => .COMMA, + c.SDLK_MINUS => .MINUS, + c.SDLK_PERIOD => .PERIOD, + c.SDLK_SLASH => .SLASH, + c.SDLK_0 => ._0, + c.SDLK_1 => ._1, + c.SDLK_2 => ._2, + c.SDLK_3 => ._3, + c.SDLK_4 => ._4, + c.SDLK_5 => ._5, + c.SDLK_6 => ._6, + c.SDLK_7 => ._7, + c.SDLK_8 => ._8, + c.SDLK_9 => ._9, + c.SDLK_SEMICOLON => .SEMICOLON, + c.SDLK_EQUALS => .EQUAL, + c.SDLK_A => .A, + c.SDLK_B => .B, + c.SDLK_C => .C, + c.SDLK_D => .D, + c.SDLK_E => .E, + c.SDLK_F => .F, + c.SDLK_G => .G, + c.SDLK_H => .H, + c.SDLK_I => .I, + c.SDLK_J => .J, + c.SDLK_K => .K, + c.SDLK_L => .L, + c.SDLK_M => .M, + c.SDLK_N => .N, + c.SDLK_O => .O, + c.SDLK_P => .P, + c.SDLK_Q => .Q, + c.SDLK_R => .R, + c.SDLK_S => .S, + c.SDLK_T => .T, + c.SDLK_U => .U, + c.SDLK_V => .V, + c.SDLK_W => .W, + c.SDLK_X => .X, + c.SDLK_Y => .Y, + c.SDLK_Z => .Z, + c.SDLK_LEFTBRACKET => .LEFT_BRACKET, + c.SDLK_BACKSLASH => .BACKSLASH, + c.SDLK_RIGHTBRACKET => .RIGHT_BRACKET, + c.SDLK_GRAVE => .GRAVE_ACCENT, + // c.SDLK_WORLD_1 => .WORLD_1, + // c.SDLK_WORLD_2 => .WORLD_2, + c.SDLK_ESCAPE => .ESCAPE, + c.SDLK_RETURN => .ENTER, + c.SDLK_TAB => .TAB, + c.SDLK_BACKSPACE => .BACKSPACE, + c.SDLK_INSERT => .INSERT, + c.SDLK_DELETE => .DELETE, + c.SDLK_RIGHT => .RIGHT, + c.SDLK_LEFT => .LEFT, + c.SDLK_DOWN => .DOWN, + c.SDLK_UP => .UP, + c.SDLK_PAGEUP => .PAGE_UP, + c.SDLK_PAGEDOWN => .PAGE_DOWN, + c.SDLK_HOME => .HOME, + c.SDLK_END => .END, + c.SDLK_CAPSLOCK => .CAPS_LOCK, + c.SDLK_SCROLLLOCK => .SCROLL_LOCK, + c.SDLK_NUMLOCKCLEAR => .NUM_LOCK, + c.SDLK_PRINTSCREEN => .PRINT_SCREEN, + c.SDLK_PAUSE => .PAUSE, + c.SDLK_F1 => .F1, + c.SDLK_F2 => .F2, + c.SDLK_F3 => .F3, + c.SDLK_F4 => .F4, + c.SDLK_F5 => .F5, + c.SDLK_F6 => .F6, + c.SDLK_F7 => .F7, + c.SDLK_F8 => .F8, + c.SDLK_F9 => .F9, + c.SDLK_F10 => .F10, + c.SDLK_F11 => .F11, + c.SDLK_F12 => .F12, + c.SDLK_F13 => .F13, + c.SDLK_F14 => .F14, + c.SDLK_F15 => .F15, + c.SDLK_F16 => .F16, + c.SDLK_F17 => .F17, + c.SDLK_F18 => .F18, + c.SDLK_F19 => .F19, + c.SDLK_F20 => .F20, + c.SDLK_F21 => .F21, + c.SDLK_F22 => .F22, + c.SDLK_F23 => .F23, + c.SDLK_F24 => .F24, + // c.SDLK_F25 => .F25, + c.SDLK_KP_0 => .KP_0, + c.SDLK_KP_1 => .KP_1, + c.SDLK_KP_2 => .KP_2, + c.SDLK_KP_3 => .KP_3, + c.SDLK_KP_4 => .KP_4, + c.SDLK_KP_5 => .KP_5, + c.SDLK_KP_6 => .KP_6, + c.SDLK_KP_7 => .KP_7, + c.SDLK_KP_8 => .KP_8, + c.SDLK_KP_9 => .KP_9, + c.SDLK_KP_DECIMAL => .KP_DECIMAL, + c.SDLK_KP_DIVIDE => .KP_DIVIDE, + c.SDLK_KP_MULTIPLY => .KP_MULTIPLY, + c.SDLK_KP_MINUS => .KP_SUBTRACT, + c.SDLK_KP_PLUS => .KP_ADD, + c.SDLK_KP_ENTER => .KP_ENTER, + c.SDLK_KP_EQUALS => .KP_EQUAL, + c.SDLK_LSHIFT => .LEFT_SHIFT, + c.SDLK_LCTRL => .LEFT_CONTROL, + c.SDLK_LALT => .LEFT_ALT, + c.SDLK_LGUI => .LEFT_SUPER, + c.SDLK_RSHIFT => .RIGHT_SHIFT, + c.SDLK_RCTRL => .RIGHT_CONTROL, + c.SDLK_RALT => .RIGHT_ALT, + c.SDLK_RGUI => .RIGHT_SUPER, + c.SDLK_MENU => .MENU, + else => .INVALID, + }; + + return keycode; +} diff --git a/src/framework/platform/backends/sokol/app.zig b/src/framework/platform/backends/sokol/app.zig deleted file mode 100644 index 9781619c..00000000 --- a/src/framework/platform/backends/sokol/app.zig +++ /dev/null @@ -1,169 +0,0 @@ -const std = @import("std"); -const main_app = @import("../../../app.zig"); -const debug = @import("../../../debug.zig"); -// const gfx = @import("graphics.zig"); -const input = @import("../../input.zig"); -// const modules = @import("../modules.zig"); - -const sokol = @import("sokol"); -const slog = sokol.log; -const sg = sokol.gfx; -const sapp = sokol.app; -const sglue = sokol.glue; -const simgui = sokol.imgui; - -var app_config: main_app.AppConfig = undefined; - -pub const SokolAppConfig = struct { - on_init_fn: *const fn () void, - on_frame_fn: *const fn () void, - on_cleanup_fn: *const fn () void, - // maybe an on_event fn? -}; - -// keep a static version of the app around -var app: App = undefined; - -pub const App = struct { - on_init_fn: *const fn () void, - on_frame_fn: *const fn () void, - on_cleanup_fn: *const fn () void, - - pub fn init(cfg: SokolAppConfig) void { - debug.log("Creating Sokol App backend", .{}); - - app = App{ - .on_init_fn = cfg.on_init_fn, - .on_frame_fn = cfg.on_frame_fn, - .on_cleanup_fn = cfg.on_cleanup_fn, - }; - } - - pub fn deinit() void { - debug.log("Sokol App Backend stopping", .{}); - } - - export fn sokol_init() void { - debug.log("Sokol app context initializing", .{}); - - // TODO: Put the buffer pool size and the shader pool size into a config - sg.setup(.{ - .environment = sglue.environment(), - .logger = .{ .func = slog.func }, - .buffer_pool_size = app_config.buffer_pool_size, // sokol default is 128 - .shader_pool_size = app_config.shader_pool_size, // sokol default is 64 - .image_pool_size = app_config.image_pool_size, // sokol default is 128 - .pipeline_pool_size = app_config.pipeline_pool_size, // sokol default is 64 - .sampler_pool_size = app_config.sampler_pool_size, // sokol default is 64 - .attachments_pool_size = app_config.pass_pool_size, // sokol default is 16, - }); - - simgui.setup(.{ - .logger = .{ .func = slog.func }, - }); - - debug.log("Sokol setup backend: {}", .{sg.queryBackend()}); - - // call the callback that will tell everything else to start up - app.on_init_fn(); - } - - export fn sokol_cleanup() void { - app.on_cleanup_fn(); - sg.shutdown(); - } - - export fn sokol_frame() void { - app.on_frame_fn(); - } - - export fn sokol_input(event: ?*const sapp.Event) void { - const ev = event.?; - - const imgui_did_handle = simgui.handleEvent(ev.*); - if (imgui_did_handle) - return; - - if (ev.type == .MOUSE_DOWN) { - input.onMouseDown(@intFromEnum(ev.mouse_button)); - } else if (ev.type == .MOUSE_UP) { - input.onMouseUp(@intFromEnum(ev.mouse_button)); - } else if (ev.type == .MOUSE_MOVE) { - input.onMouseMoved(ev.mouse_x, ev.mouse_y, ev.mouse_dx, ev.mouse_dy); - } else if (ev.type == .KEY_DOWN) { - if (!ev.key_repeat) - input.onKeyDown(@intFromEnum(ev.key_code)); - } else if (ev.type == .KEY_UP) { - input.onKeyUp(@intFromEnum(ev.key_code)); - } else if (ev.type == .CHAR) { - input.onKeyChar(ev.char_code); - } else if (ev.type == .TOUCHES_BEGAN) { - for (ev.touches) |touch| { - if (touch.changed) - input.onTouchBegin(touch.pos_x, touch.pos_y, touch.identifier); - } - } else if (ev.type == .TOUCHES_MOVED) { - for (ev.touches) |touch| { - if (touch.changed) - input.onTouchMoved(touch.pos_x, touch.pos_y, touch.identifier); - } - } else if (ev.type == .TOUCHES_ENDED) { - for (ev.touches) |touch| { - if (touch.changed) - input.onTouchEnded(touch.pos_x, touch.pos_y, touch.identifier); - } - } - } - - pub fn startMainLoop(config: main_app.AppConfig) void { - app_config = config; - - debug.log("Sokol app starting main loop", .{}); - - sapp.run(.{ - .init_cb = sokol_init, - .frame_cb = sokol_frame, - .cleanup_cb = sokol_cleanup, - .event_cb = sokol_input, - .width = config.width, - .height = config.height, - .icon = .{ - .sokol_default = true, - }, - .window_title = config.title, - .logger = .{ - .func = slog.func, - }, - // .win32_console_attach = true, - }); - } - - pub fn getWidth() i32 { - return sapp.width(); - } - - pub fn getHeight() i32 { - return sapp.height(); - } - - pub fn captureMouse(captured: bool) void { - sapp.lockMouse(captured); - } -}; - -pub fn startImguiFrame() void { - simgui.newFrame(.{ - .width = sapp.width(), - .height = sapp.height(), - .delta_time = sapp.frameDuration(), - .dpi_scale = sapp.dpiScale(), - }); -} - -pub fn renderImgui() void { - simgui.render(); -} - -pub fn exit() void { - sapp.quit(); -} diff --git a/src/framework/platform/backends/sokol/graphics.zig b/src/framework/platform/backends/sokol/graphics.zig index 837d575f..c122c3b3 100644 --- a/src/framework/platform/backends/sokol/graphics.zig +++ b/src/framework/platform/backends/sokol/graphics.zig @@ -9,7 +9,6 @@ const shader_default = @import("../../../graphics/shaders/default.glsl.zig"); const slog = sokol.log; const sg = sokol.gfx; -const sapp = sokol.app; const debugtext = sokol.debugtext; pub const Bindings = graphics.Bindings; diff --git a/src/framework/platform/backends/sokol_app.zig b/src/framework/platform/backends/sokol_app.zig new file mode 100644 index 00000000..accd53b9 --- /dev/null +++ b/src/framework/platform/backends/sokol_app.zig @@ -0,0 +1,154 @@ +const std = @import("std"); +const debug = @import("../../debug.zig"); +const app = @import("../../app.zig"); +const platform = @import("../app.zig"); +const input = @import("../input.zig"); + +const sokol = @import("sokol"); +const slog = sokol.log; +const sg = sokol.gfx; +const sapp = sokol.app; +const sglue = sokol.glue; +const simgui = sokol.imgui; + +var app_config: app.AppConfig = undefined; +var hooks: platform.PlatformHooks = undefined; + +pub fn init(cfg: platform.PlatformHooks) void { + debug.log("Initializing Sokol App backend", .{}); + hooks = cfg; +} + +pub fn deinit() void { + debug.log("Deinitializing Sokol App Backend", .{}); + app_config = undefined; + hooks = undefined; +} + +export fn sokol_init() void { + debug.log("Sokol app context initializing", .{}); + + // TODO: Put the buffer pool size and the shader pool size into a config + sg.setup(.{ + .environment = sglue.environment(), + .logger = .{ .func = slog.func }, + .buffer_pool_size = app_config.buffer_pool_size, // sokol default is 128 + .shader_pool_size = app_config.shader_pool_size, // sokol default is 64 + .image_pool_size = app_config.image_pool_size, // sokol default is 128 + .pipeline_pool_size = app_config.pipeline_pool_size, // sokol default is 64 + .sampler_pool_size = app_config.sampler_pool_size, // sokol default is 64 + .attachments_pool_size = app_config.pass_pool_size, // sokol default is 16, + }); + + simgui.setup(.{ + .logger = .{ .func = slog.func }, + }); + + debug.log("Sokol setup backend: {}", .{sg.queryBackend()}); + + // call the callback that will tell everything else to start up + hooks.on_init_fn(); +} + +export fn sokol_cleanup() void { + hooks.on_cleanup_fn(); + sg.shutdown(); +} + +export fn sokol_frame() void { + hooks.on_frame_fn(); +} + +export fn sokol_input(event: ?*const sapp.Event) void { + const ev = event.?; + + const imgui_did_handle = simgui.handleEvent(ev.*); + if (imgui_did_handle) + return; + + if (ev.type == .MOUSE_DOWN) { + input.onMouseDown(@intFromEnum(ev.mouse_button)); + } else if (ev.type == .MOUSE_UP) { + input.onMouseUp(@intFromEnum(ev.mouse_button)); + } else if (ev.type == .MOUSE_MOVE) { + input.onMouseMoved(ev.mouse_x, ev.mouse_y, ev.mouse_dx, ev.mouse_dy); + } else if (ev.type == .KEY_DOWN) { + if (!ev.key_repeat) + input.onKeyDown(@intFromEnum(ev.key_code)); + } else if (ev.type == .KEY_UP) { + input.onKeyUp(@intFromEnum(ev.key_code)); + } else if (ev.type == .CHAR) { + input.onKeyChar(ev.char_code); + } else if (ev.type == .TOUCHES_BEGAN) { + for (ev.touches) |touch| { + if (touch.changed) + input.onTouchBegin(touch.pos_x, touch.pos_y, touch.identifier); + } + } else if (ev.type == .TOUCHES_MOVED) { + for (ev.touches) |touch| { + if (touch.changed) + input.onTouchMoved(touch.pos_x, touch.pos_y, touch.identifier); + } + } else if (ev.type == .TOUCHES_ENDED) { + for (ev.touches) |touch| { + if (touch.changed) + input.onTouchEnded(touch.pos_x, touch.pos_y, touch.identifier); + } + } +} + +pub fn startMainLoop(config: app.AppConfig) void { + app_config = config; + + debug.log("Sokol app starting main loop", .{}); + + sapp.run(.{ + .init_cb = sokol_init, + .frame_cb = sokol_frame, + .cleanup_cb = sokol_cleanup, + .event_cb = sokol_input, + .width = config.width, + .height = config.height, + .icon = .{ + .sokol_default = true, + }, + .window_title = config.title, + .logger = .{ + .func = slog.func, + }, + // .win32_console_attach = true, + }); +} + +pub fn getWidth() i32 { + return sapp.width(); +} + +pub fn getHeight() i32 { + return sapp.height(); +} + +pub fn captureMouse(captured: bool) void { + sapp.lockMouse(captured); +} + +pub fn startImguiFrame() void { + simgui.newFrame(.{ + .width = sapp.width(), + .height = sapp.height(), + .delta_time = sapp.frameDuration(), + .dpi_scale = sapp.dpiScale(), + }); +} + +pub fn renderImgui() void { + simgui.render(); +} + +pub fn exit() void { + sapp.quit(); +} + +pub fn getDpiScale() f32 { + sapp.dpiScale(); +} diff --git a/src/framework/platform/graphics.zig b/src/framework/platform/graphics.zig index 8104b0bd..450fc76e 100644 --- a/src/framework/platform/graphics.zig +++ b/src/framework/platform/graphics.zig @@ -5,14 +5,13 @@ const images = @import("../images.zig"); const math = @import("../math.zig"); const mem = @import("../mem.zig"); const mesh = @import("../graphics/mesh.zig"); -const papp = @import("app.zig"); +const platform = @import("app.zig"); const sokol_gfx_backend = @import("backends/sokol/graphics.zig"); const shaders = @import("../graphics/shaders.zig"); const sokol = @import("sokol"); const slog = sokol.log; const sg = sokol.gfx; -const sapp = sokol.app; const sglue = sokol.glue; const debugtext = sokol.debugtext; @@ -1107,6 +1106,22 @@ pub fn deinit() void { tex_grey.destroy(); } +fn swapchain() sg.Swapchain { + const config = @import("config"); + if (config.platform_backend == .sdl) { + // TODO: DirectX devices??? Metal devices??? + return .{ + .width = platform.getWidth(), + .height = platform.getHeight(), + .sample_count = 1, + .color_format = sg.PixelFormat.RGBA8, + .depth_format = sg.PixelFormat.DEPTH_STENCIL, + }; + } else { + return sglue.swapchain(); + } +} + /// Called at the start of a frame pub fn startFrame() void { if (state.in_offscreen_pass) { @@ -1115,13 +1130,13 @@ pub fn startFrame() void { } // reset debug text - debugtext.canvas(sapp.widthf() * 0.5, sapp.heightf() * 0.5); + debugtext.canvas(@as(f32, @floatFromInt(platform.getWidth())) * 0.5, @as(f32, @floatFromInt(platform.getHeight())) * 0.5); debugtext.layer(0); state.in_default_pass = true; - // reset to drawing to the swapchain on every frame start - sg.beginPass(.{ .action = default_pass_action, .swapchain = sglue.swapchain() }); + // TODO: reset to drawing to the swapchain on every frame start + sg.beginPass(.{ .action = default_pass_action, .swapchain = swapchain() }); } /// Called at the end of a frame @@ -1154,16 +1169,18 @@ pub fn setClearColor(color: Color) void { /// Returns a perspective projection matrix for our current app pub fn getProjectionPerspective(fov: f32, near: f32, far: f32) Mat4 { - const aspect = papp.getAspectRatio(); + const aspect = platform.getAspectRatio(); return Mat4.persp(fov, aspect, near, far); } /// Returns an orthographic projection matrix for our current app pub fn getProjectionOrtho(near: f32, far: f32, flip_y: bool) Mat4 { + const w = @as(f32, @floatFromInt(platform.getWidth())); + const h = @as(f32, @floatFromInt(platform.getHeight())); if (flip_y) { - return Mat4.ortho(0.0, sapp.widthf(), sapp.heightf(), 0.0, near, far); + return Mat4.ortho(0.0, w, h, 0.0, near, far); } - return Mat4.ortho(0.0, sapp.widthf(), 0.0, sapp.heightf(), near, far); + return Mat4.ortho(0.0, w, 0.0, h, near, far); } /// Returns a custom orthographic projection matrix for our current app @@ -1191,7 +1208,9 @@ pub fn drawDebugTextChar(x: f32, y: f32, char: u8) void { /// Sets the scaling used when drawing debug text pub fn setDebugTextScale(scale: f32) void { - debugtext.canvas(sapp.widthf() / (scale * 2.0), sapp.heightf() / (scale * 2.0)); + const w = @as(f32, @floatFromInt(platform.getWidth())); + const h = @as(f32, @floatFromInt(platform.getHeight())); + debugtext.canvas(w / (scale * 2.0), h / (scale * 2.0)); state.debug_text_scale = scale * 2.0; } @@ -1244,17 +1263,17 @@ pub fn setDebugDrawColorOverride(color: Color) void { /// Returns the app's display width pub fn getDisplayWidth() i32 { - return sapp.width(); + return platform.getWidth(); } /// Returns the app's display height pub fn getDisplayHeight() i32 { - return sapp.height(); + return platform.getHeight(); } /// Returns the pixel DPI scaling used for the app pub fn getDisplayDPIScale() f32 { - return sapp.dpiScale(); + return platform.getDpiScale(); } /// Draw part of a binding