|
|
@ -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)) |
|
|
|