#| This file is a part of stoe project. Copyright (c) 2015 Renaud Casenave-Péré (renaud@casenave-pere.fr) |# (uiop:define-package :stoe/engine/render (:use :cl :cffi :maths :shader :stoe/core/utils :stoe/core/containers :stoe/core/time :stoe/core/modules :stoe/core/thread :stoe/core/jobs :stoe/engine/gl-utils :stoe/engine/mesh :stoe/engine/viewport :stoe/engine/scene) (:export #:on-render-thread)) (in-package :stoe/engine/render) (defclass render-thread (specialized-thread) ()) (defvar *render-thread* nil) (defvar *frames-per-second* 0.0) (defun initialize (&optional argv) "Initialize the render module. Create an opengl context attached to a window." (format t "Initialize Render module~%") (viewport-configure argv) (setf *render-thread* (push-new-thread 'render-thread "Render thread"))) (defun finalize () "Finalize the render module. Destroy the opengl context and the related resources." (format t "Finalize Render module~%") (terminate-thread *render-thread*)) (defun update (delta-time) (declare (ignore delta-time))) (defmodule stoe/engine/render :render) (let ((time-counter 0.0) (frames-counter 0)) (defun compute-fps (delta-time) (incf time-counter delta-time) (incf frames-counter) (when (> time-counter 1000000.0) (setf *frames-per-second* frames-counter) (setf time-counter 0.0) (setf frames-counter 0)))) (defun render-single-mesh (mesh transform) (using-program (program 'blue-shader) (with-locations (model-to-camera camera-to-clip) program (let ((mtc (m* (view (get-current-camera)) transform)) (ctc (projection (get-current-camera)))) (gl:uniform-matrix model-to-camera 4 (vector (raw-data mtc)) nil) (gl:uniform-matrix camera-to-clip 4 (vector (raw-data ctc)) nil))) (render-mesh mesh program))) (defun render-scene-node (node scene) (loop for mesh-idx in (meshes node) do (render-single-mesh (aref (meshes scene) mesh-idx) (transform node))) (loop for child in (children node) do (render-scene-node child scene))) (defun render-world (world) (unless (null world) (with-lock-held ((scene-lock world)) (with-accessors ((scene world-scene)) world (unless (null scene) (render-scene-node (root-node scene) scene)))))) (defmethod thread-initialize ((thread render-thread)) (format t "Initialize ~a~%" (name thread)) (viewport-initialize) (compile-all-shaders)) (defmethod thread-finalize ((thread render-thread)) (format t "Finalize ~a~%" (name thread)) (destroy-all-shaders) (viewport-finalize)) (defmethod thread-process ((thread render-thread)) (let ((clock (make-clock))) (loop until (thread-terminate-p thread) do (restartable (during-one-frame (loop for job = (get-next-job thread) while job do (progn (format t "Thread ~a: Running job ~a~%" (name thread) (id job)) (job-run job thread))) (render-world (get-world))) (update-clock clock) (compute-fps (clock-delta clock)))))) (defmacro on-render-thread (args &body body) `(eval-on-thread ,args *render-thread* ,@body))