diff --git a/src/nol/core.clj b/src/nol/core.clj index d0c9404..04c0250 100644 --- a/src/nol/core.clj +++ b/src/nol/core.clj @@ -17,6 +17,8 @@ (defmacro with-gl [& body] `(let [result# (promise)] + (when-not (and @gl-thread (.isAlive @gl-thread)) + (throw (RuntimeException. "GL thread is not running"))) (.put render-queue #(deliver result# (try (do ~@body) (catch Exception e# e#)))) (let [r# (deref result#)] @@ -24,10 +26,6 @@ (throw r#) r#)))) -(def vertex-shader-text (slurp "shaders/base.vert")) - -(def fragment-shader-text (slurp "shaders/base.frag")) - (defn- compile-shader [type source] (let [shader (GL20/glCreateShader type)] (GL20/glShaderSource shader ^String source) @@ -45,16 +43,8 @@ (throw (RuntimeException. (str "Program link error: " (GL20/glGetProgramInfoLog program))))) program)) -(def vertices (float-array [0.0 1.0 0.0 - -1.0 -1.0 0.0 - 1.0 -1.0 0.0])) - -(def loaded (atom false)) -(def meshes nil) -(def textures nil) -(def program nil) -(def gl-meshes nil) -(def gl-textures nil) +(def loaded-scenes (atom [])) +(def shaders (atom nil)) (defn- update-loop [window stack data] (let [w-buf (.mallocInt stack 1) @@ -66,24 +56,25 @@ (GL11/glViewport 0 0 w h) (GL11/glClear GL11/GL_COLOR_BUFFER_BIT) - (swap! state assoc :last-time t) + ;; (swap! state assoc :last-time t) (try - (when @loaded - (GL20/glUseProgram program) - (let [color-loc (GL20/glGetUniformLocation program "uColor") - tex-loc (GL20/glGetUniformLocation program "texture_id")] - (doseq [m gl-meshes - :let [[r g b a] (:color (:mesh m)) - tex-idx (:texture-idx (:mesh m))]] - (GL20/glUniform4f color-loc r g b a) - (GL30/glBindVertexArray (:vao m)) - (when tex-idx - (let [tex-id (:gl-id (nth gl-textures tex-idx))] - (println tex-idx tex-id) - (GL45/glActiveTexture GL45/GL_TEXTURE0) - (GL11/glBindTexture GL11/GL_TEXTURE_2D tex-id) - (GL20/glUniform1i tex-loc 0))) - (GL11/glDrawElements GL11/GL_TRIANGLES (:indices-count m) GL11/GL_UNSIGNED_INT 0)))) + (when-let [program @shaders] + (doseq [scene @loaded-scenes + :let [{:keys [meshes gl-meshes gl-textures]} scene]] + (GL20/glUseProgram program) + (let [color-loc (GL20/glGetUniformLocation program "uColor") + tex-loc (GL20/glGetUniformLocation program "texture_id")] + (doseq [m gl-meshes + :let [[r g b a] (:color (:mesh m)) + tex-idx (:texture-idx (:mesh m))]] + (GL20/glUniform4f color-loc r g b a) + (GL30/glBindVertexArray (:vao m)) + (when tex-idx + (let [tex-id (:gl-id (nth gl-textures tex-idx))] + (GL45/glActiveTexture GL45/GL_TEXTURE0) + (GL11/glBindTexture GL11/GL_TEXTURE_2D tex-id) + (GL20/glUniform1i tex-loc 0))) + (GL11/glDrawElements GL11/GL_TRIANGLES (:indices-count m) GL11/GL_UNSIGNED_INT 0))))) (catch Exception e (println "Update Loop GL thread error:" e))) @@ -93,7 +84,6 @@ (GLFW/glfwSwapBuffers window))) (defn stop! [] - (reset! loaded false) (with-gl (GLFW/glfwSetWindowShouldClose (:window @state) true))) @@ -124,19 +114,20 @@ (when (and (= key GLFW/GLFW_KEY_ESCAPE) (= action GLFW/GLFW_PRESS)) (swap! state assoc :should-close true))))) - (let [] + (loop [] (loop [] - (while (not (.isEmpty render-queue)) - ((.take render-queue))) - (when-not (or (:should-close @state) - (GLFW/glfwWindowShouldClose window)) - (GLFW/glfwPollEvents) - (let [stack (MemoryStack/stackPush)] - (try - (update-loop window stack {}) - (finally - (MemoryStack/stackPop)))) - (recur)))) + (when-let [f (.poll render-queue)] + (f) + (recur))) + (when-not (or (:should-close @state) + (GLFW/glfwWindowShouldClose window)) + (GLFW/glfwPollEvents) + (let [stack (MemoryStack/stackPush)] + (try + (update-loop window stack {}) + (finally + (MemoryStack/stackPop)))) + (recur))) (GLFW/glfwDestroyWindow window) (GLFW/glfwTerminate))) @@ -199,106 +190,75 @@ Assimp/aiProcess_FlipUVs)] (Assimp/aiImportFile path flags))) +(defn load-scene [path] + (let [scene (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)) + buf (.pcDataCompressed ai-tex) + w (int-array 1) + h (int-array 1) + channels (int-array 1)] + {:data (STBImage/stbi_load_from_memory buf w h channels 4) + :w (aget w 0) :h (aget h 0)}))))] + {:scene scene :meshes meshes :textures textures})) + +(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) + (GL45/glVertexArrayElementBuffer vao ebo) + (GL45/glVertexArrayVertexBuffer vao 0 vbo 0 (* 5 Float/BYTES)) + + (GL45/glVertexArrayAttribFormat vao 0 3 GL11/GL_FLOAT false 0) + (GL45/glVertexArrayAttribBinding vao 0 0) + + (GL45/glVertexArrayAttribFormat vao 1 2 GL11/GL_FLOAT false (* 3 Float/BYTES)) + (GL45/glVertexArrayAttribBinding vao 1 0) + + (GL45/glEnableVertexArrayAttrib vao 0) + (GL45/glEnableVertexArrayAttrib vao 1) + {:vbo vbo :vao vao :ebo ebo + :mesh % + :indices-count (alength (:indices %))}) + (:meshes scene)) + gl-textures + (mapv + #(let [w (:w %) + 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/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 %)) + (assoc % :gl-id tex-id)) + (:textures scene))] + (assoc scene :gl-textures gl-textures :gl-meshes gl-meshes))) + +(defn load-shaders! [vert-path frag-path] + (let [vert (compile-shader GL20/GL_VERTEX_SHADER (slurp vert-path)) + frag (compile-shader GL20/GL_FRAGMENT_SHADER (slurp frag-path))] + (link-program vert frag))) + (comment (start!) (stop!) - (let [mesh (AIMesh/create (long (.get (.mMeshes scene) i))) - _ (Assimp/aiGetMaterialTexture material Assimp/aiTextureType_DIFFUSE 0 path no-int no-int no-float no-int no-int no-int) - data-path (.dataString path)] - (when (.startsWith data-path "*") - (println (parse-long (subs data-path 1))))) - - (doseq [i (range (.mNumMeshes scene))] - (let [mesh (AIMesh/create (long (.get (.mMeshes scene) i))) - ^IntBuffer no-int nil - ^FloatBuffer no-float nil - path (AIString/create) - _ (Assimp/aiGetMaterialTexture material Assimp/aiTextureType_DIFFUSE 0 path no-int no-int no-float no-int no-int no-int) - data-path (.dataString path)] - (when (.startsWith data-path "*") - (println (parse-long (subs data-path 1)))))) - - (reset! loaded true) - (reset! loaded false) - - (def ^AIScene scene (load-model "assets/model.glb")) - - (def meshes (doall - (for [i (range (.mNumMeshes scene))] - (extract-mesh scene i)))) - - (def textures (let [texs (.mTextures scene)] - (doall - (for [i (range (.mNumTextures scene))] - (let [ai-tex (AITexture/create (.get texs i)) - buf (.pcDataCompressed ai-tex) - w (int-array 1) - h (int-array 1) - channels (int-array 1)] - {:data (STBImage/stbi_load_from_memory buf w h channels 4) - :w (aget w 0) :h (aget h 0)}))))) - - (def gl-meshes - (with-gl - (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) - (GL45/glVertexArrayElementBuffer vao ebo) - (GL45/glVertexArrayVertexBuffer vao 0 vbo 0 (* 5 Float/BYTES)) - - (GL45/glVertexArrayAttribFormat vao 0 3 GL11/GL_FLOAT false 0) - (GL45/glVertexArrayAttribBinding vao 0 0) - - (GL45/glVertexArrayAttribFormat vao 1 2 GL11/GL_FLOAT false (* 3 Float/BYTES)) - (GL45/glVertexArrayAttribBinding vao 1 0) - - (GL45/glEnableVertexArrayAttrib vao 0) - (GL45/glEnableVertexArrayAttrib vao 1) - {:vbo vbo :vao vao :ebo ebo - :mesh % - :indices-count (alength (:indices %))}) - meshes))) - - (def gl-textures - (with-gl - (mapv - #(let [w (:w %) - 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/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 %)) - (assoc % :gl-id tex-id)) - textures))) - - (def program (with-gl (let [vert (compile-shader GL20/GL_VERTEX_SHADER (slurp "shaders/base.vert")) - frag (compile-shader GL20/GL_FRAGMENT_SHADER (slurp "shaders/base.frag"))] - (link-program vert frag)))) + (swap! loaded-scenes conj (with-gl (upload-scene! (load-scene "assets/model.glb")))) + (reset! shaders (with-gl (load-shaders! "shaders/base.vert" "shaders/base.frag"))) (with-gl (GL11/glClearColor 0.392 0.584 0.929 1.0)) (with-gl (GL11/glClearColor 0.0 0.0 0.0 1.0)) - (with-gl - (GL45/glNamedBufferSubData (:vbo @state) 0 ^floats (float-array [ 0.0 0.5 0.0 - -0.5 -0.5 0.0 - 0.5 -0.5 0.0]))) - (with-gl - (GL45/glNamedBufferSubData (:vbo @state) 0 ^floats (float-array [ 0.0 1.0 0.0 - -1.0 -1.0 0.0 - 1.0 -1.0 0.0]))) - - (with-gl (GL45/glVertexArrayVertexBuffer vao 0 vbo 0 12)) - - (with-gl (GL45/glEnableVertexArrayAttrib vao 0) - (GL45/glVertexArrayAttribFormat vao 0 3 GL45/GL_FLOAT false 0) - (GL45/glVertexArrayAttribBinding vao 0 0)) - :-)