diff --git a/src/camera.lisp b/src/camera.lisp new file mode 100644 index 0000000..1a8266d --- /dev/null +++ b/src/camera.lisp @@ -0,0 +1,40 @@ +#| + This file is a part of stoe project. + Copyright (c) 2014 Renaud Casenave-Péré (renaud@casenave-pere.fr) +|# + +(in-package :cl-user) +(defpackage stoe.camera + (:nicknames :camera) + (:use :cl) + (:export :camera :view :proj + :make-camera + :update-view) + (:import-from :object + :object :pos :dir)) +(in-package :stoe.camera) + +(defclass camera (object) + ((fovy :initarg :fovy :accessor fovy) + (aspect :initarg :aspect :accessor aspect) + (near :initarg :near :accessor near) + (far :initarg :far :accessor far) + (projection :initarg :projection :accessor proj :type 'f44:float44) + (view :accessor view :type 'f44:float44)) + (:documentation "Base class for a camera representing a view of the game world.")) + +(defun make-camera (fovy aspect near far) + (let ((camera (make-instance 'camera :position (v:vec 0 0 2) + :direction (q:from-axis-and-angle (v:vec 0 0 1) 0) + :fovy fovy + :aspect aspect + :near near + :far far + :projection (geom:make-persp-matrix fovy aspect near far)))) + (update-view camera) + camera)) + +(defun update-view (camera) + "Compute the world to view matrix from the position and the direction of `camera'." + (with-accessors ((pos pos) (dir dir) (view view)) camera + (setf view (m:* (m::transpose (q:to-float44 dir)) (geom:mat-trans (v:- pos)))))) diff --git a/src/game/game.lisp b/src/game.lisp similarity index 83% rename from src/game/game.lisp rename to src/game.lisp index 2827524..aa0c0e7 100644 --- a/src/game/game.lisp +++ b/src/game.lisp @@ -10,7 +10,9 @@ (:export :get-world-origin :get-current-camera) (:import-from :modules - :defmodule)) + :defmodule) + (:import-from :camera + :make-camera :update-view)) (in-package :stoe.game) (defconstant +loop-step-time+ 16000.0 @@ -31,9 +33,9 @@ we need to keep the remaining time.") (declare (ignore argv)) (format t "Initialize Game module~%") (input:initialize) - (setf *world-origin* (go:make-object)) - (setf *current-camera* (go:make-camera 90 (/ 16 9) 1.0 1000.0)) - (go:attach *current-camera* *world-origin*)) + (setf *world-origin* (object:make-object)) + (setf *current-camera* (make-camera 90 (/ 16 9) 1.0 1000.0)) + (scene:attach *current-camera* *world-origin*)) (defun finalize () "Finalize the game module." @@ -48,7 +50,7 @@ Advance the world by `delta-time', +loop-step-time+ at a time." (loop while (> delta-time +loop-step-time+) do (progn (when *current-camera* - (go:update-view *current-camera*)) + (update-view *current-camera*)) (input:update +loop-step-time+) (decf delta-time +loop-step-time+))) (setf *last-frame-remaining-time* delta-time)) diff --git a/src/game/game-object.lisp b/src/game/game-object.lisp deleted file mode 100644 index 805ea7b..0000000 --- a/src/game/game-object.lisp +++ /dev/null @@ -1,100 +0,0 @@ -#| - This file is a part of stoe project. - Copyright (c) 2014 Renaud Casenave-Péré (renaud@casenave-pere.fr) -|# - -(in-package :cl-user) -(defpackage stoe.game.game-object - (:use :cl) - (:nicknames :game-object :go) - (:shadow :position) - (:export :node - :parent - :children - :attach - :detach - :walk - :position - :direction - :make-object - :update-trans-matrix - :make-camera - :view - :update-view)) -(in-package :stoe.game.game-object) - -(defclass scene-node () - ((parent :initform nil :reader parent) - (children :initform nil :reader children)) - (:documentation "Base class for a node in the scene graph.")) - -(defgeneric attach (scene-node parent) - (:documentation "Attach a new node to the scene graph to be rendered.")) - -(defmethod attach ((scene-node scene-node) (parent scene-node)) - (with-slots (children) parent - (with-slots ((new-parent parent)) scene-node - (push scene-node children) - (setf new-parent parent)))) - -(defgeneric detach (scene-node) - (:documentation "Detach a node from the scene graph to prevent it and its -children from being rendered.")) - -(defmethod detach ((scene-node scene-node)) - (with-slots (parent) scene-node - (with-slots (children) parent - (setf children (remove scene-node children)) - (setf parent nil)))) - -(defun walk (fun node) - "Walk through the scene graph and apply `fun' at each node." - (with-slots (children) node - (loop for child in children - do (progn - (apply fun child) - (walk fun child))))) - -(defclass game-object (scene-node) - ((position :initarg :position :accessor position :type 'f3:float3) - (direction :initarg :direction :accessor direction :type 'q:quaternion) - (trans-matrix :initform (f44:mat-ident) :accessor trans-matrix :type 'f44:float44) - (components :initform nil)) - (:documentation "Base class for all objects existing in the game world.")) - -(defclass camera (game-object) - ((fovy :initarg :fovy :accessor fovy) - (aspect :initarg :aspect :accessor aspect) - (near :initarg :near :accessor near) - (far :initarg :far :accessor far) - (projection :initarg :projection :accessor projection :type 'f44:float44) - (view :accessor view :type 'f44:float44)) - (:documentation "Base class for a camera representing a view of the game world.")) - -(defun make-object (&key (pos (v:vec 0 0 0)) (dir (q:from-axis-and-angle (v:vec 0 0 1) 0)) mesh) - (let ((obj (make-instance 'game-object :position pos :direction dir))) - (when mesh - (with-slots (components) obj - (push mesh components))) - obj)) - -(defun update-trans-matrix (node) - (setf (trans-matrix node) (m:* (trans-matrix (parent node)) - (geom:mat-trans (position node)) - (q:to-float44 (direction node))))) - -(defun make-camera (fovy aspect near far) - (let ((camera (make-instance 'camera :position (v:vec 0 0 2) - :direction (q:from-axis-and-angle (v:vec 0 0 1) 0) - :fovy fovy - :aspect aspect - :near near - :far far - :projection (geom:make-persp-matrix fovy aspect near far)))) - (update-view camera) - camera)) - -(defun update-view (camera) - "Compute the world to view matrix from the position and the direction of `camera'." - (with-accessors ((pos go:position) (dir go:direction) (view view)) camera - (setf view (m:* (m::transpose (q:to-float44 dir)) (geom:mat-trans (v:- pos)))))) diff --git a/src/game/input.lisp b/src/input.lisp similarity index 99% rename from src/game/input.lisp rename to src/input.lisp index 5e0823d..94b46e7 100644 --- a/src/game/input.lisp +++ b/src/input.lisp @@ -4,7 +4,7 @@ |# (in-package :cl-user) -(defpackage stoe.game.input +(defpackage stoe.input (:nicknames :input) (:use :cl :alexandria :utils :containers) @@ -13,7 +13,7 @@ :make-keymap :set-global-keymap :define-key :global-set-key :define-motion :global-set-motion)) -(in-package :stoe.game.input) +(in-package :stoe.input) (define-constant +keyevent-classes+ '(:press :release :repeat :continuous) :test #'equal :documentation "List of the available key event classes.") diff --git a/src/object.lisp b/src/object.lisp new file mode 100644 index 0000000..3f18036 --- /dev/null +++ b/src/object.lisp @@ -0,0 +1,33 @@ +#| + This file is a part of stoe project. + Copyright (c) 2014 Renaud Casenave-Péré (renaud@casenave-pere.fr) +|# + +(in-package :cl-user) +(defpackage stoe.object + (:use :cl) + (:nicknames :object) + (:export :object :pos :dir :trans-mat :components + :make-object :update-trans-matrix) + (:import-from :scene + :scene-node :parent)) +(in-package :stoe.object) + +(defclass object (scene-node) + ((position :initarg :position :accessor pos :type 'f3:float3) + (direction :initarg :direction :accessor dir :type 'q:quaternion) + (trans-matrix :initform (f44:mat-ident) :accessor trans-mat :type 'f44:float44) + (components :initform nil :reader components)) + (:documentation "Base class for all objects existing in the game world.")) + +(defun make-object (&key (pos (v:vec 0 0 0)) (dir (q:from-axis-and-angle (v:vec 0 0 1) 0)) mesh) + (let ((obj (make-instance 'object :position pos :direction dir))) + (when mesh + (with-slots (components) obj + (push mesh components))) + obj)) + +(defun update-trans-matrix (node) + (setf (trans-mat node) (m:* (trans-mat (parent node)) + (geom:mat-trans (pos node)) + (q:to-float44 (dir node))))) diff --git a/src/render/render.lisp b/src/render/render.lisp index 7ce8b6e..e6e5afa 100644 --- a/src/render/render.lisp +++ b/src/render/render.lisp @@ -10,7 +10,15 @@ :utils) (:export :poll-events) (:import-from :modules - :defmodule)) + :defmodule) + (:import-from :game + :get-current-camera) + (:import-from :scene + :children) + (:import-from :object + :trans-mat :components :update-trans-matrix) + (:import-from :camera + :proj :view)) (in-package :stoe.render) (defvar *window* nil) @@ -84,7 +92,7 @@ This needs to be called once per frame, at the beginning of the loop." (defvar *height* 0) (defun on-resize-event (width height) - (setf (go::projection (game:get-current-camera)) (geom:make-persp-matrix 30 (/ width height) 1.0 1000.0)) + (setf (proj (get-current-camera)) (geom:make-persp-matrix 30 (/ width height) 1.0 1000.0)) (setf *width* width) (setf *height* height) (gl:viewport 0 0 width height)) @@ -94,9 +102,9 @@ This needs to be called once per frame, at the beginning of the loop." (loop for stream in (mesh::mesh-streams mesh) do (shader::using-program (program (mesh::mesh-stream-program stream)) (shader::with-uniforms (model-to-camera camera-to-clip) program - (gl:uniform-matrix model-to-camera 4 (vector (m:* (go::view (game:get-current-camera)) - (go::trans-matrix node)))) - (gl:uniform-matrix camera-to-clip 4 (vector (go::projection (game:get-current-camera))))) + (gl:uniform-matrix model-to-camera 4 (vector (m:* (view (get-current-camera)) + (trans-mat node)))) + (gl:uniform-matrix camera-to-clip 4 (vector (proj (get-current-camera))))) (let* ((vertex-buffer (mesh::mesh-stream-vertex-buffer stream)) (index-buffer (mesh::mesh-stream-index-buffer stream)) (attribs (mesh::vertex-buffer-attribs vertex-buffer))) @@ -118,16 +126,16 @@ This needs to be called once per frame, at the beginning of the loop." (defun render-node (node) "Render a single node." - (with-slots ((components go::components)) node + (with-accessors ((components components)) node (let ((mesh (car (member-if (lambda (c) (typep c 'mesh::mesh)) components)))) (when mesh (render-mesh node mesh))))) (defun render-scene (node) "Walk the scene graph and render the graphical components." - (with-slots ((children go::children)) node + (with-accessors ((children children)) node (loop for child in children do (progn - (go:update-trans-matrix child) + (update-trans-matrix child) (render-node child) (render-scene child))))) diff --git a/src/scene.lisp b/src/scene.lisp new file mode 100644 index 0000000..52caf90 --- /dev/null +++ b/src/scene.lisp @@ -0,0 +1,45 @@ +#| + This file is a part of stoe project. + Copyright (c) 2014 Renaud Casenave-Péré (renaud@casenave-pere.fr) +|# + +(in-package :cl-user) +(defpackage stoe.scene + (:use :cl) + (:nicknames :scene) + (:export :scene-node :parent :children + :attach :detach + :walk)) +(in-package :stoe.scene) + +(defclass scene-node () + ((parent :initform nil :reader parent) + (children :initform nil :reader children)) + (:documentation "Base class for a node in the scene graph.")) + +(defgeneric attach (scene-node parent) + (:documentation "Attach a new node to the scene graph to be rendered.")) + +(defmethod attach ((scene-node scene-node) (parent scene-node)) + (with-slots (children) parent + (with-slots ((new-parent parent)) scene-node + (push scene-node children) + (setf new-parent parent)))) + +(defgeneric detach (scene-node) + (:documentation "Detach a node from the scene graph to prevent it and its +children from being rendered.")) + +(defmethod detach ((scene-node scene-node)) + (with-slots (parent) scene-node + (with-slots (children) parent + (setf children (remove scene-node children)) + (setf parent nil)))) + +(defun walk (fun node) + "Walk through the scene graph and apply `fun' at each node." + (with-slots (children) node + (loop for child in children + do (progn + (apply fun child) + (walk fun child))))) diff --git a/src/stoe.lisp b/src/stoe.lisp index c88d659..93541f0 100644 --- a/src/stoe.lisp +++ b/src/stoe.lisp @@ -6,8 +6,17 @@ (in-package :cl-user) (defpackage stoe (:use :cl - :utils :input) - (:export :main :quit)) + :utils) + (:import-from :scene + :attach) + (:import-from :object + :make-object :dir) + (:import-from :game + :get-current-camera + :get-world-origin) + (:import-from :input + :global-set-key + :global-set-motion)) (in-package :stoe) (let ((exit-main-loop nil)) @@ -35,25 +44,25 @@ continue unless `unprotected' is t." (start-coords '(0.0 . 0.0))) (defun set-freelook (enable) (setf freelook-mode enable) - (setf start-orient (go:direction (game:get-current-camera)))) + (setf start-orient (dir (get-current-camera)))) (defun freelook-move (x y) (if freelook-mode (let ((dx (- (car start-coords) x)) (dy (- (cdr start-coords) y))) - (setf (go:direction (game:get-current-camera)) (q:* (q:from-axis-and-angle (v:vec 0 1 0) (maths:deg-to-rad dx)) - start-orient - (q:from-axis-and-angle (v:vec 1 0 0) (maths:deg-to-rad dy))))) - (setf start-coords (cons x y))))) + (setf (dir (get-current-camera)) (q:* (q:from-axis-and-angle (v:vec 0 1 0) (maths:deg-to-rad (- dx))) + start-orient + (q:from-axis-and-angle (v:vec 1 0 0) (maths:deg-to-rad dy))))) + (setf start-coords (cons x y)))) -(global-set-key 3 #'set-freelook t) -(global-set-key (3 :release) #'set-freelook nil) -(global-set-motion #'freelook-move :x :y) + (global-set-key 3 #'set-freelook t) + (global-set-key (3 :release) #'set-freelook nil) + (global-set-motion #'freelook-move :x :y)) (defun game-start () (let ((f (file:load-file #P"../data/cube.lisp" :sync t :type 'character))) - (go:attach (go:make-object :mesh (with-input-from-string (s f) - (mesh:make-mesh (read s)))) (game:get-world-origin)))) + (attach (make-object :mesh (with-input-from-string (s f) + (mesh:make-mesh (read s)))) (get-world-origin)))) (defun initialize (&optional argv) "Initialize all the modules passing the optional argv" diff --git a/stoe.asd b/stoe.asd index 3a6db23..340880e 100644 --- a/stoe.asd +++ b/stoe.asd @@ -49,11 +49,11 @@ :depends-on ("thread" "containers" "utils")) (:file "file" :depends-on ("jobs")) - (:module "game" - :components - ((:file "game-object") - (:file "input") - (:file "game"))) + (:file "scene") + (:file "object") + (:file "camera") + (:file "input") + (:file "game") (:module "render" :components ((:file "gl-utils")