diff --git a/src/render/mesh.lisp b/src/render/mesh.lisp index 76dfaba..1b0de20 100644 --- a/src/render/mesh.lisp +++ b/src/render/mesh.lisp @@ -11,19 +11,22 @@ (in-package :stoe.render.mesh) (defstruct attrib - name + (name "") type size offset) (defstruct (vertex-buffer (:constructor %make-vertex-buffer)) data - attribs) + attribs + buffer-object) (defstruct (index-buffer (:constructor %make-index-buffer)) type mode - data) + size + data + buffer-object) (defstruct (mesh-stream (:constructor %make-mesh-stream)) program @@ -44,12 +47,12 @@ (size (third attrib)) (buffer (fourth attrib))) (prog1 - (make-attrib :name name :type type + (make-attrib :name (symbol-name name) :type type :size size :offset end-offset) (setf buffer-data (cons buffer buffer-data)) (let ((len (length buffer))) (incf buffer-size len) - (incf end-offset (* len size (gl-utils:size-of type))))))) + (incf end-offset (* len (gl-utils:size-of type))))))) data)) (vertex-buffer (%make-vertex-buffer :data (make-array buffer-size) :attribs attribs)) (buffer-index 0)) @@ -58,10 +61,27 @@ do (dotimes (i (length buffer)) (setf (aref (vertex-buffer-data vertex-buffer) buffer-index) (aref buffer i)) (incf buffer-index))) + (setf (vertex-buffer-buffer-object vertex-buffer) (first (gl:gen-buffers 1))) + (let ((ptr (cffi:foreign-alloc :float :initial-contents (vertex-buffer-data vertex-buffer) :count end-offset))) + (gl:bind-buffer :array-buffer (vertex-buffer-buffer-object vertex-buffer)) + (%gl:buffer-data :array-buffer end-offset ptr :static-draw) + (gl:bind-buffer :array-buffer 0) + (cffi:foreign-free ptr)) vertex-buffer))) (defun make-index-buffer (data) - (%make-index-buffer :type (first data) :mode (second data) :data (third data))) + (let ((type (first data)) + (mode (second data)) + (size (length (third data))) + (data (third data))) + (let ((index-buffer (%make-index-buffer :type type :mode mode :size size :data data))) + (setf (index-buffer-buffer-object index-buffer) (first (gl:gen-buffers 1))) + (let ((ptr (cffi:foreign-alloc type :initial-contents data :count size))) + (gl:bind-buffer :element-array-buffer (index-buffer-buffer-object index-buffer)) + (%gl:buffer-data :element-array-buffer (* size (gl-utils:size-of type)) ptr :static-draw) + (gl:bind-buffer :element-array-buffer 0) + (cffi:foreign-free ptr)) + index-buffer))) (defun %set-mesh-stream-program (stream symbol) (setf (mesh-stream-program stream) symbol)) diff --git a/src/render/render.lisp b/src/render/render.lisp index c84079e..04554f4 100644 --- a/src/render/render.lisp +++ b/src/render/render.lisp @@ -54,9 +54,10 @@ Destroy the opengl context and the related resources." "Update the render module. Render a frame and swap buffers." (declare (ignore delta-time)) - (gl:clear-color 0.0 0 0 0) + (gl:clear-color 0 0 0 0) (gl:clear-depth 1.0) (gl:clear :color-buffer-bit :depth-buffer-bit) + (render-scene (game:get-world-origin)) (glop:swap-buffers *window*)) (modules:register-initialize-fun #'initialize) @@ -71,3 +72,46 @@ This needs to be called once per frame, at the beginning of the loop." (defmethod glop:on-event (window event) (declare (ignore window event))) + +(defun render-mesh (node mesh) + "Render a single mesh." + (loop for stream in (mesh::mesh-streams mesh) + do (shader::using-program (program (mesh::mesh-stream-program stream)) + (shader::with-uniforms (model-to-camera camera-to-clip) program + (gl:uniform-matrix model-to-camera 4 (vector (m:* (go::view (game:get-current-camera)) + (go::trans-matrix node)))) + (gl:uniform-matrix camera-to-clip 4 (vector (go::projection (game:get-current-camera))))) + (let* ((vertex-buffer (mesh::mesh-stream-vertex-buffer stream)) + (index-buffer (mesh::mesh-stream-index-buffer stream)) + (attribs (mesh::vertex-buffer-attribs vertex-buffer))) + (gl:bind-buffer :array-buffer (mesh::vertex-buffer-buffer-object vertex-buffer)) + (loop for attrib in attribs + do (let* ((attrib-name (mesh::attrib-name attrib)) + (attrib-loc (shader::get-attrib-location program attrib-name))) + (gl-utils:gl-assert (gl:enable-vertex-attrib-array attrib-loc)) + (gl-utils:gl-assert (gl:vertex-attrib-pointer attrib-loc (mesh::attrib-size attrib) + (mesh::attrib-type attrib) :false 0 + (mesh::attrib-offset attrib))))) + (gl:bind-buffer :element-array-buffer (mesh::index-buffer-buffer-object index-buffer)) + (gl-utils:gl-assert (%gl:draw-elements (mesh::index-buffer-mode index-buffer) + (mesh::index-buffer-size index-buffer) + (mesh::index-buffer-type index-buffer) 0)) + (gl:disable-vertex-attrib-array 0) + (gl:bind-buffer :element-array-buffer 0) + (gl:bind-buffer :array-buffer 0))))) + +(defun render-node (node) + "Render a single node." + (with-slots ((components go::components)) node + (let ((mesh (car (member-if (lambda (c) (typep c 'mesh::mesh)) components)))) + (when mesh + (render-mesh node mesh))))) + +(defun render-scene (node) + "Walk the scene graph and render the graphical components." + (with-slots ((children go::children)) node + (loop for child in children + do (progn + (go:update-trans-matrix child) + (render-node child) + (render-scene child))))) diff --git a/src/render/shader/shader.lisp b/src/render/shader/shader.lisp index 254cf94..e57a98a 100644 --- a/src/render/shader/shader.lisp +++ b/src/render/shader/shader.lisp @@ -136,10 +136,47 @@ Retrieve the attributes and uniform locations." (format t "~%") (setf i 0)) (format t ".") - (compile-program program-symbol))))) + (compile-program program-symbol))) + (format t "~%"))) (defun destroy-all-shaders () "Destroy the programs registered in opengl." (format t "Deleting shaders") (loop for program-symbol being the symbol in :%stoe.shaders do (delete-program program-symbol))) + +(defun get-attrib-location (program symbol) + (fourth (first (member symbol (program-attribs program) :key #'car :test #'equal)))) + +(defmacro using-program ((var program) &body body) + "Use the specified program and bind all its attributes and uniform for use in `body'." + `(let ((,var (symbol-value (find-symbol (symbol-name ,program) :%stoe.shaders)))) + (gl-utils:gl-assert (gl:use-program (program-gl-program ,var))) + ,@body + (gl-utils:gl-assert (gl:use-program 0)))) + +(defmacro with-uniforms (vars program &body body) + `(let ,(mapcar (lambda (var) + (cond + ((listp var) (list (first var) + `(fourth (first (member (symbol-name ',(second var)) + (program-uniforms ,program) + :key #'car :test #'equal))))) + ((symbolp var) (list var `(fourth (first (member (symbol-name ',var) + (program-uniforms ,program) + :key #'car :test #'equal))))))) + vars) + ,@body)) + +(defmacro with-attribs (vars program &body body) + `(let ,(mapcar (lambda (var) + (cond + ((listp var) (list (first var) + `(fourth (first (member (symbol-name ',(second var)) + (program-attribs ,program) + :key #'car :test #'equal))))) + ((symbolp var) (list var `(fourth (first (member (symbol-name ',var) + (program-attribs ,program) + :key #'car :test #'equal))))))) + vars) + ,@body)) diff --git a/src/render/shaders.lisp b/src/render/shaders.lisp new file mode 100644 index 0000000..d63f50e --- /dev/null +++ b/src/render/shaders.lisp @@ -0,0 +1,30 @@ +#| + This file is a part of stoe project. + Copyright (c) 2014 Renaud Casenave-Péré (renaud@casenave-pere.fr) +|# + +(in-package :cl-user) +(defpackage stoe.render.shaders + (:nicknames :shaders) + (:use :cl + :shader)) +(in-package :stoe.render.shaders) + +(defshader simple-vertex (:version 330 + :in ((position :vec4 :location 0) + (color :vec4 :location 1)) + :out ((out-color :vec4 :interp :smooth)) + :uniform ((camera-to-clip :mat4) + (model-to-camera :mat4)) + ) + "gl_Position = camera_to_clip * model_to_camera * position; +out_color = color;") + +(defshader simple-fragment (:version 330 + :in ((out-color :vec4)) + :out ((frag-color :vec4))) + "frag_color = out_color;") + +(defprogram simple-shader () + :vertex-shader simple-vertex + :fragment-shader simple-fragment) diff --git a/stoe.asd b/stoe.asd index 171c833..6dd2522 100644 --- a/stoe.asd +++ b/stoe.asd @@ -61,7 +61,8 @@ ((:file "glsl-compiler") (:file "shader"))) (:file "mesh") - (:file "render")) + (:file "render") + (:file "shaders")) :depends-on ("modules" "utils")) (:file "stoe" :depends-on ("utils" "modules")))))