Automatically select all cells with colors, spit to edn file

This commit is contained in:
Joseph Ferano 2026-08-29 23:46:20 +07:00
parent d6495103e1
commit 79980f3da3
5 changed files with 86 additions and 17 deletions

View File

@ -10,6 +10,12 @@
(defonce texture-cache (atom {}))
;; (reset! texture-cache {})
(defn load-texture-once [id path]
(or (@texture-cache path)
(let [t (assoc (rl/load-texture path) :name id)]
(swap! texture-cache assoc path t)
t)))
(defn load-texture-once [id path]
(or (@texture-cache path)
(let [t (assoc (rl/load-texture path) :name id)]

View File

@ -265,8 +265,11 @@
;; Called once at startup, so the map-taking form is fine.
(defcfn load-texture-raw* "LoadTexture" [::mem/c-string] ::texture)
(defcfn load-image-raw* "LoadImage" [::mem/c-string] ::image)
(defcfn image-from-image-raw* "ImageFromImage" [::image ::rectangle] ::image)
(defcfn load-texture-from-image "LoadTextureFromImage" [::image] ::texture)
(defcfn unload-texture! "UnloadTexture" [::texture] ::mem/void)
(defcfn unload-image! "UnloadImage" [::image] ::mem/void)
(defcfn set-texture-filter! "SetTextureFilter" [::texture ::mem/int] ::mem/void)
(defcfn get-font-default "GetFontDefault" [] ::font)
@ -285,6 +288,10 @@
(ffi/make-downcall "MeasureTextEx"
[::font ::mem/c-string ::mem/float ::mem/float] ::vector-2))
(def ^:private get-image-color-raw!*
(ffi/make-downcall "GetImageColor"
[::image ::mem/int ::mem/int] ::color))
;;; --------------------------------------------------- macros
(defmacro with-drawing!
@ -349,6 +356,9 @@
(defn vec2-seg [x y]
(mem/serialize {:x (float x) :y (float y)} ::vector-2 arena))
(defn image-seg [img]
(mem/serialize img ::image arena))
(defn texture-seg [tex]
(mem/serialize tex ::texture arena))
@ -356,6 +366,22 @@
(let [tex (load-texture-raw* path)]
(assoc tex :seg (texture-seg tex))))
(defn load-image [path]
(let [img (load-image-raw* path)]
(assoc img :seg (image-seg img))))
(defn image-from-image [img {:keys [x y width height]}]
(let [cropped (image-from-image-raw*
img
{:x (float x) :y (float y)
:width (float width) :height (float height)})]
(assoc cropped :seg (image-seg cropped))))
(defn get-image-color!* [img x y]
(mem/deserialize
(get-image-color-raw!* arena (:seg img) (int x) (int y))
::color))
(defn n-patch-info-seg [{:keys [source left top right bottom layout]}]
(mem/serialize {:source source :left (int left) :top (int top)
:right (int right) :bottom (int bottom) :layout (int layout)}

View File

@ -6,7 +6,9 @@
[engine :as e]
[rl :as rl]
[watch :as w])
(:import (java.awt FileDialog Frame)))
(:import
(java.io File)
(java.awt FileDialog Frame)))
(def screen-width 1280)
(def screen-height 630)
@ -14,20 +16,18 @@
;; (def screen-height 490)
(def cell-size 16)
(defn sprite-atlas-path []
(let [asset-path "./source-assets/Sprout Lands Premium/"
level-deco "Objects/Mushrooms, Flowers, Stones.png"]
(str asset-path level-deco)))
(def sprite-atlas-path "./source-assets/Sprout Lands Premium/Objects/Mushrooms, Flowers, Stones.png")
(defn zoom-to-fit [{:keys [width height]}]
(min (/ screen-width (double width))
(/ screen-height (double height))))
(defn init-sprite-atlas [config]
(let [atlas (e/load-texture-once :main-atlas (sprite-atlas-path))]
(let [atlas (e/load-texture-once :main-atlas sprite-atlas-path)]
{:zoom (zoom-to-fit atlas)
:selected-cells #{}
:atlas atlas
:atlas-img (rl/load-image "./source-assets/Sprout Lands Premium/Objects/Mushrooms, Flowers, Stones.png")
:atlas-pos [0 0]
:drag-delta [0 0]}))
@ -38,6 +38,19 @@
end-y (max ay by)]
{:x start-x :y start-y :w (- end-x start-x) :h (- end-y start-y)}))
(defn auto-select-tiles [{:keys [atlas-img atlas]}]
;; TODO: This should come from game, so should cell-size
(let [rows (quot (:height atlas) cell-size)
cols (quot (:width atlas) cell-size)]
(into #{}
(for [r (range rows) c (range cols)
:when (let [rect {:x (* c cell-size) :y (* r cell-size) :width cell-size :height cell-size}
sub-img (rl/image-from-image atlas-img rect)
all-zero (all-zero? sub-img)]
(rl/unload-image! sub-img)
(not all-zero))]
[r c]))))
(defn handle-input [_ game]
(update-as-> [g game]
(when (rl/key-pressed? rl/key-r)
@ -45,23 +58,30 @@
;; TODO: We want to add auto sprite sheet gen, so first detect non-empty, and we populate with that
;; then we have a selection box that allows grouping
(when (rl/key-pressed? rl/key-enter)
(let [d (doto (FileDialog. (Frame.) "Open" FileDialog/LOAD)
(let [d (doto (FileDialog. (Frame.) "Save" FileDialog/SAVE)
;; TODO: Maybe add a check if the directory exists?
(.setDirectory (str (System/getProperty "user.dir") "/assets"))
(.setFile (change-ext (.getName (File. sprite-atlas-path)) "edn"))
(.setVisible true))]
(when-let [f (.getFile d)]
(println (str (.getDirectory d) f)))
(let [base-path (System/getProperty "user.dir")
full-path (str (.getDirectory d) f)]
(spit full-path (pr-str {:texture-path (str (.relativize (.toPath (io/file base-path))
(.toPath (io/file full-path))))
:selected-cells (:selected-cells g)}))))
game)
#_(this should be to write the sprite sheet to some path))
(when (rl/key-pressed? rl/key-zero)
(assoc g :zoom (zoom-to-fit (:atlas g))))
(when (rl/key-pressed? rl/key-a)
(assoc g :selected-cells (auto-select-tiles g)))
(when (rl/mouse-button-pressed? rl/mouse-button-left)
(cond-> (assoc g
:drag-start-pos (rl/get-mouse-position)
:current-mouse-pos (rl/get-mouse-position)
:drag-mode :selecting)
(not (rl/key-down? rl/key-left-shift))
(assoc :selected-cells #{})))
(when (rl/mouse-button-released? rl/mouse-button-left)
@ -76,6 +96,9 @@
[ax ay] (:atlas-pos g)]
[(+ ax dx) (+ ay dy)]))
(dissoc :drag-start-pos :current-mouse-pos :drag-mode :drag-delta)))
;; TODO: We need to delete tiles
#_(when (rl/mouse-button-pressed? rl/mouse-button-middle)
(disj ))
(let [move (rl/get-mouse-wheel-move)]
(when (not (zero? move))
(let [new-scale (max 1.0 ((if (pos? move) * /) (:zoom g) 1.2))
@ -112,15 +135,15 @@
h (+ (- y0 start-y) (- y1 y0))
row-count (inc (quot h curr-cell-size))
col-count (inc (quot w curr-cell-size))]
(w/spy :info [row-count col-count])
(when (> (* w h) 256)
(set (for [r (range row-count)
c (range col-count)]
[(+ start-row r) (+ start-col c)])))))
(into (:selected-cells g)
(for [r (range row-count)
c (range col-count)]
[(+ start-row r) (+ start-col c)])))))
:dragging (assoc g :drag-delta (let [{mx :x my :y} (rl/get-mouse-position)
{:keys [x y]} (:drag-start-pos g)]
[(- mx x) (- my y)]))))))
(into #{[1 2]} [[1 2] [2 3]] )
(defn draw-sprite-atlas [_ {:keys [atlas atlas-pos drag-delta zoom drag-mode drag-start-pos current-mouse-pos selected-cells]}]
(rl/clear-background!* rl/black)
@ -171,7 +194,8 @@
:atlas-pos (:atlas-pos game)
#_#_:drag-delta (:drag-delta game)})
(defn unload-sprite-atlas [game])
(defn unload-sprite-atlas [game]
(rl/unload-image! (:atlas-img game)))
(defn -main [& _args]
(engine/run-game!

View File

@ -89,7 +89,7 @@
{}
tiles)
(comment
(comment
;; #C0D470
;; #A4C263
;; #78A158

View File

@ -1,11 +1,24 @@
(ns util
(:require
[clojure.pprint :as pprint]))
[clojure.pprint :as pprint])
(:import (java.lang.foreign MemorySegment ValueLayout)))
(defn spy
([x] (pprint/pprint x) x)
([tag x] (pprint/pprint [tag x]) x))
(defn change-ext [path ext]
(str (clojure.string/replace path #"\.[^./\\]*$" "") "." ext))
(defn all-zero? [{:keys [data width height]}]
(let [n (* 4 (long width) (long height))
px (.reinterpret ^MemorySegment data n)]
(loop [i 0]
(cond
(>= i n) true
(zero? (.get px ValueLayout/JAVA_INT i)) (recur (+ i 4))
:else false))))
(defmacro do-grid [[r rows c cols] & body]
`(dotimes [~r ~rows]
(dotimes [~c ~cols]