Compare commits

..
13 Commits
6 changed files with 516 additions and 38 deletions

No files matched your search

+4
View File
@@ -1,2 +1,6 @@
/.cpcache/
/.nrepl-port
/.clj-kondo/
/.lsp/
/target/
*.jsa
+14
View File
@@ -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}))
+7 -1
View File
@@ -5,7 +5,13 @@
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"}}
:paths ["src"]}
:paths ["src"]
: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}}}
+6 -2
View File
@@ -1,10 +1,14 @@
#version 330
in vec3 color;
uniform vec4 uColor;
uniform sampler2D texture_id;
in vec2 vUV;
out vec4 fragment;
void main()
{
fragment = vec4(color, 1.0);
vec4 tex_color = texture(texture_id, vUV);
fragment = uColor * tex_color;
}
+8 -6
View File
@@ -1,14 +1,16 @@
#version 330
uniform mat4 MVP;
uniform mat4 uModel;
uniform mat4 uView;
uniform mat4 uProjection;
in vec3 vCol;
in vec2 vPos;
in vec3 vPos;
in vec2 aUV;
out vec3 color;
out vec2 vUV;
void main()
{
gl_Position = MVP * vec4(vPos, 0.0, 1.0);
color = vCol;
vUV = aUV;
gl_Position = uProjection * uView * uModel * vec4(vPos, 1.0);
}
+477 -29
View File
@@ -1,14 +1,54 @@
(ns nol.core
(:import [org.lwjgl.assimp Assimp AIScene AIMesh AIVector3D AIFace]
[org.lwjgl.glfw GLFW GLFWKeyCallbackI GLFWErrorCallbackI]
[org.lwjgl.opengl GL GL45 GL33 GL20 GL15 GL11 GL30]
[org.lwjgl.system MemoryStack MemoryUtil]
[org.joml Matrix4f]
[java.nio FloatBuffer]))
(:gen-class)
(:require
[clojure.math])
(:import
[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 Vector2f Vector3f]
[org.lwjgl.system MemoryStack MemoryUtil]))
(def vertex-shader-text (slurp "shaders/base.vert"))
(def ^LinkedBlockingQueue render-queue (LinkedBlockingQueue.))
(def fragment-shader-text (slurp "shaders/base.frag"))
(defonce camera-fly (atom {:type :fly
:pos (Vector3f.)
:yaw 0.0
:pitch 0.0
:last-x 0.0
:last-y 0.0
:target (Vector3f.)
:view-matrix (.identity (Matrix4f.))}))
(defonce camera-orbit (atom {:type :orbit
:pos (Vector3f.)
:yaw 0.0
:pitch 0.0
:last-x 0.0
:last-y 0.0
:focus-point (Vector3f.)
:view-matrix (.identity (Matrix4f.))}))
(def state (atom {:last-time 0.0
:drag-start-pos nil
:current-mode :static}))
(defonce gl-thread (atom nil))
(defmacro with-gl [& body]
`(let [result# (promise)]
(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#))))
(let [r# (deref result#)]
(if (instance? Exception r#)
(throw r#)
r#))))
(defn- compile-shader [type source]
(let [shader (GL20/glCreateShader type)]
@@ -27,30 +67,255 @@
(throw (RuntimeException. (str "Program link error: " (GL20/glGetProgramInfoLog program)))))
program))
(def state (atom {:last-time (GLFW/glfwGetTime)}))
(defn ai-matrix->matrix4f [^AIMatrix4x4 m]
(Matrix4f. (.a1 m) (.b1 m) (.c1 m) (.d1 m)
(.a2 m) (.b2 m) (.c2 m) (.d2 m)
(.a3 m) (.b3 m) (.c3 m) (.d3 m)
(.a4 m) (.b4 m) (.c4 m) (.d4 m)))
(defn load-model [path]
(Assimp/aiImportFile path (bit-or Assimp/aiProcess_Triangulate
Assimp/aiProcess_FlipUVs)))
(defn matrix4f->vectors [^Matrix4f m]
[(vector (.m00 m) (.m01 m) (.m02 m) (.m03 m))
(vector (.m10 m) (.m11 m) (.m12 m) (.m13 m))
(vector (.m20 m) (.m21 m) (.m22 m) (.m23 m))
(vector (.m30 m) (.m31 m) (.m32 m) (.m33 m))])
(def vertices (float-array [0.0 0.5 0.0
-0.5 0.5 0.0
0.5 -0.5 0.0]))
(defn node-matrix4f [^AINode c]
(-> c
(.mTransformation)
(ai-matrix->matrix4f)))
(defn- update-loop [window stack data]
(defonce loaded-scene (atom nil))
(defonce uploaded-scene (atom nil))
(defonce shaders (atom nil))
(defn camera-forward [^double yaw ^double pitch]
(Vector3f. (* (Math/cos pitch) (Math/sin yaw))
(Math/sin pitch)
(- (* (Math/cos pitch) (Math/cos yaw)))))
(defn camera-right [^double yaw]
(Vector3f. (Math/cos yaw) 0.0 (Math/sin yaw)))
(defn camera-up [^Vector3f forward ^Vector3f right]
(-> (Vector3f. forward) (.cross right)))
(defn get-ndc [^double x ^double y ^long w ^long h]
[(- (* 2 (/ x w)) 1)
(- 1 (* 2 (/ y h)))])
(defn- key-down? [window key]
(= (GLFW/glfwGetKey window key) GLFW/GLFW_PRESS))
(defn- handle-key-actions! [_win key _scancode action _mods]
(when (= action GLFW/GLFW_PRESS)
(when (= key GLFW/GLFW_KEY_ESCAPE)
(swap! state assoc :should-close true))
(when (= key GLFW/GLFW_KEY_R)
(swap! state update :current-camera
#(merge % {:pos (Vector3f. 0.0 0.0 10.0)
:yaw 0.0
:pitch 0.0
:focus-point (Vector3f. 0.0 0.0 0.0)
:target (Vector3f.)})))))
(defn- drag-detected? [^double x1 ^double y1 ^double x2 ^double y2]
(let [threshold 10.0
dx (- x2 x1)
dy (- y2 y1)]
(< threshold (+ (* dx dx) (* dy dy)))))
(def cam-speed 0.04)
(defn- handle-keyboard-state! [window]
(when-let [camera (when (= (:current-mode @state) :fly)
@camera-fly)]
(let [move-dir (Vector3f.)
{:keys [yaw pitch ^Vector3f pos]} camera]
(when (key-down? window GLFW/GLFW_KEY_W)
(.add move-dir 0.0 0.0 1.0))
(when (key-down? window GLFW/GLFW_KEY_S)
(.add move-dir 0.0 0.0 -1.0))
(when (key-down? window GLFW/GLFW_KEY_A)
(.add move-dir -1.0 0.0 0.0))
(when (key-down? window GLFW/GLFW_KEY_D)
(.add move-dir 1.0 0.0 0.0))
(when (key-down? window GLFW/GLFW_KEY_Q)
(.add move-dir 0.0 1.0 0.0))
(when (key-down? window GLFW/GLFW_KEY_E)
(.add move-dir 0.0 -1.0 0.0))
(when (> (.length move-dir) 0.0)
(.normalize move-dir)
(let [forward ^Vector3f (camera-forward yaw pitch)
right ^Vector3f (camera-right yaw)
up ^Vector3f (camera-up forward right)
velocity ^Vector3f (-> (Vector3f. right)
(.mul (.x move-dir))
(.fma (.z move-dir) forward)
(.fma (.y move-dir) up)
(.mul ^double cam-speed))]
(.add pos velocity)))
(.set move-dir 0.0 0.0 0.0))))
(defn- handle-mouse-move! [_window ^double xpos ^double ypos]
(when-let [camera (case (:current-mode @state)
:fly camera-fly
:orbit camera-orbit
:static nil)]
(when (and (= (:type @camera) :orbit))
(let [{:keys [^double yaw ^double pitch last-x last-y]} @camera
last-x (double (or last-x xpos))
last-y (double (or last-y ypos))
sensitivity 0.005
dx (- last-x xpos)
dy (- last-y ypos)
fwd ^Vector3f (camera-forward yaw pitch)]
(swap! camera assoc
:last-x xpos
:last-y ypos
:yaw (- yaw (* dx sensitivity))
:pitch (-> (- pitch (* dy sensitivity))
(max (- (/ Math/PI 2)))
(min (/ Math/PI 2))))))
#_(when-let [cursor-pos ^Vector2f (:drag-start-pos @state)]
(when (and (drag-detected? xpos ypos (.x cursor-pos) (.y cursor-pos)))
(swap! state assoc :orbit-mode true)))
(when (and (= (:type @camera) :fly))
(let [{:keys [^double yaw ^double pitch pos last-x last-y]} @camera
last-x (double (or last-x xpos))
last-y (double (or last-y ypos))
sensitivity 0.001
dx (- last-x xpos)
dy (- last-y ypos)]
(swap! camera assoc
:last-x xpos
:last-y ypos
:yaw (- yaw (* dx sensitivity))
:pitch (+ pitch (* dy sensitivity)))))))
(defn- get-current-cursor-pos! ^Vector2f [^MemoryStack stack ^long window]
(let [xbuf (.mallocDouble stack 1)
ybuf (.mallocDouble stack 1)]
(GLFW/glfwGetCursorPos window xbuf ybuf)
(Vector2f. (.get xbuf 0) (.get ybuf 0))))
(defn- handle-mouse-buttons! [^long win button action mods]
(cond
(and (= button GLFW/GLFW_MOUSE_BUTTON_RIGHT) (= action GLFW/GLFW_PRESS))
(let []
(swap! state assoc :current-mode :fly)
(GLFW/glfwSetInputMode win GLFW/GLFW_CURSOR GLFW/GLFW_CURSOR_DISABLED))
(and (= button GLFW/GLFW_MOUSE_BUTTON_RIGHT) (= action GLFW/GLFW_RELEASE))
(let []
(swap! state assoc :current-mode :static)
(swap! camera-fly assoc :last-x nil :last-y nil)
(GLFW/glfwSetInputMode win GLFW/GLFW_CURSOR GLFW/GLFW_CURSOR_NORMAL))
(and (= button GLFW/GLFW_MOUSE_BUTTON_LEFT) (= action GLFW/GLFW_PRESS))
(do
(when (mods :ctrl)
(swap! state assoc :current-mode :orbit))
(swap! state assoc :drag-start-pos (get-current-cursor-pos! (MemoryStack/stackGet) win)))
(and (= button GLFW/GLFW_MOUSE_BUTTON_LEFT) (= action GLFW/GLFW_RELEASE))
(let []
(swap! state assoc :current-mode :static :drag-start-pos nil)
(GLFW/glfwSetCursor win MemoryUtil/NULL))))
(defn render-scene [^MemoryStack stack scene node ^Matrix4f mtx]
(let [buf (.mallocFloat stack 16)
model-mtx (Matrix4f.)]
(.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
{:keys [_program uniforms]} @shaders]
(doseq [idx mesh-indices
:let [gl-mesh (nth gl-meshes idx)
mesh (:mesh gl-mesh)
[r g b a] (:color mesh)
tex-idx (:texture-idx mesh)]]
(GL20/glUniform4f (:color uniforms) r g b a)
(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))]
(GL45/glActiveTexture GL45/GL_TEXTURE0)
(GL11/glBindTexture GL11/GL_TEXTURE_2D tex-id)
(GL20/glUniform1i (:tex uniforms) 0)))
(GL11/glDrawElements GL11/GL_TRIANGLES (:indices-count gl-mesh) GL11/GL_UNSIGNED_INT 0))))
(when-let [children (seq (:children node))]
(doseq [child children]
(render-scene stack scene child model-mtx)))))
(defn- camera-view-matrix [{:keys [yaw pitch ^Vector3f pos ^Vector3f target ^Matrix4f view-matrix]}]
(-> view-matrix
(.identity)
(.lookAt (.x pos) (.y pos) (.z pos)
(.x target) (.y target) (.z target)
0.0 1.0 0.0)))
(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)
current-time (GLFW/glfwGetTime)]
t (GLFW/glfwGetTime)]
(GL11/glViewport 0 0 w h)
(GL11/glClear GL11/GL_COLOR_BUFFER_BIT)
(GL11/glClear (bit-or GL11/GL_COLOR_BUFFER_BIT GL11/GL_DEPTH_BUFFER_BIT))
(swap! state assoc :last-time current-time)
(try
(when (and @uploaded-scene @shaders)
(handle-keyboard-state! window)
(let [scene @uploaded-scene
{:keys [program uniforms]} @shaders]
(GL20/glUseProgram program)
(let [vbuf (.mallocFloat stack 16)
pbuf (.mallocFloat stack 16)
camera (if (= :orbit (:current-mode @state))
camera-orbit
camera-fly)
view (camera-view-matrix @camera)
proj (:projection-matrix @state)]
(.get ^Matrix4f view vbuf)
(.get ^Matrix4f proj 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)))
(GL30/glBindVertexArray 0)
(GL20/glUseProgram 0)
(GLFW/glfwSwapBuffers window)))
(defn stop! []
(when @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 [^int gl-id]} (:gl-textures @uploaded-scene)]
(GL11/glDeleteTextures gl-id)))
(reset! uploaded-scene nil)
(reset! shaders nil)
(swap! state assoc :should-close true))
(defn- init [window width height]
(swap! state assoc
:window window
:should-close false
:projection-matrix
(-> (Matrix4f.)
(.identity)
(.perspective (float (Math/toRadians 45))
(float (/ (float width) (float height)))
(float 0.1)
(float 100.0)))))
(defn -main []
(when-not (GLFW/glfwInit)
(throw (RuntimeException. "Failed to init GLFW")))
@@ -59,37 +324,220 @@
(GLFW/glfwWindowHint GLFW/GLFW_CONTEXT_VERSION_MINOR 5)
(GLFW/glfwWindowHint GLFW/GLFW_OPENGL_PROFILE GLFW/GLFW_OPENGL_CORE_PROFILE)
(let [window (GLFW/glfwCreateWindow 960 592 "NOL" MemoryUtil/NULL MemoryUtil/NULL)]
(let [width 960 #_1900
height 500 #_1100
window (GLFW/glfwCreateWindow 960 500 "NOL" MemoryUtil/NULL MemoryUtil/NULL)]
(when (= window MemoryUtil/NULL)
(GLFW/glfwTerminate)
(throw (RuntimeException. "Failed to create window")))
(GLFW/glfwMakeContextCurrent window)
(GL/createCapabilities)
(GL11/glEnable GL11/GL_DEPTH_TEST)
(GL11/glEnable GL11/GL_CULL_FACE)
(GL11/glCullFace GL11/GL_BACK)
(GLFW/glfwSwapInterval 1)
(GLFW/glfwSetKeyCallback window
(reify GLFWKeyCallbackI
(invoke [_ win key scancode action mods]
(when (and (= key GLFW/GLFW_KEY_ESCAPE) (= action GLFW/GLFW_PRESS))
(GLFW/glfwSetWindowShouldClose win true)))))
(try
(handle-key-actions! win key scancode action mods)
(catch Exception e
(println "Key Callback Exception:" e))))))
(when (GLFW/glfwRawMouseMotionSupported)
(GLFW/glfwSetInputMode window GLFW/GLFW_RAW_MOUSE_MOTION GLFW/GLFW_TRUE))
(GLFW/glfwSetCursorPosCallback window
(reify org.lwjgl.glfw.GLFWCursorPosCallbackI
(invoke [_ win xpos ypos]
(try
(handle-mouse-move! win xpos ypos)
(catch Exception e
(println "Cursor Pos Callback Exception:" e))))))
(GLFW/glfwSetMouseButtonCallback window
(reify org.lwjgl.glfw.GLFWMouseButtonCallbackI
(invoke [_ win button action mods]
(try
(let [mods (cond-> #{}
(pos? (bit-and mods GLFW/GLFW_MOD_SHIFT)) (conj :shift)
(pos? (bit-and mods GLFW/GLFW_MOD_CONTROL)) (conj :ctrl)
(pos? (bit-and mods GLFW/GLFW_MOD_ALT)) (conj :alt)
(pos? (bit-and mods GLFW/GLFW_MOD_SUPER)) (conj :super))]
(handle-mouse-buttons! win button action mods))
(catch Exception e
(println "Mouse Button Callback Exception:" e))))))
(init window width height)
(loop []
(when-not (GLFW/glfwWindowShouldClose window)
(loop []
(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)
(update-loop window stack {})
(finally
(MemoryStack/stackPop))))
(recur)))
(stop!)
(GLFW/glfwDestroyWindow window)
(GLFW/glfwTerminate)))
(defn start! []
(when (and @gl-thread (.isAlive ^Thread @gl-thread))
(throw (RuntimeException. "Already running")))
(reset! gl-thread
(doto (Thread. (fn []
(try
(-main)
(catch Exception e
(println "GL thread error:" e)))))
(.setName "opengl-thread")
(.setDaemon true)
(.start))))
(defn load-model [^String path]
(let [flags (bit-or Assimp/aiProcess_Triangulate
Assimp/aiProcess_FlipUVs)]
(Assimp/aiImportFile path flags)))
(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)
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 (* 5 n))
faces (.mFaces mesh)
nf (.mNumFaces mesh)
idx-arr (int-array (* 3 nf))
uvs (.mTextureCoords mesh 0)]
(dotimes [i n]
(let [vert ^AIVector3D (.get verts i)
uv (when uvs (.get uvs i))
[^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 ^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))
(aset idx-arr (+ (* i 3) 2) (.get idxs 2))))
{:verts vert-arr :indices idx-arr :mat-idx (.mMaterialIndex mesh)
: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 traverse [^AINode node]
{:node node
:meshes (let [buf (.mMeshes node)]
(mapv #(.get buf ^int %) (range (.mNumMeshes node))))
:transform (node-matrix4f node)
:children (mapv #(traverse (AINode/create ^long (.get (.mChildren node) ^int %)))
(range (.mNumChildren node)))})
(defn load-scene [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 ^int 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)}))))
hiearchy (traverse (.mRootNode scene))]
(Assimp/aiReleaseImport scene)
{:meshes meshes :textures textures :hiearchy hiearchy}))
(defn upload-scene! [scene]
(let [gl-meshes
(mapv
#(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))
(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 ^ints (: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 ^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)
(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))
program (link-program vert frag)]
{:program program
: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")}}))
(comment
(-main)
(def ^AIScene scene (load-model "assets/model.glb"))
(.mNumMeshes scene) ;; 54
(.mNumMaterials scene) ;; 17
(start!)
(with-gl (stop!))
(reset! loaded-scene
(do
(when @loaded-scene
(doseq [tex (:textures @loaded-scene)]
(when-let [data (:data tex)]
(STBImage/stbi_image_free ^ByteBuffer data))))
(load-scene "assets/model.glb")))
(reset! uploaded-scene (with-gl (upload-scene! @loaded-scene)))
(reset! shaders (with-gl (load-shaders! "shaders/base.vert" "shaders/base.frag")))
(swap! state assoc :current-state :static)
(with-gl
(GL11/glClearColor 0.392 0.584 0.929 1.0))
(with-gl
(GL11/glClearColor 0.2 0.25 0.3 1.0))
:-)