#| 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))