;;;; affine.lisp (in-package #:wheelwork) (defclass/std affine (unit) ((cached-model cached-projected-matrix cached-application :a) (base-width base-height :r :std 1.0 :doc "Determined by content.") (scale-x scale-y :std 1.0) (rotation x y :std 0.0))) (defmethod (setf closer-mop:slot-value-using-class) :after (newval class (affine affine) slot) (case (closer-mop:slot-definition-name slot) ((x y scale-x scale-y rotation) (setf (cached-model affine) nil (cached-projected-matrix affine) nil)))) (defun scale-by (affine amount) (with-slots (scale-x scale-y) affine (setf scale-x (* amount scale-x) scale-y (* amount scale-y)))) (defun set-width-preserve-aspect (affine new-width) (scale-by affine (/ new-width (width affine)))) (defun set-height-preserve-aspect (affine new-height) (scale-by affine (/ new-height (height affine) ))) (defun width (affine) (with-slots (scale-x base-width) affine (* scale-x base-width))) (defun height (affine) (with-slots (scale-y base-height) affine (* scale-y base-height))) (defun (setf width) (newval affine) (with-slots (scale-x base-width) affine (setf scale-x (coerce (/ newval base-width) 'single-float)))) (defun (setf height) (newval affine) (with-slots (scale-y base-height) affine (setf scale-y (coerce (/ newval base-height) 'single-float)))) (defmethod model-matrix :around ((u affine)) (or (cached-model u) (setf (cached-model u) (call-next-method)))) (defmethod model-matrix ((u affine)) (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 projected-matrix (affine) (or (cached-projected-matrix affine) (setf (cached-projected-matrix affine) (mat:marr (mat:m* (application-projection (app-of-unit affine)) (model-matrix affine))))))