120 lines
5.0 KiB
Common Lisp
120 lines
5.0 KiB
Common Lisp
;;;; 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))))
|