Browse Source

Added a UI

* Make it possible to select via the atlas, which is useful for
disambiguating overlapping shapes
* Added simple immediate-mode buttons
master
Macoy Madson 2 months ago
parent
commit
58d28ac356
  1. 288
      src/VectorPuppetShow.cake

288
src/VectorPuppetShow.cake

@ -31,6 +31,7 @@
(define-keybind s-view-puppet-keybind (array SDL_SCANCODE_F4))
(define-keybind s-do-inverse-kinematics-keybind (array SDL_SCANCODE_SPACE))
(define-keybind s-toggle-inverse-kinematics-keybind (array SDL_SCANCODE_I))
(define-keybind s-assigning-parent-keybind (array SDL_SCANCODE_P))
(define-keybind s-toggle-fullscreen-keybind (array SDL_SCANCODE_F11))
@ -109,7 +110,7 @@
(def-introspect-struct skeleton-data
svg-name (array 64 char)
bones (array 64 skeleton-bone) ('array-allow-subset))
bones (array 128 skeleton-bone) ('array-allow-subset))
(defun-local get-skeleton-filename-from-svg-filename (svg-name (addr (const char))
filename-out (addr char)
@ -405,6 +406,129 @@
(set (path child-bone > pose-start-position) child-pose-start-position)
(set (path child-bone > pose-end-position) child-pose-end-position)))))
(defun-local get-bone-for-shape (shape (addr NSVGshape)
skeleton (addr skeleton-data)
&return (addr skeleton-bone))
(var selected-bone (addr skeleton-bone) null)
(each-item-addr-in-array (path skeleton > bones) bone-index bone (addr skeleton-bone)
;; Assign bone to empty slot
(unless (at 0 (path bone > shape-id))
(snprintf (path bone > shape-id) (sizeof (path bone > shape-id))
"%s" (path shape > id))
(set selected-bone bone)
(break))
(when (= 0 (strncmp (path shape > id) (path bone > shape-id)
(sizeof (path bone > shape-id))))
(set selected-bone bone)
(break)))
(return selected-bone))
;; Hack!
(defmacro on-select-shape (shape-to-select any
sized-bounds any)
(tokenize-push output
(var previous-selected-bone (addr skeleton-bone) selected-bone)
(set selected-shape (token-splice shape-to-select))
(memcpy selected-shape-bounds (token-splice sized-bounds) (sizeof selected-shape-bounds))
(set selected-bone (get-bone-for-shape (token-splice shape-to-select) (addr skeleton)))
(when (and previous-selected-bone assigning-parent)
(set assigning-parent false)
(snprintf (path previous-selected-bone > parent-shape-id)
(sizeof (path previous-selected-bone > parent-shape-id))
"%s" (path shape > id))))
(return true))
(defun-local is-point-in-sdl-rect (point-x int point-y int
rectangle (addr SDL_Rect)
&return bool)
(return (and (>= point-x (path rectangle > x))
(>= point-y (path rectangle > y))
(< point-x (+ (path rectangle > x)
(path rectangle > w)))
(< point-y (+ (path rectangle > y)
(path rectangle > h))))))
(defstruct imgui-state
mouse-state-changed bool
is-mouse-down bool
;; Note that this is cleared when the mouse is released, but mouse-down-x is still usable
active-widget (unsigned int)
mouse-down-x int
mouse-down-y int)
(var s-imgui-state imgui-state (array 0))
(defun-local imgui-start-frame ()
(var mouse-x int 0)
(var mouse-y int 0)
(var mouse-button-state Uint32
(SDL_GetMouseState (addr mouse-x) (addr mouse-y)))
(set (field s-imgui-state mouse-state-changed) false)
(when (and (not (field s-imgui-state is-mouse-down))
(bit-and mouse-button-state SDL_BUTTON_LMASK))
(set (field s-imgui-state mouse-state-changed) true)
(set (field s-imgui-state mouse-down-x) mouse-x)
(set (field s-imgui-state mouse-down-y) mouse-y))
(when (and (field s-imgui-state is-mouse-down)
(not (bit-and mouse-button-state SDL_BUTTON_LMASK)))
(set (field s-imgui-state mouse-state-changed) true)
(set (field s-imgui-state active-widget) 0))
(set (field s-imgui-state is-mouse-down) (bit-and mouse-button-state SDL_BUTTON_LMASK)))
(defun-local widget-id-from-string (text (addr (const char))
&return (unsigned int))
(var crc uint32_t 0)
(hash-crc32 text (strlen text) (addr crc))
(return crc))
(defun-local do-button (renderer (addr SDL_Renderer)
atlas (addr font-atlas) font-texture (addr SDL_Texture)
top-left-x int top-left-y int
width int height int
button-text (addr (const char))
&return bool)
(var button-rectangle SDL_Rect
(array top-left-x top-left-y
width height))
(var mouse-x int 0)
(var mouse-y int 0)
(var mouse-button-state Uint32
(SDL_GetMouseState (addr mouse-x) (addr mouse-y)))
(var is-mouse-hovered bool
(is-point-in-sdl-rect mouse-x mouse-y (addr button-rectangle)))
(var is-mouse-down-in-area bool
(is-point-in-sdl-rect (field s-imgui-state mouse-down-x)
(field s-imgui-state mouse-down-y)
(addr button-rectangle)))
(cond
;; Click and hold
((and is-mouse-down-in-area
(bit-and mouse-button-state SDL_BUTTON_LMASK))
(set (field s-imgui-state active-widget) (widget-id-from-string button-text))
(SDL_SetRenderDrawColor renderer 100 100 100 255))
(is-mouse-hovered
(SDL_SetRenderDrawColor renderer 50 50 50 255))
(true
(SDL_SetRenderDrawColor renderer 25 25 25 255)))
(SDL_RenderFillRect renderer (addr button-rectangle))
(render-string
renderer atlas font-texture
(+ 10 top-left-x) (+ (/ height 2) top-left-y (/ (path atlas > font-height) 4))
button-text)
(return
(and
;; The mouse started in the button's area
is-mouse-down-in-area
;; The mouse remained in the button's area (this check lets you change your mind and move off
;; the button before releasing to abort the click)
is-mouse-hovered
;; The mouse was just released
(not (field s-imgui-state is-mouse-down))
(field s-imgui-state mouse-state-changed))))
(defun main (&return int)
(hash-crc32-initialize)
(comptime-cond
@ -518,8 +642,8 @@
(var puppet-atlas-width int 0)
(var puppet-atlas-height int 0)
(var skeleton skeleton-data (array 0))
(var svg-filename (addr (const char)) "data/TestPuppet.svg")
;; (var svg-filename (addr (const char)) "data/DoNotCheckIn.svg")
;; (var svg-filename (addr (const char)) "data/TestPuppet.svg")
(var svg-filename (addr (const char)) "data/DoNotCheckIn.svg")
(defer
(free-introspect-struct-fields skeleton-data--metadata (addr skeleton) free))
(scope
@ -613,10 +737,17 @@
(var enable-fullscreen bool false)
(var view-selection bool true)
(var view-atlas bool false)
(var view-atlas bool true)
(var view-svg bool false)
(var view-puppet bool true)
(var assigning-parent bool false)
(var continuous-ik bool false)
(var effector-target (addr (const char)) "path3369")
(var last-frame-mouse-button-state Uint32 0)
(var start-ui-pane int 795)
(var exit-reason (addr (const char)) null)
(while true
@ -646,6 +777,8 @@
(set view-puppet (not view-puppet)))
(when (keybind-tapped (addr s-assigning-parent-keybind) (addr s-key-states))
(set assigning-parent (not assigning-parent)))
(when (keybind-tapped (addr s-toggle-inverse-kinematics-keybind) (addr s-key-states))
(set continuous-ik (not continuous-ik)))
(var true-window-width int 0)
(var true-window-height int 0)
@ -678,6 +811,15 @@
(SDL_SetRenderDrawColor renderer 11 11 11 255)
(SDL_RenderClear renderer)
(scope
(var ui-pane-rectangle SDL_Rect
(array start-ui-pane
0
(- true-window-width start-ui-pane)
true-window-height))
(SDL_SetRenderDrawColor renderer 17 17 17 255)
(SDL_RenderFillRect renderer (addr ui-pane-rectangle)))
(when view-svg ;; Draw entire SVG
(var source-rectangle SDL_Rect
(array 0
@ -699,6 +841,7 @@
(SDL_GetMouseState (addr mouse-x) (addr mouse-y)))
(var mouse-vec vec2 (array (type-cast mouse-x float)
(type-cast mouse-y float)))
(imgui-start-frame)
(when (and view-atlas puppet-atlas-texture)
(var atlas-rectangle SDL_Rect
@ -706,13 +849,19 @@
0
puppet-atlas-width
puppet-atlas-height))
(unless (= 0 (SDL_RenderCopy renderer puppet-atlas-texture (addr atlas-rectangle) (addr atlas-rectangle)))
(var destination-rectangle SDL_Rect
(array (- true-window-width puppet-atlas-width 10)
0
puppet-atlas-width
puppet-atlas-height))
(unless (= 0 (SDL_RenderCopy renderer puppet-atlas-texture (addr atlas-rectangle) (addr destination-rectangle)))
(sdl-print-error)
(set exit-reason "Failed to render atlas texture")))
;; Start over selection to always ensure we pick the smallest shape
(when (bit-and mouse-button-state SDL_BUTTON_LMASK)
(set selected-shape null))
(when (and (bit-and mouse-button-state SDL_BUTTON_LMASK)
(< mouse-x start-ui-pane))
(set selected-shape null)
(set continuous-ik false))
(when view-selection ;; Shape selection and debug viewing
(var hovered-shape-id-buffer (array 1024 char) (array 0))
(var hovered-write-head (addr char) hovered-shape-id-buffer)
@ -735,12 +884,7 @@
(SDL_SetRenderDrawColor renderer 230 10 10 255))
;; Selection coloring
(when (and (>= mouse-x (field point-rect x))
(>= mouse-y (field point-rect y))
(< mouse-x (+ (field point-rect x)
(field point-rect w)))
(< mouse-y (+ (field point-rect y)
(field point-rect h))))
(when (is-point-in-sdl-rect mouse-x mouse-y (addr point-rect))
(set hovered-write-head
(+ hovered-write-head
(snprintf hovered-write-head
@ -773,25 +917,7 @@
;; Select shape
(when (and (bit-and mouse-button-state SDL_BUTTON_LMASK)
(or (not selected-shape) (is-shape-smaller sized-bounds selected-shape-bounds)))
(var previous-selected-bone (addr skeleton-bone) selected-bone)
(set selected-shape shape)
(memcpy selected-shape-bounds sized-bounds (sizeof selected-shape-bounds))
(each-item-addr-in-array (field skeleton bones) bone-index bone (addr skeleton-bone)
;; Assign bone to empty slot
(unless (at 0 (path bone > shape-id))
(snprintf (path bone > shape-id) (sizeof (path bone > shape-id))
"%s" (path shape > id))
(set selected-bone bone)
(break))
(when (= 0 (strncmp (path shape > id) (path bone > shape-id)
(sizeof (path bone > shape-id))))
(set selected-bone bone)
(break)))
(when (and previous-selected-bone assigning-parent)
(set assigning-parent false)
(snprintf (path previous-selected-bone > parent-shape-id)
(sizeof (path previous-selected-bone > parent-shape-id))
"%s" (path shape > id))))
(on-select-shape shape sized-bounds))
(SDL_SetRenderDrawColor renderer 10 230 10 255)
(set hovered-write-head
(+ hovered-write-head
@ -809,12 +935,10 @@
hovered-shape-id-buffer))
(when packed-rectangles
(when (or true (keybind-tapped (addr s-do-inverse-kinematics-keybind) (addr s-key-states)))
(when (or continuous-ik (keybind-tapped (addr s-do-inverse-kinematics-keybind) (addr s-key-states)))
(var effector skeleton-effector (array 0))
(var effector-target (addr (const char)) "Hand_Right")
(var hard-coded-target vec2 (array 297 463))
(set-fields effector
position mouse-vec ;; hard-coded-target
position mouse-vec
shape-id (id-from-string (addr g-string-table)
effector-target
(strlen effector-target)))
@ -829,19 +953,30 @@
(path current-rectangle > w)
(path current-rectangle > h)))
(when view-atlas
(var sized-bounds (array 4 int) (array 0))
(nanosvg-get-shape-bounds-with-stroke-int shape sized-bounds)
(SDL_SetRenderDrawColor renderer 100 100 100 255)
(var offset-atlas-rectangle SDL_Rect draw-rectangle)
(set (field offset-atlas-rectangle x)
(+ (field offset-atlas-rectangle x)
(- true-window-width puppet-atlas-width 10)))
(scope ;; Allow selection from atlas
(when (= selected-shape shape)
(SDL_SetRenderDrawColor renderer 10 100 250 255))
(when (is-point-in-sdl-rect mouse-x mouse-y (addr offset-atlas-rectangle))
(when (bit-and mouse-button-state SDL_BUTTON_LMASK)
(on-select-shape shape sized-bounds))
(SDL_SetRenderDrawColor renderer 10 200 250 255)))
(scope ;; Color on hover
(var sized-bounds (array 4 int) (array 0))
(nanosvg-get-shape-bounds-with-stroke-int shape sized-bounds)
(when (and (>= mouse-x (at 0 sized-bounds))
(>= mouse-y (at 1 sized-bounds))
(< mouse-x (at 2 sized-bounds))
(< mouse-y (at 3 sized-bounds)))
(SDL_SetRenderDrawColor renderer 10 10 230 255)))
(SDL_RenderDrawRect renderer (addr draw-rectangle)))
(SDL_RenderDrawRect renderer (addr offset-atlas-rectangle)))
(when view-puppet
(var this-bone (addr skeleton-bone) selected-bone)
(var this-bone (addr skeleton-bone) (addr empty-bone))
(each-item-addr-in-array (field skeleton bones) i bone (addr skeleton-bone)
(unless (= 0 (strcmp (path bone > shape-id)
(path shape > id)))
@ -900,7 +1035,9 @@
(set-fields (deref selected-bone)
shape selected-shape
(end-position X) mouse-x
(end-position Y) mouse-y)))
(end-position Y) mouse-y
(pose-end-position X) mouse-x
(pose-end-position Y) mouse-y)))
(when selected-shape
(draw-bone renderer selected-bone))
@ -929,25 +1066,72 @@
10 (- true-window-height 90)
buffer))
(when (do-button renderer
(addr (field (at body-font-index font-atlases) atlas))
(field (at body-font-index font-atlases) texture)
(+ start-ui-pane 5) 800 250 75 "Toggle atlas")
(set view-atlas (not view-atlas)))
(when (do-button renderer
(addr (field (at body-font-index font-atlases) atlas))
(field (at body-font-index font-atlases) texture)
(+ start-ui-pane 260) 800 250 75 "Reset pose")
(reset-skeleton-pose (addr skeleton)))
(when (do-button renderer
(addr (field (at body-font-index font-atlases) atlas))
(field (at body-font-index font-atlases) texture)
(+ start-ui-pane 515) 800 250 75 "Mouse (I)K")
(set continuous-ik (not continuous-ik)))
(when (and selected-shape selected-bone)
(when (do-button renderer
(addr (field (at body-font-index font-atlases) atlas))
(field (at body-font-index font-atlases) texture)
(+ start-ui-pane 5) 880 250 75 "Clear pose")
(set-fields (deref selected-bone)
(pose-start-position X) (path selected-bone > start-position . X)
(pose-start-position Y) (path selected-bone > start-position . Y)
(pose-end-position X) (path selected-bone > end-position . X)
(pose-end-position Y) (path selected-bone > end-position . Y)))
(when (do-button renderer
(addr (field (at body-font-index font-atlases) atlas))
(field (at body-font-index font-atlases) texture)
(+ start-ui-pane 260) 880 250 75 "Set IK target")
(set effector-target (path selected-shape > id)))
(when (do-button renderer
(addr (field (at body-font-index font-atlases) atlas))
(field (at body-font-index font-atlases) texture)
(+ start-ui-pane 515) 880 250 75 "(P)arent")
(set assigning-parent (not assigning-parent))))
(when selected-shape
(render-string
renderer (addr (field (at body-font-index font-atlases) atlas))
(field (at body-font-index font-atlases) texture)
10 (- true-window-height 140)
"MMB: Start RMB: End C-MMB: Pose end"))
(SDL_RenderPresent renderer)
(SDL_UpdateWindowSurface window)
(dynarray-set-length (field s-key-states last-frame-states) num-keys)
(memcpy (field s-key-states last-frame-states) (field s-key-states this-frame-states) num-keys)
(set last-frame-mouse-button-state mouse-button-state)
(when exit-reason
(break)))
;; (scope ;; Save edited skeleton
;; (var filename (array 2048 char) (array 0))
;; (get-skeleton-filename-from-svg-filename svg-filename filename (sizeof filename))
;; (if-open-file-scoped filename "wb" out-file
;; (write-introspect-struct-s-expr
;; skeleton-data--metadata
;; (addr skeleton)
;; write-introspect-struct-file-writer out-file
;; write-introspect-struct-add-newline)
;; (vpslog "Failed to write skeleton to %s\n" filename)))
(scope ;; Save edited skeleton
(var filename (array 2048 char) (array 0))
(get-skeleton-filename-from-svg-filename svg-filename filename (sizeof filename))
(if-open-file-scoped filename "wb" out-file
(write-introspect-struct-s-expr
skeleton-data--metadata
(addr skeleton)
write-introspect-struct-file-writer out-file
write-introspect-struct-add-newline)
(vpslog "Failed to write skeleton to %s\n" filename)))
(when exit-reason
(vpslog "Exited reason: %s\n" exit-reason))

Loading…
Cancel
Save