;;;; units/unit.lisp (in-package #:wheelwork) (defclass/std unit () ((cached-model cached-projected-matrix cached-application :a) (container :with :a) (base-width base-height :r :std 1.0 :doc "Determined by content.") (scale-x scale-y :with :std 1.0) (rotation x y :with :std 0.0) (opacity :std 1.0 :doc "0.0 indicates it will not be rendred."))) (defmethod (setf closer-mop:slot-value-using-class) :after (newval class (unit unit) slot) (case (closer-mop:slot-definition-name slot) ((x y scale-x scale-y rotation) (setf (cached-model unit) nil (cached-projected-matrix unit) nil)) (container (setf (cached-application unit) nil)))) (defun scale-by (unit amount) (with-slots (scale-x scale-y) unit (setf scale-x (* amount scale-x) scale-y (* amount scale-y)))) (defun set-width-preserve-aspect (unit new-width) (scale-by unit (/ new-width (unit-width unit)))) (defun set-height-preserve-aspect (unit new-height) (scale-by unit (/ new-height (unit-height unit) ))) (defmethod unit-width ((unit unit)) (with-slots (scale-x base-width) unit (* scale-x base-width))) (defmethod unit-height ((unit unit)) (with-slots (scale-y base-height) unit (* scale-y base-height))) (defmethod (setf unit-width) (newval (unit unit)) (with-slots (scale-x base-width) unit (setf scale-x (coerce (/ newval base-width) 'single-float)))) (defmethod (setf unit-height) (newval (unit unit)) (with-slots (scale-y base-height) unit (setf scale-y (coerce (/ newval base-height) 'single-float)))) (defmethod model-matrix :around ((u unit)) (or (cached-model u) (setf (cached-model u) (call-next-method)))) (defmethod model-matrix ((u unit)) (let ((m (mat:meye 4))) (with-slots (x y base-width scale-x base-height scale-y rotation) u (let ((uw (* base-width scale-x)) (uh (* base-height scale-y))) (mat:nmtranslate m (vec:vec x y 0.0)) (mat:nmtranslate m (vec:v* 0.5 (vec:vec uw uh 0.0))) (mat:nmrotate m vec:+vz+ rotation) (mat:nmtranslate m (vec:v* -0.5 (vec:vec uw uh 0.0))) (mat:nmscale m (vec:vec uw uh 1.0)))) m)) (defun app-of-unit (unit) "Returns the APPLICATION instance, if any, of which this UNIT is a part. NIL indicates that the unit has not been added to any container in this application." (or (cached-application unit) (setf (cached-application unit) (labels ((rec (u) (when-let (c (unit-container u)) (etypecase c (application c) (unit (rec c)) (null nil))))) (rec unit))))) (defun projected-matrix (unit) (or (cached-projected-matrix unit) (setf (cached-projected-matrix unit) (mat:marr (mat:m* (application-projection (app-of-unit unit)) (model-matrix unit))))))