From 348612b62f4f2909053e47fe185d8b761356a06f Mon Sep 17 00:00:00 2001 From: oakes Date: Wed, 30 Apr 2014 18:18:00 -0400 Subject: [PATCH] Add global asset manager --- doclet/resources/classes.edn | 37 ++++++++------------- src/play_clj/core.clj | 17 +++++++++- src/play_clj/core_basics.clj | 13 ++++---- src/play_clj/core_graphics.clj | 22 +++++++++---- src/play_clj/core_utils.clj | 58 +++++++++++++++++++++++++++----- src/play_clj/g2d.clj | 60 ++++++++++++++++++++++++---------- src/play_clj/g3d.clj | 7 ++++ src/play_clj/utils.clj | 12 ++++++- 8 files changed, 161 insertions(+), 65 deletions(-) diff --git a/doclet/resources/classes.edn b/doclet/resources/classes.edn index 5b26d33..627ced4 100644 --- a/doclet/resources/classes.edn +++ b/doclet/resources/classes.edn @@ -11,15 +11,13 @@ "gdx-array-map!" :methods} "AssetManager" {"asset-manager" :methods "asset-manager!" :methods} - "AtlasTmxMapLoader" {"loader :atlas-tmx-map" :constructors - "loader! :atlas-tmx-map" :methods} + "AtlasTmxMapLoader" {"loader! :atlas-tmx-map" :methods} "Audio" {"audio!" :methods} "Bezier" {"bezier" :methods "bezier!" :methods} - "BitmapFont" {"bitmap-font" :constructors + "BitmapFont" {"bitmap-font" :methods "bitmap-font!" :methods} - "BitmapFontLoader" {"loader :bitmap-font" :constructors - "loader! :bitmap-font" :methods} + "BitmapFontLoader" {"loader! :bitmap-font" :methods} "BlendingAttribute" {"attribute :blending" :constructors "attribute-type :blending" :static-fields "attribute! :blending" :static-methods} @@ -82,8 +80,7 @@ "FrictionJointDef" {"joint-def :friction" :fields} "Frustum" {"frustum" :methods "frustum!" :methods} - "G3dModelLoader" {"loader :g3d-model" :constructors - "loader! :g3d-model" :methods} + "G3dModelLoader" {"loader! :g3d-model" :methods} "GearJointDef" {"joint-def :gear" :fields} "GeometryUtils" {"geometry!" :static-methods} "Graphics" {"graphics!" :methods} @@ -141,11 +138,9 @@ "model-builder!" :methods} "ModelInstance" {"model" :methods "model!" :methods} - "ModelLoader" {"loader :model" :constructors - "loader! :model" :methods} + "ModelLoader" {"loader! :model" :methods} "MouseJointDef" {"joint-def :mouse" :fields} - "MusicLoader" {"loader :music" :constructors - "loader! :music" :methods} + "MusicLoader" {"loader! :music" :methods} "Net" {"net!" :methods} "NinePatch" {"nine-patch" :methods "nine-patch!" :methods} @@ -154,16 +149,14 @@ "orthogonal-tiled-map!" :methods} "OrthographicCamera" {"orthographic" :methods "orthographic!" :methods} - "ObjLoader" {"loader :obj" :constructors - "loader! :obj" :methods} + "ObjLoader" {"loader! :obj" :methods} "ParticleEffect" {"particle-effect" :methods "particle-effect!" :methods} "PerspectiveCamera" {"perspective" :methods "perspective!" :methods} - "Pixmap" {"pixmap" :constructors + "Pixmap" {"pixmap" :methods "pixmap!" :methods} - "PixmapLoader" {"loader :pixmap" :constructors - "loader! :pixmap" :methods} + "PixmapLoader" {"loader! :pixmap" :methods} "Plane" {"plane" :methods "plane!" :methods} "Plane.PlaneSide" {"plane-side" :static-fields} @@ -202,14 +195,12 @@ "ShapeRenderer.ShapeType" {"shape-type" :static-fields} "Skin" {"skin" :methods "skin!" :methods} - "SkinLoader" {"loader :skin" :constructors - "loader! :skin" :methods} + "SkinLoader" {"loader! :skin" :methods} "Slider" {"slider" :methods "slider!" :methods} "Sound" {"sound" :methods "sound!" :methods} - "SoundLoader" {"loader :sound" :constructors - "loader! :sound" :methods} + "SoundLoader" {"loader! :sound" :methods} "Sphere" {"sphere" :methods "sphere!" :methods} "SplitPane.SplitPaneStyle" {"style :split-pane" :constructors} @@ -231,16 +222,14 @@ "TextField" {"text-field" :methods "text-field!" :methods} "TextField.TextFieldStyle" {"style :text-field" :constructors} - "TextureLoader" {"loader :texture" :constructors - "loader! :texture" :methods} + "TextureLoader" {"loader! :texture" :methods} "TextureMapObject" {"map-object :texture" :methods} "TextureRegion" {"texture" :methods "texture!" :methods} "TextureRegionDrawable" {"drawable :texture-region" :constructors} "Tree" {"tree" :methods "tree!" :methods} - "TmxMapLoader" {"loader :tmx-map" :constructors - "loader! :tmx-map" :methods} + "TmxMapLoader" {"loader! :tmx-map" :methods} "Touchpad.TouchpadStyle" {"style :touchpad" :constructors} "TiledMap" {"tiled-map" :methods "tiled-map!" :methods} diff --git a/src/play_clj/core.clj b/src/play_clj/core.clj index 1c71ef1..0bdbaa1 100644 --- a/src/play_clj/core.clj +++ b/src/play_clj/core.clj @@ -8,10 +8,11 @@ [com.badlogic.gdx.audio Sound] [com.badlogic.gdx.assets AssetManager] [com.badlogic.gdx.assets.loaders AsynchronousAssetLoader] + [com.badlogic.gdx.files FileHandle] [com.badlogic.gdx.graphics Camera Color GL20 OrthographicCamera PerspectiveCamera Pixmap Pixmap$Format PixmapIO Texture VertexAttributes$Usage] - [com.badlogic.gdx.graphics.g2d SpriteBatch] + [com.badlogic.gdx.graphics.g2d ParticleEffect SpriteBatch] [com.badlogic.gdx.graphics.g3d ModelBatch] [com.badlogic.gdx.graphics.glutils ShapeRenderer] [com.badlogic.gdx.input GestureDetector @@ -165,6 +166,20 @@ handle errors and perform other custom actions each time they run. [wrapper-fn] (intern 'play-clj.core 'wrapper wrapper-fn)) +(defn set-asset-manager! + "Sets a global asset manager, which will keep track of objects that need to +be manually disposed, such as `texture` entities and `pixmap` objects. The +asset manager will then allow you to dispose them all at once. + + ; create an asset manager + (def manager (asset-manager)) + ; set it to be used by play-clj + (set-asset-manager! manager) + ; dispose all assets at once + (asset-manager! manager :clear)" + [am] + (intern 'play-clj.utils '*asset-manager* am)) + (defn update! "Runs the equivalent of `(swap! screen-atom assoc ...)`, where `screen-atom` is the atom storing the screen map behind the scenes. Returns the updated diff --git a/src/play_clj/core_basics.clj b/src/play_clj/core_basics.clj index 04b37f4..9c1db34 100644 --- a/src/play_clj/core_basics.clj +++ b/src/play_clj/core_basics.clj @@ -140,19 +140,20 @@ (defn sound* [path] - (audio! :new-sound (if (string? path) - (files! :internal path) - path))) + (let [^FileHandle fh (if (string? path) + (files! :internal path) + path)] + (or (u/load-asset (.path fh) Sound) + (audio! :new-sound fh)))) (defmacro sound "Returns a [Sound](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/audio/Sound.html). -When no longer needed, you must call `(sound! object :dispose)` to free it from -memory. (sound \"playerhurt.wav\") (sound \"playerhurt.wav\" :play)" [path & options] - `(u/calls! ^Sound (sound* ~path) ~@options)) + `(let [^Sound object# (sound* ~path)] + (u/calls! object# ~@options))) (defmacro sound! "Calls a single method on a `sound`. diff --git a/src/play_clj/core_graphics.clj b/src/play_clj/core_graphics.clj index f18c813..faf5ac1 100644 --- a/src/play_clj/core_graphics.clj +++ b/src/play_clj/core_graphics.clj @@ -1,13 +1,20 @@ (in-ns 'play-clj.core) +(defn pixmap* + [path] + (let [^FileHandle fh (if (string? path) + (files! :internal path) + path)] + (or (u/load-asset (.path fh) Pixmap) + (Pixmap. fh)))) + (defmacro pixmap "Returns a [Pixmap](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/Pixmap.html). (pixmap \"image.png\")" - [& args] - `~(if (string? (first args)) - `(Pixmap. (files! :internal ~(first args))) - `(Pixmap. ~@args))) + [path & options] + `(let [^Pixmap object# (pixmap* ~path)] + (u/calls! object# ~@options))) (defmacro pixmap! "Calls a single method on a `pixmap`. @@ -78,7 +85,8 @@ complicated shapes. If you use `assoc` to set the overall :x and :y of the (TiledMap.)) ([s] (if (string? s) - (.load (TmxMapLoader.) s) + (or (u/load-asset s TiledMap) + (.load (TmxMapLoader.) s)) s))) (defmacro tiled-map @@ -237,8 +245,8 @@ in the `layer`. "Returns a subclass of [MapObject](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/maps/MapObject.html). (map-object :circle)" - [k & options] - `(let [^MapObject object# (~(map-object-init k))] + [type & options] + `(let [^MapObject object# (~(map-object-init type))] (u/calls! object# ~@options))) (defmacro map-object! diff --git a/src/play_clj/core_utils.clj b/src/play_clj/core_utils.clj index 1a2cbb0..83c6181 100644 --- a/src/play_clj/core_utils.clj +++ b/src/play_clj/core_utils.clj @@ -135,20 +135,35 @@ found." ; assets -(defn ^:private loader-init +(defn ^:private loader-class [k] (cond (contains? #{:atlas-tmx-map :tmx-map} k) - (u/gdx :maps :tiled (str (u/key->pascal k) "Loader.")) + (u/gdx :maps :tiled (str (u/key->pascal k) "Loader")) (contains? #{:g3d-model :obj} k) - (u/gdx :graphics :g3d :loader (str (u/key->pascal k) "Loader.")) + (u/gdx :graphics :g3d :loader (str (u/key->pascal k) "Loader")) :else - (u/gdx :assets :loaders (str (u/key->pascal k) "Loader.")))) + (u/gdx :assets :loaders (str (u/key->pascal k) "Loader")))) (defmacro loader - "Returns a subclass of [AsynchronousAssetLoader](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/assets/loaders/AsynchronousAssetLoader.html)." - [type & options] - `(~(loader-init type) ~@options)) + "Returns a subclass of [AssetLoader](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/assets/loaders/AssetLoader.html). + + (loader :atlas-tmx-map (resolver :internal-file-handle)) + (loader :bitmap-font (resolver :internal-file-handle)) + (loader :g3d-model (resolver :internal-file-handle)) + (loader :model (resolver :internal-file-handle)) + (loader :music (resolver :internal-file-handle)) + (loader :obj (resolver :internal-file-handle)) + (loader :pixmap (resolver :internal-file-handle)) + (loader :skin (resolver :internal-file-handle)) + (loader :sound (resolver :internal-file-handle)) + (loader :texture (resolver :internal-file-handle)) + (loader :tmx-map (resolver :internal-file-handle)) + (loader :tmx-map + (resolver :internal-file-handle) + (load [file-name] nil))" + [type resolver & options] + `(proxy [~(loader-class type)] [~resolver] ~@options)) (defmacro loader! "Calls a single method in a subclass of [AsynchronousAssetLoader](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/assets/loaders/AsynchronousAssetLoader.html). @@ -158,11 +173,36 @@ found." `(let [^AsynchronousAssetLoader object# ~object] (u/call! object# ~@options))) +(defn ^:private resolver-class + [k] + (u/gdx :assets :loaders :resolvers (str (u/key->pascal k) "Resolver"))) + +(defmacro resolver + "Returns an implementation of [FileHandleResolver](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/assets/loaders/FileHandleResolver.html). + + (resolver :internal-file-handle) + (resolver :internal-file-handle + (resolve [file-name] + (files! :internal file-name)))" + [type & options] + `(proxy [~(resolver-class type)] [] ~@options)) + +(defn ^:private set-loaders + [^AssetManager am] + (->> (loader :tmx-map (resolver :internal-file-handle)) + (.setLoader am TiledMap)) + (->> (loader :particle-effect + (resolver :internal-file-handle) + (load [am file-name fh param] + (doto (ParticleEffect.) + (.load fh (.parent fh))))) + (.setLoader am ParticleEffect))) + (defn asset-manager* ([] - (AssetManager.)) + (doto (AssetManager.) set-loaders)) ([resolver] - (AssetManager. resolver))) + (doto (AssetManager. resolver) set-loaders))) (defmacro asset-manager "Returns an [AssetManager](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/assets/AssetManager.html). diff --git a/src/play_clj/g2d.clj b/src/play_clj/g2d.clj index 658f55f..720a502 100644 --- a/src/play_clj/g2d.clj +++ b/src/play_clj/g2d.clj @@ -1,19 +1,33 @@ (ns play-clj.g2d (:require [play-clj.entities] [play-clj.utils :as u]) - (:import [com.badlogic.gdx.graphics Pixmap Texture] + (:import [com.badlogic.gdx Files Gdx] + [com.badlogic.gdx.files FileHandle] + [com.badlogic.gdx.graphics Pixmap Texture] [com.badlogic.gdx.graphics.g2d Animation BitmapFont NinePatch ParticleEffect TextureAtlas TextureRegion] [play_clj.entities TextureEntity NinePatchEntity ParticleEffectEntity])) +(defn bitmap-font* + [path] + (if (nil? path) + (BitmapFont.) + (let [^Files files (Gdx/files) + ^FileHandle fh (if (string? path) + (.internal files path) + path)] + (or (u/load-asset (.path fh) BitmapFont) + (BitmapFont. fh))))) + (defmacro bitmap-font "Returns a [BitmapFont](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g2d/BitmapFont.html). (bitmap-font) - (bitmap-font (files! :internal \"default.fnt\"))" - [& options] - `(BitmapFont. ~@options)) + (bitmap-font \"default.fnt\")" + [& [path & options]] + `(let [^BitmapFont object# (bitmap-font* ~path)] + (u/calls! object# ~@options))) (defmacro bitmap-font! "Calls a single method on a `bitmap-font`." @@ -27,7 +41,9 @@ (TextureEntity. (cond (string? arg) - (-> ^String arg Texture. TextureRegion.) + (-> (or (u/load-asset arg Texture) + (Texture. ^String arg)) + TextureRegion.) (isa? (type arg) Pixmap) (-> ^Pixmap arg Texture. TextureRegion.) (isa? (type arg) TextureRegion) @@ -70,12 +86,14 @@ (NinePatchEntity. (cond (string? arg) - (-> ^String arg Texture. TextureRegion. NinePatch.) + (-> (or (u/load-asset arg Texture) + (Texture. ^String arg)) + TextureRegion. + NinePatch.) (:object arg) (NinePatch. (:object arg)) (map? arg) (let [{:keys [region left right top bottom]} arg] - (assert (and region left right top bottom)) (NinePatch. region left right top bottom)) :else arg))) @@ -84,8 +102,7 @@ "Returns an entity based on [NinePatch](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g2d/NinePatch.html). (nine-patch \"image.png\") - (nine-patch \"image.png\" :set-color (color :blue)) - (nine-patch {:image \"image.png\" :left 10 :right 10 :top 10 :bottom 10})" + (nine-patch \"image.png\" :set-color (color :blue))" [arg & options] `(let [entity# (nine-patch* ~arg)] (u/calls! ^NinePatch (u/get-obj entity# :object) ~@options) @@ -107,17 +124,25 @@ ; particle-effect (defn particle-effect* - [] - (ParticleEffectEntity. (ParticleEffect.))) + [path] + (ParticleEffectEntity. + (if (nil? path) + (ParticleEffect.) + (let [^Files files (Gdx/files) + ^FileHandle fh (if (string? path) + (.internal files path) + path)] + (or (u/load-asset (.path fh) ParticleEffect) + (doto (ParticleEffect.) + (.load fh (.parent fh)))))))) (defmacro particle-effect "Returns an entity based on [ParticleEffect](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g2d/ParticleEffect.html). - (particle-effect :load - (files! :internal \"fire.p\") - (files! :internal \"fire-images\"))" - [& options] - `(let [entity# (particle-effect*)] + (particle-effect) + (particle-effect \"particles/fire.p\")" + [& [path & options]] + `(let [entity# (particle-effect* ~path)] (u/calls! ^ParticleEffect (u/get-obj entity# :object) ~@options) entity#)) @@ -137,7 +162,8 @@ (defn texture-atlas* [^String path] - (TextureAtlas. path)) + (or (u/load-asset path TextureAtlas) + (TextureAtlas. path))) (defmacro texture-atlas "Returns a [TextureAtlas](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g2d/TextureAtlas.html). diff --git a/src/play_clj/g3d.clj b/src/play_clj/g3d.clj index b5caf2e..4d72be7 100644 --- a/src/play_clj/g3d.clj +++ b/src/play_clj/g3d.clj @@ -73,12 +73,19 @@ ; model +(defn model* + [^String path] + (or (u/load-asset path Model) + (throw (Exception. "Asset manager not found. See set-asset-manager!")))) + (defmacro model "Returns an entity based on [ModelInstance](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g3d/ModelInstance.html)." [& args] `(ModelEntity. (let [arg1# ~(first args)] (cond + (string? arg1#) + (ModelInstance. (model* arg1#)) (:object arg1#) (ModelInstance. ^ModelInstance (:object arg1#)) (isa? arg1# ModelData) diff --git a/src/play_clj/utils.clj b/src/play_clj/utils.clj index b54be1f..a2fd296 100644 --- a/src/play_clj/utils.clj +++ b/src/play_clj/utils.clj @@ -1,9 +1,19 @@ (ns play-clj.utils (:require [clojure.string :as s]) - (:import [com.badlogic.gdx.utils Array ArrayMap])) + (:import [com.badlogic.gdx.assets AssetManager] + [com.badlogic.gdx.utils Array ArrayMap])) ; misc +(def ^:dynamic *asset-manager* nil) + +(defn load-asset + [path type] + (when-let [^AssetManager am *asset-manager*] + (.load am path type) + (.finishLoading am) + (.get am path type))) + (defn throw-key-not-found [k] (throw (Exception. (str "The keyword " k " is not found."))))