diff --git a/examples/objects/lod.cpp b/examples/objects/lod.cpp index e1f588566..b4906c0b3 100644 --- a/examples/objects/lod.cpp +++ b/examples/objects/lod.cpp @@ -16,17 +16,25 @@ int main() { OrbitControls controls{camera, canvas}; - LOD lod; - scene.add(lod); + LOD lod1; + scene.add(lod1); float radius = 0.5; auto material = MeshBasicMaterial::create({{"wireframe", true}}); for (int z = 0; z <= 5; z++) { int detail = 6 - z; auto obj = Mesh::create(IcosahedronGeometry::create(radius, detail), material); - lod.addLevel(obj, static_cast(z)); + lod1.addLevel(obj, static_cast(z)); } + LOD lod2; + lod2.copy(lod1); + scene.add(lod2); + + float spacing = 1; + lod1.position.x = spacing; + lod2.position.x = -spacing; + canvas.onWindowResize([&](WindowSize size) { camera.aspect = size.aspect(); camera.updateProjectionMatrix(); @@ -38,12 +46,18 @@ int main() { const auto font = *fontLoader.load("data/fonts/gentilis_bold.typeface.json"); TextGeometry::Options opts(font, 20, 5); - auto handle = Text2D(opts, ""); - handle.setColor(Color::gray); - hud.add(handle); + + Text2D handle1(opts); + handle1.setColor(Color::gray); + hud.add(handle1, HUD::Options().setNormalizedPosition({0.f, 0.05f})); + + Text2D handle2(opts); + handle2.setColor(Color::gray); + hud.add(handle2); canvas.animate([&]() { - handle.setText("LOD level: " + std::to_string(lod.getCurrentLevel()), opts); + handle1.setText("LOD1 level: " + std::to_string(lod1.getCurrentLevel())); + handle2.setText("LOD2 level: " + std::to_string(lod2.getCurrentLevel())); renderer.clear(); renderer.render(scene, camera); diff --git a/include/threepp/core/Object3D.hpp b/include/threepp/core/Object3D.hpp index 93deb6357..708c47f4f 100644 --- a/include/threepp/core/Object3D.hpp +++ b/include/threepp/core/Object3D.hpp @@ -240,18 +240,40 @@ namespace threepp { return dynamic_cast(this); } + template + const T* as() const { + + static_assert(std::is_base_of::type>::type>::value, + "T must be a base class of Object3D"); + + return dynamic_cast(this); + } + template [[nodiscard]] bool is() const { return dynamic_cast(this) != nullptr; } - void copy(const Object3D& source, bool recursive = true); + virtual void copy(const Object3D& source, bool recursive = true); - virtual std::shared_ptr clone(bool recursive = true); + template + std::shared_ptr clone(bool recursive = true) { + + auto clone = createDefault(); + clone->copy(*this, recursive); + + return std::dynamic_pointer_cast(clone); + } ~Object3D() override; + protected: + virtual std::shared_ptr createDefault() { + + return std::make_shared(); + } + private: inline static unsigned int _object3Did{0}; diff --git a/include/threepp/objects/Bone.hpp b/include/threepp/objects/Bone.hpp index 76b2aa414..804566d41 100644 --- a/include/threepp/objects/Bone.hpp +++ b/include/threepp/objects/Bone.hpp @@ -18,6 +18,12 @@ namespace threepp { return std::make_shared(); } + + protected: + std::shared_ptr createDefault() override { + + return create(); + } }; }// namespace threepp diff --git a/include/threepp/objects/Group.hpp b/include/threepp/objects/Group.hpp index 82da30f25..eb6172165 100644 --- a/include/threepp/objects/Group.hpp +++ b/include/threepp/objects/Group.hpp @@ -12,11 +12,12 @@ namespace threepp { public: [[nodiscard]] std::string type() const override; - std::shared_ptr clone(bool recursive = true) override; - static std::shared_ptr create(); ~Group() override = default; + + protected: + std::shared_ptr createDefault() override; }; }// namespace threepp diff --git a/include/threepp/objects/LOD.hpp b/include/threepp/objects/LOD.hpp index 6377198f9..8546016d7 100644 --- a/include/threepp/objects/LOD.hpp +++ b/include/threepp/objects/LOD.hpp @@ -35,8 +35,13 @@ namespace threepp { void update(Camera& camera); + void copy(const Object3D& source, bool recursive = false) override; + static std::shared_ptr create(); + protected: + std::shared_ptr createDefault() override; + private: size_t _currentLevel = 0; std::vector levels; diff --git a/include/threepp/objects/Line.hpp b/include/threepp/objects/Line.hpp index cb99da1a8..cbaf2ac3b 100644 --- a/include/threepp/objects/Line.hpp +++ b/include/threepp/objects/Line.hpp @@ -27,14 +27,16 @@ namespace threepp { virtual void computeLineDistances(); - void raycast(const Raycaster& raycaster, std::vector& intersects) override; + void copy(const Object3D& source, bool recursive = true) override; - std::shared_ptr clone(bool recursive = true) override; + void raycast(const Raycaster& raycaster, std::vector& intersects) override; static std::shared_ptr create(const std::shared_ptr& geometry = nullptr, const std::shared_ptr& material = nullptr); protected: std::shared_ptr geometry_; + + std::shared_ptr createDefault() override; }; }// namespace threepp diff --git a/include/threepp/objects/LineLoop.hpp b/include/threepp/objects/LineLoop.hpp index 911006c1c..03ed08a87 100644 --- a/include/threepp/objects/LineLoop.hpp +++ b/include/threepp/objects/LineLoop.hpp @@ -14,8 +14,6 @@ namespace threepp { [[nodiscard]] std::string type() const override; - std::shared_ptr clone(bool recursive = true) override; - static std::shared_ptr create( const std::shared_ptr& geometry = nullptr, const std::shared_ptr& material = nullptr); diff --git a/include/threepp/objects/LineSegments.hpp b/include/threepp/objects/LineSegments.hpp index 910816905..a5342c33f 100644 --- a/include/threepp/objects/LineSegments.hpp +++ b/include/threepp/objects/LineSegments.hpp @@ -18,8 +18,6 @@ namespace threepp { void computeLineDistances() override; - std::shared_ptr clone(bool recursive = true) override; - static std::shared_ptr create( const std::shared_ptr& geometry = nullptr, const std::shared_ptr& material = nullptr); diff --git a/include/threepp/objects/Mesh.hpp b/include/threepp/objects/Mesh.hpp index 48075fb57..e6a3b669b 100644 --- a/include/threepp/objects/Mesh.hpp +++ b/include/threepp/objects/Mesh.hpp @@ -29,7 +29,7 @@ namespace threepp { void raycast(const Raycaster& raycaster, std::vector& intersects) override; - std::shared_ptr clone(bool recursive = true) override; + void copy(const Object3D& source, bool recursive = true) override; static std::shared_ptr create( std::shared_ptr geometry = nullptr, @@ -43,6 +43,8 @@ namespace threepp { protected: std::shared_ptr geometry_; + + std::shared_ptr createDefault() override; }; }// namespace threepp diff --git a/include/threepp/objects/Points.hpp b/include/threepp/objects/Points.hpp index 8f14ea050..106a82c8a 100644 --- a/include/threepp/objects/Points.hpp +++ b/include/threepp/objects/Points.hpp @@ -22,16 +22,18 @@ namespace threepp { void setGeometry(const std::shared_ptr& geometry); - std::shared_ptr clone(bool recursive = true) override; - void raycast(const Raycaster& raycaster, std::vector& intersects) override; + void copy(const Object3D& source, bool recursive = true) override; + static std::shared_ptr create( std::shared_ptr geometry = BufferGeometry::create(), std::shared_ptr material = PointsMaterial::create()); protected: std::shared_ptr geometry_; + + std::shared_ptr createDefault() override; }; }// namespace threepp diff --git a/include/threepp/objects/Sprite.hpp b/include/threepp/objects/Sprite.hpp index 7379ada72..b016848bd 100644 --- a/include/threepp/objects/Sprite.hpp +++ b/include/threepp/objects/Sprite.hpp @@ -26,8 +26,13 @@ namespace threepp { void setMaterial(const std::shared_ptr& material); + void copy(const Object3D& source, bool recursive = true) override; + static std::shared_ptr create(const std::shared_ptr& material = nullptr); + protected: + std::shared_ptr createDefault() override; + private: std::shared_ptr _geometry; std::shared_ptr _material; diff --git a/src/threepp/core/Object3D.cpp b/src/threepp/core/Object3D.cpp index 2e36251f0..80f1e8d2d 100644 --- a/src/threepp/core/Object3D.cpp +++ b/src/threepp/core/Object3D.cpp @@ -442,7 +442,7 @@ void Object3D::copy(const Object3D& source, bool recursive) { if (recursive) { - for (auto& child : source.children) { + for (const auto& child : source.children) { auto clone = child->clone(); this->add(clone); @@ -450,14 +450,6 @@ void Object3D::copy(const Object3D& source, bool recursive) { } } -std::shared_ptr Object3D::clone(bool recursive) { - - auto clone = std::make_shared(); - clone->copy(*this, recursive); - - return clone; -} - Object3D::Object3D(Object3D&& source) noexcept: Object3D() { this->name = std::move(source.name); diff --git a/src/threepp/loaders/OBJLoader.cpp b/src/threepp/loaders/OBJLoader.cpp index a85b8fa17..7920aadcd 100644 --- a/src/threepp/loaders/OBJLoader.cpp +++ b/src/threepp/loaders/OBJLoader.cpp @@ -295,7 +295,7 @@ struct OBJLoader::Impl { auto cached = cache_[path.string()]; if (!cached.expired()) { - return std::dynamic_pointer_cast(cached.lock()->clone()); + return cached.lock()->clone(); } else { cache_.erase(path.string()); } diff --git a/src/threepp/objects/Group.cpp b/src/threepp/objects/Group.cpp index a25e12099..de538c409 100644 --- a/src/threepp/objects/Group.cpp +++ b/src/threepp/objects/Group.cpp @@ -10,14 +10,12 @@ std::string Group::type() const { return "Group"; } -std::shared_ptr Group::clone(bool recursive) { - auto clone = create(); - clone->copy(*this, recursive); +std::shared_ptr Group::create() { - return clone; + return std::make_shared(); } -std::shared_ptr Group::create() { +std::shared_ptr Group::createDefault() { - return std::make_shared(); + return create(); } diff --git a/src/threepp/objects/LOD.cpp b/src/threepp/objects/LOD.cpp index 7b8e1431c..d6cd2818b 100644 --- a/src/threepp/objects/LOD.cpp +++ b/src/threepp/objects/LOD.cpp @@ -101,3 +101,22 @@ void LOD::update(Camera& camera) { } } } + +void LOD::copy(const Object3D& source, bool recursive) { + Object3D::copy(source, false); + + if (const auto l = source.as()) { + + for (auto level : l->levels) { + + this->addLevel(level.object->clone(), level.distance); + } + + this->autoUpdate = l->autoUpdate; + } +} + +std::shared_ptr LOD::createDefault() { + + return create(); +} diff --git a/src/threepp/objects/Line.cpp b/src/threepp/objects/Line.cpp index 1daeadf59..6b05932c7 100644 --- a/src/threepp/objects/Line.cpp +++ b/src/threepp/objects/Line.cpp @@ -36,13 +36,6 @@ void Line::setGeometry(const std::shared_ptr& geometry) { this->geometry_ = geometry; } -std::shared_ptr Line::clone(bool recursive) { - auto clone = create(geometry_, materials_.front()); - clone->copy(*this, recursive); - - return clone; -} - std::shared_ptr Line::create(const std::shared_ptr& geometry, const std::shared_ptr& material) { return std::make_shared(geometry, (material)); @@ -172,3 +165,18 @@ void Line::raycast(const Raycaster& raycaster, std::vector& inters } } } + +void Line::copy(const Object3D& source, bool recursive) { + Object3D::copy(source, recursive); + + if (const auto l = source.as()) { + + materials_ = l->materials_; + geometry_ = l->geometry_; + } +} + +std::shared_ptr Line::createDefault() { + + return create(); +} diff --git a/src/threepp/objects/LineLoop.cpp b/src/threepp/objects/LineLoop.cpp index 54170419e..6423ff3f1 100644 --- a/src/threepp/objects/LineLoop.cpp +++ b/src/threepp/objects/LineLoop.cpp @@ -17,13 +17,6 @@ std::string LineLoop::type() const { return "LineLoop"; } -std::shared_ptr LineLoop::clone(bool recursive) { - auto clone = create(); - clone->copy(*this, recursive); - - return clone; -} - std::shared_ptr LineLoop::create(const std::shared_ptr& geometry, const std::shared_ptr& material) { return std::make_shared(geometry, (material)); diff --git a/src/threepp/objects/LineSegments.cpp b/src/threepp/objects/LineSegments.cpp index d526b1fb8..6763a97d8 100644 --- a/src/threepp/objects/LineSegments.cpp +++ b/src/threepp/objects/LineSegments.cpp @@ -46,13 +46,6 @@ void LineSegments::computeLineDistances() { } } -std::shared_ptr LineSegments::clone(bool recursive) { - auto clone = create(); - clone->copy(*this, recursive); - - return clone; -} - std::shared_ptr LineSegments::create( const std::shared_ptr& geometry, const std::shared_ptr& material) { diff --git a/src/threepp/objects/Mesh.cpp b/src/threepp/objects/Mesh.cpp index 4f0ea3fef..e7c9f5dff 100644 --- a/src/threepp/objects/Mesh.cpp +++ b/src/threepp/objects/Mesh.cpp @@ -333,14 +333,6 @@ void Mesh::raycast(const Raycaster& raycaster, std::vector& inters } } -std::shared_ptr Mesh::clone(bool recursive) { - - auto clone = create(geometry_, materials_); - clone->copy(*this, recursive); - - return clone; -} - std::string Mesh::type() const { return "Mesh"; @@ -370,3 +362,19 @@ std::shared_ptr Mesh::create(std::shared_ptr geometry, std return std::make_shared(std::move(geometry), std::move(materials)); } + +void Mesh::copy(const Object3D& source, bool recursive) { + Object3D::copy(source, recursive); + + if (const auto m = source.as()) { + + // TODO morphs + + materials_ = m->materials_; + geometry_ = m->geometry_; + } +} + +std::shared_ptr Mesh::createDefault() { + return create(); +} diff --git a/src/threepp/objects/Points.cpp b/src/threepp/objects/Points.cpp index 4197b3f1f..c8c9e90b2 100644 --- a/src/threepp/objects/Points.cpp +++ b/src/threepp/objects/Points.cpp @@ -65,13 +65,6 @@ void Points::setGeometry(const std::shared_ptr& geometry) { this->geometry_ = geometry; } -std::shared_ptr Points::clone(bool recursive) { - auto clone = create(geometry_, materials_.front()); - clone->copy(*this, recursive); - - return clone; -} - std::shared_ptr Points::create(std::shared_ptr geometry, std::shared_ptr material) { return std::make_shared(std::move(geometry), std::move(material)); @@ -131,3 +124,18 @@ void Points::raycast(const Raycaster& raycaster, std::vector& inte } } } + +void Points::copy(const Object3D& source, bool recursive) { + Object3D::copy(source, recursive); + + if (auto p = source.as()) { + + materials_ = p->materials_; + geometry_ = p->geometry_; + } +} + +std::shared_ptr Points::createDefault() { + + return create(); +} diff --git a/src/threepp/objects/Sprite.cpp b/src/threepp/objects/Sprite.cpp index 19cb610dd..1bc92b338 100644 --- a/src/threepp/objects/Sprite.cpp +++ b/src/threepp/objects/Sprite.cpp @@ -165,3 +165,19 @@ void Sprite::raycast(const Raycaster& raycaster, std::vector& inte Triangle::getUV(_intersectPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, *intersection.uv); intersects.emplace_back(intersection); } + +void Sprite::copy(const Object3D& source, bool recursive) { + Object3D::copy(source, recursive); + + if (const auto s = source.as()) { + + this->center.copy(s->center); + + this->_material = s->_material; + } +} + +std::shared_ptr Sprite::createDefault() { + + return create(); +}