stoe/engine/mesh.lisp
Renaud Casenave-Péré 8838362c26 Implement an entity-component system and a scene graph
Use entities and components to define objects in the game world
and represent the game scene as a graph
2016-04-04 22:46:46 +02:00

101 lines
4.1 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
#:mesh-initialize
#:render-mesh))
(in-package :stoe/engine/mesh)
(defclass mesh ()
((streams :initarg :streams :reader vertex-streams)
(faces :initarg :faces :reader faces)
(material :initarg :material :reader material)
(vertex-buffers :initform nil :accessor vertex-buffers)
(index-buffer :initform nil :accessor index-buffer))
(:documentation "Class for a single mesh."))
(defun make-mesh (&optional streams faces)
(make-instance 'mesh :streams streams :faces faces :material nil))
(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 :reader 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 mesh-initialize (mesh)
(let ((vertex-buffers (gl:gen-buffers (length (vertex-streams mesh))))
(index-buffer (gl:gen-buffer)))
(loop for stream in (vertex-streams mesh)
for buffer-object in vertex-buffers
do (let* ((ctype (ctype stream)) (size (size stream)) (bsize (bsize stream))
(data (raw-data stream))
(ptr (foreign-alloc ctype :count size)))
(dotimes (i (length data))
(setf (mem-aref ptr ctype i) (aref data i)))
(gl:bind-buffer :array-buffer buffer-object)
(%gl:buffer-data :array-buffer bsize ptr :static-draw)
(foreign-free ptr)))
(gl:bind-buffer :array-buffer 0)
(let* ((faces (faces mesh)) (data (raw-data faces))
(size (size faces)) (bsize (bsize faces))
(ptr (foreign-alloc (ctype faces) :initial-contents data :count size)))
(gl:bind-buffer :element-array-buffer index-buffer)
(%gl:buffer-data :element-array-buffer bsize ptr :static-draw)
(foreign-free ptr)
(gl:bind-buffer :element-array-buffer 0))
(setf (vertex-buffers mesh) vertex-buffers
(index-buffer mesh) index-buffer)))
(defun render-mesh (mesh program)
(with-accessors ((vertex-buffers vertex-buffers) (streams vertex-streams)
(index-buffer index-buffer) (faces faces)) mesh
(loop for i below (length vertex-buffers)
for vertex in vertex-buffers
for stream in streams
with offset = 0
do (let* ((ctype (ctype stream)) (attrib (attrib stream))
(bsize (bsize stream)) (stride (stride stream))
(loc (get-location program attrib)))
(gl:bind-buffer :array-buffer vertex)
(gl-assert (gl:enable-vertex-attrib-array loc)
(gl:vertex-attrib-pointer loc stride ctype
:false 0 offset))
(incf offset bsize)))
(gl:bind-buffer :element-array-buffer index-buffer)
(gl-assert (%gl:draw-elements (mode faces) (bsize faces)
(ctype-to-gltype (ctype faces)) 0))
(gl:bind-buffer :element-array-buffer 0)
(gl:bind-buffer :array-buffer 0)))