diff --git a/.gitignore b/.gitignore index 03d1617..962edd7 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ /.nrepl-port /.clj-kondo/ /.lsp/ +/target/ +*.jsa diff --git a/build.clj b/build.clj new file mode 100644 index 0000000..90bea05 --- /dev/null +++ b/build.clj @@ -0,0 +1,14 @@ +(ns build + (:require [clojure.tools.build.api :as b])) + +(def basis (delay (b/create-basis {:project "deps.edn"}))) + +(defn uberjar [_] + (b/delete {:path "target"}) + (b/compile-clj {:basis @basis + :src-dirs ["src"] + :class-dir "target/classes"}) + (b/uber {:class-dir "target/classes" + :uber-file "target/nol.jar" + :basis @basis + :main 'nol.core})) diff --git a/deps.edn b/deps.edn index 818d813..34bfe79 100644 --- a/deps.edn +++ b/deps.edn @@ -11,4 +11,7 @@ org.lwjgl/lwjgl-assimp$natives-linux {:mvn/version "3.3.3"} org.joml/joml {:mvn/version "1.10.7"}} :paths ["src"] - :aliases {:dev {:jvm-opts ["-Djdk.attach.allowAttachSelf=true"]}}} + :aliases {:dev {:jvm-opts ["-Djdk.attach.allowAttachSelf=true"]} + :build {:extra-deps {io.github.clojure/tools.build {:mvn/version "0.10.6"}} + :jvm-opts ["-Dclojure.compiler.direct-linking=true"] + :ns-default build}}} diff --git a/src/nol/core.clj b/src/nol/core.clj index e85bbdf..7add083 100644 --- a/src/nol/core.clj +++ b/src/nol/core.clj @@ -1,24 +1,27 @@ (ns nol.core + (:gen-class) (:require [clojure.math]) (:import - [java.nio FloatBuffer IntBuffer] - [org.lwjgl.assimp AIColor4D AIMaterial AIMatrix4x4 AIMesh AINode AIScene AIString AITexture Assimp] + [java.nio ByteBuffer FloatBuffer IntBuffer] + [java.util.concurrent LinkedBlockingQueue] + [org.lwjgl PointerBuffer] + [org.lwjgl.assimp AIColor4D AIFace AIMaterial AIMatrix4x4 AIMesh AINode AIScene AIString AITexture AIVector3D Assimp] [org.lwjgl.glfw GLFW GLFWKeyCallbackI] [org.lwjgl.opengl GL GL11 GL20 GL30 GL45] [org.lwjgl.stb STBImage] [org.joml Matrix4f] [org.lwjgl.system MemoryStack MemoryUtil])) -(def render-queue (java.util.concurrent.LinkedBlockingQueue.)) +(def ^LinkedBlockingQueue render-queue (LinkedBlockingQueue.)) -(def state (atom {:last-time (GLFW/glfwGetTime) :window nil})) +(def state (atom {:last-time 0.0 :window nil})) (def gl-thread (atom nil)) (defmacro with-gl [& body] `(let [result# (promise)] - (when-not (and @gl-thread (.isAlive @gl-thread)) + (when-not (and @gl-thread (.isAlive ^Thread @gl-thread)) (throw (RuntimeException. "GL thread is not running"))) (.put render-queue #(deliver result# (try (do ~@body) (catch Exception e# e#)))) @@ -44,12 +47,6 @@ (throw (RuntimeException. (str "Program link error: " (GL20/glGetProgramInfoLog program))))) program)) -#_(defn ai-matrix->matrix4f [^AIMatrix4x4 m] - (Matrix4f. (.a1 m) (.a2 m) (.a3 m) (.a4 m) - (.b1 m) (.b2 m) (.b3 m) (.b4 m) - (.c1 m) (.c2 m) (.c3 m) (.c4 m) - (.d1 m) (.d2 m) (.d3 m) (.d4 m))) - (defn ai-matrix->matrix4f [^AIMatrix4x4 m] (Matrix4f. (.a1 m) (.b1 m) (.c1 m) (.d1 m) (.a2 m) (.b2 m) (.c2 m) (.d2 m) @@ -77,10 +74,10 @@ (def uploaded-scene (atom nil)) (def shaders (atom nil)) -(defn render-scene [stack scene node mtx] +(defn render-scene [^MemoryStack stack scene node ^Matrix4f mtx] (let [buf (.mallocFloat stack 16) model-mtx (Matrix4f.)] - (.mul mtx (:transform node) model-mtx) + (.mul mtx ^Matrix4f (:transform node) model-mtx) (.get model-mtx buf) (when-let [mesh-indices (seq (:meshes node))] (let [{:keys [gl-meshes gl-textures]} scene @@ -91,7 +88,7 @@ [r g b a] (:color mesh) tex-idx (:texture-idx mesh)]] (GL20/glUniform4f (:color uniforms) r g b a) - (GL20/glUniformMatrix4fv (:mm uniforms) false buf) + (GL20/glUniformMatrix4fv ^int (:mm uniforms) false buf) (GL30/glBindVertexArray (:vao gl-mesh)) (when tex-idx (let [tex-id (:gl-id (nth gl-textures tex-idx))] @@ -103,10 +100,10 @@ (doseq [child children] (render-scene stack scene child model-mtx))))) -(defn- update-loop [window stack data] +(defn- update-loop [window ^MemoryStack stack data] (let [w-buf (.mallocInt stack 1) h-buf (.mallocInt stack 1) - _ (GLFW/glfwGetFramebufferSize window w-buf h-buf) + _ (GLFW/glfwGetFramebufferSize ^long window w-buf h-buf) w (.get w-buf 0) h (.get h-buf 0) t (GLFW/glfwGetTime)] @@ -138,8 +135,8 @@ (float 100.0)))] (.get vm vbuf) (.get pm pbuf) - (GL20/glUniformMatrix4fv (:mv uniforms) false vbuf) - (GL20/glUniformMatrix4fv (:mp uniforms) false pbuf) + (GL20/glUniformMatrix4fv ^int (:mv uniforms) false vbuf) + (GL20/glUniformMatrix4fv ^int (:mp uniforms) false pbuf) (render-scene stack scene (:hiearchy scene) (Matrix4f.))))) (catch Exception e (println "Update Loop GL thread error:" e))) @@ -152,11 +149,11 @@ (defn stop! [] (with-gl (when @uploaded-scene - (doseq [{:keys [vbo vao ebo]} (:gl-meshes @uploaded-scene)] + (doseq [{:keys [^int vbo ^int vao ^int ebo]} (:gl-meshes @uploaded-scene)] (GL45/glDeleteBuffers vbo) (GL45/glDeleteBuffers ebo) (GL30/glDeleteVertexArrays vao)) - (doseq [{:keys [gl-id]} (:gl-textures @uploaded-scene)] + (doseq [{:keys [^int gl-id]} (:gl-textures @uploaded-scene)] (GL11/glDeleteTextures gl-id))) (when @shaders (GL20/glDeleteProgram (:program @shaders))) @@ -213,7 +210,7 @@ (GLFW/glfwTerminate))) (defn start! [] - (when (and @gl-thread (.isAlive @gl-thread)) + (when (and @gl-thread (.isAlive ^Thread @gl-thread)) (throw (RuntimeException. "Already running"))) (reset! gl-thread (doto (Thread. (fn [] @@ -225,13 +222,13 @@ (.setDaemon true) (.start)))) -(defn load-model [path] +(defn load-model [^String path] (let [flags (bit-or Assimp/aiProcess_Triangulate Assimp/aiProcess_FlipUVs)] (Assimp/aiImportFile path flags))) -(defn extract-mesh [^AIScene scene idx] - (let [meshes (.mMeshes scene)] +(defn extract-mesh [^AIScene scene ^long idx] + (let [meshes ^PointerBuffer (.mMeshes scene)] (let [mesh (AIMesh/create (long (.get meshes idx))) mat-idx (.mMaterialIndex mesh) mat-ptr ^long (.get (.mMaterials scene) mat-idx) @@ -251,16 +248,16 @@ idx-arr (int-array (* 3 nf)) uvs (.mTextureCoords mesh 0)] (dotimes [i n] - (let [vert (.get verts i) + (let [vert ^AIVector3D (.get verts i) uv (when uvs (.get uvs i)) - [^float u ^float v] (if uvs [(.x uv) (.y uv)] [0.0 0.0])] + [^float u ^float v] (if uvs [(.x ^AIVector3D uv) (.y ^AIVector3D uv)] [0.0 0.0])] (aset vert-arr (+ (* i 5) 0) (.x vert)) (aset vert-arr (+ (* i 5) 1) (.y vert)) (aset vert-arr (+ (* i 5) 2) (.z vert)) (aset vert-arr (+ (* i 5) 3) u) (aset vert-arr (+ (* i 5) 4) v))) (dotimes [i nf] - (let [face (.get faces i) + (let [face ^AIFace (.get faces i) idxs (.mIndices face)] (aset idx-arr (+ (* i 3) 0) (.get idxs 0)) (aset idx-arr (+ (* i 3) 1) (.get idxs 1)) @@ -273,20 +270,20 @@ (defn traverse [^AINode node] {:node node :meshes (let [buf (.mMeshes node)] - (mapv #(.get buf %) (range (.mNumMeshes node)))) + (mapv #(.get buf ^int %) (range (.mNumMeshes node)))) :transform (node-matrix4f node) - :children (mapv #(traverse (AINode/create ^long (.get (.mChildren node) %))) + :children (mapv #(traverse (AINode/create ^long (.get (.mChildren node) ^int %))) (range (.mNumChildren node)))}) (defn load-scene [path] - (let [scene (load-model path) + (let [scene ^AIScene (load-model path) meshes (doall (for [i (range (.mNumMeshes scene))] (extract-mesh scene i))) textures (let [texs (.mTextures scene)] (doall (for [i (range (.mNumTextures scene))] - (let [ai-tex (AITexture/create (.get texs i)) + (let [ai-tex (AITexture/create (.get texs ^int i)) buf (.pcDataCompressed ai-tex) w (int-array 1) h (int-array 1) @@ -300,11 +297,11 @@ (defn upload-scene! [scene] (let [gl-meshes (mapv - #(let [vbo (GL45/glCreateBuffers) - ebo (GL45/glCreateBuffers) - vao (GL45/glCreateVertexArrays)] - (GL45/glNamedBufferStorage vbo (:verts %) GL45/GL_DYNAMIC_STORAGE_BIT) - (GL45/glNamedBufferStorage ebo (:indices %) GL45/GL_DYNAMIC_STORAGE_BIT) + #(let [vbo ^int (GL45/glCreateBuffers) + ebo ^int (GL45/glCreateBuffers) + vao ^int (GL45/glCreateVertexArrays)] + (GL45/glNamedBufferStorage vbo ^floats (:verts %) GL45/GL_DYNAMIC_STORAGE_BIT) + (GL45/glNamedBufferStorage ebo ^ints (:indices %) GL45/GL_DYNAMIC_STORAGE_BIT) (GL45/glVertexArrayElementBuffer vao ebo) (GL45/glVertexArrayVertexBuffer vao 0 vbo 0 (* 5 Float/BYTES)) @@ -318,7 +315,7 @@ (GL45/glEnableVertexArrayAttrib vao 1) {:vbo vbo :vao vao :ebo ebo :mesh % - :indices-count (alength (:indices %))}) + :indices-count (alength ^ints (:indices %))}) (:meshes scene)) gl-textures (mapv @@ -326,10 +323,10 @@ h (:h %) tex-id (GL45/glCreateTextures GL11/GL_TEXTURE_2D)] (GL45/glTextureStorage2D tex-id 1 GL11/GL_RGBA8 w h) - (GL45/glTextureSubImage2D tex-id 0 0 0 w h GL11/GL_RGBA GL11/GL_UNSIGNED_BYTE (:data %)) + (GL45/glTextureSubImage2D tex-id 0 0 0 ^int w ^int h GL11/GL_RGBA GL11/GL_UNSIGNED_BYTE ^ByteBuffer (:data %)) (GL45/glTextureParameteri tex-id GL11/GL_TEXTURE_MIN_FILTER GL11/GL_LINEAR) (GL45/glTextureParameteri tex-id GL11/GL_TEXTURE_MAG_FILTER GL11/GL_LINEAR) - (STBImage/stbi_image_free (:data %)) + (STBImage/stbi_image_free ^ByteBuffer (:data %)) (assoc % :gl-id tex-id)) (:textures scene))] (assoc scene :gl-textures gl-textures :gl-meshes gl-meshes))) @@ -339,11 +336,11 @@ frag (compile-shader GL20/GL_FRAGMENT_SHADER (slurp frag-path)) program (link-program vert frag)] {:program program - :uniforms {:color (GL20/glGetUniformLocation program "uColor") - :tex (GL20/glGetUniformLocation program "texture_id") - :mm (GL20/glGetUniformLocation program "uModel") - :mv (GL20/glGetUniformLocation program "uView") - :mp (GL20/glGetUniformLocation program "uProjection")}})) + :uniforms {:color (GL20/glGetUniformLocation ^int program "uColor") + :tex (GL20/glGetUniformLocation ^int program "texture_id") + :mm (GL20/glGetUniformLocation ^int program "uModel") + :mv (GL20/glGetUniformLocation ^int program "uView") + :mp (GL20/glGetUniformLocation ^int program "uProjection")}})) (reset! loaded-scene (load-scene "assets/model.glb"))