From d2adfa5c5bae5d8ee20564ec9e50cae4b75f945d Mon Sep 17 00:00:00 2001 From: David Thompson Date: Sat, 30 Sep 2023 19:42:01 -0400 Subject: WIP: Switch to WebGPU-like API --- chickadee.scm | 126 +++++++++++++++++++++++++++++++--------------------------- 1 file changed, 67 insertions(+), 59 deletions(-) (limited to 'chickadee.scm') diff --git a/chickadee.scm b/chickadee.scm index 656ce0b..8343a6b 100644 --- a/chickadee.scm +++ b/chickadee.scm @@ -16,7 +16,7 @@ ;;; Commentary: ;; -;; Simple SDL + OpenGL game loop implementation. +;; Core event loop. ;; ;;; Code: @@ -26,12 +26,12 @@ #:use-module (chickadee game-loop) #:use-module (chickadee math matrix) #:use-module (chickadee graphics color) - #:use-module (chickadee graphics engine) #:use-module (chickadee graphics gpu) - #:use-module (chickadee graphics viewport) + ;; #:use-module (chickadee graphics viewport) #:use-module (chickadee utils) #:use-module (ice-9 atomic) #:use-module (ice-9 match) + #:use-module (ice-9 threads) #:use-module (sdl2) #:use-module (sdl2 events) #:use-module ((sdl2 input game-controller) #:prefix sdl2:) @@ -76,6 +76,9 @@ #:re-export (abort-game current-timestep)) + + + (define %time-freq (exact->inexact internal-time-units-per-second)) (define (elapsed-time) @@ -155,10 +158,8 @@ not being pushed at all." (define* (make-window #:key (title "Chickadee") fullscreen? resizable? (width 640) (height 480) (multisample? #t)) - ;; Hint that we want OpenGL 3.2 Core profile. Doesn't mean we'll - ;; get it, though! - (sdl2:set-gl-attribute! 'context-major-version 3) - (sdl2:set-gl-attribute! 'context-major-version 2) + ;; Hint that we want the core profile with deprecated features + ;; disabled. Doesn't mean we'll get it, though! (sdl2:set-gl-attribute! 'context-profile-mask 1) ; core profile (sdl2:set-gl-attribute! 'stencil-size 8) ; 8-bit stencil buffer (if multisample? @@ -254,7 +255,8 @@ border is disabled, otherwise it is enabled.") (window-height 480) window-fullscreen? window-resizable? - (clear-color %default-clear-color) + (clear-color black;; %default-clear-color + ) (update-hz 60) (load noop) (update noop) @@ -304,20 +306,19 @@ border is disabled, otherwise it is enabled.") #:fullscreen? window-fullscreen? #:resizable? window-resizable? #:multisample? #f))) - (default-viewport (vector - (make-viewport 0 0 window-width window-height - #:clear-color clear-color))) + ;; (default-viewport (vector + ;; (make-viewport 0 0 window-width window-height + ;; #:clear-color clear-color))) (default-projection (vector (orthographic-projection 0 window-width window-height 0 0 1))) - (gpu (make-gpu (window-gl-context window))) - (gfx (make-graphics-engine gpu))) + (gpu (make-gpu (unwrap-window window) (window-gl-context window)))) (define (invert-y y) ;; SDL's origin is the top-left, but our origin is the bottom ;; left so we need to invert Y coordinates that SDL gives us. (- window-height y)) - (define (input-sdl) + (define (flush-sdl-input) (define (process-event event) (cond ((quit-event? event) @@ -398,9 +399,9 @@ border is disabled, otherwise it is enabled.") ((width height) (set! window-width width) (set! window-height height) - (vector-set! default-viewport 0 - (make-viewport 0 0 width height - #:clear-color clear-color)) + ;; (vector-set! default-viewport 0 + ;; (make-viewport 0 0 width height + ;; #:clear-color clear-color)) (vector-set! default-projection 0 (orthographic-projection 0 width height 0 0 1)) (window-resize width height)))))) @@ -409,51 +410,58 @@ border is disabled, otherwise it is enabled.") (when event (process-event event) (loop (poll-event))))) - (define (update-sdl dt) - (input-sdl) - (update dt) - ;; Update audio after updating game state so that any sounds - ;; that were queued to play this frame start playing immediately. - (update-audio) - ;; Free any GPU resources that have been GC'd. - (graphics-engine-gc gfx)) - (define (render-sdl-opengl alpha) - (graphics-engine-reset! gfx) - ;; Enable seamless cube maps. - ;; TODO: This should go somewhere else. - (set-gpu-seamless-cube-maps! (current-gpu) #t) - (with-viewport (vector-ref default-viewport 0) - (clear-viewport) - (with-graphics-state ((projection (vector-ref default-projection 0))) - (draw alpha))) - (sdl2:swap-gl-window (unwrap-window window))) (define (on-error e stack) (error e stack) ;; Flush all input events that have occurred while in the error ;; state. (while (poll-event) #t)) - (dynamic-wind - (const #t) - (lambda () - (parameterize ((current-window window) - (current-graphics-engine gfx)) - ;; Attempt to activate vsync, if possible. Some systems do - ;; not support setting the OpenGL swap interval. - (catch #t - (lambda () - (sdl2:set-gl-swap-interval! 'vsync)) - (lambda args - (display "warning: could not enable vsync\n" - (current-error-port)))) - (sdl2:load-game-controller-mappings! - (scope-datadir "gamecontrollerdb.txt")) - (run-game* #:init load - #:update update-sdl - #:render render-sdl-opengl - #:error (and error on-error) - #:time elapsed-time - #:update-hz update-hz))) + ;; The game loop will run in its own thread so that updating game + ;; state can happen while rendering and input are being processed + ;; in the main thread and thus improving overall performance. + ;; This is where all user code is executed. + (define (game-loop) + (parameterize ((current-window window) + (current-gpu gpu)) + (run-game* #:init load + #:update update + #:render draw + #:error (and error on-error) + #:time elapsed-time + #:update-hz update-hz))) + ;; The main loop handles the input and rendering queues, as input + ;; polling and GPU calls have to be done from the main thread in + ;; SDL. + (define (main-loop) + (flush-sdl-input) + (update-audio) + ;; (graphics-engine-reset! gfx) + ;; Enable seamless cube maps. + ;; TODO: This should go somewhere else. + ;; (set-gpu-seamless-cube-maps! (current-gpu) #t) + ;; (with-viewport (vector-ref default-viewport 0) + ;; (clear-viewport) + ;; (with-graphics-state ((projection (vector-ref default-projection 0))) + ;; (draw alpha))) + (gpu-tick gpu) + (gpu-swap gpu) + ;; Free any GPU resources that have been GC'd. + (gpu-gc gpu) + (usleep 1) ; don't use 100% of the cpu pls + (main-loop)) + ;; Attempt to activate vsync, if possible. Some systems do + ;; not support setting the OpenGL swap interval. + (catch #t (lambda () - (quit-audio) - (sdl2:delete-gl-context! (window-gl-context window)) - (sdl2:close-window! (unwrap-window window)))))) + (sdl2:set-gl-swap-interval! 'vsync)) + (lambda args + (display "warning: could not enable vsync\n" + (current-error-port)))) + ;; Make lots of game controllers "just work." + (sdl2:load-game-controller-mappings! + (scope-datadir "gamecontrollerdb.txt")) + ;; Launch game loop in a separate thread and start the main loop. + (let ((game-thread (call-with-new-thread game-loop))) + (main-loop) + (quit-audio) + (sdl2:delete-gl-context! (window-gl-context window)) + (sdl2:close-window! (unwrap-window window))))) -- cgit v1.2.3