(in-package #:existenz-common) (defun ones-vector3d () (make-vector3d 1.0 1.0 1.0)) (defun identity-matrix44 () (make-matrix44* (identity-matrix44*))) (defclass transformation () ((relative-position :initarg :relative-position :accessor relative-position :initform (new-vector3d)) (relative-rotation :initarg :relative-rotation :accessor relative-rotation :initform (new-quaternion)) (relative-scale :initarg :relative-scale :accessor relative-scale :initform (ones-vector3d)) (relative-dirty-p :initarg :relative-dirty-p :accessor relative-dirty-p :initform T) (relative-transformation :initarg :relative-transformation :accessor relative-transformation :initform (new-matrix44)) (absolute-transformation :initarg :absolute-transformation :accessor absolute-transformation :initform (new-matrix44))) (:documentation "Contains information about the position, rotation and scale relative to some other entity (usually the parent), or the coordinate origin. Also contains a scratch slot ABSOLUTE-TRANSFORMATION, which is used destructively to calculate the absolute transformation, i.e. relative to the coordinate origin.")) (defgeneric relative-transformation (object) (:documentation "Returns the transformation of the OBJECT relative to its parent as a MATRIX44.")) (defmethod relative-transformation (object) (relative-transformation (transformation object))) (defgeneric absolute-transformation (object) (:documentation "Returns the transformation of the OBJECT relative to the coordinate origin.")) (defmethod absolute-transformation (object) (absolute-transformation (transformation object))) (defmethod (setf relative-position) :after (new-value (transformation transformation)) (setf (relative-dirty-p transformation) T)) (defmethod (setf relative-rotation) :after (new-value (transformation transformation)) (setf (relative-dirty-p transformation) T)) (defmethod (setf relative-scale) :after (new-value (transformation transformation)) (setf (relative-dirty-p transformation) T)) (defun calculate-relative-transformation (position rotation scale relative-transformation) (matrix44-setter* relative-transformation (matrix44-product* (matrix44-product* (matrix33-matrix44* (quaternion-matrix33* (quaternion* rotation))) (with-vector3d position (tx ty tz) (translation-matrix44* tx ty tz))) (with-vector3d scale (sx sy sz) (scaling-matrix44* sx sy sz))))) (defmethod relative-transformation :before ((transformation transformation)) (when (relative-dirty-p transformation) (calculate-relative-transformation (relative-position transformation) (relative-rotation transformation) (relative-scale transformation) (slot-value transformation 'relative-transformation)) (setf (relative-dirty-p transformation) NIL))) (defmethod update-absolute-transformation (object parent-transformation) "Calculates the absolute transformation, returns and stores it in the slot ABSOLUTE-TRANSFORMATION of OBJECT." (let ((transformation (absolute-transformation object))) (matrix44-setter* transformation (matrix44-product* (matrix44* (relative-transformation object)) (matrix44* parent-transformation))))) (defun make-transformation () (make-instance 'transformation))