WASD + Free Camera look, fix double free, callbacks with exception handling
This commit is contained in:
parent
e9a19baa84
commit
734100d52d
171
src/nol/core.clj
171
src/nol/core.clj
@ -10,12 +10,16 @@
|
||||
[org.lwjgl.glfw GLFW GLFWKeyCallbackI]
|
||||
[org.lwjgl.opengl GL GL11 GL20 GL30 GL45]
|
||||
[org.lwjgl.stb STBImage]
|
||||
[org.joml Matrix4f]
|
||||
[org.joml Matrix4f Vector3f]
|
||||
[org.lwjgl.system MemoryStack MemoryUtil]))
|
||||
|
||||
(def ^LinkedBlockingQueue render-queue (LinkedBlockingQueue.))
|
||||
|
||||
(def state (atom {:last-time 0.0 :window nil}))
|
||||
(def state (atom {:last-time 0.0
|
||||
:camera-pos (Vector3f. 0.0 0.0 10.0)
|
||||
:camera-yaw 0.0
|
||||
:camera-pitch 0.0
|
||||
:camera-target (Vector3f.)}))
|
||||
|
||||
(def gl-thread (atom nil))
|
||||
|
||||
@ -64,16 +68,91 @@
|
||||
(.mTransformation)
|
||||
(ai-matrix->matrix4f)))
|
||||
|
||||
(defn node-matrix [^AINode c]
|
||||
(-> c
|
||||
(.mTransformation)
|
||||
(ai-matrix->matrix4f)
|
||||
(matrix4f->vectors)))
|
||||
|
||||
(def loaded-scene (atom nil))
|
||||
(def uploaded-scene (atom nil))
|
||||
(def shaders (atom nil))
|
||||
|
||||
(def cam-speed 0.03)
|
||||
|
||||
(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- key-down? [window key]
|
||||
(= (GLFW/glfwGetKey window key) GLFW/GLFW_PRESS))
|
||||
|
||||
(def ^Vector3f move-dir (Vector3f.))
|
||||
|
||||
(defn- handle-input! [window]
|
||||
(let [{:keys [camera-yaw camera-pitch ^Vector3f camera-pos]} @state]
|
||||
(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 camera-yaw camera-pitch)
|
||||
right ^Vector3f (camera-right camera-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 camera-pos velocity)))
|
||||
(.set move-dir 0.0 0.0 0.0)))
|
||||
|
||||
(defn- handle-mouse-input! [window ^double xpos ^double ypos]
|
||||
(when (:fps-mode @state)
|
||||
(let [{:keys [^double camera-yaw ^double camera-pitch]} @state
|
||||
last-cursor-x (double (or (:last-cursor-x @state) xpos))
|
||||
last-cursor-y (double (or (:last-cursor-y @state) ypos))
|
||||
sensitivity 0.001
|
||||
dx (- last-cursor-x xpos)
|
||||
dy (- last-cursor-y ypos)]
|
||||
(swap! state assoc
|
||||
:last-cursor-x xpos
|
||||
:last-cursor-y ypos
|
||||
:camera-yaw (- camera-yaw (* dx sensitivity))
|
||||
:camera-pitch (+ camera-pitch (* dy sensitivity))))))
|
||||
|
||||
(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 :fps-mode true)
|
||||
(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 :fps-mode false :last-cursor-x nil :last-cursor-y nil)
|
||||
(GLFW/glfwSetInputMode win GLFW/GLFW_CURSOR GLFW/GLFW_CURSOR_NORMAL))
|
||||
|
||||
(and (= button GLFW/GLFW_MOUSE_BUTTON_LEFT) (= action GLFW/GLFW_PRESS))
|
||||
(let [cursor (GLFW/glfwCreateStandardCursor GLFW/GLFW_RESIZE_ALL_CURSOR)]
|
||||
(swap! state assoc :orbit-mode true)
|
||||
(GLFW/glfwSetCursor win cursor))
|
||||
|
||||
(and (= button GLFW/GLFW_MOUSE_BUTTON_LEFT) (= action GLFW/GLFW_RELEASE))
|
||||
(let []
|
||||
(swap! state assoc :orbit-mode false)
|
||||
(GLFW/glfwSetCursor win MemoryUtil/NULL))))
|
||||
|
||||
(defn render-scene [^MemoryStack stack scene node ^Matrix4f mtx]
|
||||
(let [buf (.mallocFloat stack 16)
|
||||
model-mtx (Matrix4f.)]
|
||||
@ -114,19 +193,26 @@
|
||||
;; (swap! state assoc :last-time t)
|
||||
(try
|
||||
(when (and @uploaded-scene @shaders)
|
||||
(handle-input! window)
|
||||
(let [scene @uploaded-scene
|
||||
{:keys [program uniforms]} @shaders]
|
||||
(GL20/glUseProgram program)
|
||||
(let [vbuf (.mallocFloat stack 16)
|
||||
pbuf (.mallocFloat stack 16)
|
||||
radius 10.0
|
||||
cam-x (* radius (Math/sin t))
|
||||
cam-z (* radius (Math/cos t))
|
||||
;; cam-x (* radius (Math/sin t))
|
||||
;; cam-z (* radius (Math/cos t))
|
||||
{:keys [^double camera-yaw ^double camera-pitch ^Vector3f camera-pos camera-target]} @state
|
||||
fwd (camera-forward camera-yaw camera-pitch)
|
||||
target ^Vector3f (:camera-target @state)
|
||||
_ (doto ^Vector3f target
|
||||
(.set camera-pos)
|
||||
(.add fwd))
|
||||
vm (-> (Matrix4f.)
|
||||
(.identity)
|
||||
(.lookAt (float cam-x) (float 0.0) (float cam-z)
|
||||
(float 0.0) (float 0.0) (float 0.0)
|
||||
(float 0.0) (float 1.0) (float 0.0)))
|
||||
(.lookAt (.x camera-pos) (.y camera-pos) (.z camera-pos) ;; eye (camera position)
|
||||
(.x target) (.y target) (.z target) ;; center (where to look)
|
||||
0.0 1.0 0.0)) ;; up
|
||||
pm (-> (Matrix4f.)
|
||||
(.identity)
|
||||
(.perspective (float (Math/toRadians 45))
|
||||
@ -147,20 +233,16 @@
|
||||
(GLFW/glfwSwapBuffers window)))
|
||||
|
||||
(defn stop! []
|
||||
(with-gl
|
||||
(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)))
|
||||
(when @shaders
|
||||
(GL20/glDeleteProgram (:program @shaders)))
|
||||
(GLFW/glfwSetWindowShouldClose
|
||||
(:window @state) true))
|
||||
(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))
|
||||
(reset! shaders nil)
|
||||
(swap! state assoc :should-close true))
|
||||
|
||||
(defn -main []
|
||||
(when-not (GLFW/glfwInit)
|
||||
@ -170,7 +252,7 @@
|
||||
(GLFW/glfwWindowHint GLFW/GLFW_CONTEXT_VERSION_MINOR 5)
|
||||
(GLFW/glfwWindowHint GLFW/GLFW_OPENGL_PROFILE GLFW/GLFW_OPENGL_CORE_PROFILE)
|
||||
|
||||
(let [window (GLFW/glfwCreateWindow 960 300 #_#_1900 1100 "NOL" MemoryUtil/NULL MemoryUtil/NULL)]
|
||||
(let [window (GLFW/glfwCreateWindow 960 400 #_#_1900 1100 "NOL" MemoryUtil/NULL MemoryUtil/NULL)]
|
||||
(when (= window MemoryUtil/NULL)
|
||||
(GLFW/glfwTerminate)
|
||||
(throw (RuntimeException. "Failed to create window")))
|
||||
@ -188,8 +270,28 @@
|
||||
(GLFW/glfwSetKeyCallback window
|
||||
(reify GLFWKeyCallbackI
|
||||
(invoke [_ win key scancode action mods]
|
||||
#_(try
|
||||
(handle-input! win key scancode action mods)
|
||||
(catch Exception e
|
||||
(println "GLFW Input error:" e)))
|
||||
(when (and (= key GLFW/GLFW_KEY_ESCAPE) (= action GLFW/GLFW_PRESS))
|
||||
(swap! state assoc :should-close true)))))
|
||||
(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-input! 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
|
||||
(handle-mouse-buttons! win button action mods)
|
||||
(catch Exception e
|
||||
(println "Mouse Button Callback Exception:" e))))))
|
||||
|
||||
(loop []
|
||||
(loop []
|
||||
@ -206,6 +308,7 @@
|
||||
(MemoryStack/stackPop))))
|
||||
(recur)))
|
||||
|
||||
(stop!)
|
||||
(GLFW/glfwDestroyWindow window)
|
||||
(GLFW/glfwTerminate)))
|
||||
|
||||
@ -326,7 +429,6 @@
|
||||
(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 ^ByteBuffer (:data %))
|
||||
(assoc % :gl-id tex-id))
|
||||
(:textures scene))]
|
||||
(assoc scene :gl-textures gl-textures :gl-meshes gl-meshes)))
|
||||
@ -342,17 +444,20 @@
|
||||
:mv (GL20/glGetUniformLocation ^int program "uView")
|
||||
:mp (GL20/glGetUniformLocation ^int program "uProjection")}}))
|
||||
|
||||
(reset! loaded-scene (load-scene "assets/model.glb"))
|
||||
|
||||
(comment
|
||||
(start!)
|
||||
(stop!)
|
||||
(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")))
|
||||
|
||||
(with-gl
|
||||
(GL11/glClear (bit-or GL11/GL_COLOR_BUFFER_BIT GL11/GL_DEPTH_BUFFER_BIT)))
|
||||
(with-gl
|
||||
(GL11/glClearColor 0.392 0.584 0.929 1.0))
|
||||
(with-gl
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user