From d51528dd0f80eafdc218f741a7415c59f47a281a Mon Sep 17 00:00:00 2001 From: Dane Johnson Date: Sun, 24 Jan 2021 16:37:35 -0600 Subject: [PATCH] Add instancing system --- core/Camera.h | 5 +++-- core/Light.cpp | 33 +++++++++++++++++++++++++++ core/Light.h | 6 +++++ core/Mesh.cpp | 29 ++++++++++++++++++++++-- core/Mesh.h | 5 ++++- core/Node.cpp | 32 +++++++++++++++++++++++++- core/Node.h | 10 ++++++++- core/Skybox.cpp | 16 +++++++++++++ core/Skybox.h | 3 +++ core/Spatial.cpp | 16 +++++++++++++ core/Spatial.h | 3 +++ core/Util.h | 1 + demo/main.lua | 57 +++++++++++++++++++++++++---------------------- roadmap.md | 1 + scripting/couch.i | 14 ------------ 15 files changed, 183 insertions(+), 48 deletions(-) diff --git a/core/Camera.h b/core/Camera.h index aff6f1e..31d81e1 100644 --- a/core/Camera.h +++ b/core/Camera.h @@ -1,10 +1,11 @@ #ifndef CAMERA_H #define CAMERA_H -#include "Spatial.h" +#include "Transform.h" -class Camera : public Spatial { +class Camera { public: + Transform transform; Camera(); void MakeCurrent(); static Camera *GetCurrentCamera(); diff --git a/core/Light.cpp b/core/Light.cpp index 39f7e56..c97e608 100644 --- a/core/Light.cpp +++ b/core/Light.cpp @@ -2,6 +2,24 @@ Name Light::GetType() const {return "Light";} +Light *Light::Duplicate() { + Light *light = static_cast(Spatial::Duplicate()); + light->color = color; + light->ambient = ambient; + light->diffuse = diffuse; + light->specular = specular; + + return light; +} + +Light *Light::Instance() { + return static_cast(Node::Instance()); +} + +Light *Light::Create() { + return new Light; +} + Name DirectionalLight::GetType() const {return "DirectionalLight";} DirectionalLight::DirectionalLight() { @@ -19,3 +37,18 @@ DirectionalLight::DirectionalLight(Vector3 direction, Vector3 color, cfloat ambi this->diffuse = diffuse; this->specular = specular; } + +DirectionalLight *DirectionalLight::Create() { + return new DirectionalLight; +} + +DirectionalLight *DirectionalLight::Duplicate() { + DirectionalLight *directionalLight = static_cast(Light::Duplicate()); + directionalLight->direction = direction; + + return directionalLight; +} + +DirectionalLight *DirectionalLight::Instance() { + return static_cast(Node::Instance()); +} diff --git a/core/Light.h b/core/Light.h index 8a9be98..790199e 100644 --- a/core/Light.h +++ b/core/Light.h @@ -9,6 +9,9 @@ public: Vector3 color; cfloat ambient, diffuse, specular; virtual Name GetType() const; + virtual Light *Create(); + virtual Light *Duplicate(); + virtual Light *Instance(); }; class DirectionalLight : public Light { @@ -17,6 +20,9 @@ public: DirectionalLight(); DirectionalLight(Vector3 direction, Vector3 color, cfloat ambient, cfloat diffuse, cfloat specular); virtual Name GetType() const; + virtual DirectionalLight *Create(); + virtual DirectionalLight *Duplicate(); + virtual DirectionalLight *Instance(); }; #endif /* LIGHT_H */ diff --git a/core/Mesh.cpp b/core/Mesh.cpp index 910e418..a3b7138 100644 --- a/core/Mesh.cpp +++ b/core/Mesh.cpp @@ -41,6 +41,16 @@ void SubMesh::Draw(Shader *shader) { glBindVertexArray(0); } +SubMesh *SubMesh::Duplicate() { + SubMesh* submesh = new SubMesh(); + + submesh->VAO = VAO; + submesh->indices = indices; + submesh->material = material; + + return submesh; +} + Name Mesh::GetType() const {return "Mesh";} Mesh::Mesh() {} @@ -51,9 +61,24 @@ Mesh::~Mesh() { } } +Mesh *Mesh::Create() { + return new Mesh; +} + Mesh *Mesh::Duplicate() { - Mesh *dup = new Mesh(*this); - return dup; + Mesh *mesh = static_cast(Spatial::Duplicate()); + // Duplicate submeshes + mesh->submeshes = SubMeshList(); + + for (SubMesh *submesh : submeshes) { + mesh->submeshes.push_back(submesh->Duplicate()); + } + + return mesh; +} + +Mesh *Mesh::Instance() { + return static_cast(Node::Instance()); } void Mesh::SetupMesh() { diff --git a/core/Mesh.h b/core/Mesh.h index a4062ea..a355abe 100644 --- a/core/Mesh.h +++ b/core/Mesh.h @@ -26,6 +26,7 @@ public: IndexList indices; Material material; void Draw(Shader *shader); + SubMesh *Duplicate(); private: Id VAO, VBO, EBO; void SetupSubMesh(); @@ -44,7 +45,9 @@ public: virtual bool IsDrawable() const {return true;} virtual void Draw(Shader *shader); virtual Name GetType() const; - Mesh *Duplicate(); + virtual Mesh *Create(); + virtual Mesh *Duplicate(); + virtual Mesh *Instance(); protected: SubMeshList submeshes; virtual void SetupMesh(); diff --git a/core/Node.cpp b/core/Node.cpp index c8a5f40..263cb6c 100644 --- a/core/Node.cpp +++ b/core/Node.cpp @@ -1,8 +1,9 @@ #include "Node.h" +#include "Util.h" Name Node::GetType() const {return "Node";} -Node *Node::root = {new Node()}; +Node *Node::root = {Node().Instance()}; Node *Node::GetRoot() { return root; } @@ -13,6 +14,35 @@ bool Node::IsTransformable() const { return false; } +Node* Node::Create() { + return new Node; +} + +Node* Node::Duplicate() { + return Create(); +} + +Node* Node::Instance() { + if (not this->isPrefab) { + Util::Die("Attempt to instance an instanced node!"); + } + Node* instance = Duplicate(); + instance->isPrefab = false; + instance->children = NodeList(); + instance->children.isPrefabList = false; + for (Node *child : children) { + instance->children.Append(child->Instance()); + } + + return instance; +} + void NodeList::Append(Node *node) { + if (this->isPrefabList and not node->isPrefab) { + Util::Die("Attempt to add instanced node to prefab list!"); + } + if (node->isPrefab and not this->isPrefabList) { + Util::Die("Attempt to add prefab node to instanced list!"); + } push_back(node); } diff --git a/core/Node.h b/core/Node.h index 5a4364e..ad6b4b9 100644 --- a/core/Node.h +++ b/core/Node.h @@ -9,6 +9,9 @@ class Node; // Forwards declare class NodeList : public std::vector { public: void Append(Node *node); +private: + bool isPrefabList = true; + friend class Node; }; class Node { @@ -16,11 +19,16 @@ public: NodeList children; static Node *GetRoot(); virtual bool IsDrawable() const; - virtual void Draw(){}; + virtual void Draw() {}; virtual bool IsTransformable() const; virtual Name GetType() const; + virtual Node* Create(); + virtual Node* Instance(); + virtual Node* Duplicate(); private: static Node *root; + bool isPrefab = true; + friend class NodeList; }; #endif /* NODE_H */ diff --git a/core/Skybox.cpp b/core/Skybox.cpp index 10edf16..6a80d74 100644 --- a/core/Skybox.cpp +++ b/core/Skybox.cpp @@ -63,6 +63,22 @@ Skybox::Skybox() { Name Skybox::GetType() const { return "Skybox"; } +Skybox *Skybox::Create() { + return new Skybox; +} + +Skybox *Skybox::Duplicate() { + Skybox* skybox = static_cast(Node::Duplicate()); + skybox->id = id; + skybox->cube = cube; + + return skybox; +} + +Skybox *Skybox::Instance() { + return static_cast(Node::Instance()); +} + Skybox *Skybox::FromFiles(const char *right, const char* left, const char* top, const char* bottom, const char* front, const char* back) { // HOCUS: https://learnopengl.com/Advanced-OpenGL/Cubemaps Skybox *sb = new Skybox(); diff --git a/core/Skybox.h b/core/Skybox.h index 89f4ae4..a8e5033 100644 --- a/core/Skybox.h +++ b/core/Skybox.h @@ -11,6 +11,9 @@ class Skybox : public Node { public: Skybox(); virtual Name GetType() const; + virtual Skybox *Create(); + virtual Skybox *Duplicate(); + virtual Skybox *Instance(); static Skybox *FromFiles(const char *right, const char* left, const char* top, const char* bottom, const char* front, const char* back); void DrawSkybox(); Id id; diff --git a/core/Spatial.cpp b/core/Spatial.cpp index ac8ddae..81b0c67 100644 --- a/core/Spatial.cpp +++ b/core/Spatial.cpp @@ -1,3 +1,19 @@ #include "Spatial.h" Name Spatial::GetType() const {return "Spatial";} + +Spatial *Spatial::Create() { + return new Spatial; +} + +Spatial *Spatial::Duplicate() { + Spatial *spatial = static_cast(Node::Duplicate()); + spatial->transform = transform; + + return spatial; +} + +Spatial *Spatial::Instance() { + return static_cast(Node::Instance()); +} + diff --git a/core/Spatial.h b/core/Spatial.h index 49766fa..20f9c95 100644 --- a/core/Spatial.h +++ b/core/Spatial.h @@ -9,6 +9,9 @@ public: Transform transform; virtual bool IsTransformable() const { return true;} virtual Name GetType() const; + virtual Spatial *Create(); + virtual Spatial *Duplicate(); + virtual Spatial *Instance(); }; #endif /* SPATIAL_H */ diff --git a/core/Util.h b/core/Util.h index 6774ce2..9335e61 100644 --- a/core/Util.h +++ b/core/Util.h @@ -6,6 +6,7 @@ #include #include "types.h" +class Node; #include "Node.h" namespace Util { diff --git a/demo/main.lua b/demo/main.lua index 892fe1f..2d487b7 100644 --- a/demo/main.lua +++ b/demo/main.lua @@ -1,7 +1,7 @@ local min = math.min local max = math.max +local cube local ball -local ball1 local camera local vx = 0.0 @@ -28,15 +28,15 @@ function init() camera:MakeCurrent() camera.transform:Translate(0.0, 0.0, 10.0) - light = couch.DirectionalLight.new() + local light = couch.DirectionalLight() light.direction = couch.Vector3(0.0, -1.0, -1.0) light.color = couch.Vector3(1.0, 1.0, 1.0) light.ambient = 0.2 light.diffuse = 1.0 light.specular = 0.1 - couch.Node.GetRoot().children:Append(light) + couch.Node.GetRoot().children:Append(light:Instance()) - skybox = couch.Skybox.FromFiles( + local skybox = couch.Skybox.FromFiles( "skybox/px.png", "skybox/nx.png", "skybox/py.png", @@ -44,35 +44,37 @@ function init() "skybox/pz.png", "skybox/nz.png" ) - couch.Node.GetRoot().children:Append(skybox) + couch.Node.GetRoot().children:Append(skybox:Instance()) make_ground() - - ball = couch.Mesh.FromFile("cube.obj") - material = ball:GetMaterial(0) + + local cube_prefab = couch.Mesh.FromFile("cube.obj") + material = cube_prefab:GetMaterial(0) material.ambient = RED material.diffuse = RED - ball:SetMaterial(0, material) - couch.Node.GetRoot().children:Append(ball) + 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) - ball.children:Append(orbiter) + cube_prefab.children:Append(orbiter) + cube = cube_prefab:Instance() + couch.Node.GetRoot().children:Append(cube) - ball1 = couch.Mesh.FromFile("ball.obj") - - print(material.diffuse.b) - material = ball1:GetMaterial(0) - ball1:SetMaterial(0, material) - couch.Node.GetRoot().children:Append(ball1) + local ball_prefab = couch.Mesh.FromFile("ball.obj") + material = ball_prefab:GetMaterial(0) + ball_prefab:SetMaterial(0, material) + ball = ball_prefab:Instance() + couch.Node.GetRoot().children:Append(ball) - ball1.transform:Translate(0.0, 3.0, 0.0) + ball.transform:Translate(0.0, 3.0, 0.0) - trough = couch.TexturedMesh("trough.obj", "wood_lowres.png") + local trough_prefab = couch.TexturedMesh("trough.obj", "wood_lowres.png") + trough = trough_prefab:Instance() couch.Node.GetRoot().children:Append(trough) trough.transform:Translate(10.0, 0.0, 0.0) - scaffold = couch.TexturedMesh("scaffold.obj", "grate_floor_lowres.png", "railing.png") + local scaffold_prefab = couch.TexturedMesh("scaffold.obj", "grate_floor_lowres.png", "railing.png") + local scaffold = scaffold_prefab:Instance() material = scaffold:GetMaterial(0) material.alphaScissor = 0.9 scaffold:SetMaterial(0, material) @@ -85,7 +87,8 @@ function init() couch.Node.GetRoot().children:Append(scaffold) scaffold.transform:Translate(-3.0, 3.0, 0.0) - barn = couch.TexturedMesh("barn.obj", "paintedwood.jpg", "barnroof_lowres.png", "wood_lowres.png") + local barn_prefab = couch.TexturedMesh("barn.obj", "paintedwood.jpg", "barnroof_lowres.png", "wood_lowres.png") + local barn = barn_prefab:Instance() material = barn:GetMaterial(0) material.cullBack = false barn:SetMaterial(0, material) @@ -109,16 +112,16 @@ function update(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 = ball1.transform.position + local loc = ball.transform.position if loc.y > 4.0 then ballvy = -1.0 elseif loc.y < 2.0 then ballvy = 1.0 end - ball1.transform.position.y = ball1.transform.position.y + ballvy * delta + ball.transform.position.y = ball.transform.position.y + ballvy * delta - ball.transform.rotation.y = ball.transform.rotation.y + 2.0 * delta; - ball.transform.rotation.z = ball.transform.rotation.z + 1.0 * delta; + cube.transform.rotation.y = cube.transform.rotation.y + 2.0 * delta; + cube.transform.rotation.z = cube.transform.rotation.z + 1.0 * delta; end function action_dir(key, action, pos, neg, curr) @@ -155,12 +158,12 @@ function make_ground() 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 = couch.Spatial.new() + ground = couch.Spatial():Instance() couch.Node.GetRoot().children:Append(ground) for x = -20, 20, 1 do for z = -20, 20, 1 do - local piece = ground_prefab:Duplicate() + local piece = ground_prefab:Instance() piece.transform.position = couch.Vector3(6.0 * x, -2.0, 6.0 * z) ground.children:Append(piece) end diff --git a/roadmap.md b/roadmap.md index cc5eed3..600f69d 100644 --- a/roadmap.md +++ b/roadmap.md @@ -74,3 +74,4 @@ Yeah sure let's do physics - [ ] Static, Kinematic and Rigidbodies - [ ] Collision areas - [ ] Ray tracing +- [ ] Axis pinning diff --git a/scripting/couch.i b/scripting/couch.i index 8641095..79a43c0 100644 --- a/scripting/couch.i +++ b/scripting/couch.i @@ -18,8 +18,6 @@ #include "Skybox.h" %} -%rename("%(strip:[script_])s") ""; - typedef float cfloat; %ignore "cfloat"; @@ -40,18 +38,6 @@ public: } %ignore "Vector3"; -%extend Spatial { - static Spatial* script_new() { - return new Spatial(); - } -} - -%extend DirectionalLight { - static DirectionalLight* script_new() { - return new DirectionalLight(); - } -} - %include "types.h" %include "constants.h" %include "Node.h"