Clean up code, create loading functions, check for gl thread

This commit is contained in:
Joseph Ferano 2026-03-09 09:30:59 +07:00
parent 44ef432386
commit f68619b25e

View File

@ -17,6 +17,8 @@
(defmacro with-gl [& body] (defmacro with-gl [& body]
`(let [result# (promise)] `(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) (.put render-queue #(deliver result# (try (do ~@body)
(catch Exception e# e#)))) (catch Exception e# e#))))
(let [r# (deref result#)] (let [r# (deref result#)]
@ -24,10 +26,6 @@
(throw r#) (throw r#)
r#)))) r#))))
(def vertex-shader-text (slurp "shaders/base.vert"))
(def fragment-shader-text (slurp "shaders/base.frag"))
(defn- compile-shader [type source] (defn- compile-shader [type source]
(let [shader (GL20/glCreateShader type)] (let [shader (GL20/glCreateShader type)]
(GL20/glShaderSource shader ^String source) (GL20/glShaderSource shader ^String source)
@ -45,16 +43,8 @@
(throw (RuntimeException. (str "Program link error: " (GL20/glGetProgramInfoLog program))))) (throw (RuntimeException. (str "Program link error: " (GL20/glGetProgramInfoLog program)))))
program)) program))
(def vertices (float-array [0.0 1.0 0.0 (def loaded-scenes (atom []))
-1.0 -1.0 0.0 (def shaders (atom nil))
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)
(defn- update-loop [window stack data] (defn- update-loop [window stack data]
(let [w-buf (.mallocInt stack 1) (let [w-buf (.mallocInt stack 1)
@ -66,24 +56,25 @@
(GL11/glViewport 0 0 w h) (GL11/glViewport 0 0 w h)
(GL11/glClear GL11/GL_COLOR_BUFFER_BIT) (GL11/glClear GL11/GL_COLOR_BUFFER_BIT)
(swap! state assoc :last-time t) ;; (swap! state assoc :last-time t)
(try (try
(when @loaded (when-let [program @shaders]
(GL20/glUseProgram program) (doseq [scene @loaded-scenes
(let [color-loc (GL20/glGetUniformLocation program "uColor") :let [{:keys [meshes gl-meshes gl-textures]} scene]]
tex-loc (GL20/glGetUniformLocation program "texture_id")] (GL20/glUseProgram program)
(doseq [m gl-meshes (let [color-loc (GL20/glGetUniformLocation program "uColor")
:let [[r g b a] (:color (:mesh m)) tex-loc (GL20/glGetUniformLocation program "texture_id")]
tex-idx (:texture-idx (:mesh m))]] (doseq [m gl-meshes
(GL20/glUniform4f color-loc r g b a) :let [[r g b a] (:color (:mesh m))
(GL30/glBindVertexArray (:vao m)) tex-idx (:texture-idx (:mesh m))]]
(when tex-idx (GL20/glUniform4f color-loc r g b a)
(let [tex-id (:gl-id (nth gl-textures tex-idx))] (GL30/glBindVertexArray (:vao m))
(println tex-idx tex-id) (when tex-idx
(GL45/glActiveTexture GL45/GL_TEXTURE0) (let [tex-id (:gl-id (nth gl-textures tex-idx))]
(GL11/glBindTexture GL11/GL_TEXTURE_2D tex-id) (GL45/glActiveTexture GL45/GL_TEXTURE0)
(GL20/glUniform1i tex-loc 0))) (GL11/glBindTexture GL11/GL_TEXTURE_2D tex-id)
(GL11/glDrawElements GL11/GL_TRIANGLES (:indices-count m) GL11/GL_UNSIGNED_INT 0)))) (GL20/glUniform1i tex-loc 0)))
(GL11/glDrawElements GL11/GL_TRIANGLES (:indices-count m) GL11/GL_UNSIGNED_INT 0)))))
(catch Exception e (catch Exception e
(println "Update Loop GL thread error:" e))) (println "Update Loop GL thread error:" e)))
@ -93,7 +84,6 @@
(GLFW/glfwSwapBuffers window))) (GLFW/glfwSwapBuffers window)))
(defn stop! [] (defn stop! []
(reset! loaded false)
(with-gl (with-gl
(GLFW/glfwSetWindowShouldClose (GLFW/glfwSetWindowShouldClose
(:window @state) true))) (:window @state) true)))
@ -124,19 +114,20 @@
(when (and (= key GLFW/GLFW_KEY_ESCAPE) (= action GLFW/GLFW_PRESS)) (when (and (= key GLFW/GLFW_KEY_ESCAPE) (= action GLFW/GLFW_PRESS))
(swap! state assoc :should-close true))))) (swap! state assoc :should-close true)))))
(let [] (loop []
(loop [] (loop []
(while (not (.isEmpty render-queue)) (when-let [f (.poll render-queue)]
((.take render-queue))) (f)
(when-not (or (:should-close @state) (recur)))
(GLFW/glfwWindowShouldClose window)) (when-not (or (:should-close @state)
(GLFW/glfwPollEvents) (GLFW/glfwWindowShouldClose window))
(let [stack (MemoryStack/stackPush)] (GLFW/glfwPollEvents)
(try (let [stack (MemoryStack/stackPush)]
(update-loop window stack {}) (try
(finally (update-loop window stack {})
(MemoryStack/stackPop)))) (finally
(recur)))) (MemoryStack/stackPop))))
(recur)))
(GLFW/glfwDestroyWindow window) (GLFW/glfwDestroyWindow window)
(GLFW/glfwTerminate))) (GLFW/glfwTerminate)))
@ -199,106 +190,75 @@
Assimp/aiProcess_FlipUVs)] Assimp/aiProcess_FlipUVs)]
(Assimp/aiImportFile path flags))) (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 (comment
(start!) (start!)
(stop!) (stop!)
(let [mesh (AIMesh/create (long (.get (.mMeshes scene) i))) (swap! loaded-scenes conj (with-gl (upload-scene! (load-scene "assets/model.glb"))))
_ (Assimp/aiGetMaterialTexture material Assimp/aiTextureType_DIFFUSE 0 path no-int no-int no-float no-int no-int no-int) (reset! shaders (with-gl (load-shaders! "shaders/base.vert" "shaders/base.frag")))
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))))
(with-gl (with-gl
(GL11/glClearColor 0.392 0.584 0.929 1.0)) (GL11/glClearColor 0.392 0.584 0.929 1.0))
(with-gl (with-gl
(GL11/glClearColor 0.0 0.0 0.0 1.0)) (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))
:-) :-)