(define spite-inited? #f) (define started? #f) (define exit? #f) (define scale-x 1.0) (define scale-y 1.0) (define events (list)) (define current-bitmap-font #f) (define current-line-size 1) (define draw-color-r 0) (define draw-color-g 0) (define draw-color-b 0) (define draw-color-a 255) (define-c-library sdl2* '("SDL2/SDL.h") "SDL2-2.0" `((additional-paths ("retropikzel/spite" "snow/retropikzel/spite")) (additional-versions ("0")))) (define-c-library sdl2-image* '("SDL2/SDL_image.h") "SDL2_image-2.0" `((additional-paths ("retropikzel/spite" "snow/retropikzel/spite")) (additional-versions ("0")))) (define-c-procedure sdl-init sdl2* 'SDL_Init 'int '(int)) (define-c-procedure sdl-get-window-flags sdl2* 'SDL_GetWindowFlags 'int '(pointer)) (define-c-procedure sdl-create-window sdl2* 'SDL_CreateWindow 'pointer '(pointer int int int int int)) (define-c-procedure sdl-create-renderer sdl2* 'SDL_CreateRenderer 'pointer '(pointer int int)) (define-c-procedure sdl-render-setlogial-size sdl2* 'SDL_RenderSetLogicalSize 'int '(pointer int int)) (define-c-procedure sdl-render-set-integer-scale sdl2* 'SDL_RenderSetIntegerScale 'int '(pointer int)) (define-c-procedure sdl-set-render-draw-color sdl2* 'SDL_SetRenderDrawColor 'int '(pointer int int int int)) (define-c-procedure sdl-render-clear sdl2* 'SDL_RenderClear 'int '(pointer)) (define-c-procedure sdl-render-present sdl2* 'SDL_RenderPresent 'void '(pointer)) (define-c-procedure sdl-get-key-from-scancode sdl2* 'SDL_GetKeyFromScancode 'int '(int)) (define-c-procedure sdl-get-key-name sdl2* 'SDL_GetKeyName 'pointer '(int)) (define-c-procedure sdl-poll-event sdl2* 'SDL_PollEvent 'int '(pointer)) (define-c-procedure sdl-img-load-texture sdl2-image* 'IMG_LoadTexture 'pointer '(pointer pointer)) (define-c-procedure sdl-render-copy sdl2* 'SDL_RenderCopy 'int '(pointer pointer pointer pointer)) (define-c-procedure sdl-render-draw-line sdl2* 'SDL_RenderDrawLine 'int '(pointer int int int int)) (define-c-procedure sdl-render-draw-rect sdl2* 'SDL_RenderDrawRect 'int '(pointer pointer)) (define-c-procedure sdl-render-fill-rect sdl2* 'SDL_RenderFillRect 'int '(pointer pointer)) (define-c-procedure sdl-render-set-scale sdl2* 'SDL_RenderSetScale 'int '(pointer float float)) (define-c-procedure sdl-render-fill-rect sdl2* 'SDL_RenderFillRect 'int '(pointer pointer)) (define-c-procedure sdl-create-texture-from-surface sdl2* 'SDL_CreateTextureFromSurface 'pointer '(pointer pointer)) (define-c-procedure sdl-set-window-resizable sdl2* 'SDL_SetWindowResizable 'void '(pointer int)) (define-c-procedure sdl-render-get-scale sdl2* 'SDL_RenderGetScale 'void '(pointer pointer pointer)) (define-c-procedure sdl-render-geometry sdl2* 'SDL_RenderGeometry 'void '(pointer pointer pointer int pointer int)) (define window* #f) (define renderer* #f) (define event* (make-c-bytevector 4000)) (define draw-rect* (make-c-bytevector (* (c-type-size 'int) 4))) (define draw-slice-rect* (make-c-bytevector (* (c-type-size 'int) 4))) (define fill-triangle-vertex-size 128 #;(+ (* (c-type-size 'int) 6) (* (c-type-size 'float) 2))) (define fill-triangle-vertex1* (make-c-bytevector fill-triangle-vertex-size 0)) (define fill-triangle-vertex2* (make-c-bytevector fill-triangle-vertex-size 0)) (define fill-triangle-vertex3* (make-c-bytevector fill-triangle-vertex-size 0)) (define fill-triangle-vertexes* (make-c-bytevector (* fill-triangle-vertex-size 3 0))) (c-bytevector-pointer-set! fill-triangle-vertexes* (* fill-triangle-vertex-size 0) fill-triangle-vertex1*) (c-bytevector-pointer-set! fill-triangle-vertexes* (* fill-triangle-vertex-size 1) fill-triangle-vertex2*) (c-bytevector-pointer-set! fill-triangle-vertexes* (* fill-triangle-vertex-size 2) fill-triangle-vertex3*) (define null* (make-c-null)) (define update-procedure #f) (define draw-procedure #f) (define main-loop-start-time 0) (define delta-time 0) (define main-loop (lambda () (set! main-loop-start-time (current-jiffy)) (sdl2-events-get) (update-procedure delta-time (poll-events!)) (render-clear) (draw-procedure) (render-present) (set! delta-time (/ (- (current-jiffy) main-loop-start-time) (jiffies-per-second))) (unless exit? (main-loop)))) (define sdl2-event->spite-event (lambda (event) (let ((type (c-bytevector-sint-ref event 0 (native-endianness) (c-type-size 'int)))) (cond ((= type 256) (let ((type 'quit)) (list (cons 'type type)))) ((or (= type 768) (= type 769)) (let* ((type (if (= type 768) 'key-down 'key-up)) (scancode (c-bytevector-sint-ref event (+ (* (c-type-size 'int) 3) (* (c-type-size 'uint8) 4)) (native-endianness) (c-type-size 'int))) (keycode (sdl-get-key-from-scancode scancode)) (key (c-utf8->string (sdl-get-key-name keycode))) (repeat? (= (c-bytevector-u8-ref event (+ (* (c-type-size 'int) 3) (c-type-size 'uint8))) 1))) (list (cons 'type type) (cons 'key key) (cons 'scancode scancode) (cons 'repeat? repeat?)))) ((= type 1024) (let ((type 'mouse-motion) (x (c-bytevector-sint-ref event (+ (* (c-type-size 'int) 5)) (native-endianness) (c-type-size 'int))) (y (c-bytevector-sint-ref event (+ (* (c-type-size 'int) 6)) (native-endianness) (c-type-size 'int)))) (list (cons 'type type) (cons 'x x) (cons 'y y)))) ((or (= type 1025) (= type 1026)) (let ((type (if (= type 1025) 'mouse-button-down 'mouse-button-up)) (x (c-bytevector-sint-ref event (+ (* (c-type-size 'int) 4) (* (c-type-size 'uint8) 4)) (native-endianness) (c-type-size 'int))) (y (c-bytevector-sint-ref event (+ (* (c-type-size 'int) 4) (* (c-type-size 'uint8) 4) (c-type-size 'int)) (native-endianness) (c-type-size 'int))) (button (c-bytevector-sint-ref event (+ (* (c-type-size 'uint32) 4)) (native-endianness) (c-type-size 'uint8))) (clicks (c-bytevector-sint-ref event (+ (* (c-type-size 'uint32) 4) (* (c-type-size 'uint8) 2)) (native-endianness) (c-type-size 'uint8)))) (list (cons 'type type) (cons 'x x) (cons 'y y) (cons 'button button) (cons 'clicks clicks)))) (else (list (cons 'type 'sdl2-event) (cons 'sdl2-type-number type))))))) (define sdl2-events-get (lambda () (let ((poll-result (sdl-poll-event event*))) (cond ((= poll-result 1) (let ((event (sdl2-event->spite-event event*))) (cond ((equal? (cdr (assoc 'type event)) 'quit) (set! exit? #t))) (push-event event) (sdl2-events-get))))))) (define render-clear (lambda () (sdl-set-render-draw-color renderer* 255 255 255 255) (sdl-render-clear renderer*))) (define render-present (lambda () (sdl-render-present renderer*))) (define-record-type image (make-image pointer path) image? (pointer image-pointer) (path image-path)) (define load-image (lambda (path) (when (not spite-inited?) (error "Can not load images until spite is inited." path)) (when (not (string? path)) (error "Load path must be string" path)) (when (not (file-exists? path)) (error (string-append "Could not load image, no such file: " path))) (make-image (sdl-img-load-texture renderer* (string->c-utf8 path)) path))) (define draw-image (lambda (image x y width height) (c-bytevector-sint-set! draw-rect* (* (c-type-size 'int) 0) x (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! draw-rect* (* (c-type-size 'int) 1) y (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! draw-rect* (* (c-type-size 'int) 2) width (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! draw-rect* (* (c-type-size 'int) 3) height (native-endianness) (c-type-size 'int)) (sdl-render-copy renderer* (image-pointer image) (make-c-null) draw-rect*))) (define draw-image-slice (lambda (image x y width height slice-x slice-y slice-width slice-height) (c-bytevector-sint-set! draw-rect* (* (c-type-size 'int) 0) x (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! draw-rect* (* (c-type-size 'int) 1) y (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! draw-rect* (* (c-type-size 'int) 2) width (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! draw-rect* (* (c-type-size 'int) 3) height (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! draw-slice-rect* (* (c-type-size 'int) 0) slice-x (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! draw-slice-rect* (* (c-type-size 'int) 1) slice-y (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! draw-slice-rect* (* (c-type-size 'int) 2) slice-width (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! draw-slice-rect* (* (c-type-size 'int) 3) slice-height (native-endianness) (c-type-size 'int)) (sdl-render-copy renderer* (image-pointer image) draw-slice-rect* draw-rect*))) (define (set-draw-color r g b . a) (set! draw-color-r r) (set! draw-color-g g) (set! draw-color-b b) (set! draw-color-a (if (null? a) 255 a)) (c-bytevector-sint-set! fill-triangle-vertex1* (* (c-type-size 'int) 2) draw-color-r (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! fill-triangle-vertex1* (* (c-type-size 'int) 3) draw-color-g (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! fill-triangle-vertex1* (* (c-type-size 'int) 4) draw-color-b (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! fill-triangle-vertex1* (* (c-type-size 'int) 5) draw-color-b (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! fill-triangle-vertex2* (* (c-type-size 'int) 2) draw-color-r (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! fill-triangle-vertex2* (* (c-type-size 'int) 3) draw-color-g (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! fill-triangle-vertex2* (* (c-type-size 'int) 4) draw-color-b (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! fill-triangle-vertex2* (* (c-type-size 'int) 5) draw-color-b (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! fill-triangle-vertex3* (* (c-type-size 'int) 2) draw-color-r (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! fill-triangle-vertex3* (* (c-type-size 'int) 3) draw-color-g (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! fill-triangle-vertex3* (* (c-type-size 'int) 4) draw-color-b (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! fill-triangle-vertex3* (* (c-type-size 'int) 5) draw-color-b (native-endianness) (c-type-size 'int)) (sdl-set-render-draw-color renderer* r g b draw-color-a)) (define (set-line-size size) (set! current-line-size size) (sdl-render-set-scale renderer* (inexact (/ size 1)) (inexact (/ size 1)))) (define (draw-point x y) (sdl-render-draw-line renderer* (exact (round (/ x current-line-size))) (exact (round (/ y current-linesize))) (exact (round (/ x current-line-size))) (exact (round (/ y current-line-size))))) (define (draw-line x1 y1 x2 y2) (sdl-render-draw-line renderer* (exact (round (/ x1 current-line-size))) (exact (round (/ y1 current-line-size))) (exact (round (/ x2 current-line-size))) (exact (round (/ y2 current-line-size))))) (define (draw-rectangle x y width height) (c-bytevector-sint-set! draw-rect* (* (c-type-size 'int) 0) x (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! draw-rect* (* (c-type-size 'int) 1) y (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! draw-rect* (* (c-type-size 'int) 2) width (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! draw-rect* (* (c-type-size 'int) 3) height (native-endianness) (c-type-size 'int)) (sdl-render-draw-rect renderer* draw-rect*)) (define (fill-rectangle x y width height) (c-bytevector-sint-set! draw-rect* (* (c-type-size 'int) 0) x (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! draw-rect* (* (c-type-size 'int) 1) y (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! draw-rect* (* (c-type-size 'int) 2) width (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! draw-rect* (* (c-type-size 'int) 3) height (native-endianness) (c-type-size 'int)) (sdl-render-fill-rect renderer* draw-rect*)) (define (draw-triangle x1 y1 x2 y2 x3 y3) (draw-line x1 y1 x2 y2) (draw-line x2 y2 x3 y3) (draw-line x3 y3 x1 y1)) ;; FIXME #;(define (fill-triangle x1 y1 x2 y2 x3 y3) (c-bytevector-sint-set! fill-triangle-vertex1* (* (c-type-size 'int) 0) x1 (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! fill-triangle-vertex1* (* (c-type-size 'int) 1) y1 (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! fill-triangle-vertex2* (* (c-type-size 'int) 0) x2 (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! fill-triangle-vertex2* (* (c-type-size 'int) 1) y2 (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! fill-triangle-vertex3* (* (c-type-size 'int) 0) x3 (native-endianness) (c-type-size 'int)) (c-bytevector-sint-set! fill-triangle-vertex3* (* (c-type-size 'int) 1) y3 (native-endianness) (c-type-size 'int)) (sdl-render-geometry renderer* (make-c-null) fill-triangle-vertexes* 3 (make-c-null) 0)) (define (spite-option-set! name . value) (cond ((equal? name 'allow-window-resizing) (cond ((equal? value '(#t)) (sdl-set-window-resizable window* 1)) ((equal? value '(#f)) (sdl-set-window-resizable window* 0)) (else (error "Wrong option value for 'allow-window-resizing, must be #t or #f" value)))) ((equal? name 'renderer-size) (if (and (= (length value) 2) (number? (car value)) (number? (cadr value))) (sdl-render-setlogial-size renderer* (car value) (cadr value)) (error "Wrong option value for renderer-size, must be two numbers"))) (else (error "No such option!" name)))) ;; TODO Move to options, add spite-option-get (define spite-renderer-scale-get (lambda () (let ((x (make-c-bytevector (c-type-size 'float))) (y (make-c-bytevector (c-type-size 'float)))) (sdl-render-get-scale renderer* x y) (list (cons 'x (c-bytevector-ieee-single-ref x 0 (native-endianness))) (cons 'y (c-bytevector-ieee-single-ref y 0 (native-endianness))))))) (define spite-start (lambda (new-update-procedure new-draw-procedure) (set! update-procedure new-update-procedure) (set! draw-procedure new-draw-procedure) (cond ((not started?) (set! started? #t) (main-loop))))) (define spite-init (lambda (title width height) (cond ((not started?) (sdl-init 32) (set! window* (sdl-create-window (string->c-utf8 title) 0 0 width height 4)) (set! renderer* (sdl-create-renderer window* -1 2)) (sdl-render-setlogial-size renderer* width height) (sdl-render-set-integer-scale renderer* 1) (render-clear) (render-present) (set! spite-inited? #t))))) (define poll-events! (lambda () (let ((events-copy (list-copy events))) (set! events (list)) events-copy))) (define wait-for-event! (lambda () (if (not (= (length events) 0)) (poll-events!) (wait-for-event!)))) (define push-event (lambda (event) (set! events (append events (list event))))) (define clear-events! (lambda () (set! events (list)))) (define-record-type bitmap-font (internal-make-bitmap-font data) bitmap-font? (data bitmap-font-data)) (define (bitmap-font-get key bitmap) (cdr (assoc key (bitmap-font-data bitmap)))) (define-record-type bitmap-char (make-bitmap-char char x y) bitmap-char? (char bitmap-char-char) (x bitmap-char-x) (y bitmap-char-y)) (define (make-bitmap-font image character-width character-height draw-width draw-height character-lines) (let* ((line-items-count (string-length (car character-lines))) (characters (apply string-append character-lines)) (index -1) (character-indexes (list)) (character-positions (map (lambda (character) (set! index (+ index 1)) (set! character-indexes (append character-indexes (list character index))) (list character (* (modulo index line-items-count) character-width) (* (floor (/ index line-items-count)) character-height))) (string->list characters)))) (internal-make-bitmap-font `((image . ,image) (character-width . ,character-width) (character-height . ,character-height) (character-draw-width . ,draw-width) (character-draw-height . ,draw-height) (line-items-count . ,line-items-count) (characters . ,characters) (character-indexes . ,character-indexes) (character-positions . ,character-positions))))) (define (set-bitmap-font font) (set! current-bitmap-font font)) (define (make-bitmap-text text font) (map (lambda (c) (make-bitmap-char c (cadr (assq c (bitmap-font-get 'character-positions font))) (cadr (cdr (assq c (bitmap-font-get 'character-positions font)))))) (string->list text))) (define draw-bitmap-text (lambda (text x y) (when (not current-bitmap-font) (error "Current bitmap font not set, use make-bitmap-font and set-bitmap-font")) (let ((offset-x x)) (for-each (lambda (bitmap-char) (draw-image-slice (bitmap-font-get 'image current-bitmap-font) offset-x y (bitmap-font-get 'character-draw-width current-bitmap-font) (bitmap-font-get 'character-draw-height current-bitmap-font) (bitmap-char-x bitmap-char) (bitmap-char-y bitmap-char) (bitmap-font-get 'character-width current-bitmap-font) (bitmap-font-get 'character-height current-bitmap-font)) (set! offset-x (+ offset-x (bitmap-font-get 'character-draw-width current-bitmap-font)))) (make-bitmap-text text current-bitmap-font)))))