diff --git a/core/Camera.h b/core/Camera.h index 31d81e1..a320b94 100644 --- a/core/Camera.h +++ b/core/Camera.h @@ -1,11 +1,35 @@ +/** + @file + @author Dane Johnson + + @section LICENSE + + Couch Copyright (C) 2021 Dane Johnson + + This program comes with ABSOLUTELY NO WARRANTY; without event the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for details at + https://www.gnu.org/licenses/gpl-3.0.html + + This is free software, and you are welcome to redistribute it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + @section DESCRIPTION + + This file defines the cameras that can be used to render the scene +*/ #ifndef CAMERA_H #define CAMERA_H -#include "Transform.h" +#include "Spatial.h" -class Camera { +/** + The common 3D camera + */ +class Camera : public Spatial { public: - Transform transform; Camera(); void MakeCurrent(); static Camera *GetCurrentCamera(); diff --git a/core/Node.cpp b/core/Node.cpp index 2dbbdb9..f40ec0b 100644 --- a/core/Node.cpp +++ b/core/Node.cpp @@ -1,8 +1,7 @@ -/** - @file - @author Dane Johnson +/* + Dane Johnson - @section LICENSE + LICENSE Couch Copyright (C) 2021 Dane Johnson @@ -16,7 +15,7 @@ by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - @section DESCRIPTION + DESCRIPTION Node is the parent class for all classes that would be in the scene tree. The root of the scene tree is always a node. diff --git a/core/Rigidbody.cpp b/core/Rigidbody.cpp index 8b707d9..16ac284 100644 --- a/core/Rigidbody.cpp +++ b/core/Rigidbody.cpp @@ -56,23 +56,26 @@ RigidbodyMotionState::RigidbodyMotionState(Rigidbody *rigidbody) { } void RigidbodyMotionState::getWorldTransform(btTransform &worldTrans) const { + Transform transform = rigidbody->GetTransform(); worldTrans.setOrigin(btVector3( - rigidbody->transform.position.x, - rigidbody->transform.position.y, - rigidbody->transform.position.z)); + transform.position.x, + transform.position.y, + transform.position.z)); btQuaternion quat; - quat.setEuler(rigidbody->transform.rotation.z, - rigidbody->transform.rotation.y, - rigidbody->transform.rotation.x); + quat.setEuler(transform.rotation.z, + transform.rotation.y, + transform.rotation.x); worldTrans.setRotation(quat); } void RigidbodyMotionState::setWorldTransform(const btTransform &worldTrans) { - rigidbody->transform.position = Vector3(worldTrans.getOrigin().getX(), + Transform transform = rigidbody->GetTransform(); + transform.position = Vector3(worldTrans.getOrigin().getX(), worldTrans.getOrigin().getY(), worldTrans.getOrigin().getZ()); - worldTrans.getRotation().getEulerZYX(rigidbody->transform.rotation.z, - rigidbody->transform.rotation.y, - rigidbody->transform.rotation.x); + worldTrans.getRotation().getEulerZYX(transform.rotation.z, + transform.rotation.y, + transform.rotation.x); + rigidbody->SetTransform(transform); } diff --git a/core/Spatial.cpp b/core/Spatial.cpp index 81b0c67..1b44eef 100644 --- a/core/Spatial.cpp +++ b/core/Spatial.cpp @@ -1,11 +1,71 @@ +/* + Dane Johnson + + LICENSE + + Couch Copyright (C) 2021 Dane Johnson + + This program comes with ABSOLUTELY NO WARRANTY; without event the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for details at + https://www.gnu.org/licenses/gpl-3.0.html + + This is free software, and you are welcome to redistribute it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + DESCRIPTION + + A spatial is a node with a transform property, i.e. position, scale or rotation. + They can be instanced on the scene tree as an anchor for some other nodes. +*/ #include "Spatial.h" Name Spatial::GetType() const {return "Spatial";} +Transform Spatial::GetTransform() { + return transform; +} + +void Spatial::SetTransform(Transform transform) { + this->transform = transform; +} + Spatial *Spatial::Create() { return new Spatial; } +void Spatial::Translate(Vector3 offset) { + Transform t = this->GetTransform(); + t.position += offset; + this->SetTransform(t); +} + +void Spatial::RotateX(cfloat phi) { + Transform t = this->GetTransform(); + t.rotation.x += phi; + this->SetTransform(t); +} + +void Spatial::RotateY(cfloat phi) { + Transform t = this->GetTransform(); + t.rotation.y += phi; + this->SetTransform(t); +} + +void Spatial::RotateZ(cfloat phi) { + Transform t = this->GetTransform(); + t.rotation.z += phi; + this->SetTransform(t); +} + +void Spatial::UniformScale(cfloat scale) { + Transform t = this->GetTransform(); + t.scale *= scale; + this->SetTransform(t); +} + Spatial *Spatial::Duplicate() { Spatial *spatial = static_cast(Node::Duplicate()); spatial->transform = transform; diff --git a/core/Spatial.h b/core/Spatial.h index 20f9c95..cd47382 100644 --- a/core/Spatial.h +++ b/core/Spatial.h @@ -1,17 +1,83 @@ +/** + @file + @author Dane Johnson + + @section LICENSE + + Couch Copyright (C) 2021 Dane Johnson + + This program comes with ABSOLUTELY NO WARRANTY; without event the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for details at + https://www.gnu.org/licenses/gpl-3.0.html + + This is free software, and you are welcome to redistribute it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + @section DESCRIPTION + + A spatial is a node with a transform property, i.e. position, scale or rotation. + They can be instanced on the scene tree as an anchor for some other nodes. +*/ #ifndef SPATIAL_H #define SPATIAL_H +#include "types.h" #include "Node.h" #include "Transform.h" +/** + Spatial nodes have a transform property. They can be subclassed or instanced + as an anchor for their children. + */ class Spatial : public Node { public: - Transform transform; - virtual bool IsTransformable() const { return true;} virtual Name GetType() const; + + /** + Gets the transform property of this spatial + @return The transform + */ + Transform GetTransform(); + /** + Sets the transform property of this spatial. + @param transform The transform property + */ + void SetTransform(Transform transform); + + /** + Directly translates the spatial by offset + @param offset The offset of the transform operation + */ + void Translate(Vector3 offset); + /** + Rotates the Camera phi radians about the X axis + @param phi The amount to rotate in radians + */ + void RotateX(cfloat phi); + /** + Rotates the Camera phi radians about the Y axis + @param phi The amount to rotate in radians + */ + void RotateY(cfloat phi); + /** + Rotates the Camera phi radians about the Z axis + @param phi The amount to rotate in radians + */ + void RotateZ(cfloat phi); + /** + Scales the spatial by scale uniformly + @param scale The amount to scale by. + */ + void UniformScale(cfloat scale); + virtual Spatial *Create(); virtual Spatial *Duplicate(); virtual Spatial *Instance(); +private: + Transform transform; }; #endif /* SPATIAL_H */ diff --git a/core/Transform.cpp b/core/Transform.cpp index 0ba97eb..c6709a3 100644 --- a/core/Transform.cpp +++ b/core/Transform.cpp @@ -1,4 +1,26 @@ +/* + Dane Johnson + + LICENSE + + Couch Copyright (C) 2021 Dane Johnson + + This program comes with ABSOLUTELY NO WARRANTY; without event the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for details at + https://www.gnu.org/licenses/gpl-3.0.html + + This is free software, and you are welcome to redistribute it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + DESCRIPTION + + A transform represents various aspects of 3d space. +*/ #include "Transform.h" +#include Transform::Transform() { position = Vector3(0.0f); @@ -19,21 +41,6 @@ Transform::Transform(Vector3 position, Vector3 rotation, Vector3 scale) { } -void Transform::Translate(cfloat x, cfloat y, cfloat z) { - position = position + Vector3(x, y, z); -} - - -Matrix Transform::RotationMatrix() { - Matrix mat(1.0f); - - mat = glm::rotate(mat, this->rotation.z, Vector3(0.0f, 0.0f, 1.0f)); - mat = glm::rotate(mat, this->rotation.y, Vector3(0.0f, 1.0f, 0.0f)); - mat = glm::rotate(mat, this->rotation.x, Vector3(1.0f, 0.0f, 0.0f)); - - return mat; -} - Vector3 Transform::Forward() { return glm::vec3(RotationMatrix() * glm::vec4(0.0f, 0.0f, -1.0f, 1.0f)); } @@ -45,3 +52,13 @@ Vector3 Transform::Up() { Vector3 Transform::Right() { return glm::vec3(RotationMatrix() * glm::vec4(1.0f, 0.0f, 0.0f, 1.0f)); } + +Matrix Transform::RotationMatrix() { + Matrix mat(1.0f); + + mat = glm::rotate(mat, this->rotation.z, Vector3(0.0f, 0.0f, 1.0f)); + mat = glm::rotate(mat, this->rotation.y, Vector3(0.0f, 1.0f, 0.0f)); + mat = glm::rotate(mat, this->rotation.x, Vector3(1.0f, 0.0f, 0.0f)); + + return mat; +} diff --git a/core/Transform.h b/core/Transform.h index cb7d804..3fa79e7 100644 --- a/core/Transform.h +++ b/core/Transform.h @@ -1,21 +1,65 @@ +/** + @file + @author Dane Johnson + + @section LICENSE + + Couch Copyright (C) 2021 Dane Johnson + + This program comes with ABSOLUTELY NO WARRANTY; without event the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for details at + https://www.gnu.org/licenses/gpl-3.0.html + + This is free software, and you are welcome to redistribute it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + @section DESCRIPTION + + A transform represents various aspects of 3d space. +*/ #ifndef TRANSFORM_H #define TRANSFORM_H -#include - #include "types.h" +/** + A Transform represents a position, rotation, and scale in 3D space. +*/ struct Transform { Transform(); Transform(Vector3 position, Vector3 rotation); Transform(Vector3 position, Vector3 rotation, Vector3 scale); + /** + The position, according to the left-hand rule + */ Vector3 position; + /** + The rotation, in Euler angles + */ Vector3 rotation; + /** + Scaling along the specified axis + */ Vector3 scale; - void Translate(cfloat x, cfloat y, cfloat z); + /** + Returns a vector that is -Z, rotated by @ref rotation. + */ Vector3 Forward(); + /** + Returns a vector that is +X, rotated by @ref rotation. + */ Vector3 Right(); + /** + Returns a vector that is +Y, rotated by @ref rotation. + */ Vector3 Up(); + /** + Returns a matrix that, when multiplied by a @ref Vector3 + gives a Vector rotated by @ref rotation + */ Matrix RotationMatrix(); }; diff --git a/core/couch.cpp b/core/couch.cpp index 2db11e5..716b652 100644 --- a/core/couch.cpp +++ b/core/couch.cpp @@ -43,11 +43,12 @@ Node *root; void render(Node *curr, Shader *shader, Matrix model) { Spatial *spatial = dynamic_cast(curr); if (spatial) { - model = glm::rotate(model, spatial->transform.rotation.x, Vector3(1.0f, 0.0f, 0.0f)); - model = glm::rotate(model, spatial->transform.rotation.y, Vector3(0.0f, 1.0f, 0.0f)); - model = glm::rotate(model, spatial->transform.rotation.z, Vector3(0.0f, 0.0f, 1.0f)); - model = glm::translate(model, spatial->transform.position); - model = glm::scale(model, spatial->transform.scale); + Transform transform = spatial->GetTransform(); + model = glm::rotate(model, transform.rotation.x, Vector3(1.0f, 0.0f, 0.0f)); + model = glm::rotate(model, transform.rotation.y, Vector3(0.0f, 1.0f, 0.0f)); + model = glm::rotate(model, transform.rotation.z, Vector3(0.0f, 0.0f, 1.0f)); + model = glm::translate(model, transform.position); + model = glm::scale(model, transform.scale); shader->UpdateModel(model); shader->UpdateNormal(glm::mat3(glm::transpose(glm::inverse(model)))); } @@ -126,10 +127,11 @@ int main() { shader->UpdateProjection(projection); Matrix view(1.0f); Camera *camera = Camera::GetCurrentCamera(); - view = glm::rotate(view, -camera->transform.rotation.x, Vector3(1.0f, 0.0f, 0.0f)); - view = glm::rotate(view, -camera->transform.rotation.y, Vector3(0.0f, 1.0f, 0.0f)); - view = glm::rotate(view, -camera->transform.rotation.z, Vector3(0.0f, 0.0f, 1.0f)); - view = glm::translate(view, -camera->transform.position); + Transform camera_transform = camera->GetTransform(); + view = glm::rotate(view, -camera_transform.rotation.x, Vector3(1.0f, 0.0f, 0.0f)); + view = glm::rotate(view, -camera_transform.rotation.y, Vector3(0.0f, 1.0f, 0.0f)); + view = glm::rotate(view, -camera_transform.rotation.z, Vector3(0.0f, 0.0f, 1.0f)); + view = glm::translate(view, -camera_transform.position); shader->UpdateView(view); // Find the lights diff --git a/demo/main.lua b/demo/main.lua index dc01f5a..2742e51 100644 --- a/demo/main.lua +++ b/demo/main.lua @@ -27,10 +27,11 @@ local light function init() local material + local transform camera = couch.Camera() camera:MakeCurrent() - camera.transform:Translate(0.0, 0.0, 10.0) + camera:Translate(couch.Vector3(0.0, 0.0, 10.0)) local light = couch.DirectionalLight() light.direction = couch.Vector3(0.0, -1.0, -1.0) @@ -38,7 +39,6 @@ function init() light.ambient = 0.2 light.diffuse = 1.0 light.specular = 0.1 - print(couch.Node.GetRoot().GetChildren) couch.Node.GetRoot():AddChild(light:Instance()) local skybox = couch.Skybox.FromFiles( @@ -58,7 +58,7 @@ function init() material.diffuse = BLUE physics_ball_mesh:SetMaterial(0, material) physics_ball_prefab:AddChild(physics_ball_mesh); - physics_ball_prefab.transform.position = couch.Vector3(0.0, 30.0, -10.0) + physics_ball_prefab:Translate(couch.Vector3(0.0, 30.0, -10.0)) physics_ball = physics_ball_prefab:Instance() couch.Node.GetRoot():AddChild(physics_ball) @@ -75,7 +75,7 @@ function init() character_body:SetCollisionShape(couch.CapsuleCollisionShape(1.0, 1.0)) character_body:SetCharacter(true) character_body:AddChild(character_prefab) - character_body.transform.position = couch.Vector3(0.0, 3.0, 0.0) + character_body:Translate(couch.Vector3(0.0, 3.0, 0.0)) character = character_body:Instance() couch.Node.GetRoot():AddChild(character) @@ -85,8 +85,8 @@ function init() material.diffuse = RED cube_prefab:SetMaterial(0, material) local orbiter = couch.Mesh.FromFile("ball.obj") - orbiter.transform.scale = orbiter.transform.scale * 0.25; - orbiter.transform:Translate(1.0, 0.0, 0.0) + orbiter:UniformScale(0.25); + orbiter:Translate(couch.Vector3(1.0, 0.0, 0.0)) cube_prefab:AddChild(orbiter) cube = cube_prefab:Instance() couch.Node.GetRoot():AddChild(cube) @@ -97,12 +97,12 @@ function init() ball = ball_prefab:Instance() couch.Node.GetRoot():AddChild(ball) - ball.transform:Translate(0.0, 3.0, 0.0) + ball:Translate(couch.Vector3(0.0, 3.0, 0.0)) local trough_prefab = couch.TexturedMesh("trough.obj", "wood_lowres.png") trough = trough_prefab:Instance() couch.Node.GetRoot():AddChild(trough) - trough.transform:Translate(10.0, 0.0, 0.0) + trough:Translate(couch.Vector3(10.0, 0.0, 0.0)) local scaffold_prefab = couch.TexturedMesh("scaffold.obj", "grate_floor_lowres.png", "railing.png") local scaffold = scaffold_prefab:Instance() @@ -116,7 +116,7 @@ function init() material.alphaScissor = 0.1 scaffold:SetMaterial(1, material) couch.Node.GetRoot():AddChild(scaffold) - scaffold.transform:Translate(-3.0, 3.0, 0.0) + scaffold:Translate(couch.Vector3(-3.0, 3.0, 0.0)) local barn_prefab = couch.TexturedMesh("barn.obj", "paintedwood.jpg", "barnroof_lowres.png", "wood_lowres.png") local barn = barn_prefab:Instance() @@ -127,35 +127,37 @@ function init() material.cullBack = false barn:SetMaterial(1, material) couch.Node.GetRoot():AddChild(barn) - barn.transform:Translate(-15.0, 0.0, 0.0) + barn:Translate(couch.Vector3(-15.0, 0.0, 0.0)) end function update(delta) local move_vec = couch.Vector3() - move_vec = camera.transform.position + camera.transform:Forward() * delta * vz * SPEED - move_vec = move_vec + camera.transform:Right() * delta * vx * SPEED - move_vec = move_vec + camera.transform:Up() * delta * vy * SPEED - camera.transform.position = move_vec + local camera_transform = camera:GetTransform() + move_vec = camera_transform.position + camera_transform:Forward() * delta * vz * SPEED + move_vec = move_vec + camera_transform:Right() * delta * vx * SPEED + move_vec = move_vec + camera_transform:Up() * delta * vy * SPEED + camera_transform.position = move_vec - camera.transform.rotation.y = camera.transform.rotation.y - cam_rot_x * delta + camera_transform.rotation.y = camera_transform.rotation.y - cam_rot_x * delta cam_rot_x = 0.0 - camera.transform.rotation.x = camera.transform.rotation.x - cam_rot_y * delta - camera.transform.rotation.x = min(max(camera.transform.rotation.x, -3.14 / 2.0), 3.14 / 2.0) + camera_transform.rotation.x = camera_transform.rotation.x - cam_rot_y * delta + camera_transform.rotation.x = min(max(camera_transform.rotation.x, -3.14 / 2.0), 3.14 / 2.0) cam_rot_y = 0.0 - local loc = ball.transform.position + camera:SetTransform(camera_transform) + + local loc = ball:GetTransform().position if loc.y > 4.0 then ballvy = -1.0 elseif loc.y < 2.0 then ballvy = 1.0 end - ball.transform.position.y = ball.transform.position.y + ballvy * delta + ball:Translate(couch.Vector3(ballvy * delta, 0.0, 0.0)) - cube.transform.rotation.y = cube.transform.rotation.y + 2.0 * delta; - cube.transform.rotation.z = cube.transform.rotation.z + 1.0 * delta; + cube:RotateY(2.0 * delta) + cube:RotateZ(1.0 * delta) character:ApplyForce(character_move_vec * 10.0) - print(character_move_vec.z) end function action_dir(key, action, pos, neg, curr) @@ -189,8 +191,11 @@ end function make_ground() local ground_prefab = couch.TexturedMesh("ground.obj", "grass_lowres.png") - ground_prefab.transform.position = couch.Vector3(0.0, -2.0, 0.0) - ground_prefab.transform.scale = couch.Vector3(3.0, 1.0, 3.0) + + local ground_prefab_transform = ground_prefab:GetTransform() + ground_prefab_transform.position = couch.Vector3(0.0, -2.0, 0.0) + ground_prefab_transform.scale = couch.Vector3(3.0, 1.0, 3.0) + ground_prefab:SetTransform(ground_prefab_transform) ground = couch.Spatial():Instance() couch.Node.GetRoot():AddChild(ground) @@ -199,13 +204,13 @@ function make_ground() local ground_shape_prefab = couch.Rigidbody() ground_shape_prefab.mass = 0.0 ground_shape_prefab:SetCollisionShape(couch.BoxCollisionShape(180.0, 1.0, 180.0)) - ground_shape_prefab.transform:Translate(0.0, -2.5, 0.0) + ground_shape_prefab:Translate(couch.Vector3(0.0, -2.5, 0.0)) ground:AddChild(ground_shape_prefab:Instance()) for x = -20, 20, 1 do for z = -20, 20, 1 do local piece = ground_prefab:Instance() - piece.transform.position = couch.Vector3(6.0 * x, -2.0, 6.0 * z) + piece:Translate(couch.Vector3(6.0 * x, -2.0, 6.0 * z)) ground:AddChild(piece) end end