stoe/engine/model.lisp

73 lines
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/model
(:use :cl :maths
:stoe/core/utils
:stoe/core/entity
:stoe/core/resources
:stoe/engine/scene-graph
:stoe/engine/mesh
:stoe/engine/scene
:stoe/engine/render)
(:export #:model-node #:mesh-indexes #:make-model-node
#:model-resource #:root-node #:meshes #:meshref
#:mesh-component #:model #:make-mesh-component
#:create-model))
(in-package :stoe/engine/model)
(defclass model-node (node)
((name :initarg :name :accessor name)
(mesh-indexes :initarg :mesh-indexes :accessor mesh-indexes)
(transform :initarg :transform :reader transform :type float44)))
(defun make-model-node (name mesh-indexes &optional parent (transform (mat-id 4 'single-float)))
(make-instance 'model-node :parent parent :name name :mesh-indexes mesh-indexes :transform transform))
(defclass model-resource (shared-resource)
((root-node :initarg :root-node :accessor root-node :type model-node)
(meshes :initarg :meshes :accessor meshes))
(:documentation "Resource class containing the actual model data."))
(defmethod root-node ((res resource-proxy))
(with-slots (resource) res
(when (tg:weak-pointer-value resource)
(root-node (tg:weak-pointer-value resource)))))
(defmethod meshes ((res resource-proxy))
(with-slots (resource) res
(when (tg:weak-pointer-value resource)
(meshes (tg:weak-pointer-value resource)))))
(defun meshref (model-proxy subscript)
(aref (meshes model-proxy) subscript))
(defmethod resource-initialize ((res model-resource))
(with-slots (meshes) res
(on-render-thread (meshes)
(loop for mesh across meshes
do (mesh-initialize mesh)))))
(defcomponent mesh-component (graph-node-component)
((model :initarg :model :reader model)
(model-node :initarg :model-node :reader model-node :type model-node))
(:needs graph-node-component)
(:documentation "A graph node component that contains a single mesh."))
(defun create-model (name path &optional (parent-entity (current-scene)))
"Create a model from a resource file and attach it to the parent entity or root."
(ret entity (create-entity name
(graph-node-component :parent parent-entity))
(with-resource (path model)
(with-components ((node graph-node-component)) entity
(labels ((clone-mesh (node parent)
(setf parent (make-instance 'mesh-component :owner entity :parent parent
:transform (transform node) :model model :model-node node))
(mapc (lambda (child) (clone-mesh child parent)) (children node))))
(mapc (lambda (child) (clone-mesh child node)) (children (root-node model))))))))
(defmethod render ((mesh mesh-component))
(loop for mesh-idx in (mesh-indexes (model-node mesh))
do (render-single-mesh (meshref (model mesh) mesh-idx) (transform mesh))))