stoe/engine/mesh.lisp
Renaud Casenave-Péré 0a5d24fe3e Use the renderer to show some meshes
Create some classes to store the mesh data streams and adapt the import
file accordingly.
Add object and camera classes to be manipulated by the game.
Render the meshes in the graph scene using only position vertex stream
and an unicolor shader.
Also add some models and a startup package to ease testing.
2015-12-27 17:09:06 +01:00

85 lines
3.3 KiB
Common Lisp

#|
This file is a part of stoe project.
Copyright (c) 2015 Renaud Casenave-Péré (renaud@casenave-pere.fr)
|#
(uiop:define-package :stoe/engine/mesh
(:use :cl :cffi :maths :shader
:stoe/core/utils
:stoe/engine/gl-utils)
(:export #:mesh #:vertex-streams #:faces #:make-mesh
#:stream-array #:ctype
#:vertex-stream #:attrib
#:index-stream #:mode
#:make-stream-array #:make-vertex-stream #:make-index-stream #:bsize
#:render-mesh))
(in-package :stoe/engine/mesh)
(defclass mesh ()
((streams :initarg :streams :accessor vertex-streams)
(faces :initarg :faces :accessor faces))
(:documentation "Class for a single mesh."))
(defun make-mesh (&optional streams faces)
(make-instance 'mesh :streams streams :faces faces))
(defclass stream-array ()
((array :initarg :array :reader raw-data)
(ctype :initarg :ctype :reader ctype)
(count :initarg :count)))
(defclass vertex-stream (stream-array)
((attrib :initarg :attrib :reader attrib)
(stride :initarg :stride)))
(defclass index-stream (stream-array)
((mode :initarg :mode :reader mode)))
(defun make-stream-array (array ctype count stride)
(make-instance 'stream-array :array array :ctype ctype :count count :stride stride))
(defun make-vertex-stream (array ctype count attrib stride)
(make-instance 'vertex-stream :array array :ctype ctype :count count :attrib attrib :stride stride))
(defun make-index-stream (array ctype count mode)
(make-instance 'index-stream :array array :ctype ctype :count count :mode mode))
(defmethod size ((stream stream-array))
(length (raw-data stream)))
(defgeneric bsize (object))
(defmethod bsize ((stream stream-array))
(* (ctype-size (ctype stream)) (length (raw-data stream))))
(defun render-mesh (mesh program)
(loop for stream in (vertex-streams mesh)
with offset = 0
do (let* ((ctype (ctype stream)) (size (size stream)) (bsize (bsize stream))
(data (raw-data stream)) (attrib (attrib stream))
(ptr (foreign-alloc ctype :count size)))
;; create the data for opengl
(dotimes (i (length data))
(setf (mem-aref ptr ctype i) (aref data i)))
(let ((buffer-object (first (gl:gen-buffers 1))))
(gl:bind-buffer :array-buffer buffer-object)
(%gl:buffer-data :array-buffer bsize ptr :static-draw)
;; use it
(let ((loc (get-location program attrib)))
(gl-assert (gl:enable-vertex-attrib-array loc)
(gl:vertex-attrib-pointer loc 3 ctype :false 0 offset))
(incf offset bsize)
(foreign-free ptr)))))
(let* ((faces (faces mesh)) (data (raw-data faces))
(size (size faces)) (bsize (bsize faces))
(index-object (first (gl:gen-buffers 1)))
(ptr (foreign-alloc (ctype faces) :initial-contents data :count size)))
(gl:bind-buffer :element-array-buffer index-object)
(%gl:buffer-data :element-array-buffer bsize ptr :static-draw)
(foreign-free ptr)
(gl-assert (%gl:draw-elements (mode faces) bsize (ctype-to-gltype (ctype faces)) 0)))
;; cleanup data
(loop for stream in (vertex-streams mesh)
do (let ((loc (get-location program (attrib stream))))
(gl:disable-vertex-attrib-array loc)))
(gl:bind-buffer :element-array-buffer 0)
(gl:bind-buffer :array-buffer 0))