implement our own gui module, drop microui
This commit is contained in:
parent
2555bec8eb
commit
8baf5f06ea
25 changed files with 495 additions and 507 deletions
|
|
@ -7,7 +7,7 @@
|
||||||
./pxl8.sh run [game.cart | project_dir] # Run pxl8 demo (or a specific game)
|
./pxl8.sh run [game.cart | project_dir] # Run pxl8 demo (or a specific game)
|
||||||
./pxl8.sh run [game.cart | project_dir] --repl # Run pxl8 demo (or a specific game) with a REPL
|
./pxl8.sh run [game.cart | project_dir] --repl # Run pxl8 demo (or a specific game) with a REPL
|
||||||
```
|
```
|
||||||
**Note** The demo has keys 1-9 bound for different examples.
|
**Note** The demo has keys 1-8 bound for different examples.
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> <strong>Heavy development. So... <em>here be dragons :3</em></strong>
|
> <strong>Heavy development. So... <em>here be dragons :3</em></strong>
|
||||||
|
|
@ -38,4 +38,4 @@ pxl8 is free and open source! All code in this repository is licensed under:
|
||||||
|
|
||||||
- Mozilla Public License, Version 2.0 ([LICENSE](LICENSE) or https://mozilla.org/MPL/2.0/)
|
- Mozilla Public License, Version 2.0 ([LICENSE](LICENSE) or https://mozilla.org/MPL/2.0/)
|
||||||
|
|
||||||
Third-party dependencies (Fennel, LuaJIT, linenoise, microui, miniz, SDL3) retain their original licenses.
|
Third-party dependencies (Fennel, linenoise, log.c, LuaJIT, miniz, SDL3) retain their original licenses.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(local pxl8 (require :pxl8))
|
(local pxl8 (require :pxl8))
|
||||||
(local cube3d (require :mod.cube3d))
|
(local menu (require :mod.menu))
|
||||||
(local worldgen (require :mod.worldgen))
|
(local worldgen (require :mod.worldgen))
|
||||||
|
|
||||||
(var time 0)
|
(var time 0)
|
||||||
|
|
@ -29,53 +29,59 @@
|
||||||
(pxl8.load_palette "res/sprites/pxl8_logo.ase")
|
(pxl8.load_palette "res/sprites/pxl8_logo.ase")
|
||||||
(set logo-sprite (pxl8.load_sprite "res/sprites/pxl8_logo.ase"))
|
(set logo-sprite (pxl8.load_sprite "res/sprites/pxl8_logo.ase"))
|
||||||
(set particles (pxl8.particles_new 1000))
|
(set particles (pxl8.particles_new 1000))
|
||||||
(cube3d.init)
|
|
||||||
(worldgen.init)))
|
(worldgen.init)))
|
||||||
|
|
||||||
(global update (fn [dt]
|
(global update (fn [dt]
|
||||||
(set time (+ time dt))
|
(when (pxl8.key_pressed "escape")
|
||||||
|
(menu.toggle)
|
||||||
|
(when (= active-demo :worldgen)
|
||||||
|
(pxl8.set_relative_mouse_mode (not (menu.is-paused)))))
|
||||||
|
|
||||||
(when transition
|
(when (not (menu.is-paused))
|
||||||
(pxl8.transition_update transition dt)
|
(set time (+ time dt))
|
||||||
(when (pxl8.transition_is_complete transition)
|
|
||||||
(when transition-pending
|
|
||||||
(when (and (= active-demo :worldgen) (not= transition-pending :worldgen))
|
|
||||||
(pxl8.set_relative_mouse_mode false))
|
|
||||||
(set active-demo transition-pending)
|
|
||||||
(set transition-pending nil)
|
|
||||||
(when (= active-demo :fire) (set fire-init? false))
|
|
||||||
(when (= active-demo :rain) (set rain-init? false))
|
|
||||||
(when (= active-demo :snow) (set snow-init? false)))
|
|
||||||
(pxl8.transition_destroy transition)
|
|
||||||
(set transition nil)))
|
|
||||||
|
|
||||||
(when (pxl8.key_pressed "1") (switch-demo :logo))
|
(when transition
|
||||||
(when (pxl8.key_pressed "2") (switch-demo :plasma))
|
(pxl8.transition_update transition dt)
|
||||||
(when (pxl8.key_pressed "3") (switch-demo :tunnel))
|
(when (pxl8.transition_is_complete transition)
|
||||||
(when (pxl8.key_pressed "4") (switch-demo :raster))
|
(when transition-pending
|
||||||
(when (pxl8.key_pressed "5") (switch-demo :fire))
|
(when (and (= active-demo :worldgen) (not= transition-pending :worldgen))
|
||||||
(when (pxl8.key_pressed "6") (switch-demo :rain))
|
(pxl8.set_relative_mouse_mode false))
|
||||||
(when (pxl8.key_pressed "7") (switch-demo :snow))
|
(set active-demo transition-pending)
|
||||||
(when (pxl8.key_pressed "8") (switch-demo :cube3d))
|
(set transition-pending nil)
|
||||||
(when (pxl8.key_pressed "9") (switch-demo :worldgen))
|
(when (= active-demo :fire) (set fire-init? false))
|
||||||
(when (pxl8.key_pressed "=")
|
(when (= active-demo :rain) (set rain-init? false))
|
||||||
(set use-famicube-palette? (not use-famicube-palette?))
|
(when (= active-demo :snow) (set snow-init? false)))
|
||||||
(local palette-path (if use-famicube-palette? "res/palettes/famicube.ase" "res/sprites/pxl8_logo.ase"))
|
(pxl8.transition_destroy transition)
|
||||||
(pxl8.load_palette palette-path))
|
(set transition nil)))
|
||||||
|
|
||||||
(case active-demo
|
(when (pxl8.key_pressed "1") (switch-demo :logo))
|
||||||
:logo (do
|
(when (pxl8.key_pressed "2") (switch-demo :plasma))
|
||||||
(set logo-x (+ logo-x (* logo-dx dt)))
|
(when (pxl8.key_pressed "3") (switch-demo :tunnel))
|
||||||
(set logo-y (+ logo-y (* logo-dy dt)))
|
(when (pxl8.key_pressed "4") (switch-demo :raster))
|
||||||
(when (or (< logo-x 0) (> logo-x 512))
|
(when (pxl8.key_pressed "5") (switch-demo :fire))
|
||||||
(set logo-dx (- logo-dx)))
|
(when (pxl8.key_pressed "6") (switch-demo :rain))
|
||||||
(when (or (< logo-y 0) (> logo-y 296))
|
(when (pxl8.key_pressed "7") (switch-demo :snow))
|
||||||
(set logo-dy (- logo-dy))))
|
(when (pxl8.key_pressed "8") (switch-demo :worldgen))
|
||||||
:cube3d (cube3d.update dt)
|
(when (pxl8.key_pressed "=")
|
||||||
:worldgen (worldgen.update dt))
|
(set use-famicube-palette? (not use-famicube-palette?))
|
||||||
|
(local palette-path (if use-famicube-palette? "res/palettes/famicube.ase" "res/sprites/pxl8_logo.ase"))
|
||||||
|
(pxl8.load_palette palette-path))
|
||||||
|
|
||||||
(when particles
|
(case active-demo
|
||||||
(pxl8.particles_update particles dt))))
|
:logo (do
|
||||||
|
(set logo-x (+ logo-x (* logo-dx dt)))
|
||||||
|
(set logo-y (+ logo-y (* logo-dy dt)))
|
||||||
|
(when (or (< logo-x 0) (> logo-x 512))
|
||||||
|
(set logo-dx (- logo-dx)))
|
||||||
|
(when (or (< logo-y 0) (> logo-y 296))
|
||||||
|
(set logo-dy (- logo-dy))))
|
||||||
|
:worldgen (worldgen.update dt))
|
||||||
|
|
||||||
|
(when particles
|
||||||
|
(pxl8.particles_update particles dt)))
|
||||||
|
|
||||||
|
(when (menu.is-paused)
|
||||||
|
(menu.update))))
|
||||||
|
|
||||||
(global frame (fn []
|
(global frame (fn []
|
||||||
(case active-demo
|
(case active-demo
|
||||||
|
|
@ -122,11 +128,12 @@
|
||||||
(set snow-init? true))
|
(set snow-init? true))
|
||||||
(pxl8.particles_render particles)))
|
(pxl8.particles_render particles)))
|
||||||
|
|
||||||
:cube3d (cube3d.frame)
|
|
||||||
|
|
||||||
:worldgen (worldgen.frame)
|
:worldgen (worldgen.frame)
|
||||||
|
|
||||||
_ (pxl8.clear 0))
|
_ (pxl8.clear 0))
|
||||||
|
|
||||||
(when transition
|
(when transition
|
||||||
(pxl8.transition_render transition))))
|
(pxl8.transition_render transition))
|
||||||
|
|
||||||
|
(when (menu.is-paused)
|
||||||
|
(menu.draw))))
|
||||||
|
|
|
||||||
|
|
@ -1,251 +0,0 @@
|
||||||
(local pxl8 (require :pxl8))
|
|
||||||
(local debug-ui (require :mod.debug_ui))
|
|
||||||
|
|
||||||
(var angle-x 0)
|
|
||||||
(var angle-y 0)
|
|
||||||
(var angle-z 0)
|
|
||||||
(var auto-rotate? true)
|
|
||||||
(var orthographic? false)
|
|
||||||
(var wireframe? true)
|
|
||||||
(var time 0)
|
|
||||||
(var zoom 5.0)
|
|
||||||
(var texture-id nil)
|
|
||||||
(var use-texture? false)
|
|
||||||
(var affine? false)
|
|
||||||
(var cam-x 0)
|
|
||||||
(var cam-y 2)
|
|
||||||
(var cam-z 12)
|
|
||||||
(var cam-yaw 0)
|
|
||||||
(var cam-pitch -0.2)
|
|
||||||
(var show-debug-ui? false)
|
|
||||||
(var fps 0)
|
|
||||||
(var fps-accumulator 0)
|
|
||||||
(var fps-frame-count 0)
|
|
||||||
|
|
||||||
(fn init []
|
|
||||||
(set angle-x 0)
|
|
||||||
(set angle-y 0)
|
|
||||||
(set angle-z 0)
|
|
||||||
(set auto-rotate? true)
|
|
||||||
(set orthographic? false)
|
|
||||||
(set wireframe? true)
|
|
||||||
(set time 0)
|
|
||||||
(set zoom 5.0)
|
|
||||||
(set use-texture? false)
|
|
||||||
(set affine? false)
|
|
||||||
(set cam-x 0)
|
|
||||||
(set cam-y 2)
|
|
||||||
(set cam-z 12)
|
|
||||||
(set cam-yaw 0)
|
|
||||||
(set cam-pitch -0.2)
|
|
||||||
(set show-debug-ui? false)
|
|
||||||
(set fps 0)
|
|
||||||
(set fps-accumulator 0)
|
|
||||||
(set fps-frame-count 0)
|
|
||||||
(set texture-id (pxl8.load_sprite "res/sprites/pxl8_logo.ase"))
|
|
||||||
(pxl8.upload_atlas))
|
|
||||||
|
|
||||||
(fn make-cube-vertices []
|
|
||||||
[[-1 -1 -1] [1 -1 -1] [1 1 -1] [-1 1 -1]
|
|
||||||
[-1 -1 1] [1 -1 1] [1 1 1] [-1 1 1]])
|
|
||||||
|
|
||||||
(fn make-cube-faces []
|
|
||||||
[[0 1 2] [0 2 3]
|
|
||||||
[1 5 6] [1 6 2]
|
|
||||||
[5 4 7] [5 7 6]
|
|
||||||
[4 0 3] [4 3 7]
|
|
||||||
[3 2 6] [3 6 7]
|
|
||||||
[4 5 1] [4 1 0]])
|
|
||||||
|
|
||||||
(fn make-cube-faces-with-uvs []
|
|
||||||
[{:tri [0 1 2] :uvs [[0 0] [1 0] [1 1]]}
|
|
||||||
{:tri [0 2 3] :uvs [[0 0] [1 1] [0 1]]}
|
|
||||||
{:tri [1 5 6] :uvs [[0 0] [1 0] [1 1]]}
|
|
||||||
{:tri [1 6 2] :uvs [[0 0] [1 1] [0 1]]}
|
|
||||||
{:tri [5 4 7] :uvs [[0 0] [1 0] [1 1]]}
|
|
||||||
{:tri [5 7 6] :uvs [[0 0] [1 1] [0 1]]}
|
|
||||||
{:tri [4 0 3] :uvs [[0 0] [1 0] [1 1]]}
|
|
||||||
{:tri [4 3 7] :uvs [[0 0] [1 1] [0 1]]}
|
|
||||||
{:tri [3 2 6] :uvs [[0 0] [1 0] [1 1]]}
|
|
||||||
{:tri [3 6 7] :uvs [[0 0] [1 1] [0 1]]}
|
|
||||||
{:tri [4 5 1] :uvs [[0 0] [1 0] [1 1]]}
|
|
||||||
{:tri [4 1 0] :uvs [[0 0] [1 1] [0 1]]}])
|
|
||||||
|
|
||||||
(fn get-face-color [face-idx]
|
|
||||||
(let [colors [12 22 30 16 28 20]]
|
|
||||||
(. colors (+ 1 (% face-idx 6)))))
|
|
||||||
|
|
||||||
(fn update [dt]
|
|
||||||
(set time (+ time dt))
|
|
||||||
(set fps-accumulator (+ fps-accumulator dt))
|
|
||||||
(set fps-frame-count (+ fps-frame-count 1))
|
|
||||||
|
|
||||||
(when (>= fps-accumulator 0.25)
|
|
||||||
(set fps (/ fps-frame-count fps-accumulator))
|
|
||||||
(set fps-accumulator 0)
|
|
||||||
(set fps-frame-count 0))
|
|
||||||
|
|
||||||
(let [wheel-y (pxl8.mouse_wheel_y)]
|
|
||||||
(when (and (not= wheel-y 0) (not (pxl8.ui_has_mouse_focus)))
|
|
||||||
(if orthographic?
|
|
||||||
(set zoom (math.max 0.5 (math.min (- zoom (* wheel-y 0.2)) 10.0)))
|
|
||||||
(let [zoom-speed 0.5
|
|
||||||
forward-x (* (math.sin cam-yaw) wheel-y zoom-speed)
|
|
||||||
forward-z (* (math.cos cam-yaw) wheel-y zoom-speed)]
|
|
||||||
(set cam-x (+ cam-x forward-x))
|
|
||||||
(set cam-z (- cam-z forward-z))))))
|
|
||||||
|
|
||||||
(let [move-speed 5.0
|
|
||||||
rot-speed 2.0
|
|
||||||
zoom-speed 2.0
|
|
||||||
forward-x (* (math.sin cam-yaw) move-speed dt)
|
|
||||||
forward-z (* (math.cos cam-yaw) move-speed dt)
|
|
||||||
right-x (* (math.cos cam-yaw) move-speed dt)
|
|
||||||
right-z (* (- (math.sin cam-yaw)) move-speed dt)]
|
|
||||||
|
|
||||||
(if orthographic?
|
|
||||||
(do
|
|
||||||
(when (pxl8.key_down "w")
|
|
||||||
(set zoom (math.max 0.5 (- zoom (* zoom-speed dt)))))
|
|
||||||
(when (pxl8.key_down "s")
|
|
||||||
(set zoom (math.min 10.0 (+ zoom (* zoom-speed dt)))))
|
|
||||||
(when (pxl8.key_down "a")
|
|
||||||
(set cam-x (- cam-x right-x))
|
|
||||||
(set cam-z (- cam-z right-z)))
|
|
||||||
(when (pxl8.key_down "d")
|
|
||||||
(set cam-x (+ cam-x right-x))
|
|
||||||
(set cam-z (+ cam-z right-z)))
|
|
||||||
(when (pxl8.key_down "q")
|
|
||||||
(set cam-y (- cam-y (* move-speed dt))))
|
|
||||||
(when (pxl8.key_down "e")
|
|
||||||
(set cam-y (+ cam-y (* move-speed dt)))))
|
|
||||||
(do
|
|
||||||
(when (pxl8.key_down "w")
|
|
||||||
(set cam-x (+ cam-x forward-x))
|
|
||||||
(set cam-z (- cam-z forward-z)))
|
|
||||||
(when (pxl8.key_down "s")
|
|
||||||
(set cam-x (- cam-x forward-x))
|
|
||||||
(set cam-z (+ cam-z forward-z)))
|
|
||||||
(when (pxl8.key_down "a")
|
|
||||||
(set cam-x (- cam-x right-x))
|
|
||||||
(set cam-z (- cam-z right-z)))
|
|
||||||
(when (pxl8.key_down "d")
|
|
||||||
(set cam-x (+ cam-x right-x))
|
|
||||||
(set cam-z (+ cam-z right-z)))
|
|
||||||
(when (pxl8.key_down "q")
|
|
||||||
(set cam-y (- cam-y (* move-speed dt))))
|
|
||||||
(when (pxl8.key_down "e")
|
|
||||||
(set cam-y (+ cam-y (* move-speed dt))))))
|
|
||||||
|
|
||||||
(when (pxl8.key_down "left")
|
|
||||||
(set cam-yaw (- cam-yaw (* rot-speed dt))))
|
|
||||||
(when (pxl8.key_down "right")
|
|
||||||
(set cam-yaw (+ cam-yaw (* rot-speed dt))))
|
|
||||||
(when (pxl8.key_down "up")
|
|
||||||
(set cam-pitch (+ cam-pitch (* rot-speed dt))))
|
|
||||||
(when (pxl8.key_down "down")
|
|
||||||
(set cam-pitch (- cam-pitch (* rot-speed dt))))
|
|
||||||
|
|
||||||
(set cam-pitch (math.max -1.5 (math.min cam-pitch 1.5))))
|
|
||||||
|
|
||||||
(when (pxl8.key_pressed " ")
|
|
||||||
(set wireframe? (not wireframe?)))
|
|
||||||
(when (pxl8.key_pressed "f")
|
|
||||||
(set affine? (not affine?)))
|
|
||||||
(when (pxl8.key_pressed "p")
|
|
||||||
(set orthographic? (not orthographic?)))
|
|
||||||
(when (pxl8.key_pressed "r")
|
|
||||||
(set auto-rotate? (not auto-rotate?)))
|
|
||||||
(when (pxl8.key_pressed "t")
|
|
||||||
(set use-texture? (not use-texture?)))
|
|
||||||
(when (pxl8.key_pressed "F8")
|
|
||||||
(set show-debug-ui? (not show-debug-ui?))
|
|
||||||
(pxl8.ui_window_set_open "Debug Menu (F8)" show-debug-ui?))
|
|
||||||
|
|
||||||
(when auto-rotate?
|
|
||||||
(set angle-x (+ angle-x (* dt 0.7)))
|
|
||||||
(set angle-y (+ angle-y (* dt 0.5)))
|
|
||||||
(set angle-z (+ angle-z (* dt 0.3)))))
|
|
||||||
|
|
||||||
(fn draw-cube [pos scale rotation-offset]
|
|
||||||
(let [[x y z] pos
|
|
||||||
model (-> (pxl8.mat4_translate x y z)
|
|
||||||
(pxl8.mat4_multiply (pxl8.mat4_rotate_z (+ angle-z (* rotation-offset 0.7))))
|
|
||||||
(pxl8.mat4_multiply (pxl8.mat4_rotate_y (+ angle-y (* rotation-offset 1.3))))
|
|
||||||
(pxl8.mat4_multiply (pxl8.mat4_rotate_x (+ angle-x rotation-offset)))
|
|
||||||
(pxl8.mat4_multiply (pxl8.mat4_scale scale scale scale)))]
|
|
||||||
(pxl8.set_model model))
|
|
||||||
|
|
||||||
(let [vertices (make-cube-vertices)]
|
|
||||||
(if (and use-texture? texture-id)
|
|
||||||
(let [faces (make-cube-faces-with-uvs)]
|
|
||||||
(each [_i face-data (ipairs faces)]
|
|
||||||
(let [tri-indices face-data.tri
|
|
||||||
tri-uvs face-data.uvs
|
|
||||||
v0 (. vertices (+ 1 (. tri-indices 1)))
|
|
||||||
v1 (. vertices (+ 1 (. tri-indices 2)))
|
|
||||||
v2 (. vertices (+ 1 (. tri-indices 3)))
|
|
||||||
uv0 (. tri-uvs 1)
|
|
||||||
uv1 (. tri-uvs 2)
|
|
||||||
uv2 (. tri-uvs 3)]
|
|
||||||
(pxl8.draw_triangle_3d_textured
|
|
||||||
v0 v1 v2
|
|
||||||
uv0 uv1 uv2
|
|
||||||
texture-id))))
|
|
||||||
(let [faces (make-cube-faces)]
|
|
||||||
(each [i face (ipairs faces)]
|
|
||||||
(let [[i0 i1 i2] face
|
|
||||||
v0 (. vertices (+ 1 i0))
|
|
||||||
v1 (. vertices (+ 1 i1))
|
|
||||||
v2 (. vertices (+ 1 i2))
|
|
||||||
color (get-face-color (math.floor (/ (- i 1) 2)))]
|
|
||||||
(pxl8.draw_triangle_3d v0 v1 v2 color)))))))
|
|
||||||
|
|
||||||
(fn frame []
|
|
||||||
(pxl8.clear 0)
|
|
||||||
|
|
||||||
(pxl8.clear_zbuffer)
|
|
||||||
(pxl8.set_affine_textures affine?)
|
|
||||||
(pxl8.set_backface_culling true)
|
|
||||||
(pxl8.set_wireframe wireframe?)
|
|
||||||
|
|
||||||
(if orthographic?
|
|
||||||
(let [size zoom
|
|
||||||
aspect (/ (pxl8.get_width) (pxl8.get_height))
|
|
||||||
w (* size aspect)
|
|
||||||
h size]
|
|
||||||
(pxl8.set_projection (pxl8.mat4_ortho (- w) w (- h) h 1.0 100.0)))
|
|
||||||
(let [aspect (/ (pxl8.get_width) (pxl8.get_height))
|
|
||||||
fov (* (/ 60.0 180.0) 3.14159)]
|
|
||||||
(pxl8.set_projection (pxl8.mat4_perspective fov aspect 0.1 100.0))))
|
|
||||||
|
|
||||||
(let [target-x (* (math.sin cam-yaw) (math.cos cam-pitch))
|
|
||||||
target-y (math.sin cam-pitch)
|
|
||||||
target-z (* (- (math.cos cam-yaw)) (math.cos cam-pitch))
|
|
||||||
look-x (+ cam-x target-x)
|
|
||||||
look-y (+ cam-y target-y)
|
|
||||||
look-z (+ cam-z target-z)]
|
|
||||||
(pxl8.set_view (pxl8.mat4_lookat [cam-x cam-y cam-z] [look-x look-y look-z] [0 1 0])))
|
|
||||||
|
|
||||||
(draw-cube [0 0 0] 1.0 0)
|
|
||||||
(draw-cube [-3 0 -4] 0.8 0.5)
|
|
||||||
(draw-cube [3 1 -7] 0.9 1.2)
|
|
||||||
(draw-cube [0 -2 -10] 1.1 -0.7)
|
|
||||||
|
|
||||||
(let [new-state (debug-ui.render {:show-debug-ui show-debug-ui?
|
|
||||||
:fps fps
|
|
||||||
:wireframe wireframe?
|
|
||||||
:auto-rotate auto-rotate?
|
|
||||||
:orthographic orthographic?
|
|
||||||
:use-texture use-texture?
|
|
||||||
:affine affine?})]
|
|
||||||
(when (not= new-state.show-debug-ui nil) (set show-debug-ui? new-state.show-debug-ui))
|
|
||||||
(when (not= new-state.wireframe nil) (set wireframe? new-state.wireframe))
|
|
||||||
(when (not= new-state.auto-rotate nil) (set auto-rotate? new-state.auto-rotate))
|
|
||||||
(when (not= new-state.orthographic nil) (set orthographic? new-state.orthographic))
|
|
||||||
(when (not= new-state.use-texture nil) (set use-texture? new-state.use-texture))
|
|
||||||
(when (not= new-state.affine nil) (set affine? new-state.affine))))
|
|
||||||
|
|
||||||
{:init init
|
|
||||||
:update update
|
|
||||||
:frame frame}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
(local pxl8 (require :pxl8))
|
|
||||||
|
|
||||||
(fn render [state]
|
|
||||||
(var new-state {})
|
|
||||||
(when state.show-debug-ui
|
|
||||||
(let [window-open (pxl8.ui_window_begin "Debug Menu (F8)" 10 10 256 128)]
|
|
||||||
(when window-open
|
|
||||||
(pxl8.ui_layout_row 1 0 0)
|
|
||||||
(pxl8.ui_label (string.format "FPS: %.0f" (or state.fps 0)))
|
|
||||||
(let [(changed new-val) (pxl8.ui_checkbox "Wireframe" state.wireframe)]
|
|
||||||
(when changed (set new-state.wireframe new-val)))
|
|
||||||
(let [(changed new-val) (pxl8.ui_checkbox "Auto-rotate" state.auto-rotate)]
|
|
||||||
(when changed (set new-state.auto-rotate new-val)))
|
|
||||||
(let [(changed new-val) (pxl8.ui_checkbox "Orthographic" state.orthographic)]
|
|
||||||
(when changed (set new-state.orthographic new-val)))
|
|
||||||
(let [(changed new-val) (pxl8.ui_checkbox "Texture" state.use-texture)]
|
|
||||||
(when changed (set new-state.use-texture new-val)))
|
|
||||||
(when state.use-texture
|
|
||||||
(pxl8.ui_indent 20)
|
|
||||||
(let [(changed new-val) (pxl8.ui_checkbox "Affine mapping" state.affine)]
|
|
||||||
(when changed (set new-state.affine new-val)))
|
|
||||||
(pxl8.ui_indent -20))
|
|
||||||
(pxl8.ui_window_end))
|
|
||||||
(when (not window-open)
|
|
||||||
(set new-state.show-debug-ui false))))
|
|
||||||
new-state)
|
|
||||||
|
|
||||||
{: render}
|
|
||||||
51
demo/mod/menu.fnl
Normal file
51
demo/mod/menu.fnl
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
(local pxl8 (require :pxl8))
|
||||||
|
|
||||||
|
(var paused false)
|
||||||
|
|
||||||
|
(fn show []
|
||||||
|
(set paused true)
|
||||||
|
(pxl8.set_relative_mouse_mode false)
|
||||||
|
(pxl8.center_cursor))
|
||||||
|
|
||||||
|
(fn hide []
|
||||||
|
(set paused false)
|
||||||
|
(pxl8.set_relative_mouse_mode true))
|
||||||
|
|
||||||
|
(fn toggle []
|
||||||
|
(if paused
|
||||||
|
(hide)
|
||||||
|
(show)))
|
||||||
|
|
||||||
|
(fn update []
|
||||||
|
(let [(mx my) (pxl8.get_mouse_pos)]
|
||||||
|
(pxl8.gui_cursor_move mx my))
|
||||||
|
|
||||||
|
(when (pxl8.mouse_pressed 1)
|
||||||
|
(pxl8.gui_cursor_down))
|
||||||
|
|
||||||
|
(when (pxl8.mouse_released 1)
|
||||||
|
(pxl8.gui_cursor_up)))
|
||||||
|
|
||||||
|
(fn draw []
|
||||||
|
(pxl8.gui_begin_frame)
|
||||||
|
|
||||||
|
(pxl8.gui_window 200 100 240 140 "pxl8 demo")
|
||||||
|
|
||||||
|
(when (pxl8.gui_button 1 215 145 210 32 "Resume")
|
||||||
|
(hide))
|
||||||
|
|
||||||
|
(when (pxl8.gui_button 2 215 185 210 32 "Quit")
|
||||||
|
(pxl8.quit))
|
||||||
|
|
||||||
|
(if (pxl8.gui_is_hovering)
|
||||||
|
(pxl8.set_cursor :hand)
|
||||||
|
(pxl8.set_cursor :arrow))
|
||||||
|
|
||||||
|
(pxl8.gui_end_frame))
|
||||||
|
|
||||||
|
{:is-paused (fn [] paused)
|
||||||
|
:toggle toggle
|
||||||
|
:show show
|
||||||
|
:hide hide
|
||||||
|
:update update
|
||||||
|
:draw draw}
|
||||||
|
|
@ -70,11 +70,6 @@
|
||||||
(pxl8.error (.. "Failed to apply textures - result: " result))))))))
|
(pxl8.error (.. "Failed to apply textures - result: " result))))))))
|
||||||
|
|
||||||
(fn update [dt]
|
(fn update [dt]
|
||||||
(pxl8.set_relative_mouse_mode mouse-look?)
|
|
||||||
|
|
||||||
(when (pxl8.key_pressed "escape")
|
|
||||||
(set mouse-look? (not mouse-look?)))
|
|
||||||
|
|
||||||
(when (pxl8.key_pressed "`")
|
(when (pxl8.key_pressed "`")
|
||||||
(set auto-run? (not auto-run?)))
|
(set auto-run? (not auto-run?)))
|
||||||
|
|
||||||
|
|
|
||||||
24
pxl8.sh
24
pxl8.sh
|
|
@ -82,7 +82,7 @@ compile_source_file() {
|
||||||
|
|
||||||
|
|
||||||
make_lib_dirs() {
|
make_lib_dirs() {
|
||||||
mkdir -p lib/linenoise lib/fennel lib/microui/src lib/miniz
|
mkdir -p lib/linenoise lib/fennel lib/miniz
|
||||||
}
|
}
|
||||||
|
|
||||||
print_error() {
|
print_error() {
|
||||||
|
|
@ -216,17 +216,6 @@ update_luajit() {
|
||||||
print_info "Updated LuaJIT (${version})"
|
print_info "Updated LuaJIT (${version})"
|
||||||
}
|
}
|
||||||
|
|
||||||
update_microui() {
|
|
||||||
print_info "Fetching microui"
|
|
||||||
|
|
||||||
if curl -sL --max-time 5 -o lib/microui/src/microui.c https://raw.githubusercontent.com/rxi/microui/master/src/microui.c 2>/dev/null && \
|
|
||||||
curl -sL --max-time 5 -o lib/microui/src/microui.h https://raw.githubusercontent.com/rxi/microui/master/src/microui.h 2>/dev/null; then
|
|
||||||
print_info "Updated microui"
|
|
||||||
else
|
|
||||||
print_error "Failed to download microui"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
update_miniz() {
|
update_miniz() {
|
||||||
print_info "Fetching miniz"
|
print_info "Fetching miniz"
|
||||||
|
|
@ -291,8 +280,7 @@ case "$COMMAND" in
|
||||||
mkdir -p "$BUILDDIR"
|
mkdir -p "$BUILDDIR"
|
||||||
mkdir -p "$BINDIR"
|
mkdir -p "$BINDIR"
|
||||||
|
|
||||||
if [[ ! -f "lib/microui/src/microui.c" ]] || \
|
if [[ ! -d "lib/luajit" ]] || \
|
||||||
[[ ! -d "lib/luajit" ]] || \
|
|
||||||
[[ ! -f "lib/linenoise/linenoise.c" ]] || \
|
[[ ! -f "lib/linenoise/linenoise.c" ]] || \
|
||||||
[[ ! -f "lib/miniz/miniz.c" ]] || \
|
[[ ! -f "lib/miniz/miniz.c" ]] || \
|
||||||
[[ ! -f "lib/fennel/fennel.lua" ]]; then
|
[[ ! -f "lib/fennel/fennel.lua" ]]; then
|
||||||
|
|
@ -302,7 +290,6 @@ case "$COMMAND" in
|
||||||
update_fennel
|
update_fennel
|
||||||
update_linenoise
|
update_linenoise
|
||||||
update_luajit
|
update_luajit
|
||||||
update_microui
|
|
||||||
update_miniz
|
update_miniz
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -333,13 +320,13 @@ case "$COMMAND" in
|
||||||
print_info "Compiler cache: ccache enabled"
|
print_info "Compiler cache: ccache enabled"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
INCLUDES="-Isrc -Ilib -Ilib/microui/src -Ilib/luajit/src -Ilib/linenoise -Ilib/miniz"
|
INCLUDES="-Isrc -Ilib -Ilib/luajit/src -Ilib/linenoise -Ilib/miniz"
|
||||||
COMPILE_FLAGS="$CFLAGS $INCLUDES"
|
COMPILE_FLAGS="$CFLAGS $INCLUDES"
|
||||||
DEP_COMPILE_FLAGS="$DEP_CFLAGS $INCLUDES"
|
DEP_COMPILE_FLAGS="$DEP_CFLAGS $INCLUDES"
|
||||||
|
|
||||||
EXECUTABLE="$BINDIR/pxl8"
|
EXECUTABLE="$BINDIR/pxl8"
|
||||||
|
|
||||||
LIB_SOURCE_FILES="lib/linenoise/linenoise.c lib/microui/src/microui.c lib/miniz/miniz.c"
|
LIB_SOURCE_FILES="lib/linenoise/linenoise.c lib/miniz/miniz.c"
|
||||||
|
|
||||||
PXL8_SOURCE_FILES="
|
PXL8_SOURCE_FILES="
|
||||||
src/pxl8.c
|
src/pxl8.c
|
||||||
|
|
@ -359,7 +346,7 @@ case "$COMMAND" in
|
||||||
src/pxl8_tilemap.c
|
src/pxl8_tilemap.c
|
||||||
src/pxl8_tilesheet.c
|
src/pxl8_tilesheet.c
|
||||||
src/pxl8_transition.c
|
src/pxl8_transition.c
|
||||||
src/pxl8_ui.c
|
src/pxl8_gui.c
|
||||||
src/pxl8_vfx.c
|
src/pxl8_vfx.c
|
||||||
src/pxl8_world.c
|
src/pxl8_world.c
|
||||||
"
|
"
|
||||||
|
|
@ -473,7 +460,6 @@ case "$COMMAND" in
|
||||||
update_fennel
|
update_fennel
|
||||||
update_linenoise
|
update_linenoise
|
||||||
update_luajit
|
update_luajit
|
||||||
update_microui
|
|
||||||
update_miniz
|
update_miniz
|
||||||
print_info "All dependencies updated"
|
print_info "All dependencies updated"
|
||||||
;;
|
;;
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,12 @@ local particles = require("pxl8.particles")
|
||||||
local tilemap = require("pxl8.tilemap")
|
local tilemap = require("pxl8.tilemap")
|
||||||
local gfx3d = require("pxl8.gfx3d")
|
local gfx3d = require("pxl8.gfx3d")
|
||||||
local math3d = require("pxl8.math")
|
local math3d = require("pxl8.math")
|
||||||
local ui = require("pxl8.ui")
|
local gui = require("pxl8.gui")
|
||||||
local world = require("pxl8.world")
|
local world = require("pxl8.world")
|
||||||
local transition = require("pxl8.transition")
|
local transition = require("pxl8.transition")
|
||||||
local anim = require("pxl8.anim")
|
local anim = require("pxl8.anim")
|
||||||
|
|
||||||
core.init(_pxl8_gfx, _pxl8_input, _pxl8_sys, _pxl8_ui)
|
core.init(_pxl8_gfx, _pxl8_input, _pxl8_sys)
|
||||||
|
|
||||||
local pxl8 = {}
|
local pxl8 = {}
|
||||||
|
|
||||||
|
|
@ -25,6 +25,7 @@ pxl8.warn = core.warn
|
||||||
pxl8.error = core.error
|
pxl8.error = core.error
|
||||||
pxl8.debug = core.debug
|
pxl8.debug = core.debug
|
||||||
pxl8.trace = core.trace
|
pxl8.trace = core.trace
|
||||||
|
pxl8.quit = core.quit
|
||||||
|
|
||||||
pxl8.clear = gfx2d.clear
|
pxl8.clear = gfx2d.clear
|
||||||
pxl8.pixel = gfx2d.pixel
|
pxl8.pixel = gfx2d.pixel
|
||||||
|
|
@ -51,6 +52,11 @@ pxl8.mouse_wheel_x = input.mouse_wheel_x
|
||||||
pxl8.mouse_wheel_y = input.mouse_wheel_y
|
pxl8.mouse_wheel_y = input.mouse_wheel_y
|
||||||
pxl8.mouse_x = input.mouse_x
|
pxl8.mouse_x = input.mouse_x
|
||||||
pxl8.mouse_y = input.mouse_y
|
pxl8.mouse_y = input.mouse_y
|
||||||
|
pxl8.get_mouse_pos = input.get_mouse_pos
|
||||||
|
pxl8.mouse_pressed = input.mouse_pressed
|
||||||
|
pxl8.mouse_released = input.mouse_released
|
||||||
|
pxl8.center_cursor = input.center_cursor
|
||||||
|
pxl8.set_cursor = input.set_cursor
|
||||||
pxl8.set_relative_mouse_mode = input.set_relative_mouse_mode
|
pxl8.set_relative_mouse_mode = input.set_relative_mouse_mode
|
||||||
|
|
||||||
pxl8.vfx_raster_bars = vfx.raster_bars
|
pxl8.vfx_raster_bars = vfx.raster_bars
|
||||||
|
|
@ -116,15 +122,18 @@ pxl8.mat4_perspective = math3d.mat4_perspective
|
||||||
pxl8.mat4_lookat = math3d.mat4_lookat
|
pxl8.mat4_lookat = math3d.mat4_lookat
|
||||||
pxl8.bounds = math3d.bounds
|
pxl8.bounds = math3d.bounds
|
||||||
|
|
||||||
pxl8.ui_button = ui.button
|
pxl8.gui_state_create = gui.state_create
|
||||||
pxl8.ui_checkbox = ui.checkbox
|
pxl8.gui_state_destroy = gui.state_destroy
|
||||||
pxl8.ui_has_mouse_focus = ui.has_mouse_focus
|
pxl8.gui_begin_frame = gui.begin_frame
|
||||||
pxl8.ui_indent = ui.indent
|
pxl8.gui_end_frame = gui.end_frame
|
||||||
pxl8.ui_label = ui.label
|
pxl8.gui_cursor_move = gui.cursor_move
|
||||||
pxl8.ui_layout_row = ui.layout_row
|
pxl8.gui_cursor_down = gui.cursor_down
|
||||||
pxl8.ui_window_begin = ui.window_begin
|
pxl8.gui_cursor_up = gui.cursor_up
|
||||||
pxl8.ui_window_end = ui.window_end
|
pxl8.gui_button = gui.button
|
||||||
pxl8.ui_window_set_open = ui.window_set_open
|
pxl8.gui_window = gui.window
|
||||||
|
pxl8.gui_label = gui.label
|
||||||
|
pxl8.gui_is_hovering = gui.is_hovering
|
||||||
|
pxl8.gui_get_cursor_pos = gui.get_cursor_pos
|
||||||
|
|
||||||
pxl8.world_new = world.new
|
pxl8.world_new = world.new
|
||||||
pxl8.world_destroy = world.destroy
|
pxl8.world_destroy = world.destroy
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,10 @@ local C = ffi.C
|
||||||
|
|
||||||
local core = {}
|
local core = {}
|
||||||
|
|
||||||
function core.init(gfx_ptr, input_ptr, sys_ptr, ui_ptr)
|
function core.init(gfx_ptr, input_ptr, sys_ptr)
|
||||||
core.gfx = gfx_ptr
|
core.gfx = gfx_ptr
|
||||||
core.input = input_ptr
|
core.input = input_ptr
|
||||||
core.sys = sys_ptr
|
core.sys = sys_ptr
|
||||||
core.ui = ui_ptr
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function core.get_fps()
|
function core.get_fps()
|
||||||
|
|
@ -42,4 +41,8 @@ function core.trace(msg)
|
||||||
C.pxl8_lua_trace(msg)
|
C.pxl8_lua_trace(msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function core.quit()
|
||||||
|
C.pxl8_set_running(core.sys, false)
|
||||||
|
end
|
||||||
|
|
||||||
return core
|
return core
|
||||||
|
|
|
||||||
59
src/lua/pxl8/gui.lua
Normal file
59
src/lua/pxl8/gui.lua
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
local ffi = require("ffi")
|
||||||
|
local C = ffi.C
|
||||||
|
local core = require("pxl8.core")
|
||||||
|
|
||||||
|
local gui = {}
|
||||||
|
|
||||||
|
local state = nil
|
||||||
|
|
||||||
|
local function gui_state()
|
||||||
|
if not state then
|
||||||
|
state = ffi.gc(C.pxl8_gui_state_create(), C.pxl8_gui_state_destroy)
|
||||||
|
end
|
||||||
|
return state
|
||||||
|
end
|
||||||
|
|
||||||
|
function gui.begin_frame()
|
||||||
|
C.pxl8_gui_begin_frame(gui_state())
|
||||||
|
end
|
||||||
|
|
||||||
|
function gui.end_frame()
|
||||||
|
C.pxl8_gui_end_frame(gui_state())
|
||||||
|
end
|
||||||
|
|
||||||
|
function gui.cursor_move(x, y)
|
||||||
|
C.pxl8_gui_cursor_move(gui_state(), x, y)
|
||||||
|
end
|
||||||
|
|
||||||
|
function gui.cursor_down()
|
||||||
|
C.pxl8_gui_cursor_down(gui_state())
|
||||||
|
end
|
||||||
|
|
||||||
|
function gui.cursor_up()
|
||||||
|
C.pxl8_gui_cursor_up(gui_state())
|
||||||
|
end
|
||||||
|
|
||||||
|
function gui.button(id, x, y, w, h, label)
|
||||||
|
return C.pxl8_gui_button(gui_state(), core.gfx, id, x, y, w, h, label)
|
||||||
|
end
|
||||||
|
|
||||||
|
function gui.window(x, y, w, h, title)
|
||||||
|
C.pxl8_gui_window(core.gfx, x, y, w, h, title)
|
||||||
|
end
|
||||||
|
|
||||||
|
function gui.label(x, y, text, color)
|
||||||
|
C.pxl8_gui_label(core.gfx, x, y, text, color)
|
||||||
|
end
|
||||||
|
|
||||||
|
function gui.is_hovering()
|
||||||
|
return C.pxl8_gui_is_hovering(gui_state())
|
||||||
|
end
|
||||||
|
|
||||||
|
function gui.get_cursor_pos()
|
||||||
|
local x = ffi.new("i32[1]")
|
||||||
|
local y = ffi.new("i32[1]")
|
||||||
|
C.pxl8_gui_get_cursor_pos(gui_state(), x, y)
|
||||||
|
return x[0], y[0]
|
||||||
|
end
|
||||||
|
|
||||||
|
return gui
|
||||||
|
|
@ -40,8 +40,36 @@ function input.mouse_dy()
|
||||||
return C.pxl8_mouse_dy(core.input)
|
return C.pxl8_mouse_dy(core.input)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function input.get_mouse_pos()
|
||||||
|
return C.pxl8_mouse_x(core.input), C.pxl8_mouse_y(core.input)
|
||||||
|
end
|
||||||
|
|
||||||
|
function input.mouse_pressed(button)
|
||||||
|
return C.pxl8_mouse_pressed(core.input, button)
|
||||||
|
end
|
||||||
|
|
||||||
|
function input.mouse_released(button)
|
||||||
|
return C.pxl8_mouse_released(core.input, button)
|
||||||
|
end
|
||||||
|
|
||||||
function input.set_relative_mouse_mode(enabled)
|
function input.set_relative_mouse_mode(enabled)
|
||||||
C.pxl8_set_relative_mouse_mode(core.sys, enabled)
|
C.pxl8_set_relative_mouse_mode(core.sys, enabled)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function input.center_cursor()
|
||||||
|
C.pxl8_center_cursor(core.sys)
|
||||||
|
end
|
||||||
|
|
||||||
|
function input.set_cursor(cursor_type)
|
||||||
|
local cursor_enum
|
||||||
|
if cursor_type == "arrow" then
|
||||||
|
cursor_enum = C.PXL8_CURSOR_ARROW
|
||||||
|
elseif cursor_type == "hand" then
|
||||||
|
cursor_enum = C.PXL8_CURSOR_HAND
|
||||||
|
else
|
||||||
|
cursor_enum = C.PXL8_CURSOR_ARROW
|
||||||
|
end
|
||||||
|
C.pxl8_set_cursor(core.sys, cursor_enum)
|
||||||
|
end
|
||||||
|
|
||||||
return input
|
return input
|
||||||
|
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
local ffi = require("ffi")
|
|
||||||
local C = ffi.C
|
|
||||||
local core = require("pxl8.core")
|
|
||||||
|
|
||||||
local ui = {}
|
|
||||||
|
|
||||||
function ui.button(label)
|
|
||||||
return C.pxl8_ui_button(core.ui, label)
|
|
||||||
end
|
|
||||||
|
|
||||||
function ui.checkbox(label, state)
|
|
||||||
local state_ptr = ffi.new("bool[1]", state)
|
|
||||||
local changed = C.pxl8_ui_checkbox(core.ui, label, state_ptr)
|
|
||||||
return changed, state_ptr[0]
|
|
||||||
end
|
|
||||||
|
|
||||||
function ui.has_mouse_focus()
|
|
||||||
return C.pxl8_ui_has_mouse_focus(core.ui)
|
|
||||||
end
|
|
||||||
|
|
||||||
function ui.indent(amount)
|
|
||||||
C.pxl8_ui_indent(core.ui, amount)
|
|
||||||
end
|
|
||||||
|
|
||||||
function ui.label(text)
|
|
||||||
C.pxl8_ui_label(core.ui, text)
|
|
||||||
end
|
|
||||||
|
|
||||||
function ui.layout_row(item_count, widths, height)
|
|
||||||
local widths_array = widths
|
|
||||||
if type(widths) == "table" then
|
|
||||||
widths_array = ffi.new("int[?]", #widths, widths)
|
|
||||||
elseif type(widths) == "number" then
|
|
||||||
widths_array = ffi.new("int[1]", widths)
|
|
||||||
end
|
|
||||||
C.pxl8_ui_layout_row(core.ui, item_count, widths_array, height)
|
|
||||||
end
|
|
||||||
|
|
||||||
function ui.window_begin(title, x, y, w, h, options)
|
|
||||||
local rect = ffi.new("pxl8_bounds", {x = x, y = y, w = w, h = h})
|
|
||||||
return C.pxl8_ui_window_begin(core.ui, title, rect, options or 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
function ui.window_end()
|
|
||||||
C.pxl8_ui_window_end(core.ui)
|
|
||||||
end
|
|
||||||
|
|
||||||
function ui.window_set_open(title, open)
|
|
||||||
C.pxl8_ui_window_set_open(core.ui, title, open)
|
|
||||||
end
|
|
||||||
|
|
||||||
return ui
|
|
||||||
53
src/pxl8.c
53
src/pxl8.c
|
|
@ -16,7 +16,6 @@
|
||||||
#include "pxl8_script.h"
|
#include "pxl8_script.h"
|
||||||
#include "pxl8_sys.h"
|
#include "pxl8_sys.h"
|
||||||
#include "pxl8_types.h"
|
#include "pxl8_types.h"
|
||||||
#include "pxl8_ui.h"
|
|
||||||
|
|
||||||
struct pxl8 {
|
struct pxl8 {
|
||||||
pxl8_cart* cart;
|
pxl8_cart* cart;
|
||||||
|
|
@ -127,12 +126,6 @@ pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]) {
|
||||||
return PXL8_ERROR_INITIALIZATION_FAILED;
|
return PXL8_ERROR_INITIALIZATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
game->ui = pxl8_ui_create(game->gfx);
|
|
||||||
if (!game->ui) {
|
|
||||||
pxl8_error("Failed to create UI");
|
|
||||||
return PXL8_ERROR_INITIALIZATION_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
game->script = pxl8_script_create();
|
game->script = pxl8_script_create();
|
||||||
if (!game->script) {
|
if (!game->script) {
|
||||||
pxl8_error("Failed to initialize scripting: %s", pxl8_script_get_last_error(game->script));
|
pxl8_error("Failed to initialize scripting: %s", pxl8_script_get_last_error(game->script));
|
||||||
|
|
@ -170,7 +163,6 @@ pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]) {
|
||||||
pxl8_script_set_gfx(game->script, game->gfx);
|
pxl8_script_set_gfx(game->script, game->gfx);
|
||||||
pxl8_script_set_input(game->script, &game->input);
|
pxl8_script_set_input(game->script, &game->input);
|
||||||
pxl8_script_set_sys(game->script, sys);
|
pxl8_script_set_sys(game->script, sys);
|
||||||
pxl8_script_set_ui(game->script, game->ui);
|
|
||||||
|
|
||||||
if (game->script_path[0] != '\0') {
|
if (game->script_path[0] != '\0') {
|
||||||
pxl8_result result = pxl8_script_load_main(game->script, game->script_path);
|
pxl8_result result = pxl8_script_load_main(game->script, game->script_path);
|
||||||
|
|
@ -252,34 +244,6 @@ pxl8_result pxl8_update(pxl8* sys) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game->ui) {
|
|
||||||
pxl8_ui_input_mousemove(game->ui, game->input.mouse_x, game->input.mouse_y);
|
|
||||||
|
|
||||||
if (game->input.mouse_wheel_x != 0 || game->input.mouse_wheel_y != 0) {
|
|
||||||
pxl8_ui_input_scroll(game->ui, game->input.mouse_wheel_x * 10, -game->input.mouse_wheel_y * 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i32 i = 0; i < 3; i++) {
|
|
||||||
if (game->input.mouse_buttons_pressed[i]) {
|
|
||||||
pxl8_ui_input_mousedown(game->ui, game->input.mouse_x, game->input.mouse_y, i + 1);
|
|
||||||
}
|
|
||||||
if (game->input.mouse_buttons_released[i]) {
|
|
||||||
pxl8_ui_input_mouseup(game->ui, game->input.mouse_x, game->input.mouse_y, i + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i32 key = 0; key < 256; key++) {
|
|
||||||
if (game->input.keys_pressed[key]) {
|
|
||||||
pxl8_ui_input_keydown(game->ui, key);
|
|
||||||
}
|
|
||||||
if (!game->input.keys_down[key] && game->input.keys_pressed[key]) {
|
|
||||||
pxl8_ui_input_keyup(game->ui, key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pxl8_ui_frame_begin(game->ui);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (game->script_loaded) {
|
if (game->script_loaded) {
|
||||||
pxl8_script_call_function_f32(game->script, "update", dt);
|
pxl8_script_call_function_f32(game->script, "update", dt);
|
||||||
}
|
}
|
||||||
|
|
@ -315,10 +279,6 @@ pxl8_result pxl8_frame(pxl8* sys) {
|
||||||
|
|
||||||
pxl8_size render_size = pxl8_get_resolution_dimensions(game->resolution);
|
pxl8_size render_size = pxl8_get_resolution_dimensions(game->resolution);
|
||||||
|
|
||||||
if (game->ui) {
|
|
||||||
pxl8_ui_frame_end(game->ui);
|
|
||||||
}
|
|
||||||
|
|
||||||
pxl8_gfx_set_viewport(game->gfx, pxl8_gfx_viewport(bounds, render_size.w, render_size.h));
|
pxl8_gfx_set_viewport(game->gfx, pxl8_gfx_viewport(bounds, render_size.w, render_size.h));
|
||||||
pxl8_gfx_upload_framebuffer(game->gfx);
|
pxl8_gfx_upload_framebuffer(game->gfx);
|
||||||
pxl8_gfx_upload_atlas(game->gfx);
|
pxl8_gfx_upload_atlas(game->gfx);
|
||||||
|
|
@ -332,8 +292,6 @@ pxl8_result pxl8_frame(pxl8* sys) {
|
||||||
game->input.mouse_dy = 0;
|
game->input.mouse_dy = 0;
|
||||||
game->input.mouse_wheel_x = 0;
|
game->input.mouse_wheel_x = 0;
|
||||||
game->input.mouse_wheel_y = 0;
|
game->input.mouse_wheel_y = 0;
|
||||||
game->input.mouse_x = 0;
|
|
||||||
game->input.mouse_y = 0;
|
|
||||||
|
|
||||||
game->frame_count++;
|
game->frame_count++;
|
||||||
|
|
||||||
|
|
@ -360,7 +318,6 @@ void pxl8_quit(pxl8* sys) {
|
||||||
|
|
||||||
pxl8_gfx_destroy(game->gfx);
|
pxl8_gfx_destroy(game->gfx);
|
||||||
pxl8_script_destroy(game->script);
|
pxl8_script_destroy(game->script);
|
||||||
if (game->ui) pxl8_ui_destroy(game->ui);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pxl8_is_running(const pxl8* sys) {
|
bool pxl8_is_running(const pxl8* sys) {
|
||||||
|
|
@ -389,6 +346,16 @@ pxl8_resolution pxl8_get_resolution(const pxl8* sys) {
|
||||||
return (sys && sys->game) ? sys->game->resolution : PXL8_RESOLUTION_640x360;
|
return (sys && sys->game) ? sys->game->resolution : PXL8_RESOLUTION_640x360;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pxl8_center_cursor(pxl8* sys) {
|
||||||
|
if (!sys || !sys->hal || !sys->hal->center_cursor) return;
|
||||||
|
sys->hal->center_cursor(sys->platform_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_set_cursor(pxl8* sys, pxl8_cursor cursor) {
|
||||||
|
if (!sys || !sys->hal || !sys->hal->set_cursor) return;
|
||||||
|
sys->hal->set_cursor(sys->platform_data, cursor);
|
||||||
|
}
|
||||||
|
|
||||||
void pxl8_set_relative_mouse_mode(pxl8* sys, bool enabled) {
|
void pxl8_set_relative_mouse_mode(pxl8* sys, bool enabled) {
|
||||||
if (!sys || !sys->hal || !sys->hal->set_relative_mouse_mode) return;
|
if (!sys || !sys->hal || !sys->hal->set_relative_mouse_mode) return;
|
||||||
sys->hal->set_relative_mouse_mode(sys->platform_data, enabled);
|
sys->hal->set_relative_mouse_mode(sys->platform_data, enabled);
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,12 @@
|
||||||
#include "pxl8_gfx.h"
|
#include "pxl8_gfx.h"
|
||||||
#include "pxl8_script.h"
|
#include "pxl8_script.h"
|
||||||
#include "pxl8_types.h"
|
#include "pxl8_types.h"
|
||||||
#include "pxl8_ui.h"
|
|
||||||
|
|
||||||
typedef struct pxl8_game {
|
typedef struct pxl8_game {
|
||||||
pxl8_color_mode color_mode;
|
pxl8_color_mode color_mode;
|
||||||
pxl8_gfx* gfx;
|
pxl8_gfx* gfx;
|
||||||
pxl8_resolution resolution;
|
pxl8_resolution resolution;
|
||||||
pxl8_script* script;
|
pxl8_script* script;
|
||||||
pxl8_ui* ui;
|
|
||||||
|
|
||||||
i32 frame_count;
|
i32 frame_count;
|
||||||
u64 last_time;
|
u64 last_time;
|
||||||
|
|
|
||||||
131
src/pxl8_gui.c
Normal file
131
src/pxl8_gui.c
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
#include "pxl8_gui.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
pxl8_gui_state* pxl8_gui_state_create(void) {
|
||||||
|
pxl8_gui_state* state = (pxl8_gui_state*)malloc(sizeof(pxl8_gui_state));
|
||||||
|
if (!state) return NULL;
|
||||||
|
|
||||||
|
memset(state, 0, sizeof(pxl8_gui_state));
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_gui_state_destroy(pxl8_gui_state* state) {
|
||||||
|
if (!state) return;
|
||||||
|
free(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_gui_begin_frame(pxl8_gui_state* state) {
|
||||||
|
if (!state) return;
|
||||||
|
state->hot_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_gui_end_frame(pxl8_gui_state* state) {
|
||||||
|
if (!state) return;
|
||||||
|
|
||||||
|
if (!state->cursor_down) {
|
||||||
|
state->active_id = 0;
|
||||||
|
}
|
||||||
|
state->cursor_clicked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_gui_cursor_move(pxl8_gui_state* state, i32 x, i32 y) {
|
||||||
|
if (!state) return;
|
||||||
|
state->cursor_x = x;
|
||||||
|
state->cursor_y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_gui_cursor_down(pxl8_gui_state* state) {
|
||||||
|
if (!state) return;
|
||||||
|
state->cursor_down = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_gui_cursor_up(pxl8_gui_state* state) {
|
||||||
|
if (!state) return;
|
||||||
|
state->cursor_down = false;
|
||||||
|
state->cursor_clicked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_cursor_over(const pxl8_gui_state* state, i32 x, i32 y, i32 w, i32 h) {
|
||||||
|
return state->cursor_x >= x && state->cursor_x < (x + w) &&
|
||||||
|
state->cursor_y >= y && state->cursor_y < (y + h);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pxl8_gui_button(pxl8_gui_state* state, pxl8_gfx* gfx, u32 id, i32 x, i32 y, i32 w, i32 h, const char* label) {
|
||||||
|
if (!state || !gfx || !label) return false;
|
||||||
|
|
||||||
|
bool cursor_over = is_cursor_over(state, x, y, w, h);
|
||||||
|
bool is_hot = (state->hot_id == id);
|
||||||
|
bool is_active = (state->active_id == id);
|
||||||
|
|
||||||
|
if (cursor_over) {
|
||||||
|
state->hot_id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor_over && state->cursor_down && state->active_id == 0) {
|
||||||
|
state->active_id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool clicked = is_active && state->cursor_clicked && cursor_over;
|
||||||
|
if (clicked) {
|
||||||
|
state->active_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 bg_color;
|
||||||
|
u8 border_color;
|
||||||
|
i32 offset_x = 0;
|
||||||
|
i32 offset_y = 0;
|
||||||
|
|
||||||
|
if (is_active) {
|
||||||
|
bg_color = 4;
|
||||||
|
border_color = 3;
|
||||||
|
offset_x = 1;
|
||||||
|
offset_y = 1;
|
||||||
|
} else if (is_hot || cursor_over) {
|
||||||
|
bg_color = 4;
|
||||||
|
border_color = 8;
|
||||||
|
} else {
|
||||||
|
bg_color = 3;
|
||||||
|
border_color = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_rect_fill(gfx, x, y, w, h, bg_color);
|
||||||
|
pxl8_rect(gfx, x, y, w, h, border_color);
|
||||||
|
|
||||||
|
i32 text_len = (i32)strlen(label);
|
||||||
|
i32 text_x = x + (w / 2) - ((text_len * 8) / 2) + offset_x;
|
||||||
|
i32 text_y = y + (h / 2) - 5 + offset_y;
|
||||||
|
pxl8_text(gfx, label, text_x, text_y, 6);
|
||||||
|
|
||||||
|
return clicked;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_gui_window(pxl8_gfx* gfx, i32 x, i32 y, i32 w, i32 h, const char* title) {
|
||||||
|
if (!gfx || !title) return;
|
||||||
|
|
||||||
|
pxl8_rect_fill(gfx, x, y, w, 28, 1);
|
||||||
|
pxl8_rect_fill(gfx, x, y + 28, w, h - 28, 2);
|
||||||
|
pxl8_rect(gfx, x, y, w, h, 4);
|
||||||
|
pxl8_rect_fill(gfx, x, y + 28, w, 1, 4);
|
||||||
|
|
||||||
|
i32 title_x = x + 10;
|
||||||
|
i32 title_y = y + (28 / 2) - 5;
|
||||||
|
pxl8_text(gfx, title, title_x, title_y, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_gui_label(pxl8_gfx* gfx, i32 x, i32 y, const char* text, u8 color) {
|
||||||
|
if (!gfx || !text) return;
|
||||||
|
pxl8_text(gfx, text, x, y, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pxl8_gui_is_hovering(const pxl8_gui_state* state) {
|
||||||
|
if (!state) return false;
|
||||||
|
return state->hot_id != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_gui_get_cursor_pos(const pxl8_gui_state* state, i32* x, i32* y) {
|
||||||
|
if (!state) return;
|
||||||
|
if (x) *x = state->cursor_x;
|
||||||
|
if (y) *y = state->cursor_y;
|
||||||
|
}
|
||||||
38
src/pxl8_gui.h
Normal file
38
src/pxl8_gui.h
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pxl8_gfx.h"
|
||||||
|
#include "pxl8_types.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
i32 cursor_x;
|
||||||
|
i32 cursor_y;
|
||||||
|
bool cursor_down;
|
||||||
|
bool cursor_clicked;
|
||||||
|
u32 hot_id;
|
||||||
|
u32 active_id;
|
||||||
|
} pxl8_gui_state;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pxl8_gui_state* pxl8_gui_state_create(void);
|
||||||
|
void pxl8_gui_state_destroy(pxl8_gui_state* state);
|
||||||
|
|
||||||
|
void pxl8_gui_begin_frame(pxl8_gui_state* state);
|
||||||
|
void pxl8_gui_end_frame(pxl8_gui_state* state);
|
||||||
|
|
||||||
|
void pxl8_gui_cursor_move(pxl8_gui_state* state, i32 x, i32 y);
|
||||||
|
void pxl8_gui_cursor_down(pxl8_gui_state* state);
|
||||||
|
void pxl8_gui_cursor_up(pxl8_gui_state* state);
|
||||||
|
|
||||||
|
bool pxl8_gui_button(pxl8_gui_state* state, pxl8_gfx* gfx, u32 id, i32 x, i32 y, i32 w, i32 h, const char* label);
|
||||||
|
void pxl8_gui_window(pxl8_gfx* gfx, i32 x, i32 y, i32 w, i32 h, const char* title);
|
||||||
|
void pxl8_gui_label(pxl8_gfx* gfx, i32 x, i32 y, const char* text, u8 color);
|
||||||
|
|
||||||
|
bool pxl8_gui_is_hovering(const pxl8_gui_state* state);
|
||||||
|
void pxl8_gui_get_cursor_pos(const pxl8_gui_state* state, i32* x, i32* y);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -12,7 +12,9 @@ typedef struct pxl8_hal {
|
||||||
|
|
||||||
u64 (*get_ticks)(void);
|
u64 (*get_ticks)(void);
|
||||||
|
|
||||||
|
void (*center_cursor)(void* platform_data);
|
||||||
void (*present)(void* platform_data);
|
void (*present)(void* platform_data);
|
||||||
|
void (*set_cursor)(void* platform_data, pxl8_cursor cursor);
|
||||||
void (*set_relative_mouse_mode)(void* platform_data, bool enabled);
|
void (*set_relative_mouse_mode)(void* platform_data, bool enabled);
|
||||||
void (*upload_atlas)(void* platform_data, const pxl8_atlas* atlas,
|
void (*upload_atlas)(void* platform_data, const pxl8_atlas* atlas,
|
||||||
const u32* palette, pxl8_color_mode mode);
|
const u32* palette, pxl8_color_mode mode);
|
||||||
|
|
|
||||||
|
|
@ -170,6 +170,16 @@ i32 pxl8_mouse_wheel_y(const pxl8_input_state* input) {
|
||||||
return input->mouse_wheel_y;
|
return input->mouse_wheel_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool pxl8_mouse_pressed(const pxl8_input_state* input, i32 button) {
|
||||||
|
if (!input || button < 1 || button > 3) return false;
|
||||||
|
return input->mouse_buttons_pressed[button - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pxl8_mouse_released(const pxl8_input_state* input, i32 button) {
|
||||||
|
if (!input || button < 1 || button > 3) return false;
|
||||||
|
return input->mouse_buttons_released[button - 1];
|
||||||
|
}
|
||||||
|
|
||||||
i32 pxl8_mouse_x(const pxl8_input_state* input) {
|
i32 pxl8_mouse_x(const pxl8_input_state* input) {
|
||||||
if (!input) return 0;
|
if (!input) return 0;
|
||||||
return input->mouse_x;
|
return input->mouse_x;
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,8 @@ bool pxl8_key_down(const pxl8_input_state* input, const char* key_name);
|
||||||
bool pxl8_key_pressed(const pxl8_input_state* input, const char* key_name);
|
bool pxl8_key_pressed(const pxl8_input_state* input, const char* key_name);
|
||||||
bool pxl8_key_released(const pxl8_input_state* input, const char* key_name);
|
bool pxl8_key_released(const pxl8_input_state* input, const char* key_name);
|
||||||
|
|
||||||
|
bool pxl8_mouse_pressed(const pxl8_input_state* input, i32 button);
|
||||||
|
bool pxl8_mouse_released(const pxl8_input_state* input, i32 button);
|
||||||
i32 pxl8_mouse_wheel_x(const pxl8_input_state* input);
|
i32 pxl8_mouse_wheel_x(const pxl8_input_state* input);
|
||||||
i32 pxl8_mouse_wheel_y(const pxl8_input_state* input);
|
i32 pxl8_mouse_wheel_y(const pxl8_input_state* input);
|
||||||
i32 pxl8_mouse_x(const pxl8_input_state* input);
|
i32 pxl8_mouse_x(const pxl8_input_state* input);
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,12 @@
|
||||||
#include <lualib.h>
|
#include <lualib.h>
|
||||||
|
|
||||||
#include "pxl8_macros.h"
|
#include "pxl8_macros.h"
|
||||||
#include "pxl8_ui.h"
|
#include "pxl8_gui.h"
|
||||||
|
|
||||||
struct pxl8_script {
|
struct pxl8_script {
|
||||||
lua_State* L;
|
lua_State* L;
|
||||||
pxl8_gfx* gfx;
|
pxl8_gfx* gfx;
|
||||||
pxl8_input_state* input;
|
pxl8_input_state* input;
|
||||||
pxl8_ui* ui;
|
|
||||||
char last_error[2048];
|
char last_error[2048];
|
||||||
char main_path[256];
|
char main_path[256];
|
||||||
char watch_dir[256];
|
char watch_dir[256];
|
||||||
|
|
@ -109,13 +108,19 @@ static const char* pxl8_ffi_cdefs =
|
||||||
"bool pxl8_key_down(const pxl8_input_state* input, const char* key_name);\n"
|
"bool pxl8_key_down(const pxl8_input_state* input, const char* key_name);\n"
|
||||||
"bool pxl8_key_pressed(const pxl8_input_state* input, const char* key_name);\n"
|
"bool pxl8_key_pressed(const pxl8_input_state* input, const char* key_name);\n"
|
||||||
"bool pxl8_key_released(const pxl8_input_state* input, const char* key_name);\n"
|
"bool pxl8_key_released(const pxl8_input_state* input, const char* key_name);\n"
|
||||||
|
"bool pxl8_mouse_pressed(const pxl8_input_state* input, i32 button);\n"
|
||||||
|
"bool pxl8_mouse_released(const pxl8_input_state* input, i32 button);\n"
|
||||||
"int pxl8_mouse_wheel_x(const pxl8_input_state* input);\n"
|
"int pxl8_mouse_wheel_x(const pxl8_input_state* input);\n"
|
||||||
"int pxl8_mouse_wheel_y(const pxl8_input_state* input);\n"
|
"int pxl8_mouse_wheel_y(const pxl8_input_state* input);\n"
|
||||||
"int pxl8_mouse_x(const pxl8_input_state* input);\n"
|
"int pxl8_mouse_x(const pxl8_input_state* input);\n"
|
||||||
"int pxl8_mouse_y(const pxl8_input_state* input);\n"
|
"int pxl8_mouse_y(const pxl8_input_state* input);\n"
|
||||||
"int pxl8_mouse_dx(const pxl8_input_state* input);\n"
|
"int pxl8_mouse_dx(const pxl8_input_state* input);\n"
|
||||||
"int pxl8_mouse_dy(const pxl8_input_state* input);\n"
|
"int pxl8_mouse_dy(const pxl8_input_state* input);\n"
|
||||||
|
"typedef enum { PXL8_CURSOR_ARROW = 0, PXL8_CURSOR_HAND = 1 } pxl8_cursor;\n"
|
||||||
|
"void pxl8_center_cursor(pxl8* sys);\n"
|
||||||
|
"void pxl8_set_cursor(pxl8* sys, pxl8_cursor cursor);\n"
|
||||||
"void pxl8_set_relative_mouse_mode(pxl8* sys, bool enabled);\n"
|
"void pxl8_set_relative_mouse_mode(pxl8* sys, bool enabled);\n"
|
||||||
|
"void pxl8_set_running(pxl8* sys, bool running);\n"
|
||||||
"void pxl8_lua_debug(const char* msg);\n"
|
"void pxl8_lua_debug(const char* msg);\n"
|
||||||
"void pxl8_lua_error(const char* msg);\n"
|
"void pxl8_lua_error(const char* msg);\n"
|
||||||
"void pxl8_lua_info(const char* msg);\n"
|
"void pxl8_lua_info(const char* msg);\n"
|
||||||
|
|
@ -303,32 +308,19 @@ static const char* pxl8_ffi_cdefs =
|
||||||
"void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos);\n"
|
"void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos);\n"
|
||||||
"void pxl8_world_unload(pxl8_world* world);\n"
|
"void pxl8_world_unload(pxl8_world* world);\n"
|
||||||
"\n"
|
"\n"
|
||||||
"typedef struct pxl8_ui pxl8_ui;\n"
|
"typedef struct { i32 cursor_x; i32 cursor_y; bool cursor_down; bool cursor_clicked; u32 hot_id; u32 active_id; } pxl8_gui_state;\n"
|
||||||
"typedef struct { unsigned char bg_color; unsigned int sprite_id; int corner_size; int edge_size; int padding; } pxl8_frame_theme;\n"
|
"pxl8_gui_state* pxl8_gui_state_create(void);\n"
|
||||||
"typedef struct { bool enabled; const char* label; } pxl8_menu_item;\n"
|
"void pxl8_gui_state_destroy(pxl8_gui_state* state);\n"
|
||||||
"pxl8_ui* pxl8_ui_create(pxl8_gfx* gfx);\n"
|
"void pxl8_gui_begin_frame(pxl8_gui_state* state);\n"
|
||||||
"void pxl8_ui_destroy(pxl8_ui* ui);\n"
|
"void pxl8_gui_end_frame(pxl8_gui_state* state);\n"
|
||||||
"void pxl8_ui_frame_begin(pxl8_ui* ui);\n"
|
"void pxl8_gui_cursor_move(pxl8_gui_state* state, i32 x, i32 y);\n"
|
||||||
"void pxl8_ui_frame_end(pxl8_ui* ui);\n"
|
"void pxl8_gui_cursor_down(pxl8_gui_state* state);\n"
|
||||||
"void pxl8_ui_input_keydown(pxl8_ui* ui, int key);\n"
|
"void pxl8_gui_cursor_up(pxl8_gui_state* state);\n"
|
||||||
"void pxl8_ui_input_keyup(pxl8_ui* ui, int key);\n"
|
"bool pxl8_gui_button(pxl8_gui_state* state, pxl8_gfx* gfx, u32 id, i32 x, i32 y, i32 w, i32 h, const char* label);\n"
|
||||||
"void pxl8_ui_input_mousedown(pxl8_ui* ui, int x, int y, int button);\n"
|
"void pxl8_gui_window(pxl8_gfx* gfx, i32 x, i32 y, i32 w, i32 h, const char* title);\n"
|
||||||
"void pxl8_ui_input_mousemove(pxl8_ui* ui, int x, int y);\n"
|
"void pxl8_gui_label(pxl8_gfx* gfx, i32 x, i32 y, const char* text, u8 color);\n"
|
||||||
"void pxl8_ui_input_mouseup(pxl8_ui* ui, int x, int y, int button);\n"
|
"bool pxl8_gui_is_hovering(const pxl8_gui_state* state);\n"
|
||||||
"void pxl8_ui_input_scroll(pxl8_ui* ui, int x, int y);\n"
|
"void pxl8_gui_get_cursor_pos(const pxl8_gui_state* state, i32* x, i32* y);\n";
|
||||||
"void pxl8_ui_input_text(pxl8_ui* ui, const char* text);\n"
|
|
||||||
"bool pxl8_ui_button(pxl8_ui* ui, const char* label);\n"
|
|
||||||
"bool pxl8_ui_checkbox(pxl8_ui* ui, const char* label, bool* state);\n"
|
|
||||||
"bool pxl8_ui_has_mouse_focus(pxl8_ui* ui);\n"
|
|
||||||
"void pxl8_ui_indent(pxl8_ui* ui, int amount);\n"
|
|
||||||
"void pxl8_ui_label(pxl8_ui* ui, const char* text);\n"
|
|
||||||
"void pxl8_ui_layout_row(pxl8_ui* ui, int item_count, const int* widths, int height);\n"
|
|
||||||
"int pxl8_ui_menu(pxl8_ui* ui, pxl8_menu_item* items, int item_count);\n"
|
|
||||||
"void pxl8_ui_panel(pxl8_ui* ui, pxl8_bounds rect, pxl8_frame_theme* theme);\n"
|
|
||||||
"bool pxl8_ui_window_begin(pxl8_ui* ui, const char* title, pxl8_bounds rect, int options);\n"
|
|
||||||
"void pxl8_ui_window_end(pxl8_ui* ui);\n"
|
|
||||||
"void pxl8_ui_window_set_open(pxl8_ui* ui, const char* title, bool open);\n"
|
|
||||||
"pxl8_frame_theme pxl8_ui_theme_default(void);\n";
|
|
||||||
|
|
||||||
void pxl8_lua_info(const char* msg) {
|
void pxl8_lua_info(const char* msg) {
|
||||||
pxl8_info("%s", msg);
|
pxl8_info("%s", msg);
|
||||||
|
|
@ -444,14 +436,6 @@ void pxl8_script_set_input(pxl8_script* script, pxl8_input_state* input) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_script_set_ui(pxl8_script* script, pxl8_ui* ui) {
|
|
||||||
if (!script) return;
|
|
||||||
script->ui = ui;
|
|
||||||
if (script->L && ui) {
|
|
||||||
lua_pushlightuserdata(script->L, ui);
|
|
||||||
lua_setglobal(script->L, "_pxl8_ui");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void pxl8_script_set_sys(pxl8_script* script, void* sys) {
|
void pxl8_script_set_sys(pxl8_script* script, void* sys) {
|
||||||
if (!script) return;
|
if (!script) return;
|
||||||
|
|
@ -719,16 +703,27 @@ static time_t get_latest_script_mod_time(const char* dir_path) {
|
||||||
while ((entry = readdir(dir)) != NULL) {
|
while ((entry = readdir(dir)) != NULL) {
|
||||||
if (entry->d_name[0] == '.') continue;
|
if (entry->d_name[0] == '.') continue;
|
||||||
|
|
||||||
size_t len = strlen(entry->d_name);
|
char full_path[512];
|
||||||
bool is_script = (len > 4 && strcmp(entry->d_name + len - 4, ".fnl") == 0) ||
|
snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, entry->d_name);
|
||||||
(len > 4 && strcmp(entry->d_name + len - 4, ".lua") == 0);
|
|
||||||
|
|
||||||
if (is_script) {
|
struct stat st;
|
||||||
char full_path[512];
|
if (stat(full_path, &st) == 0) {
|
||||||
snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, entry->d_name);
|
if (S_ISDIR(st.st_mode)) {
|
||||||
time_t mod_time = get_file_mod_time(full_path);
|
time_t subdir_time = get_latest_script_mod_time(full_path);
|
||||||
if (mod_time > latest) {
|
if (subdir_time > latest) {
|
||||||
latest = mod_time;
|
latest = subdir_time;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
size_t len = strlen(entry->d_name);
|
||||||
|
bool is_script = (len > 4 && strcmp(entry->d_name + len - 4, ".fnl") == 0) ||
|
||||||
|
(len > 4 && strcmp(entry->d_name + len - 4, ".lua") == 0);
|
||||||
|
|
||||||
|
if (is_script) {
|
||||||
|
time_t mod_time = get_file_mod_time(full_path);
|
||||||
|
if (mod_time > latest) {
|
||||||
|
latest = mod_time;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#include "pxl8_gfx.h"
|
#include "pxl8_gfx.h"
|
||||||
#include "pxl8_types.h"
|
#include "pxl8_types.h"
|
||||||
#include "pxl8_ui.h"
|
|
||||||
|
|
||||||
typedef struct pxl8_script pxl8_script;
|
typedef struct pxl8_script pxl8_script;
|
||||||
typedef struct pxl8_script_repl pxl8_script_repl;
|
typedef struct pxl8_script_repl pxl8_script_repl;
|
||||||
|
|
@ -20,7 +19,6 @@ void pxl8_script_set_cart_path(pxl8_script* script, const char* cart_path, const
|
||||||
void pxl8_script_set_gfx(pxl8_script* script, pxl8_gfx* gfx);
|
void pxl8_script_set_gfx(pxl8_script* script, pxl8_gfx* gfx);
|
||||||
void pxl8_script_set_input(pxl8_script* script, pxl8_input_state* input);
|
void pxl8_script_set_input(pxl8_script* script, pxl8_input_state* input);
|
||||||
void pxl8_script_set_sys(pxl8_script* script, void* sys);
|
void pxl8_script_set_sys(pxl8_script* script, void* sys);
|
||||||
void pxl8_script_set_ui(pxl8_script* script, pxl8_ui* ui);
|
|
||||||
|
|
||||||
pxl8_result pxl8_script_call_function(pxl8_script* script, const char* name);
|
pxl8_result pxl8_script_call_function(pxl8_script* script, const char* name);
|
||||||
pxl8_result pxl8_script_call_function_f32(pxl8_script* script, const char* name, f32 arg);
|
pxl8_result pxl8_script_call_function_f32(pxl8_script* script, const char* name, f32 arg);
|
||||||
|
|
|
||||||
|
|
@ -367,11 +367,45 @@ static void sdl3_set_relative_mouse_mode(void* platform_data, bool enabled) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sdl3_set_cursor(void* platform_data, pxl8_cursor cursor) {
|
||||||
|
if (!platform_data) return;
|
||||||
|
|
||||||
|
SDL_SystemCursor sdl_cursor;
|
||||||
|
switch (cursor) {
|
||||||
|
case PXL8_CURSOR_ARROW:
|
||||||
|
sdl_cursor = SDL_SYSTEM_CURSOR_DEFAULT;
|
||||||
|
break;
|
||||||
|
case PXL8_CURSOR_HAND:
|
||||||
|
sdl_cursor = SDL_SYSTEM_CURSOR_POINTER;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sdl_cursor = SDL_SYSTEM_CURSOR_DEFAULT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Cursor* cursor_obj = SDL_CreateSystemCursor(sdl_cursor);
|
||||||
|
if (cursor_obj) {
|
||||||
|
SDL_SetCursor(cursor_obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sdl3_center_cursor(void* platform_data) {
|
||||||
|
if (!platform_data) return;
|
||||||
|
|
||||||
|
pxl8_sdl3_context* ctx = (pxl8_sdl3_context*)platform_data;
|
||||||
|
i32 w, h;
|
||||||
|
if (SDL_GetWindowSize(ctx->window, &w, &h)) {
|
||||||
|
SDL_WarpMouseInWindow(ctx->window, w / 2, h / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const pxl8_hal pxl8_hal_sdl3 = {
|
const pxl8_hal pxl8_hal_sdl3 = {
|
||||||
.create = sdl3_create,
|
.create = sdl3_create,
|
||||||
.destroy = sdl3_destroy,
|
.destroy = sdl3_destroy,
|
||||||
.get_ticks = sdl3_get_ticks,
|
.get_ticks = sdl3_get_ticks,
|
||||||
|
.center_cursor = sdl3_center_cursor,
|
||||||
.present = sdl3_present,
|
.present = sdl3_present,
|
||||||
|
.set_cursor = sdl3_set_cursor,
|
||||||
.upload_atlas = sdl3_upload_atlas,
|
.upload_atlas = sdl3_upload_atlas,
|
||||||
.upload_framebuffer = sdl3_upload_framebuffer,
|
.upload_framebuffer = sdl3_upload_framebuffer,
|
||||||
.set_relative_mouse_mode = sdl3_set_relative_mouse_mode,
|
.set_relative_mouse_mode = sdl3_set_relative_mouse_mode,
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ pxl8_gfx* pxl8_get_gfx(const pxl8* sys);
|
||||||
pxl8_input_state* pxl8_get_input(const pxl8* sys);
|
pxl8_input_state* pxl8_get_input(const pxl8* sys);
|
||||||
pxl8_resolution pxl8_get_resolution(const pxl8* sys);
|
pxl8_resolution pxl8_get_resolution(const pxl8* sys);
|
||||||
|
|
||||||
|
void pxl8_center_cursor(pxl8* sys);
|
||||||
|
void pxl8_set_cursor(pxl8* sys, pxl8_cursor cursor);
|
||||||
void pxl8_set_relative_mouse_mode(pxl8* sys, bool enabled);
|
void pxl8_set_relative_mouse_mode(pxl8* sys, bool enabled);
|
||||||
|
|
||||||
pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]);
|
pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]);
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,11 @@ typedef enum pxl8_color_mode {
|
||||||
PXL8_COLOR_MODE_SNES
|
PXL8_COLOR_MODE_SNES
|
||||||
} pxl8_color_mode;
|
} pxl8_color_mode;
|
||||||
|
|
||||||
|
typedef enum pxl8_cursor {
|
||||||
|
PXL8_CURSOR_ARROW,
|
||||||
|
PXL8_CURSOR_HAND
|
||||||
|
} pxl8_cursor;
|
||||||
|
|
||||||
typedef enum pxl8_resolution {
|
typedef enum pxl8_resolution {
|
||||||
PXL8_RESOLUTION_240x160,
|
PXL8_RESOLUTION_240x160,
|
||||||
PXL8_RESOLUTION_320x180,
|
PXL8_RESOLUTION_320x180,
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,6 @@ pxl8_result pxl8_world_generate(pxl8_world* world, pxl8_gfx* gfx, const pxl8_pro
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_debug("World generation succeeded, setting loaded=true");
|
|
||||||
world->loaded = true;
|
world->loaded = true;
|
||||||
return PXL8_OK;
|
return PXL8_OK;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue