diff --git a/deps.edn b/deps.edn index b054c1a..818d813 100644 --- a/deps.edn +++ b/deps.edn @@ -5,6 +5,8 @@ org.lwjgl/lwjgl$natives-linux {:mvn/version "3.3.4"} org.lwjgl/lwjgl-glfw$natives-linux {:mvn/version "3.3.4"} org.lwjgl/lwjgl-opengl$natives-linux {:mvn/version "3.3.4"} + org.lwjgl/lwjgl-stb {:mvn/version "3.3.4"} + org.lwjgl/lwjgl-stb$natives-linux {:mvn/version "3.3.4"} org.lwjgl/lwjgl-assimp {:mvn/version "3.3.3"} org.lwjgl/lwjgl-assimp$natives-linux {:mvn/version "3.3.3"} org.joml/joml {:mvn/version "1.10.7"}} diff --git a/shaders/base.frag b/shaders/base.frag index 5fe6e77..12b364b 100644 --- a/shaders/base.frag +++ b/shaders/base.frag @@ -1,10 +1,14 @@ #version 330 uniform vec4 uColor; +uniform sampler2D texture_id; +in vec2 vUV; out vec4 fragment; void main() { - fragment = uColor; + vec4 tex_color = texture(texture_id, vUV); + + fragment = uColor * tex_color; } diff --git a/shaders/base.vert b/shaders/base.vert index af8a967..8d743f0 100644 --- a/shaders/base.vert +++ b/shaders/base.vert @@ -1,8 +1,12 @@ #version 330 in vec3 vPos; +in vec2 aUV; + +out vec2 vUV; void main() { + vUV = aUV; gl_Position = vec4(vPos, 1.0); } diff --git a/src/nol/core.clj b/src/nol/core.clj index 342f49b..d0c9404 100644 --- a/src/nol/core.clj +++ b/src/nol/core.clj @@ -1,11 +1,13 @@ (ns nol.core - (:require [clojure.math]) - (:import [org.lwjgl.assimp AIColor4D AIFace AIMaterial AIMaterial$Buffer AIMesh AIScene AIVector3D Assimp] - [org.lwjgl.glfw GLFW GLFWErrorCallbackI GLFWKeyCallbackI] - [org.lwjgl.opengl GL GL11 GL15 GL20 GL33 GL30 GL45] - [org.lwjgl.system MemoryUtil MemoryStack] - [org.joml Matrix4f] - [java.nio FloatBuffer])) + (:require + [clojure.math]) + (:import + [java.nio FloatBuffer IntBuffer] + [org.lwjgl.assimp AIColor4D AIMaterial AIMesh AIScene AIString AITexture Assimp] + [org.lwjgl.glfw GLFW GLFWKeyCallbackI] + [org.lwjgl.opengl GL GL11 GL20 GL30 GL45] + [org.lwjgl.stb STBImage] + [org.lwjgl.system MemoryStack MemoryUtil])) (def render-queue (java.util.concurrent.LinkedBlockingQueue.)) @@ -47,6 +49,13 @@ -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) + (defn- update-loop [window stack data] (let [w-buf (.mallocInt stack 1) h-buf (.mallocInt stack 1) @@ -58,22 +67,33 @@ (GL11/glClear GL11/GL_COLOR_BUFFER_BIT) (swap! state assoc :last-time t) - (do - (GL20/glUseProgram program) + (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)))) + (catch Exception e + (println "Update Loop GL thread error:" e))) - (let [color-loc (GL20/glGetUniformLocation program "uColor")] - (doseq [m meshes - :let [[r g b a] (:color (:mesh m))]] - (GL20/glUniform4f color-loc r g b a) - (GL30/glBindVertexArray (:vao m)) - (GL11/glDrawElements GL11/GL_TRIANGLES (:indices-count m) GL11/GL_UNSIGNED_INT 0))) - - (GL30/glBindVertexArray 0) - (GL20/glUseProgram 0)) + (GL30/glBindVertexArray 0) + (GL20/glUseProgram 0) (GLFW/glfwSwapBuffers window))) (defn stop! [] + (reset! loaded false) (with-gl (GLFW/glfwSetWindowShouldClose (:window @state) true))) @@ -142,17 +162,27 @@ material (AIMaterial/create (long mat-ptr)) mat-color (AIColor4D/create) _ (Assimp/aiGetMaterialColor material Assimp/AI_MATKEY_COLOR_DIFFUSE 0 0 ^AIColor4D mat-color) + ^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) verts (.mVertices mesh) n (.mNumVertices mesh) - vert-arr (float-array (* 3 n)) + vert-arr (float-array (* 5 n)) faces (.mFaces mesh) nf (.mNumFaces mesh) - idx-arr (int-array (* 3 nf))] + idx-arr (int-array (* 3 nf)) + uvs (.mTextureCoords mesh 0)] (dotimes [i n] - (let [v (.get verts i)] - (aset vert-arr (+ (* i 3) 0) (.x v)) - (aset vert-arr (+ (* i 3) 1) (.y v)) - (aset vert-arr (+ (* i 3) 2) (.z v)))) + (let [vert (.get verts i) + uv (when uvs (.get uvs i)) + [^float u ^float v] (if uvs [(.x uv) (.y 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) idxs (.mIndices face)] @@ -160,10 +190,9 @@ (aset idx-arr (+ (* i 3) 1) (.get idxs 1)) (aset idx-arr (+ (* i 3) 2) (.get idxs 2)))) {:verts vert-arr :indices idx-arr :mat-idx (.mMaterialIndex mesh) - :color (let [color [(.r mat-color) (.g mat-color) (.b mat-color) (.a mat-color)]] - (if (= color [1.0 1.0 1.0 1.0]) - [(rand) (rand) (rand) 1.0] - color))}))) + :texture-idx (when (.startsWith data-path "*") + (parse-long (subs data-path 1))) + :color [(.r mat-color) (.g mat-color) (.b mat-color) (.a mat-color)]}))) (defn load-model [path] (let [flags (bit-or Assimp/aiProcess_Triangulate @@ -173,25 +202,84 @@ (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 (with-gl - (doall - (for [i (range (.mNumMeshes scene))] - (let [mesh (extract-mesh scene i) - vbo (GL45/glCreateBuffers) - ebo (GL45/glCreateBuffers) - vao (GL45/glCreateVertexArrays)] - (GL45/glNamedBufferStorage vbo (:verts mesh) GL45/GL_DYNAMIC_STORAGE_BIT) - (GL45/glNamedBufferStorage ebo (:indices mesh) GL45/GL_DYNAMIC_STORAGE_BIT) - (GL45/glVertexArrayElementBuffer vao ebo) - (GL45/glVertexArrayVertexBuffer vao 0 vbo 0 (* 3 Float/BYTES)) - (GL45/glVertexArrayAttribFormat vao 0 3 GL11/GL_FLOAT false 0) - (GL45/glVertexArrayAttribBinding vao 0 0) - (GL45/glEnableVertexArrayAttrib vao 0) - {:vbo vbo :vao vao :ebo ebo - :mesh mesh - :indices-count (alength (:indices mesh))}))))) + (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 (GL11/glClearColor 0.392 0.584 0.929 1.0)) @@ -207,10 +295,6 @@ -1.0 -1.0 0.0 1.0 -1.0 0.0]))) - (def program (with-gl (let [vert (compile-shader GL20/GL_VERTEX_SHADER vertex-shader-text) - frag (compile-shader GL20/GL_FRAGMENT_SHADER fragment-shader-text)] - (link-program vert frag)))) - (with-gl (GL45/glVertexArrayVertexBuffer vao 0 vbo 0 12)) (with-gl (GL45/glEnableVertexArrayAttrib vao 0)