text:
(defproject play-clj "1.2.0-SNAPSHOT"
  :description "A libGDX wrapper for easy cross-platform game development"
  :url "https://github.com/oakes/play-clj"
  :license {:name "Public Domain"
            :url "http://unlicense.org/UNLICENSE"}
  :dependencies [[com.badlogicgames.gdx/gdx "1.9.3"]
                 [com.badlogicgames.gdx/gdx-box2d "1.9.3"]
                 [com.badlogicgames.gdx/gdx-bullet "1.9.3"]
                 [org.clojure/clojure "1.7.0"]]
  :repositories [["sonatype"
                  "https://oss.sonatype.org/content/repositories/releases/"]]
  :source-paths ["src"]
  :java-source-paths ["src-java"]
  :javac-options ["-target" "1.6" "-source" "1.6" "-Xlint:-options"])


text:
## Note: I am focusing my efforts on [play-cljc](https://github.com/oakes/play-cljc), a library for games that run on both the desktop and the web.

## Introduction

A Clojure library that provides a wrapper for [libGDX](http://libgdx.badlogicgames.com/), allowing you to write 2D and 3D games that run on desktop OSes (Windows, OS X, and Linux) and Android with the same Clojure codebase.

## Getting Started

There are a few ways to create a project:

* [Leiningen](https://github.com/technomancy/leiningen): `lein new play-clj hello-world`
* [Nightmod](https://sekao.net/nightmod/): An IDE for play-clj

## Justification

The best thing about making a game in Clojure is that you can modify it in a REPL while it's running. By simply reloading a namespace, your code will be injected into the game, uninhibited by the restrictions posed by tools like HotSwap. Additionally, a REPL lets you read and modify the _state_ of your game at runtime, so you can quickly experiment and diagnose problems.

Clojure also brings the benefits of functional programming. This is becoming a big topic of discussion in gamedev circles, including by [John Carmack](http://gamasutra.com/view/news/169296/Indepth_Functional_programming_in_C.php). Part of this is due to the prevalence of multi-core hardware, making concurrency more important. Additionally, there is a general difficulty of maintaining object-oriented game codebases as they grow, due to complicated class hierarchies and state mutations.

## Documentation

* Check out [the example games](https://github.com/oakes/play-clj-examples)
* Read [the tutorial](TUTORIAL.md)
* Read [the generated docs](http://oakes.github.io/play-clj)
* Join the discussion on [/r/playclj](http://www.reddit.com/r/playclj/)
* Look at this commented example:

```clojure
(ns game-test.core
  (:require [play-clj.core :refer :all]
            [play-clj.g2d :refer :all]))

; define a screen, where all the action takes place
(defscreen main-screen
  ; all the screen functions get a map called "screen" containing various
  ; important values, and a vector called "entities" for storing game objects

  ; the entities vector is immutable, so in order to update it you must simply
  ; return a new vector at the end of each screen function

  ; this function runs only once, when the screen is first shown
  :on-show
  (fn [screen entities]
    ; update the screen map to hold a tiled map renderer and a camera
    (update! screen
             :renderer (orthogonal-tiled-map "level1.tmx" (/ 1 8))
             :camera (orthographic))
    (let [; load a sprite sheet from your resources dir
          sheet (texture "tiles.png")
          ; split the sheet into 16x16 tiles
          ; (the texture! macro lets you call TextureRegion methods directly)
          tiles (texture! sheet :split 16 16)
          ; get the tile at row 6, col 0
          player-image (texture (aget tiles 6 0))
          ; add position and size to the player-image map so it can be drawn
          player-image (assoc player-image :x 0 :y 0 :width 2 :height 2)]
      ; return a new entities vector with player-image inside of it
      [player-image]))

  ; this function runs every time a frame must be drawn (about 60 times per sec)
  :on-render
  (fn [screen entities]
    ; make the screen completely black
    (clear!)
    ; render the tiled map, draw the entities and return them
    (render! screen entities))

  ; this function runs when the screen dimensions change
  :on-resize
  (fn [screen entities]
    ; make the camera 20 tiles high, while maintaining the aspect ratio
    (height! screen 20)
    ; you can return nil if you didn't change any entities
    nil))

; define the game itself, and immediately hand off to the screen
(defgame game-test
  :on-create
  (fn [this]
    (set-screen! this main-screen)))
```

## Licensing

All files that originate from this project are dedicated to the public domain. I would love pull requests, and will assume that they are also dedicated to the public domain.

repo_name: oakes/play-clj

repo_language: Clojure

mime_type: text/plain


text:
(in-ns 'play-clj.core)

(defn find-first
  "Returns the first entity in `entities` for which `match-fn` returns true.

    (find-first :player? entities)
    (find-first #(= :menu (:id %)) entities)"
  [match-fn entities]
  (some #(when (match-fn %) %) entities))

(defmacro on-gl
  "Runs the macro body on the GL thread.

    (on-gl (set-screen! my-game main-screen))"
  [& body]
  `(app! :post-runnable (fn [] ~@body)))

(defn bundle
  "Returns an entity containing other entities. This is a useful way to keep
related entities together. They will be drawn in the order they appear in the
internal :entities vector. Any keys in the bundle, such as :x and :y, will
be passed down to all the internal entities unless they already have those keys.

    (bundle (shape :filled) (shape :line))
    (assoc (bundle (shape :filled) (shape :line))
           :x 100 :y 100)"
  [& entities]
  (BundleEntity. (vec entities)))

(defn bundle?
  "Returns true if `entity` is a `bundle`."
  [entity]
  (instance? BundleEntity entity))

(defn screenshot!
  "Captures a screenshot and either returns it as a `pixmap` or saves it to the
specified path.

    (screenshot!)
    (screenshot! \"out.png\")
    (screenshot! (files! :external \"out.png\"))"
  ([]
   (let [^Pixmap$Format pic-f (Pixmap$Format/RGBA8888)
         ^Pixmap pic (Pixmap. ^long (game :width) ^long (game :height) pic-f)
         pixel-data (ScreenUtils/getFrameBufferPixels true)
         pixels (.getPixels pic)]
     (doto pixels
       (.clear)
       (.put pixel-data)
       (.position 0))
     pic))
  ([path]
   (let [pic (screenshot!)
         handle (if (string? path)
                  (files! :local path)
                  path)]
     (PixmapIO/writePNG handle pic)
     (pixmap! pic :dispose))))

(defmacro pref!
  "Retrieves and stores preferences. The `name` should be a unique string.

    ; define the name we'll be using
    (def ^:const pref-name \"my-game.settings\")
    ; store a single preference
    (pref! pref-name :put-float \"player-health\" 40)
    ; store multiple preferences
    (pref! pref-name :put {\"player-health\" 40
                           \"player-x\" 20
                           \"player-y\" 50})
    ; save the changes to the disk
    (pref! pref-name :flush)
    ; retrieve a single preference
    (pref! pref-name :get-float \"player-health\")"
  [name k & options]
  `(let [^Preferences p# (if (string? ~name)
                           (app! :get-preferences ~name)
                           ~name)]
     (u/call! p# ~k ~@options)))

(defn rewind!
  "Returns the most recent entities vector saved in the timeline after removing
the last `steps` from it. Start recording to the timeline by calling
`(update! screen :timeline [])`.

If there are 100 items saved in the timeline and `(rewind! screen 1)` is called,
it will remove the last one and return the entities vector from the 99th item.
If `steps` is invalid, nil is returned.

If you want to do something more complex with the timeline than a simple rewind,
you can directly access it via `(:timeline screen)`. Each item inside it is a
vector containing a timestamp (seconds since the screen was first shown) and an
entities vector."
  [{:keys [timeline update-fn!] :as screen} steps]
  (when-let [[total-time entities] (get timeline (- (count timeline) steps 1))]
    (update-fn! update-in [:timeline] subvec 0 (- (count timeline) steps 1))
    entities))

; static fields

(defmacro scaling
  "Returns a static field from [Scaling](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/utils/Scaling.html).

    (scaling :fill)"
  [k]
  (u/gdx-field :utils :Scaling k))

(defmacro usage
  "Returns a static field in [VertexAttributes.Usage](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/VertexAttributes.Usage.html)."
  [k]
  (u/gdx-field :graphics "VertexAttributes$Usage" (u/key->pascal k)))

; timers

(defn ^:private task*
  [{:keys [execute-fn! on-timer]} id]
  (proxy [Timer$Task] []
    (run []
      (execute-fn! on-timer :id id))))

(defn ^:private timer*
  []
  (some-> (Class/forName "com.badlogic.gdx.utils.Timer")
          (try (catch Exception _))
          .newInstance))

(defn ^:private create-and-add-timer!
  [{:keys [update-fn!] :as screen} id]
  ; remove timer if it already exists
  (when-let [old-timer (get-in screen [:timers id])]
    (.stop old-timer)
    (some-> u/*timers* (swap! disj old-timer)))
  ; create timer, add to screen map, and return it
  (let [new-timer (timer*)]
    (update-fn! assoc-in [:timers id] new-timer)
    (some-> u/*timers* (swap! conj new-timer))
    new-timer))

(defn add-timer!
  "Returns a [Timer](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/utils/Timer.html)
which will fire the :on-timer function one or more times (depending on the given
arguments). In the :on-timer function, the id will be passed in the screen map.
If a timer with that id already exists in the screen, it will be stopped and
replaced with a new timer.

    ; wait 2 seconds and run once
    (add-timer! screen :spawn-enemy 2)
    ; wait 2 seconds and run forever at 10 second intervals
    (add-timer! screen :spawn-enemy 2 10)
    ; wait 2 seconds, run once, and then run 3 more times at 10 second intervals
    (add-timer! screen :spawn-enemy 2 10 3)"
  ([screen id delay]
   (doto (create-and-add-timer! screen id)
     (.scheduleTask (task* screen id) delay)))
  ([screen id delay interval]
   (doto (create-and-add-timer! screen id)
     (.scheduleTask (task* screen id) delay interval)))
  ([screen id delay interval repeat]
   (doto (create-and-add-timer! screen id)
     (.scheduleTask (task* screen id) delay interval repeat))))

(defn remove-timer!
  "Stops and removes the timer associated with `id`, returning it or nil if not
found."
  [{:keys [update-fn!] :as screen} id]
  (when-let [timer (get-in screen [:timers id])]
    (.stop timer)
    (update-fn! update-in [:timers] dissoc id)
    timer))

; assets

(defn ^:private set-loaders!
  ([am]
   (set-loaders! am (InternalFileHandleResolver.)))
  ([^AssetManager am res]
   (.setLoader am TiledMap (TmxMapLoader. res))
   (.setLoader am ParticleEffect (proxy [ParticleEffectLoader] [res]
                                   (load [am file-name fh param]
                                     (doto (ParticleEffect.)
                                       (.load fh (.parent fh))))))))

(defn asset-manager*
  ([]
   (doto (AssetManager.) set-loaders!))
  ([resolver]
   (doto (AssetManager. resolver) (set-loaders! resolver))))

(defmacro asset-manager
  "Returns an [AssetManager](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/assets/AssetManager.html).

    (asset-manager)"
  [& options]
  `(let [^AssetManager object# (asset-manager*)]
     (u/calls! object# ~@options)))

(defmacro asset-manager!
  "Calls a single method in an `asset-manager`.

    (asset-manager! object :clear)"
  [object k & options]
  `(let [^AssetManager object# ~object]
     (u/call! object# ~k ~@options)))

(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
    (defonce 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))


text:
(ns play-clj.entities
  (:import [com.badlogic.gdx Gdx Graphics]
           [com.badlogic.gdx.graphics Camera Color GL20]
           [com.badlogic.gdx.graphics.g2d Batch NinePatch ParticleEffect Sprite
            TextureRegion]
           [com.badlogic.gdx.graphics.g3d Environment ModelBatch ModelInstance]
           [com.badlogic.gdx.graphics.glutils ShapeRenderer]
           [com.badlogic.gdx.math Matrix4]
           [com.badlogic.gdx.scenes.scene2d Actor]))

(defprotocol Entity
  (draw! [this screen batch] "Draws the entity"))

(extend-protocol Entity
  clojure.lang.PersistentArrayMap
  (draw! [this screen batch])
  clojure.lang.PersistentHashMap
  (draw! [this screen batch])
  nil
  (draw! [this screen batch]))

(defrecord TextureEntity [object] Entity
  (draw! [{:keys [^TextureRegion object x y width height
                  scale-x scale-y angle color]}
          _
          batch]
    (let [x (float (or x 0))
          y (float (or y 0))
          width (float (or width (.getRegionWidth object)))
          height (float (or height (.getRegionHeight object)))]
      (when-let [[r g b a] color]
        (.setColor ^Batch batch r g b a))
      (if (or scale-x scale-y angle)
        (let [scale-x (float (or scale-x 1))
              scale-y (float (or scale-y 1))
              angle (float (or angle 0))]
          (.draw ^Batch batch object x y 0 0 width height
            scale-x scale-y angle))
        (.draw ^Batch batch object x y width height))
      (when color
        (.setColor ^Batch batch Color/WHITE)))))

(defrecord SpriteEntity [object] Entity
  (draw! [{:keys [^Sprite object
                          alpha
                          x y width height scale-x scale-y origin-x origin-y
                          alpha angle color]
           :or {x (.getX object)
                y (.getY object)
                width (.getWidth object)
                height (.getHeight object)
                scale-x (.getScaleX object)
                scale-y (.getScaleY object)
                origin-x (.getOriginX object)
                origin-y (.getOriginY object)
                angle (.getRotation object)
                color (.getColor object)}}
          _
          batch]
    (.setBounds object
                (float x)
                (float y)
                (float width)
                (float height))
    (.setOrigin object
                (float origin-x)
                (float origin-y))
    (.setScale object
               (float scale-x)
               (float scale-y))
    (.setRotation object angle)
    (if (instance? Color color)
      (.setColor object color)
      (let [[r g b a] color]
        (.setColor object r g b a)))
    (if alpha
      (.draw object ^Batch batch alpha)
      (.draw object ^Batch batch))))

(defrecord NinePatchEntity [object] Entity
  (draw! [{:keys [^NinePatch object x y width height]} _ batch]
    (let [x (float (or x 0))
          y (float (or y 0))
          width (float (or width (.getTotalWidth object)))
          height (float (or height (.getTotalHeight object)))]
      (.draw object ^Batch batch x y width height))))

(defrecord ParticleEffectEntity [object] Entity
  (draw! [{:keys [^ParticleEffect object x y delta-time]} _ batch]
    (let [x (float (or x 0))
          y (float (or y 0))
          ^Graphics g (Gdx/graphics)
          delta-time (float (or delta-time (.getDeltaTime g)))]
      (.setPosition object x y)
      (.draw object ^Batch batch delta-time))))

(defrecord ActorEntity [object] Entity
  (draw! [{:keys [^Actor object x y width height
                  scale-x scale-y angle origin-x origin-y]} _ batch]
    (when (.getStage object)
      (some->> x (.setX object))
      (some->> y (.setY object))
      (some->> width (.setWidth object))
      (some->> height (.setHeight object))
      (when (or scale-x scale-y angle)
        (let [scale-x (float (or scale-x 1))
              scale-y (float (or scale-y 1))
              origin-x (float (or origin-x (/ (.getWidth object) 2)))
              origin-y (float (or origin-y (/ (.getHeight object) 2)))
              angle (float (or angle 0))]
          (.setScaleX object scale-x)
          (.setScaleY object scale-y)
          (.setOriginX object origin-x)
          (.setOriginY object origin-y)
          (.setRotation object angle)))
      (.draw object ^Batch batch 1))))

(defrecord ModelEntity [object] Entity
  (draw! [{:keys [^ModelInstance object x y z]}
          {:keys [^ModelBatch renderer ^Environment attributes]}
          _]
    (when (or x y z)
      (let [^Matrix4 m (. object transform)
            x (float (or x 0))
            y (float (or y 0))
            z (float (or z 0))]
        (.setTranslation m x y z)))
    (.render renderer object attributes)))

(defrecord ShapeEntity [object] Entity
  (draw! [{:keys [^ShapeRenderer object type draw!
                  x y scale-x scale-y angle]}
          {:keys [^Camera camera]}
          batch]
    (when batch
      (.end ^Batch batch))
    (when camera
      (.setProjectionMatrix object (. camera combined)))
    (.glEnable Gdx/gl GL20/GL_BLEND)
    (.glBlendFunc Gdx/gl GL20/GL_SRC_ALPHA GL20/GL_ONE_MINUS_SRC_ALPHA)
    (.begin object type)
    (when (or x y scale-x scale-y angle)
      (let [x (float (or x 0))
            y (float (or y 0))
            scale-x (float (or scale-x 1))
            scale-y (float (or scale-y 1))
            angle (float (or angle 0))]
        (.identity object)
        (.translate object x y 0)
        (.scale object scale-x scale-y 1)
        (.rotate object 0 0 1 angle)))
    (draw!)
    (.end object)
    (.glDisable Gdx/gl GL20/GL_BLEND)
    (when batch
      (.begin ^Batch batch))))

(defrecord BundleEntity [entities] Entity
  (draw! [{:keys [entities] :as entity} screen batch]
    (doseq [e entities]
      (draw! (merge e (apply dissoc entity (keys e))) screen batch))))


text:
(ns play-clj.repl
  (:require [play-clj.core :refer :all]))

(defn s
  "Returns the screen map in `screen-object`.

    (s main-screen)"
  [screen-object]
  (-> screen-object :screen deref))

(defn s!
  "Associates values to the screen map in `screen-object`. Returns the new
screen map.

    (s! main-screen :camera (orthographic))"
  [screen-object & args]
  (apply swap! (:screen screen-object) assoc args))

(defn e
  "Returns the entities in `screen-object`, optionally filtered by a supplied
function.

    (e :player? main-screen)
    (e texture? main-screen)"
  ([screen-object]
   (-> screen-object :entities deref))
  ([filter-fn screen-object]
   (vec (filter filter-fn (e screen-object)))))

(defn e!
  "Associates values to the entities in `screen-object` that match the supplied
function. Returns the entities that were changed.

    (e! :player? main-screen :health 10)"
  [filter-fn screen-object & args]
  (swap! (:entities screen-object)
         (fn [entities]
           (vec (for [e entities]
                  (if (filter-fn e)
                    (apply assoc e args)
                    e)))))
  (e filter-fn screen-object))


text:
(ns play-clj.g2d
  (:require [play-clj.entities]
            [play-clj.utils :as u])
  (: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 Sprite
            ParticleEffect TextureAtlas TextureRegion]
           [play_clj.entities TextureEntity NinePatchEntity SpriteEntity
            ParticleEffectEntity]))

(defn bitmap-font*
  [^String path]
  (if (nil? path)
    (BitmapFont.)
    (or (u/load-asset path BitmapFont)
        (BitmapFont. (.internal (Gdx/files) path)))))

(defmacro bitmap-font
  "Returns a [BitmapFont](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g2d/BitmapFont.html).

    (bitmap-font)
    (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`."
  [object k & options]
  `(u/call! ^BitmapFont ~object ~k ~@options))

; texture

(defn texture*
  [arg]
  (TextureEntity.
    (cond
      (string? arg)
      (-> (or (u/load-asset arg Texture)
              (Texture. ^String arg))
          TextureRegion.)
      (instance? Pixmap arg)
      (-> ^Pixmap arg Texture. TextureRegion.)
      (instance? Texture arg)
      (-> ^Texture arg TextureRegion.)
      (instance? TextureEntity arg)
      (-> ^TextureRegion (:object arg) TextureRegion.)
      :else
      arg)))

(defmacro texture
  "Returns an entity based on [TextureRegion](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g2d/TextureRegion.html).

    ; load image.png
    (texture \"image.png\")
    ; load image.png, flip it, and only display the specified region
    (texture \"image.png\"
             :flip true false
             :set-region 0 0 100 100)
    ; create a new texture based on an existing one
    (texture (texture \"image.png\"))
    ; rotate a texture 45 degress
    (assoc (texture \"image.png\")
           :angle 45)"
  [arg & options]
  `(let [entity# (texture* ~arg)]
     (u/calls! ^TextureRegion (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro texture!
  "Calls a single method on a `texture`.

    (texture! entity :flip true false)
    (texture! entity :get-region-width)"
  [entity k & options]
  `(u/call! ^TextureRegion (u/get-obj ~entity :object) ~k ~@options))

(defn texture?
  "Returns true if `entity` is a `texture`."
  [entity]
  (instance? TextureRegion (u/get-obj entity :object)))

; sprite

(defn sprite*
  [arg]
  (SpriteEntity.
    (cond
      (string? arg)
      (-> (or (u/load-asset arg Texture)
              (Texture. ^String arg))
          Sprite.)
      (instance? Pixmap arg)
      (-> ^Pixmap arg Texture. Sprite.)
      (instance? Texture arg)
      (-> ^Texture arg Sprite.)
      (instance? SpriteEntity arg)
      (-> ^Sprite (:object arg) Sprite.)
      :else
      arg)))

(defmacro sprite
  [arg & options]
  `(let [entity# (sprite* ~arg)]
     (u/calls! ^Sprite (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro sprite!
  "Calls a single method on a `sprite`.

    (sprite! entity :flip true false)
    (sprite! entity :set-alpha 0.5)"
  [entity k & options]
  `(u/call! ^Sprite (u/get-obj ~entity :object) ~k ~@options))

(defn sprite?
  "Returns true if `entity` is a `sprite`."
  [entity]
  (instance? Sprite (u/get-obj entity :object)))

; nine-patch

(defn nine-patch*
  [arg]
  (NinePatchEntity.
    (cond
      (string? arg)
      (-> (or (u/load-asset arg Texture)
              (Texture. ^String arg))
          TextureRegion.
          NinePatch.)
      (instance? NinePatchEntity arg)
      (NinePatch. (:object arg))
      (map? arg)
      (let [{:keys [region left right top bottom]} arg]
        (NinePatch. region left right top bottom))
      :else
      arg)))

(defmacro nine-patch
  "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))"
  [arg & options]
  `(let [entity# (nine-patch* ~arg)]
     (u/calls! ^NinePatch (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro nine-patch!
  "Calls a single method on a `nine-patch`.

    (nine-patch! entity :set-color (color :blue))
    (nine-patch! entity :get-middle-width)"
  [entity k & options]
  `(u/call! ^NinePatch (u/get-obj ~entity :object) ~k ~@options))

(defn nine-patch?
  "Returns true if `entity` is a `nine-patch`."
  [entity]
  (instance? NinePatch (u/get-obj entity :object)))

; particle-effect

(defn particle-effect*
  [^String path]
  (ParticleEffectEntity.
    (if (nil? path)
      (ParticleEffect.)
      (or (u/load-asset path ParticleEffect)
          (let [^FileHandle fh (.internal (Gdx/files) path)]
            (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)
    (particle-effect \"particles/fire.p\")"
  [& [path & options]]
  `(let [entity# (particle-effect* ~path)]
     (u/calls! ^ParticleEffect (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro particle-effect!
  "Calls a single method on a `particle-effect`.

    (particle-effect! entity :set-position 10 10)"
  [entity k & options]
  `(u/call! ^ParticleEffect (u/get-obj ~entity :object) ~k ~@options))

(defn particle-effect?
  "Returns true if `entity` is a `particle-effect`."
  [entity]
  (instance? ParticleEffect (u/get-obj entity :object)))

; texture-atlas

(defn texture-atlas*
  [^String 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).

    (texture-atlas \"packed.txt\")"
  [path & options]
  `(let [^TextureAtlas object# (texture-atlas* ~path)]
     (u/calls! object# ~@options)
     object#))

(defmacro texture-atlas!
  "Calls a single method on a `texture-atlas`.

    (texture-atlas! object :create-patch \"test\")"
  [object k & options]
  `(u/call! ^TextureAtlas ~object ~k ~@options))

; animation

(defmacro play-mode
  "Returns a static field from [Animation.PlayMode](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g2d/Animation.PlayMode.html).

    (play-mode :loop)"
  [k]
  (u/gdx-field :graphics :g2d "Animation$PlayMode" (u/key->upper k)))

(defn animation*
  [duration textures]
  (Animation. duration
              (u/gdx-array (map #(u/get-obj % :object) textures))
              (play-mode :normal)))

(defmacro animation
  "Returns an [Animation](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g2d/Animation.html).

    (animation 0.2
               [walk-1 walk-2 walk-3]
               :set-play-mode (play-mode :loop-pingpong))"
  [duration textures & options]
  `(u/calls! ^Animation (animation* ~duration ~textures) ~@options))

(defmacro animation!
  "Calls a single method on an `animation`.

    (animation! object :set-play-mode (play-mode :loop))"
  [object k & options]
  `(u/call! ^Animation ~object ~k ~@options))

(defn animation->texture
  "Returns a `texture` entity with a frame from `animation` based on the total
time the `screen` has been showing.

    (animation->texture screen anim)"
  ([{:keys [total-time] :as screen} ^Animation animation]
   (texture* (.getKeyFrame animation total-time true)))
  ([{:keys [total-time] :as screen} ^Animation animation is-looping?]
   (texture* (.getKeyFrame animation total-time is-looping?))))


text:
(ns play-clj.g3d
  (:require [play-clj.entities]
            [play-clj.utils :as u])
  (:import [com.badlogic.gdx.graphics.g3d Environment Material Model ModelBatch
            ModelInstance]
           [com.badlogic.gdx.graphics.g3d.attributes BlendingAttribute
            ColorAttribute CubemapAttribute DepthTestAttribute FloatAttribute
            IntAttribute TextureAttribute]
           [com.badlogic.gdx.graphics.g3d.model.data ModelData]
           [com.badlogic.gdx.graphics.g3d.utils AnimationController
            ModelBuilder]
           [play_clj.entities ModelEntity]))

; animation-controller

(defn animation-controller*
  [entity]
  (AnimationController. (u/get-obj entity :object)))

(defmacro animation-controller
  "Returns an [AnimationController](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g3d/utils/AnimationController.html).

    (animation-controller model-entity)"
  [entity & options]
  `(let [^AnimationController object# (animation-controller* ~entity)]
     (u/calls! object# ~@options)))

(defmacro animation-controller!
  "Calls a single method on an `animation-controller`."
  [object k & options]
  `(let [^AnimationController object# ~object]
     (u/call! object# ~k ~@options)))

; environment

(defn environment*
  []
  (Environment.))

(defmacro environment
  "Returns an [Environment](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g3d/Environment.html).

    (environment)"
  [& options]
  `(let [^Environment object# (environment*)]
     (u/calls! object# ~@options)))

(defmacro environment!
  "Calls a single method on an `environment`."
  [screen k & options]
  `(let [^Environment object# (u/get-obj ~screen :attributes)]
     (u/call! object# ~k ~@options)))

; model-batch

(defn model-batch*
  []
  (ModelBatch.))

(defmacro model-batch
  "Returns a [ModelBatch](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g3d/ModelBatch.html).

    (model-batch)"
  [& options]
  `(let [^ModelBatch object# (model-batch*)]
     (u/calls! object# ~@options)))

(defmacro model-batch!
  "Calls a single method on a `model-batch`."
  [screen k & options]
  `(let [^ModelBatch object# (u/get-obj ~screen :renderer)]
     (u/call! object# ~k ~@options)))

; 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).
In addition to the listed options, you may also pass an internal path to a model
object created by an external application.

    ; load a model from a file
    (model \"knight.g3dj\")
    ; create a model from an existing model
    (model (model \"knight.g3dj\"))
    ; set the position of a model
    (assoc (model \"knight.g3dj\")
           :x 0 :y 0 :z 0)"
  [& args]
  `(ModelEntity.
     (let [arg1# ~(first args)]
       (cond
         (string? arg1#)
         (ModelInstance. (model* arg1#))
         (instance? ModelEntity arg1#)
         (ModelInstance. (. ^ModelInstance (:object arg1#) model) ~@(rest args))
         (instance? ModelData arg1#)
         (ModelInstance. ^Model (Model. arg1# ~@(rest args)))
         :else
         (ModelInstance. arg1# ~@(rest args))))))

(defmacro model!
  "Calls a single method on a `model`."
  [entity k & options]
  `(let [^ModelInstance object# (u/get-obj ~entity :object)]
     (u/call! object# ~k ~@options)))

(defn model?
  "Returns true if `entity` is a `model`."
  [entity]
  (instance? ModelInstance (u/get-obj entity :object)))

; model-builder

(defn model-builder*
  []
  (ModelBuilder.))

(defmacro model-builder
  "Returns a [ModelBuilder](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g3d/utils/ModelBuilder.html).

    (model-builder)"
  [& options]
  `(let [^ModelBuilder object# (model-builder*)]
     (u/calls! object# ~@options)))

(defmacro model-builder!
  "Calls a single method on a `model-builder`."
  [object k & options]
  `(u/call! ^ModelBuilder ~object ~k ~@options))

; material

(defn material*
  []
  (Material.))

(defmacro material
  "Returns a [Material](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g3d/Material.html).

    (material)"
  [& options]
  `(let [^Material object# (material*)]
     (u/calls! object# ~@options)))

(defmacro material!
  "Calls a single method on a `material`."
  [object k & options]
  `(u/call! ^Material ~object ~k ~@options))

; attribute

(defn ^:private attribute-init
  [k]
  (u/gdx :graphics :g3d :attributes (str (u/key->pascal k) "Attribute.")))

(defmacro attribute
  "Returns a subclass of [Attribute](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g3d/Attribute.html).

    (attribute :color (attribute-type :color :diffuse) (color :blue))"
  [type & args]
  `(~(attribute-init type) ~@args))

(defmacro attribute-type
  "Returns a static field in a subclass of [Attribute](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g3d/Attribute.html).

    (attribute-type :color :diffuse)"
  [type k]
  (u/gdx-field :graphics :g3d :attributes
               (str (u/key->pascal type) "Attribute")
               (u/key->pascal k)))

(defmacro attribute!
  "Calls a static method in a subclass of [Attribute](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g3d/Attribute.html).

    (attribute! :color :create-diffuse (color :blue))"
  [type k & options]
  `(~(u/gdx-field :graphics :g3d :attributes
                  (str (u/key->pascal type) "Attribute")
                  (u/key->camel k))
     ~@options))


text:
(ns play-clj.physics
  (:require [play-clj.g2d-physics :as p2d]
            [play-clj.g3d-physics :as p3d]
            [play-clj.utils :as u]))

; this namespace is for internal use only. you should use the g2d-physics and
; g3d-physics namespaces directly, instead.

(defmulti add-body!
  (fn [screen body] (some-> screen (u/get-obj :world) class .getName)))

(defmethod add-body!
  "com.badlogic.gdx.physics.box2d.World"
  [screen b-def]
  (p2d/add-body! screen b-def))

(defmethod add-body!
  "play_clj.g3d_physics.World3D"
  [screen body]
  (p3d/add-body! screen body))

(defmulti body-position!
  (fn [entity a1 a2 a3] (some-> entity (u/get-obj :body) class .getName)))

(defmethod body-position!
  "com.badlogic.gdx.physics.box2d.Body"
  [entity x y angle]
  (p2d/body-position! entity x y angle))

(defmethod body-position!
  "play_clj.g3d_physics.Body3D"
  [entity x y z]
  (p3d/body-position! entity x y z))

(defmulti body-x!
  (fn [entity x] (some-> entity (u/get-obj :body) class .getName)))

(defmethod body-x!
  "com.badlogic.gdx.physics.box2d.Body"
  [entity x]
  (p2d/body-x! entity x))

(defmethod body-x!
  "play_clj.g3d_physics.Body3D"
  [entity x]
  (p3d/body-x! entity x))

(defmulti body-y!
  (fn [entity y] (some-> entity (u/get-obj :body) class .getName)))

(defmethod body-y!
  "com.badlogic.gdx.physics.box2d.Body"
  [entity y]
  (p2d/body-y! entity y))

(defmethod body-y!
  "play_clj.g3d_physics.Body3D"
  [entity y]
  (p3d/body-y! entity y))

(defmulti body-z!
  (fn [entity z] (some-> entity (u/get-obj :body) class .getName)))

(defmethod body-z!
  "play_clj.g3d_physics.Body3D"
  [entity z]
  (p3d/body-z! entity z))

(defmulti body-angle!
  (fn [entity angle] (some-> entity (u/get-obj :body) class .getName)))

(defmethod body-angle!
  "com.badlogic.gdx.physics.box2d.Body"
  [entity angle]
  (p2d/body-angle! entity angle))

(defmulti first-entity
  (fn [screen entities] (some-> screen (u/get-obj :world) class .getName)))

(defmethod first-entity
  "com.badlogic.gdx.physics.box2d.World"
  [screen entities]
  (p2d/first-entity screen entities))

(defmethod first-entity
  "play_clj.g3d_physics.World3D"
  [screen entities]
  (p3d/first-entity screen entities))

(defmulti second-entity
  (fn [screen entities] (some-> screen (u/get-obj :world) class .getName)))

(defmethod second-entity
  "com.badlogic.gdx.physics.box2d.World"
  [screen entities]
  (p2d/second-entity screen entities))

(defmethod second-entity
  "play_clj.g3d_physics.World3D"
  [screen entities]
  (p3d/second-entity screen entities))

(defmulti add-joint!
  (fn [screen joint] (some-> screen (u/get-obj :world) class .getName)))

(defmethod add-joint!
  "com.badlogic.gdx.physics.box2d.World"
  [screen j-def]
  (p2d/add-joint! screen j-def))

(defmulti step!
  (fn [screen & [entities]] (some-> screen (u/get-obj :world) class .getName)))

(defmethod step!
  "com.badlogic.gdx.physics.box2d.World"
  [screen & [entities]]
  (p2d/step! screen entities))

(defmethod step!
  "play_clj.g3d_physics.World3D"
  [screen & [entities]]
  (p3d/step! screen entities))

(def box-2d* p2d/box-2d*)
(defmacro box-2d [& body] `(p2d/box-2d ~@body))
(defmacro box-2d! [& body] `(p2d/box-2d! ~@body))
(defmacro body-def [& body] `(p2d/body-def ~@body))
(defmacro body! [& body] `(p2d/body! ~@body))
(defmacro joint-def [& body] `(p2d/joint-def ~@body))
(defmacro joint! [& body] `(p2d/joint! ~@body))
(defmacro fixture-def [& body] `(p2d/fixture-def ~@body))
(defmacro fixture! [& body] `(p2d/fixture! ~@body))

(def chain-shape* p2d/chain-shape*)
(defmacro chain-shape [& body] `(p2d/chain-shape ~@body))
(defmacro chain-shape! [& body] `(p2d/chain-shape! ~@body))
(def circle-shape* p2d/circle-shape*)
(defmacro circle-shape [& body] `(p2d/circle-shape ~@body))
(defmacro circle-shape! [& body] `(p2d/circle-shape! ~@body))
(def edge-shape* p2d/edge-shape*)
(defmacro edge-shape [& body] `(p2d/edge-shape ~@body))
(defmacro edge-shape! [& body] `(p2d/edge-shape! ~@body))
(def polygon-shape* p2d/polygon-shape*)
(defmacro polygon-shape [& body] `(p2d/polygon-shape ~@body))
(defmacro polygon-shape! [& body] `(p2d/polygon-shape! ~@body))

(def init-bullet p3d/init-bullet)
(def bullet-3d* p3d/bullet-3d*)
(defmacro bullet-3d [& body] `(p3d/bullet-3d ~@body))
(defmacro bullet-3d! [& body] `(p3d/bullet-3d! ~@body))
(def rigid-body* p3d/rigid-body*)
(defmacro rigid-body [& body] `(p3d/rigid-body ~@body))
(defmacro rigid-body! [& body] `(p3d/rigid-body! ~@body))
(def rigid-body-info p3d/rigid-body-info)
(def soft-body* p3d/soft-body*)
(defmacro soft-body [& body] `(p3d/soft-body ~@body))
(defmacro soft-body! [& body] `(p3d/soft-body! ~@body))
(def soft-body-info p3d/soft-body-info)

(def box-shape* p3d/box-shape*)
(defmacro box-shape [& body] `(p3d/box-shape ~@body))
(defmacro box-shape! [& body] `(p3d/box-shape! ~@body))
(def capsule-shape* p3d/capsule-shape*)
(defmacro capsule-shape [& body] `(p3d/capsule-shape ~@body))
(defmacro capsule-shape! [& body] `(p3d/capsule-shape! ~@body))
(def cone-shape* p3d/cone-shape*)
(defmacro cone-shape [& body] `(p3d/cone-shape ~@body))
(defmacro cone-shape! [& body] `(p3d/cone-shape! ~@body))
(def cylinder-shape* p3d/cylinder-shape*)
(defmacro cylinder-shape [& body] `(p3d/cylinder-shape ~@body))
(defmacro cylinder-shape! [& body] `(p3d/cylinder-shape! ~@body))
(def sphere-shape* p3d/sphere-shape*)
(defmacro sphere-shape [& body] `(p3d/sphere-shape ~@body))
(defmacro sphere-shape! [& body] `(p3d/sphere-shape! ~@body))


text:
(ns play-clj.ui
  (:require [play-clj.entities]
            [play-clj.g2d :as g2d]
            [play-clj.utils :as u])
  (:import [com.badlogic.gdx Files Gdx]
           [com.badlogic.gdx.graphics Color Texture]
           [com.badlogic.gdx.graphics.g2d TextureRegion]
           [com.badlogic.gdx.scenes.scene2d Actor Stage]
           [com.badlogic.gdx.scenes.scene2d.ui ButtonGroup Cell CheckBox
            Container Dialog HorizontalGroup Image ImageButton ImageTextButton
            Label ScrollPane SelectBox Skin Slider Stack Table TextButton
            TextField Tree Tree$Node VerticalGroup WidgetGroup Window]
           [com.badlogic.gdx.scenes.scene2d.utils ActorGestureListener
            ChangeListener ClickListener DragListener FocusListener
            NinePatchDrawable SpriteDrawable TextureRegionDrawable
            TiledDrawable]
           [play_clj.entities ActorEntity]))

(defmacro drawable
  "Returns a subclass of [BaseDrawable](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/utils/BaseDrawable.html).

    (drawable :texture-region)"
  [k & options]
  `(~(u/gdx :scenes :scene2d :utils
            (str (u/key->pascal k) "Drawable."))
     ~@options))

(defmacro style
  "Returns a style object whose class is determined by the keyword `k`.

    (style :check-box)"
  [k & options]
  `(~(u/gdx-class :scenes :scene2d :ui
                  (u/key->pascal k)
                  (str (u/key->pascal k) "Style."))
     ~@options))

(defn skin*
  [^String path]
  (or (u/load-asset path Skin)
      (Skin. (.internal ^Files (Gdx/files) path))))

(defmacro skin
  "Returns a [Skin](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/Skin.html)
based on the file at `path`.

    (skin \"uiskin.json\")"
  [path & options]
  `(u/calls! ^Skin (skin* ~path) ~@options))

(defmacro skin!
  "Calls a single method on a `skin`."
  [object k & options]
  `(u/call! ^Skin ~object ~k ~@options))

(defmacro align
  "Returns a static field from [Align](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/utils/Align.html).

    (align :center)"
  [k]
  (u/gdx-field :utils :Align (u/key->camel k)))

(defn cell!
  "Calls methods on a [Cell](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/Cell.html)."
  [^Cell cell & args]
  (let [method (first args)
        [[a1 a2 a3 a4] rest-args] (split-with #(not (keyword? %)) (rest args))]
    (when method
      (case method
        :width (.width cell ^double a1)
        :height (.height cell ^double a1)
        :size (.size cell ^double a1 ^double a2)
        :min-width (.minWidth cell ^double a1)
        :min-height (.minHeight cell ^double a1)
        :min-size (.minSize cell ^double a1 ^double a2)
        :max-width (.maxWidth cell ^double a1)
        :max-height (.maxHeight cell ^double a1)
        :max-size (.minSize cell ^double a1 ^double a2)
        :space (.space cell ^double a1 ^double a2 ^double a3 ^double a4)
        :space-top (.spaceTop cell ^double a1)
        :space-left (.spaceLeft cell ^double a1)
        :space-bottom (.spaceBottom cell ^double a1)
        :space-right (.spaceRight cell ^double a1)
        :pad (.pad cell ^double a1 ^double a2 ^double a3 ^double a4)
        :pad-top (.padTop cell ^double a1)
        :pad-left (.padLeft cell ^double a1)
        :pad-bottom (.padBottom cell ^double a1)
        :pad-right (.padRight cell ^double a1)
        :fill (.fill cell ^boolean a1 ^boolean a2)
        :fill-x (.fillX cell)
        :fill-y (.fillY cell)
        :align (.align cell (int a1))
        :center (.center cell)
        :top (.top cell)
        :left (.left cell)
        :bottom (.bottom cell)
        :right (.right cell)
        :expand (.expand cell ^boolean a1 ^boolean a2)
        :expand-x (.expandX cell)
        :expand-y (.expandY cell)
        :ignore (.ignore cell ^boolean a1)
        :colspan (.colspan cell (int a1))
        :uniform (.uniform cell ^boolean a1 ^boolean a2)
        :uniform-x (.uniformX cell)
        :uniform-y (.uniformY cell)
        :row (.row cell)
        (u/throw-key-not-found method))
      (apply cell! cell rest-args))
    cell))

(defmulti add-to-group!
  #(-> % first :object type) :default WidgetGroup)

(defn ^:private create-tree-node
  [child]
  {:object (Tree$Node. ^Actor (:object child))})

(defn ^:private add-tree-nodes
  [parent children]
  (when-let [node (add-to-group! [parent (first children)])]
    (doseq [child (rest children)]
      (add-to-group! [node child]))
    node))

(defmethod add-to-group! WidgetGroup
  [[parent child]]
  (.addActor ^WidgetGroup (:object parent) ^Actor (:object child)))

(defmethod add-to-group! Table
  [[parent child]]
  (cond
    (map? child)
    (.add ^Table (:object parent) ^Actor (:object child))
    (coll? child)
    (apply cell! (add-to-group! [parent (first child)]) (rest child))
    (keyword? child)
    (case child
      :row (.row ^Table (:object parent))
      (u/throw-key-not-found child))))

(defmethod add-to-group! Tree
  [[parent child]]
  (cond
    (map? child)
    (let [node (create-tree-node child)]
      (.add ^Tree (:object parent) ^Tree$Node (:object node))
      node)
    (coll? child)
    (add-tree-nodes parent child)))

(defmethod add-to-group! Tree$Node
  [[parent child]]
  (cond
    (map? child)
    (let [node (create-tree-node child)]
      (.add ^Tree$Node (:object parent) ^Tree$Node (:object node))
      node)
    (coll? child)
    (add-tree-nodes parent child)))

(defn add!
  "Adds the entities in `children` to the `group` entity of type [WidgetGroup](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/WidgetGroup.html)."
  [group & children]
  (doseq [child children]
    (add-to-group! [group child]))
  group)

(defn ^:private create-group
  [^WidgetGroup group children]
  (apply add! (ActorEntity. group) children))

; actor

(defmacro actor!
  "Calls a single method on an actor."
  [entity k & options]
  `(u/call! ^Actor (u/get-obj ~entity :object) ~k ~@options))

(defn actor?
  "Returns true if `entity` is an actor."
  [entity]
  (instance? Actor (u/get-obj entity :object)))

; check-box

(defn check-box*
  [^String text arg]
  (ActorEntity. (CheckBox. text arg)))

(defmacro check-box
  "Returns an entity based on [CheckBox](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/CheckBox.html).

    (check-box \"I'm a check box\" (style :check-box off on font color))
    (check-box \"I'm a check box\" (style :check-box nil nil (bitmap-font) (color :white)))
    (check-box \"I'm a check box\" (skin \"uiskin.json\"))"
  [text arg & options]
  `(let [entity# (check-box* ~text ~arg)]
     (u/calls! ^CheckBox (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro check-box!
  "Calls a single method on a `check-box`."
  [entity k & options]
  `(u/call! ^CheckBox (u/get-obj ~entity :object) ~k ~@options))

(defn check-box?
  "Returns true if `entity` is a `check-box`."
  [entity]
  (instance? CheckBox (u/get-obj entity :object)))

; container

(defn container*
  [child]
  (ActorEntity. (Container. (u/get-obj child :object))))

(defmacro container
  "Returns an entity based on [Container](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/Container.html).

    (container entity)"
  [child & options]
  `(let [entity# (container* ~child)]
     (u/calls! ^Container (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro container!
  "Calls a single method on a `container`."
  [entity k & options]
  `(u/call! ^Container (u/get-obj ~entity :object) ~k ~@options))

(defn container?
  "Returns true if `entity` is a `container`."
  [entity]
  (instance? Container (u/get-obj entity :object)))

; dialog

(defn dialog*
  [text arg]
  (ActorEntity. (Dialog. text arg)))

(defmacro dialog
  "Returns an entity based on [Dialog](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/Dialog.html).

    (dialog \"I'm a dialog\" (style :window font font-color background))
    (dialog \"I'm a dialog\" (style :window (bitmap-font) (color :white) nil))
    (dialog \"I'm a dialog\" (skin \"uiskin.json\"))"
  [text arg & options]
  `(let [entity# (dialog* ~text ~arg)]
     (u/calls! ^Dialog (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro dialog!
  "Calls a single method on a `dialog`."
  [entity k & options]
  `(u/call! ^Dialog (u/get-obj ~entity :object) ~k ~@options))

(defn dialog?
  "Returns true if `entity` is a `dialog`."
  [entity]
  (instance? Dialog (u/get-obj entity :object)))

; horizontal

(defn horizontal*
  [children]
  (create-group (HorizontalGroup.) children))

(defmacro horizontal
  "Returns an entity based on [HorizontalGroup](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/HorizontalGroup.html).

    (horizontal [entity-1 entity-2])"
  [children & options]
  `(let [entity# (horizontal* ~children)]
     (u/calls! ^HorizontalGroup (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro horizontal!
  "Calls a single method on a `horizontal`."
  [entity k & options]
  `(u/call! ^HorizontalGroup (u/get-obj ~entity :object) ~k ~@options))

(defn horizontal?
  "Returns true if `entity` is a `horizontal`."
  [entity]
  (instance? HorizontalGroup (u/get-obj entity :object)))

; image

(defn image*
  [arg]
  (ActorEntity.
    (cond
      (map? arg)
      (Image. ^TextureRegion (:object arg))
      (string? arg)
      (Image. (or (u/load-asset arg Texture)
                  (Texture. ^String arg)))
      :else
      (Image. arg))))

(defmacro image
  "Returns an entity based on [Image](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/Image.html).

    (image \"image.png\")"
  [arg & options]
  `(let [entity# (image* ~arg)]
     (u/calls! ^Image (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro image!
  "Calls a single method on a `image`."
  [entity k & options]
  `(u/call! ^Image (u/get-obj ~entity :object) ~k ~@options))

(defn image?
  "Returns true if `entity` is an `image`."
  [entity]
  (instance? Image (u/get-obj entity :object)))

; image-button

(defn image-button*
  [arg]
  (ActorEntity. (ImageButton. arg)))

(defmacro image-button
  "Returns an entity based on [ImageButton](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/ImageButton.html).

    (image-button (style :image-button up dn check img-up img-dn img-check))
    (image-button (style :image-button nil nil nil nil nil nil))
    (image-button (skin \"uiskin.json\"))"
  [arg & options]
  `(let [entity# (image-button* ~arg)]
     (u/calls! ^ImageButton (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro image-button!
  "Calls a single method on a `image-button`."
  [entity k & options]
  `(u/call! ^ImageButton (u/get-obj ~entity :object) ~k ~@options))

(defn image-button?
  "Returns true if `entity` is an `image-button`."
  [entity]
  (instance? ImageButton (u/get-obj entity :object)))

; image-text-button

(defn image-text-button*
  [^String text arg]
  (ActorEntity. (ImageTextButton. text arg)))

(defmacro image-text-button
  "Returns an entity based on [ImageTextButton](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/ImageTextButton.html).

    (image-text-button \"I'm an image text button\"
                       (style :image-text-button up down checked font))
    (image-text-button \"I'm an image text button\"
                       (style :image-text-button nil nil nil (bitmap-font)))
    (image-text-button \"I'm an image text button\" (skin \"uiskin.json\"))"
  [text arg & options]
  `(let [entity# (image-text-button* ~text ~arg)]
     (u/calls! ^ImageTextButton (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro image-text-button!
  "Calls a single method on a `image-text-button`."
  [entity k & options]
  `(u/call! ^ImageTextButton (u/get-obj ~entity :object) ~k ~@options))

(defn image-text-button?
  "Returns true if `entity` is a `image-text-button`."
  [entity]
  (instance? ImageTextButton (u/get-obj entity :object)))

; label

(defn label*
  [^String text arg]
  (ActorEntity.
    (if (instance? Color arg)
      (Label. text (style :label (g2d/bitmap-font) arg))
      (Label. text arg))))

(defmacro label
  "Returns an entity based on [Label](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/Label.html).

    (label \"I'm a label\" (color :white))
    (label \"I'm a label\" (style :label (bitmap-font) (color :white)))
    (label \"I'm a label\" (skin \"uiskin.json\"))"
  [text arg & options]
  `(let [entity# (label* ~text ~arg)]
     (u/calls! ^Label (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro label!
  "Calls a single method on a `label`."
  [entity k & options]
  `(u/call! ^Label (u/get-obj ~entity :object) ~k ~@options))

(defn label?
  "Returns true if `entity` is a `label`."
  [entity]
  (instance? Label (u/get-obj entity :object)))

; scroll-pane

(defn scroll-pane*
  [child arg]
  (ActorEntity. (ScrollPane. (u/get-obj child :object) arg)))

(defmacro scroll-pane
  "Returns an entity based on [ScrollPane](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/ScrollPane.html).

    (scroll-pane table-entity (style :scroll-pane back h h-knob v v-knob))
    (scroll-pane table-entity (style :scroll-pane nil nil nil nil nil))
    (scroll-pane table-entity (skin \"uiskin.json\"))"
  [child arg & options]
  `(let [entity# (scroll-pane* ~child ~arg)]
     (u/calls! ^ScrollPane (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro scroll-pane!
  "Calls a single method on a `scroll-pane`."
  [entity k & options]
  `(u/call! ^ScrollPane (u/get-obj ~entity :object) ~k ~@options))

(defn scroll-pane?
  "Returns true if `entity` is a `scroll-pane`."
  [entity]
  (instance? ScrollPane (u/get-obj entity :object)))

; select-box

(defn select-box*
  [arg]
  (ActorEntity. (SelectBox. arg)))

(defmacro select-box
  "Returns an entity based on [SelectBox](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/SelectBox.html).

    (select-box (style :select-box font color back scroll-style list-style)
                :set-items (into-array [\"Item 1\" \"Item 2\" \"Item 3\"]))
    (select-box (style :select-box (bitmap-font) (color :white) nil
                       (style :scroll-pane nil nil nil nil nil)
                       (style :list (bitmap-font) (color :white) (color :black) nil))
                :set-items (into-array [\"Item 1\" \"Item 2\" \"Item 3\"]))
    (select-box (skin \"uiskin.json\")
                :set-items (into-array [\"Item 1\" \"Item 2\" \"Item 3\"]))"
  [arg & options]
  `(let [entity# (select-box* ~arg)]
     (u/calls! ^SelectBox (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro select-box!
  "Calls a single method on a `select-box`."
  [entity k & options]
  `(u/call! ^SelectBox (u/get-obj ~entity :object) ~k ~@options))

(defn select-box?
  "Returns true if `entity` is a `select-box`."
  [entity]
  (instance? SelectBox (u/get-obj entity :object)))

; slider

(defn slider*
  [{:keys [min max step vertical?]
    :or {min 0 max 10 step 1 vertical? false}}
   arg]
  (ActorEntity.
    (Slider. (float min) (float max) (float step) vertical? arg)))

(defmacro slider
  "Returns an entity based on [Slider](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/Slider.html).

    (slider {:min 0 :max 10 :step 1 :vertical? false} (style :slider back knob))
    (slider {:min 0 :max 10 :step 1 :vertical? false} (style :slider nil nil))
    (slider {:min 0 :max 10 :step 1 :vertical? false} (skin \"uiskin.json\"))"
  [attrs arg & options]
  `(let [entity# (slider* ~attrs ~arg)]
     (u/calls! ^Slider (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro slider!
  "Calls a single method on a `slider`."
  [entity k & options]
  `(u/call! ^Slider (u/get-obj ~entity :object) ~k ~@options))

(defn slider?
  "Returns true if `entity` is a `slider`."
  [entity]
  (instance? Slider (u/get-obj entity :object)))

; stack

(defn stack*
  [children]
  (create-group (Stack.) children))

(defmacro stack
  "Returns an entity based on [Stack](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/Stack.html).

    (stack [entity-1 entity-2])"
  [children & options]
  `(let [entity# (stack* ~children)]
     (u/calls! ^Stack (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro stack!
  "Calls a single method on a `stack`."
  [entity k & options]
  `(u/call! ^Stack (u/get-obj ~entity :object) ~k ~@options))

(defn stack?
  "Returns true if `entity` is a `stack`."
  [entity]
  (instance? Stack (u/get-obj entity :object)))

; table

(defn table*
  [children]
  (create-group (Table.) children))

(defmacro table
  "Returns an entity based on [Table](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/Table.html).

    (table [entity-1 entity-2])"
  [children & options]
  `(let [entity# (table* ~children)]
     (u/calls! ^Table (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro table!
  "Calls a single method on a `table`."
  [entity k & options]
  `(u/call! ^Table (u/get-obj ~entity :object) ~k ~@options))

(defn table?
  "Returns true if `entity` is a `table`."
  [entity]
  (instance? Table (u/get-obj entity :object)))

; text-button

(defn text-button*
  [^String text arg]
  (ActorEntity. (TextButton. text arg)))

(defmacro text-button
  "Returns an entity based on [TextButton](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/TextButton.html).

    (text-button \"I'm a text button\" (style :text-button up dn checked font))
    (text-button \"I'm a text button\" (style :text-button nil nil nil (bitmap-font)))
    (text-button \"I'm a text button\" (skin \"uiskin.json\"))"
  [text arg & options]
  `(let [entity# (text-button* ~text ~arg)]
     (u/calls! ^TextButton (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro text-button!
  "Calls a single method on a `text-button`."
  [entity k & options]
  `(u/call! ^TextButton (u/get-obj ~entity :object) ~k ~@options))

(defn text-button?
  "Returns true if `entity` is a `text-button`."
  [entity]
  (instance? TextButton (u/get-obj entity :object)))

; text-field

(defn text-field*
  [^String text arg]
  (ActorEntity. (TextField. text arg)))

(defmacro text-field
  "Returns an entity based on [TextField](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/TextField.html).

    (text-field \"I'm a text field\" (style :text-field font color cur sel back))
    (text-field \"I'm a text field\" (style :text-field (bitmap-font) (color :white) nil nil nil))
    (text-field \"I'm a text field\" (skin \"uiskin.json\"))"
  [text arg & options]
  `(let [entity# (text-field* ~text ~arg)]
     (u/calls! ^TextField (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro text-field!
  "Calls a single method on a `text-field`."
  [entity k & options]
  `(u/call! ^TextField (u/get-obj ~entity :object) ~k ~@options))

(defn text-field?
  "Returns true if `entity` is a `text-field`."
  [entity]
  (instance? TextField (u/get-obj entity :object)))

; tree

(defn tree*
  [children arg]
  (create-group (Tree. arg) children))

(defmacro tree
  "Returns an entity based on [Tree](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/Tree.html).

    (tree [entity-1 entity-2] (style :tree plus minus selection))
    (tree [entity-1 entity-2] (style :tree nil nil nil))
    (tree [entity-1 entity-2] (skin \"uiskin.json\"))"
  [children arg & options]
  `(let [entity# (tree* ~children ~arg)]
     (u/calls! ^Tree (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro tree!
  "Calls a single method on a `tree`."
  [entity k & options]
  `(u/call! ^Tree (u/get-obj ~entity :object) ~k ~@options))

(defn tree?
  "Returns true if `entity` is a `tree`."
  [entity]
  (instance? Tree (u/get-obj entity :object)))

; vertical

(defn vertical*
  [children]
  (create-group (VerticalGroup.) children))

(defmacro vertical
  "Returns an entity based on [VerticalGroup](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/VerticalGroup.html).

    (vertical [entity-1 entity-2])"
  [children & options]
  `(let [entity# (vertical* ~children)]
     (u/calls! ^VerticalGroup (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro vertical!
  "Calls a single method on a `vertical`."
  [entity k & options]
  `(u/call! ^VerticalGroup (u/get-obj ~entity :object) ~k ~@options))

(defn vertical?
  "Returns true if `entity` is a `vertical`."
  [entity]
  (instance? VerticalGroup (u/get-obj entity :object)))

; window

(defn window*
  [children ^String title arg]
  (create-group (Window. title arg) children))

(defmacro window
  "Returns an entity based on [Window](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/ui/Window.html).

    (window [entity-1 entity-2] \"I'm a window\" (style :window font color background))
    (window [entity-1 entity-2] \"I'm a window\" (style :window (bitmap-font) (color :white) nil))
    (window [entity-1 entity-2] \"I'm a window\" (skin \"uiskin.json\"))"
  [children title arg & options]
  `(let [entity# (window* ~children ~title ~arg)]
     (u/calls! ^Window (u/get-obj entity# :object) ~@options)
     entity#))

(defmacro window!
  "Calls a single method on a `window`."
  [entity k & options]
  `(u/call! ^Window (u/get-obj ~entity :object) ~k ~@options))

(defn window?
  "Returns true if `entity` is a `window`."
  [entity]
  (instance? Window (u/get-obj entity :object)))

; listeners

(defmacro actor-gesture-listener!
  "Calls a single method on the [ActorGestureListener](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/utils/ActorGestureListener.html)
in the `screen`."
  [screen k & options]
  `(let [listeners# (u/get-obj ~screen :ui-listeners)
         ^ActorGestureListener object#
         (u/get-obj listeners# :actor-gesture-listener)]
     (u/call! object# ~k ~@options)))

(defmacro change-listener!
  "Calls a single method on the [ChangeListener](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/utils/ChangeListener.html)
in the `screen`."
  [screen k & options]
  `(let [listeners# (u/get-obj ~screen :ui-listeners)
         ^ChangeListener object# (u/get-obj listeners# :change-listener)]
     (u/call! object# ~k ~@options)))

(defmacro click-listener!
  "Calls a single method on the [ClickListener](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/utils/ClickListener.html)
in the `screen`."
  [screen k & options]
  `(let [listeners# (u/get-obj ~screen :ui-listeners)
         ^ClickListener object# (u/get-obj listeners# :click-listener)]
     (u/call! object# ~k ~@options)))

(defmacro drag-listener!
  "Calls a single method on the [DragListener](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/utils/DragListener.html)
in the `screen`."
  [screen k & options]
  `(let [listeners# (u/get-obj ~screen :ui-listeners)
         ^DragListener object# (u/get-obj listeners# :drag-listener)]
     (u/call! object# ~k ~@options)))

(defmacro focus-listener!
  "Calls a single method on the [FocusListener](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/utils/FocusListener.html)
in the `screen`."
  [screen k & options]
  `(let [listeners# (u/get-obj ~screen :ui-listeners)
         ^FocusListener object# (u/get-obj listeners# :focus-listener)]
     (u/call! object# ~k ~@options)))


text:
(ns play-clj.g3d-physics
  (:require [play-clj.core :as c]
            [play-clj.math :as m]
            [play-clj.utils :as u])
  (:import [com.badlogic.gdx.math Matrix4]
           [com.badlogic.gdx.physics.bullet Bullet]
           [com.badlogic.gdx.physics.bullet.collision btBoxShape
            btCollisionDispatcher btCylinderShape btCapsuleShape btConeShape
            btCollisionObject btDefaultCollisionConfiguration btDbvtBroadphase
            btSphereShape]
           [com.badlogic.gdx.physics.bullet.dynamics btDiscreteDynamicsWorld
            btDynamicsWorld btRigidBody btRigidBody$btRigidBodyConstructionInfo
            btSequentialImpulseConstraintSolver]
           [com.badlogic.gdx.physics.bullet.linearmath btMotionState]
           [com.badlogic.gdx.physics.bullet.softbody btSoftBody
            btSoftBodyRigidBodyCollisionConfiguration btSoftBodyWorldInfo
            btSoftRigidDynamicsWorld]
           [play_clj.g3d_physics ContactListener3D]))

(def init-bullet (delay (Bullet/init)))

(defrecord World3D [object])
(defrecord Body3D [object])

; world

(defn ^:private discrete-dynamics
  []
  (let [config (btDefaultCollisionConfiguration.)
        dispatcher (btCollisionDispatcher. config)
        broad (btDbvtBroadphase.)
        solver (btSequentialImpulseConstraintSolver.)]
    (assoc (World3D. (btDiscreteDynamicsWorld. dispatcher broad solver config))
           :config config
           :dispatcher dispatcher
           :broadphase broad
           :constraint-solver solver)))

(defn ^:private soft-rigid-dynamics
  []
  (let [config (btSoftBodyRigidBodyCollisionConfiguration.)
        dispatcher (btCollisionDispatcher. config)
        broad (btDbvtBroadphase.)
        solver (btSequentialImpulseConstraintSolver.)]
    (assoc (World3D. (btSoftRigidDynamicsWorld. dispatcher broad solver config))
           :config config
           :dispatcher dispatcher
           :broadphase broad
           :constraint-solver solver)))

(defn bullet-3d*
  [type]
  @init-bullet
  (case type
    :rigid (discrete-dynamics)
    :soft-rigid (soft-rigid-dynamics)
    (u/throw-key-not-found type)))

(defmacro bullet-3d
  "Returns a world based on btDynamicsWorld.

    (bullet-3d :rigid) ; can only handle rigid bodies
    (bullet-3d :soft-rigid) ; can handle soft and rigid bodies"
  [type & options]
  `(let [world# (bullet-3d* ~type)
         ^btDynamicsWorld object# (:object world#)]
     (u/calls! object# ~@options)
     world#))

(defmacro bullet-3d!
  "Calls a single method on a `bullet-3d`."
  [screen k & options]
  `(let [^btDynamicsWorld object# (:object (u/get-obj ~screen :world))]
     (u/call! object# ~k ~@options)))

; bodies

(defn rigid-body*
  [info]
  (assoc (Body3D. (btRigidBody. info))
         :info info))

(defmacro rigid-body
  "Returns a body based on btRigidBody."
  [info & options]
  `(let [body# (rigid-body* ~info)
         ^btRigidBody object# (:object body#)]
     (u/calls! object# ~@options)
     body#))

(defmacro rigid-body!
  "Calls a single method on a `rigid-body`."
  [object k & options]
  `(let [^btRigidBody object# (:object (u/get-obj ~object :body))]
     (u/call! object# ~k ~@options)))

(defn rigid-body-info
  "Returns a btRigidBodyConstructionInfo."
  [mass motion-state collision-shape local-inertia]
  (btRigidBody$btRigidBodyConstructionInfo.
    mass motion-state collision-shape local-inertia))

(defn soft-body*
  [info]
  (assoc (Body3D. (btSoftBody. info))
         :info info))

(defmacro soft-body
  "Returns a body based on btSoftBody."
  [info & options]
  `(let [body# (soft-body* ~info)
         ^btSoftBody object# (:object body#)]
     (u/calls! object# ~@options)
     body#))

(defmacro soft-body!
  "Calls a single method on a `soft-body`."
  [object k & options]
  `(let [^btSoftBody object# (:object (u/get-obj ~object :body))]
     (u/call! object# ~k ~@options)))

(defn soft-body-info
  "Returns a btSoftBodyWorldInfo."
  []
  (btSoftBodyWorldInfo.))

(defn add-body!
  "Adds the `body` to the `screen` and returns it.

    (add-body! screen (rigid-body info))"
  [screen body]
  (cond
    (instance? btRigidBody (:object body))
    (bullet-3d! screen :add-rigid-body (:object body))
    (instance? btSoftBody (:object body))
    (bullet-3d! screen :add-soft-body (:object body)))
  body)

(defn ^:private body-x
  [entity]
  (let [^btCollisionObject object (:object (u/get-obj entity :body))]
    (-> object .getWorldTransform (. val) (aget Matrix4/M03))))

(defn ^:private body-y
  [entity]
  (let [^btCollisionObject object (:object (u/get-obj entity :body))]
    (-> object .getWorldTransform (. val) (aget Matrix4/M13))))

(defn ^:private body-z
  [entity]
  (let [^btCollisionObject object (:object (u/get-obj entity :body))]
    (-> object .getWorldTransform (. val) (aget Matrix4/M23))))

(defn body-position!
  "Changes the position of the body in `entity`."
  [entity x y z]
  (let [^btCollisionObject object (:object (u/get-obj entity :body))]
    (.setWorldTransform object
      (doto (m/matrix-4*)
        (m/matrix-4! :set-translation x y z)))))

(defn body-x!
  "Changes the `x` of the body in `entity`."
  [entity x]
  (body-position! entity x (body-y entity) (body-z entity)))

(defn body-y!
  "Changes the `y` of the body in `entity`."
  [entity y]
  (body-position! entity (body-x entity) y (body-z entity)))

(defn body-z!
  "Changes the `z` of the body in `entity`."
  [entity z]
  (body-position! entity (body-x entity) (body-y entity) z))

(defn ^:private find-body
  [body entities]
  (some #(try
           (when (= body (:object (u/get-obj % :body))) %)
           (catch Exception _))
        entities))

(defn first-entity
  "Returns the first entity in a contact. May only be used in contact functions
such as :on-begin-contact."
  [screen entities]
  (-> (u/get-obj screen :first-body)
      (find-body entities)))

(defn second-entity
  "Returns the second entity in a contact. May only be used in contact functions
such as :on-begin-contact."
  [screen entities]
  (-> (u/get-obj screen :second-body)
      (find-body entities)))

; shapes

(defn box-shape*
  [box-half-extents]
  (btBoxShape. box-half-extents))

(defmacro box-shape
  "Returns a btSphereShape."
  [box-half-extents & options]
  `(u/calls! ^btBoxShape (box-shape* ~box-half-extents) ~@options))

(defmacro box-shape!
  "Calls a single method on a `box-shape`."
  [object k & options]
  `(u/call! ^btBoxShape ~object ~k ~@options))

(defn capsule-shape*
  [radius height]
  (btCapsuleShape. radius height))

(defmacro capsule-shape
  "Returns a btCapsuleShape."
  [radius height & options]
  `(u/calls! ^btCapsuleShape (capsule-shape* ~radius ~height) ~@options))

(defmacro capsule-shape!
  "Calls a single method on a `capsule-shape`."
  [object k & options]
  `(u/call! ^btCapsuleShape ~object ~k ~@options))

(defn cone-shape*
  [radius height]
  (btConeShape. radius height))

(defmacro cone-shape
  "Returns a btConeShape."
  [radius height & options]
  `(u/calls! ^btConeShape (cone-shape* ~radius ~height) ~@options))

(defmacro cone-shape!
  "Calls a single method on a `cone-shape`."
  [object k & options]
  `(u/call! ^btConeShape ~object ~k ~@options))

(defn cylinder-shape*
  [half-extents]
  (btCylinderShape. half-extents))

(defmacro cylinder-shape
  "Returns a btCylinderShape."
  [half-extents & options]
  `(u/calls! ^btCylinderShape (cylinder-shape* ~half-extents) ~@options))

(defmacro cylinder-shape!
  "Calls a single method on a `cylinder-shape`."
  [object k & options]
  `(u/call! ^btCylinderShape ~object ~k ~@options))

(defn sphere-shape*
  [radius]
  (btSphereShape. radius))

(defmacro sphere-shape
  "Returns a btSphereShape."
  [radius & options]
  `(u/calls! ^btSphereShape (sphere-shape* ~radius) ~@options))

(defmacro sphere-shape!
  "Calls a single method on a `sphere-shape`."
  [object k & options]
  `(u/call! ^btSphereShape ~object ~k ~@options))

; misc

(defmethod c/contact-listener
  "play_clj.g3d_physics.World3D"
  [screen
   {:keys [on-begin-contact on-end-contact]}
   execute-fn!]
  (ContactListener3D.
    (fn [a b]
      (execute-fn! on-begin-contact :first-body a :second-body b))
    (fn [a b]
      (execute-fn! on-end-contact :first-body a :second-body b))))

(defn ^:private get-bodies
  [screen]
  (let [arr (bullet-3d! screen :get-collision-object-array)]
    (for [i (range (.size arr))]
      (.at arr i))))

(defmethod c/update-physics!
  "play_clj.g3d_physics.World3D"
  [screen & [entities]]
  ; initialize bodies if necessary
  (doseq [e entities]
    (let [object (u/get-obj e :object)
          body (u/get-obj e :body)]
      (when (and object (instance? btRigidBody (:object body)))
        (when-not (rigid-body! e :get-motion-state)
          (->> (proxy [btMotionState] []
                 (getWorldTransform [world-t])
                 (setWorldTransform [world-t]
                   (m/matrix-4! (. object transform) :set world-t)))
               (rigid-body! e :set-motion-state))))))
  ; remove bodies that no longer exist
  (when entities
    (doseq [^btCollisionObject body (get-bodies screen)]
      (when-not (some #(= body (-> % :body :object)) entities)
        (cond
          (instance? btRigidBody body)
          (bullet-3d! screen :remove-rigid-body body)
          (instance? btSoftBody body)
          (bullet-3d! screen :remove-soft-body body))
        (.dispose body)))))

(defn step!
  "Runs the physics simulations for a single frame and optionally returns the
`entities` with their positions updated."
  ([{:keys [delta-time max-sub-steps time-step]
     :or {max-sub-steps 5 time-step (/ 1 60)}
     :as screen}]
   (bullet-3d! screen :step-simulation delta-time max-sub-steps time-step))
  ([screen entities]
   (step! screen)
   (map (fn [e]
          (if (:body e)
            (assoc e
                   :x (body-x e)
                   :y (body-y e)
                   :z (body-z e))
            e))
        entities)))


text:
(in-ns 'play-clj.core)

(defn orthographic*
  []
  (OrthographicCamera.))

(defmacro orthographic
  "Returns an [OrthographicCamera](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/OrthographicCamera.html).

    (orthographic)"
  [& options]
  `(let [^OrthographicCamera object# (orthographic*)]
     (u/calls! object# ~@options)))

(defmacro orthographic!
  "Calls a single method on an `orthographic`."
  [screen k & options]
  `(let [^OrthographicCamera object# (u/get-obj ~screen :camera)]
     (u/call! object# ~k ~@options)))

(defn perspective*
  ([]
   (PerspectiveCamera.))
  ([field-of-view viewport-width viewport-height]
   (PerspectiveCamera. field-of-view viewport-width viewport-height)))

(defmacro perspective
  "Returns a [PerspectiveCamera](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/PerspectiveCamera.html).

    (perspective 75 (game :width) (game :height))"
  [field-of-view viewport-width viewport-height & options]
  `(let [^PerspectiveCamera object#
         (perspective* ~field-of-view ~viewport-width ~viewport-height)]
     (u/calls! object# ~@options)))

(defmacro perspective!
  "Calls a single method on a `perspective`."
  [screen k & options]
  `(let [^PerspectiveCamera object# (u/get-obj ~screen :camera)]
     (u/call! object# ~k ~@options)))

(defn size!
  "Sets the size of the camera in `screen`.

    (size! screen 480 360)"
  [screen width height]
  (let [^Camera camera (u/get-obj screen :camera)]
    (set! (. camera viewportWidth) width)
    (set! (. camera viewportHeight) height)
    (.update camera)))

(defn width
  "Returns the width of the camera in `screen`. If there is no camera, it
returns the overall width.

    (width screen)"
  [screen]
  (try
    (let [^Camera camera (u/get-obj screen :camera)]
      (. camera viewportWidth))
    (catch Exception _
      (game :width))))

(defn width!
  "Sets the width of the camera in `screen`, adjusting the height so the ratio
remains in tact.

    (width! screen 480)"
  [screen new-width]
  (size! screen new-width (* new-width (/ (game :height) (game :width)))))

(defn height
  "Returns the height of the camera in `screen`. If there is no camera, it
returns the overall height.

    (height screen)"
  [screen]
  (try
    (let [^Camera camera (u/get-obj screen :camera)]
      (. camera viewportHeight))
    (catch Exception _
      (game :height))))

(defn height!
  "Sets the height of the camera in `screen`, adjusting the width so the ratio
remains in tact.

    (height! screen 360)"
  [screen new-height]
  (size! screen (* new-height (/ (game :width) (game :height))) new-height))

(defn x
  "Returns the x position of `object`. If `object` is a screen, the x position
of the camera will be returned."
  [object]
  (cond
    (instance? Vector2 object) (. ^Vector2 object x)
    (instance? Vector3 object) (. ^Vector3 object x)
    :else (let [^Camera camera (u/get-obj object :camera)]
            (. (. camera position) x))))

(defn x!
  "Sets only the x position of `object`. If `object` is a screen, the x position
of the camera will be set."
  [object x-val]
  (cond
    (instance? Vector2 object) (let [^Vector2 v object]
                                   (.set v x-val (. v y)))
    (instance? Vector3 object) (let [^Vector3 v object]
                                   (.set v x-val (. v y) (. v z)))
    :else (let [^Camera camera (u/get-obj object :camera)]
            (set! (. (. camera position) x) x-val)
            (.update camera))))

(defn y
  "Returns the y position of `object`. If `object` is a screen, the y position
of the camera will be returned."
  [object]
  (cond
    (instance? Vector2 object) (. ^Vector2 object y)
    (instance? Vector3 object) (. ^Vector3 object y)
    :else (let [^Camera camera (u/get-obj object :camera)]
            (. (. camera position) y))))

(defn y!
  "Sets only the y position of `object`. If `object` is a screen, the y position
of the camera will be set."
  [object y-val]
  (cond
    (instance? Vector2 object) (let [^Vector2 v object]
                                   (.set v (. v x) y-val))
    (instance? Vector3 object) (let [^Vector3 v object]
                                   (.set v (. v x) y-val (. v z)))
    :else (let [^Camera camera (u/get-obj object :camera)]
            (set! (. (. camera position) y) y-val)
            (.update camera))))

(defn z
  "Returns the z position of `object`. If `object` is a screen, the z position
of the camera will be returned."
  [object]
  (cond
    (instance? Vector3 object) (. ^Vector3 object z)
    :else (let [^Camera camera (u/get-obj object :camera)]
            (. (. camera position) z))))

(defn z!
  "Sets only the z position of `object`. If `object` is a screen, the z position
of the camera will be set."
  [object z-val]
  (cond
    (instance? Vector3 object) (let [^Vector3 v object]
                                   (.set v (. v x) (. v y) z-val))
    :else (let [^Camera camera (u/get-obj object :camera)]
            (set! (. (. camera position) z) z-val)
            (.update camera))))

(defn position
  "Returns the position of the camera in `screen`."
  [screen]
  (let [^Camera camera (u/get-obj screen :camera)]
    (. camera position)))

(defn position!
  "Sets the position of the camera in `screen`."
  ([screen vec-3]
   (position! screen (x vec-3) (y vec-3) (z vec-3)))
  ([screen x-val y-val]
   (position! screen x-val y-val nil))
  ([screen x-val y-val z-val]
   (some->> x-val (x! screen))
   (some->> y-val (y! screen))
   (some->> z-val (z! screen))))

(defn direction
  "Returns the direction of the camera in `screen`."
  [screen]
  (let [^Camera camera (u/get-obj screen :camera)]
    (. camera direction)))

(defn direction!
  "Sets the direction of the camera in `screen`."
  ([screen x-val y-val z-val]
   (direction! screen x-val y-val z-val true))
  ([screen x-val y-val z-val look-at?]
   (let [^Camera camera (u/get-obj screen :camera)]
     (if look-at?
       (.lookAt camera x-val y-val z-val)
       (let [^Vector3 dir-vec (direction screen)]
         (some->> x-val (x! dir-vec))
         (some->> y-val (y! dir-vec))
         (some->> z-val (z! dir-vec))))
     (.update camera))))

(defn up [screen]
  "Returns the up vector of the camera in `screen`."
  (let [^Camera camera (u/get-obj screen :camera)]
    (. camera up)))

(defn up!
  "Sets the up vector of the camera in `screen`."
  [screen x-val y-val z-val]
  (let [^Camera camera (u/get-obj screen :camera)
        ^Vector3 up-vec (up screen)]
    (some->> x-val (x! up-vec))
    (some->> y-val (y! up-vec))
    (some->> z-val (z! up-vec))
    (.update camera)))

(defn near
  "Returns the near clipping plane distance of the camera in `screen`."
  [screen]
  (let [^Camera camera (u/get-obj screen :camera)]
    (. camera near)))

(defn near!
  "Sets the near clipping plane distance of the camera in `screen`."
  [screen n]
  (let [^Camera camera (u/get-obj screen :camera)]
    (set! (. camera near) n)
    (.update camera)))

(defn far
  "Returns the far clipping plane distance of the camera in `screen`."
  [screen]
  (let [^Camera camera (u/get-obj screen :camera)]
    (. camera far)))

(defn far!
  "Sets the far clipping plane distance of the camera in `screen`."
  [screen n]
  (let [^Camera camera (u/get-obj screen :camera)]
    (set! (. camera far) n)
    (.update camera)))


text:
(in-ns 'play-clj.core)

; graphics

(defn clear!
  "Clears the screen with a uniform color, defaulting to black.

    (clear!)
    (clear! 0.5 0.5 1 1)"
  ([]
   (clear! 0 0 0 0))
  ([r g b a]
   (doto (Gdx/gl)
     (.glClearColor (float r) (float g) (float b) (float a))
     (.glClear (bit-or GL20/GL_COLOR_BUFFER_BIT GL20/GL_DEPTH_BUFFER_BIT)))))

(defn color
  "Returns a [Color](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/Color.html).

    (color :white)
    (color 1 1 1 1)"
  ([k]
   (Color. (eval (u/gdx-field :graphics :Color (u/key->upper k)))))
  ([r g b a]
   (Color. r g b a)))

(defmacro color!
  "Calls a single method on a `color`."
  [object k & options]
  `(u/call! ^Color ~object ~k ~@options))

; interop

(defmacro app!
  "Calls a single method on [Gdx.app](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/Application.html).

    (app! :error \"MYTAG\" \"An error occurred, so I'm logging it!\")"
  [k & options]
  `(u/call! ^Application (Gdx/app) ~k ~@options))

(defmacro audio!
  "Calls a single method on [Gdx.audio](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/Audio.html).

    (audio! :new-audio-recorder 44100 false)"
  [k & options]
  `(u/call! ^Audio (Gdx/audio) ~k ~@options))

(defmacro files!
  "Calls a single method on [Gdx.files](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/Files.html).

    (files! :internal \"image.png\")"
  [k & options]
  `(u/call! ^Files (Gdx/files) ~k ~@options))

(defmacro gl
  "Returns a static field from [GL20](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/GL20.html).

    (gl :gl-triangles)"
  [k]
  (u/gdx-field :graphics :GL20 (u/key->upper k)))

(defmacro gl!
  "Calls a single method on [Gdx.gl20](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/GL20.html).

    (gl! :gl-create-program)"
  [k & options]
  `(u/call! ^GL20 (Gdx/gl20) ~k ~@options))

(defmacro graphics!
  "Calls a single method on [Gdx.graphics](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/Graphics.html).

    (graphics! :is-fullscreen)"
  [k & options]
  `(u/call! ^Graphics (Gdx/graphics) ~k ~@options))

(defmacro input!
  "Calls a single method on [Gdx.input](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/Input.html).

    (input! :is-touched)"
  [k & options]
  `(u/call! ^Input (Gdx/input) ~k ~@options))

(defmacro net!
  "Calls a single method on [Gdx.net](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/Net.html).

    (net! :open-u-r-i \"https://sekao.net/\")"
  [k & options]
  `(u/call! ^Net (Gdx/net) ~k ~@options))

; input/output

(defn game
  "Provides quick access to often-used functions.

    (game :width)"
  [k & [arg]]
  (case k
    :width (graphics! :get-width)
    :height (graphics! :get-height)
    :fps (graphics! :get-frames-per-second)
    :fullscreen? (graphics! :is-fullscreen)
    :touched? (input! :is-touched)
    :x (input! :get-x (or arg 0))
    :y (- (graphics! :get-height) (input! :get-y (or arg 0)))
    :point-x (game :x arg)
    :point-y (game :y arg)
    (u/throw-key-not-found k)))

(defn key-code
  "Returns a static field from [Input.Keys](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/Input.Keys.html).

    (key-code :a)
    (key-code :page-down)"
  [k]
  (eval (u/gdx-field "Input$Keys" (u/key->upper k))))

(defn key-pressed?
  "Returns a boolean indicating if the key cooresponding to `k` is being pressed.

    (key-pressed? :a)
    (key-pressed? :page-down)"
  [k]
  (input! :is-key-pressed (key-code k)))

(defn button-code
  "Returns a static field from [Input.Buttons](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/Input.Buttons.html).

    (button-code :left)"
  [k]
  (eval (u/gdx-field "Input$Buttons" (u/key->upper k))))

(defn button-pressed?
  "Returns a boolean indicating if the button cooresponding to `k` is being pressed.

    (button-pressed? :left)"
  [k]
  (input! :is-button-pressed (button-code k)))

(defn ^:private add-input!
  [^InputProcessor p]
  (when-let [^InputMultiplexer multi (input! :get-input-processor)]
    (.addProcessor multi p)))

(defn ^:private remove-input!
  [^InputProcessor p]
  (when-let [^InputMultiplexer multi (input! :get-input-processor)]
    (.removeProcessor multi p)))

(defn sound*
  [^String path]
  (or (u/load-asset path Sound)
      (audio! :new-sound (files! :internal path))))

(defmacro sound
  "Returns a [Sound](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/audio/Sound.html). Supports wav, mp3, and ogg.

    (sound \"playerhurt.wav\")
    (sound \"playerhurt.wav\" :play)"
  [path & options]
  `(let [^Sound object# (sound* ~path)]
     (u/calls! object# ~@options)))

(defmacro sound!
  "Calls a single method on a `sound`.

    (sound! object :play)
    (sound! object :dispose)"
  [object k & options]
  `(let [^Sound object# ~object]
     (u/call! object# ~k ~@options)))

(defn music*
  [^String path]
  (or (u/load-asset path Music)
      (audio! :new-music (files! :internal path))))

(defmacro music
  "Returns a [Music](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/audio/Music.html). Supports wav, mp3, and ogg.

    (music \"song.wav\")
    (music \"song.wav\" :play)"
  [path & options]
  `(let [^Music object# (music* ~path)]
     (u/calls! object# ~@options)))

(defmacro music!
  "Calls a single method on a `music`.

    (music! object :play)
    (music! object :dispose)"
  [object k & options]
  `(let [^Music object# ~object]
     (u/call! object# ~k ~@options)))