Created
July 7, 2024 05:57
-
-
Save danodic/8b96cf9d99ec30df684e62f6a8e442e9 to your computer and use it in GitHub Desktop.
Janet SDL Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is an example of how to use SDL in Janet using the FFI module. | |
# This is based on Lazy Foo's tutorial that can be found at: | |
# https://lazyfoo.net/tutorials/SDL/01_hello_SDL/index2.php | |
# | |
# In order to run this, you need: | |
# - To have libSDL2.so at the same folder where the source code is. | |
# - Create three separate files, as descibed by the comments below. | |
# - Read the FFI docs here: | |
# https://janet-lang.org/1.25.1/docs/ffi.html | |
# | |
# Some Notes: | |
# - Source code has been tested in Linux only. | |
# - I code in Clojure, this is my very first code written in Janet. | |
# It may not be idiomatic or following the language's conventions. | |
# | |
# In case you are not able to see the screen, run with -r and it will | |
# start the repl while the screen is running. | |
# File: hello-sdl.janet --- | |
#!/usr/bin/env janet | |
# Here we import the files which contain the FFI, contants and idiomatic api. | |
(import ./sdl :as sdl) | |
(import ./sdl-janet :as sdlj) | |
# Initializes SDL. Here we use some constants from the sdl module. | |
(sdlj/sdl-init! (get sdl/sdl-constants :sdl/sdl-init-video)) | |
# This let block will create the window and paint a surface. | |
(let [screen-size [640 480] | |
background-color [255 255 255] | |
{:window/window window | |
:window/window-surface window-surface} (sdlj/sdl-create-window "SDL Tutorial" 0 0 ;screen-size) | |
pixel-format (get window-surface :surface/sdl-pixel-format) | |
fill-color (sdlj/sdl-map-rgb pixel-format ;background-color)] | |
(sdlj/sdl-fill-rect! (get window-surface :ptr) nil fill-color)) | |
# File: sdl.janet --- | |
# This will load the SDL library into the FFI context. | |
(ffi/context "./libSDL2.so") | |
# Those constants have been copied from SDL's source code. | |
(def sdl-constants {:sdl/sdl-init-video 0x00000020 | |
:sdl/sdl-window-shown 0x00000004}) | |
# Defines the struct for the SDL surface. | |
(def SDL_Surface (ffi/struct :uint32 :ptr :int :int :ptr :ptr :int :ptr :ptr :ptr :int)) | |
# We use defbind to create a binding to the C function. | |
# We can replace _ by - so it matches the lisp convention. | |
(ffi/defbind SDL-Init :uint32 [init-video :uint32]) | |
# You can find a list of all avilable types in the FFI link mentioned above. | |
(ffi/defbind SDL-CreateWindow :ptr | |
[title :string | |
x :int | |
y :int | |
w :int | |
h :int | |
flags :uint32]) | |
(ffi/defbind SDL-GetWindowSurface :ptr [window :ptr]) | |
(ffi/defbind SDL-UpdateWindowSurface :int [window :ptr]) | |
(ffi/defbind SDL-FillRect :int | |
[surface :ptr | |
sdl-rect :ptr | |
color :uint32]) | |
(ffi/defbind SDL-MapRGB :uint32 | |
[format :ptr | |
r :uint8 | |
g :uint8 | |
b :uint8]) | |
# File: sdl-janet.janet --- | |
# Import the SDL file listed above. | |
(import ./sdl :as sdl) | |
# We access FFI structs by the index of the field in the struct. | |
# This is quite annoying, and it makes sense to create a mapped struct in which | |
# you can access fields using get and get-in. | |
# It receives a pointer to the FFI struct... | |
(defn make-sdl-surface | |
[ffi-ptr] | |
# ... and we read it to a buffer using the declared struct from the sdl module. | |
(let [surface (ffi/read sdl/SDL_Surface ffi-ptr)] | |
# Now that we have the buffer, we can access the values. | |
{:surface/ptr ffi-ptr | |
:surface/flags (get surface 0) | |
:surface/sdl-pixel-format (get surface 1) | |
:surface/w (get surface 2) | |
:surface/height (get surface 3) | |
:surface/pitch (get surface 4) | |
:surface/pixels (get surface 5) | |
:surface/userdata (get surface 6) | |
:surface/locked (get surface 7) | |
:surface/lock-data (get surface 8) | |
:surface/clip-rect (get surface 9) | |
:surface/sdl-blitmap (get surface 10) | |
:surface/refcount(get surface 11)})) | |
(defn- make-sdl-window | |
[window] | |
(let [surface (sdl/SDL-GetWindowSurface window)] | |
{:window/window window | |
:window/window-surface (make-sdl-surface surface)})) | |
(defn sdl-init! | |
[flags] | |
(let [processes-flags flags | |
status (sdl/SDL-Init flags)] | |
(when (< status 0) | |
# !!! | |
# I am not sure if this is the correct way of throwing an error. | |
# Do not use this as a reference. | |
# !!! | |
(error :sdl-janet-error/sdl-init-video)))) | |
(defn sdl-create-window | |
[title pos-x pos-y width height] | |
(let [flags (get sdl/sdl-constants :sdl/sdl-window-shown) | |
window (sdl/SDL-CreateWindow title pos-x pos-y width height flags)] | |
(when (nil? window) | |
(error :sdl-janet-error/create-window)) | |
(make-sdl-window window))) | |
(defn sdl-map-rgb | |
[pixel-format r g b] | |
(sdl/SDL-MapRGB pixel-format r g b)) | |
(defn sdl-fill-rect! | |
[surface rect color] | |
(sdl/SDL-FillRect surface rect color)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment