;;;; wh-engine/render/view.lisp (in-package wh-engine/render) (defclass view (component) ((render-pass :documentation "The render pass this view should be drawn in." :reader render-pass :type fixnum :initarg :render-pass :initform 0) (render-mask :documentation "Only include actors with at least one of these tags." :accessor render-mask :type (proper-list symbol) :initarg :render-mask :initform '(:default)) (cull-p :documentation "Whether or not to skip rendering out-of-frame objects." :accessor cull-p :type boolean :initarg :cull-p :initform t) (render-target :documentation "The render target this view renders to." :reader render-target :type (or render-target null) :initform nil)) (:documentation "Defines a view into the scene, and rendering settings for objects drawn by the view.")) (defmethod (setf render-pass) (new-val (this view)) "The render pass this view should be drawn in." (setf (o! this :slot render-pass) new-val) (sort-world-views)) (defmethod resume :after ((this view)) (unless (o! this render-target) (setf (o! this :slot render-target) (new! render-target :width *view-width* :height *view-height*)))) (defmethod activate :after ((this view) &key) ; Register (when (o! this actor tree-active-p) (pushnew (make-weak-pointer this) *world-views*) (sort-world-views))) (defmethod destroy :before ((this view)) (unless (o! this destroyed-p) ;; Unregister (setf *world-views* (delete this *world-views* :key #'weak-pointer-value)) ;; Destroy buffers (when (o! this framebuffer) (gl:delete-framebuffers (list (o! this framebuffer)))) (when (o! this render-texture) (gl:delete-texture (o! this render-texture))) (when (o! this renderbuffer) (gl:delete-renderbuffers (list (o! this renderbuffer)))) )) (defmethod view-matrix ((this view)) "The world-to-view-space transformation matrix for this object." ;; view-space = local-space, scaled by ppu, then offset so [-width/2..width/2] -> [0..width] ;; (Y+ is still up in view-space) (m* (mat *view-ppu* 0 (/ *view-width* 2) 0 *view-ppu* (/ *view-height* 2) 0 0 1) (o! this actor local-matrix))) (defmethod world-matrix ((this view)) "The view-to-world-space transformation matrix for this object." (minv (o! this view-matrix))) (defmethod view-point ((this view) point) "Transform point from world space to view space." (declare (type vec2 point)) (vxy-trunc (m* (o! this view-matrix) (vxy1 point)))) (defmethod render-view ((this view) drawables) "Render everything in this view, given all drawables in the world." (let ((view-matrix (o! this view-matrix))) ;; Apply view matrix (gl:matrix-mode :modelview) (gl:load-transpose-matrix (opengl-matrix view-matrix)) (loop for drawable-ptr in drawables for drawable = (deref-pointer drawable-ptr) when (and drawable (ensure-live drawable)) when (and (o! drawable active-p) (o! drawable actor tree-active-p) (some (lambda (x) (o! drawable actor (has-tag x))) (o! this render-mask))) do (o! this (render-drawable drawable view-matrix))) )) (defun transform-box (box drawable-matrix view-matrix) (with-vec2 (ax ay) (car box) (with-vec2 (bx by) (cdr box) (let ((box-a (vxy-trunc (n*m view-matrix (m* drawable-matrix (vec3 ax ay 1))))) (box-b (vxy-trunc (n*m view-matrix (m* drawable-matrix (vec3 bx by 1))))) (box-ab (vxy-trunc (n*m view-matrix (m* drawable-matrix (vec3 ax by 1))))) (box-ba (vxy-trunc (n*m view-matrix (m* drawable-matrix (vec3 bx ay 1)))))) (values (vmin box-a box-b box-ab box-ba) (vmax box-a box-b box-ab box-ba)))))) (defun in-view-p (drawable drawable-matrix view-matrix view-box) "Determine if drawable is in the view defined by view-matrix and view-box." (multiple-value-bind (box-min box-max) (transform-box (o! drawable culling-box) drawable-matrix view-matrix) ;; If it's in view at all, either its top-right corner is >= bottom-left of view, ;; or its bottom-left is <= top-right of view (or (v>= box-max (car view-box)) (v<= box-min (cdr view-box))))) (defmethod render-drawable ((this view) drawable view-matrix) "Render drawable with the precomputed view-matrix." (let ((drawable-matrix (o! drawable actor world-matrix))) (when (or (not (o! this cull-p)) (in-view-p drawable drawable-matrix view-matrix (cons (vec2 0 0) (vec2 *view-width* *view-height*)))) (gl:push-matrix) (gl:translate 0 0 (o! drawable actor z-layer)) (gl:mult-transpose-matrix (opengl-matrix drawable-matrix)) (o! drawable (draw this)) (gl:pop-matrix))))