From d7d5cd4265aab0b939b57ea7237b56f2f5840642 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 11 Mar 2023 12:07:29 +0000 Subject: Initial version of texture packer Determines where a collection of smaller textures can be tiled into a single bigger image. Probably non-optimal. --- assetFactory/texturePacker.cpp | 77 ++++++++++++++++++++++++++++++++++++++++++ assetFactory/texturePacker.h | 36 ++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 assetFactory/texturePacker.cpp create mode 100644 assetFactory/texturePacker.h (limited to 'assetFactory') diff --git a/assetFactory/texturePacker.cpp b/assetFactory/texturePacker.cpp new file mode 100644 index 0000000..31c9a0e --- /dev/null +++ b/assetFactory/texturePacker.cpp @@ -0,0 +1,77 @@ +#include "texturePacker.h" +#include +#include +#include +#include +#include + +TexturePacker::TexturePacker(std::vector in) : inputImages {std::move(in)} +{ + std::sort(inputImages.rbegin(), inputImages.rend(), [](const auto & a, const auto & b) { + return area(a) < area(b); + }); +} + +TexturePacker::Result +TexturePacker::pack() const +{ + return pack(minSize()); +} + +TexturePacker::Result +TexturePacker::pack(Size size) const +{ + using Spaces = std::set; + Spaces spaces {{{}, size}}; + + Positions result; + for (const auto & image : inputImages) { + if (const auto spaceItr = std::find_if(spaces.begin(), spaces.end(), + [image](const Space & s) { + return image.x <= s.size.x && image.y <= s.size.y; + }); + spaceItr != spaces.end()) { + auto space = *spaceItr; + result.push_back(space.position); + spaces.erase(spaceItr); + if (space.size.x > image.x) { + spaces.emplace(Position {space.position.x + image.x, space.position.y}, + Size {space.size.x - image.x, image.y}); + } + if (space.size.y > image.y) { + spaces.emplace(Position {space.position.x, space.position.y + image.y}, + Size {space.size.x, space.size.y - image.y}); + } + } + else { + if (size.x < size.y) { + return pack({size.x * 2, size.y}); + } + else { + return pack({size.x, size.y * 2}); + } + } + } + + return {result, size}; +} + +TexturePacker::Size +TexturePacker::minSize() const +{ + return std::accumulate(inputImages.begin(), inputImages.end(), Size {1}, [](Size size, const Image & i) { + while (size.x < i.x) { + size.x *= 2; + } + while (size.y < i.y) { + size.y *= 2; + } + return size; + }); +} + +decltype(TexturePacker::Size::x) +TexturePacker::area(const Size & size) +{ + return size.x * size.y; +} diff --git a/assetFactory/texturePacker.h b/assetFactory/texturePacker.h new file mode 100644 index 0000000..8e2061b --- /dev/null +++ b/assetFactory/texturePacker.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include + +class TexturePacker { +public: + using Position = glm::uvec2; + using Size = glm::uvec2; + + struct Area { + Position position; + Size size; + bool + operator<(const Area & other) const + { + return area(size) < area(other.size); + } + }; + using Image = Size; + using Space = Area; + using Positions = std::vector; + using Result = std::pair; + + TexturePacker(std::vector); + + Result pack(Size) const; + Result pack() const; + + Size minSize() const; + static decltype(Size::x) area(const Size & size); + +private: + std::vector inputImages; +}; -- cgit v1.2.3 From 88c9d66352c2f4856682efd48482b5b72aca18bf Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 12 Mar 2023 00:54:24 +0000 Subject: Support loading references to texture fragments --- assetFactory/assetFactory.cpp | 3 +++ assetFactory/assetFactory.h | 3 +++ assetFactory/textureFragment.cpp | 7 +++++++ assetFactory/textureFragment.h | 14 ++++++++++++++ 4 files changed, 27 insertions(+) create mode 100644 assetFactory/textureFragment.cpp create mode 100644 assetFactory/textureFragment.h (limited to 'assetFactory') diff --git a/assetFactory/assetFactory.cpp b/assetFactory/assetFactory.cpp index f5fc2b3..de13579 100644 --- a/assetFactory/assetFactory.cpp +++ b/assetFactory/assetFactory.cpp @@ -75,11 +75,14 @@ AssetFactory::parseColour(std::string_view in) const } throw std::runtime_error("No such asset factory colour"); } + bool AssetFactory::persist(Persistence::PersistenceStore & store) { using MapObjects = Persistence::MapByMember>; using MapAssets = Persistence::MapByMember; + using MapTextureFragments = Persistence::MapByMember; return STORE_TYPE && STORE_NAME_HELPER("object", shapes, MapObjects) + && STORE_NAME_HELPER("textureFragment", textureFragments, MapTextureFragments) && STORE_NAME_HELPER("asset", assets, MapAssets); } diff --git a/assetFactory/assetFactory.h b/assetFactory/assetFactory.h index b47d408..3d52f7f 100644 --- a/assetFactory/assetFactory.h +++ b/assetFactory/assetFactory.h @@ -3,12 +3,14 @@ #include "asset.h" #include "persistence.h" #include "shape.h" +#include "textureFragment.h" #include class AssetFactory : public Persistence::Persistable { public: using Shapes = std::map>; using Assets = std::map>; + using TextureFragments = std::map>; using Colour = glm::vec3; using ColourAlpha = glm::vec4; using Colours = std::map>; @@ -20,6 +22,7 @@ public: Shapes shapes; Assets assets; Colours colours; + TextureFragments textureFragments; static Colours parseX11RGB(const char * rgbtxtpath); static void normalizeColourName(std::string &); diff --git a/assetFactory/textureFragment.cpp b/assetFactory/textureFragment.cpp new file mode 100644 index 0000000..72107a5 --- /dev/null +++ b/assetFactory/textureFragment.cpp @@ -0,0 +1,7 @@ +#include "textureFragment.h" + +bool +TextureFragment::persist(Persistence::PersistenceStore & store) +{ + return STORE_TYPE && STORE_MEMBER(id) && STORE_MEMBER(path); +} diff --git a/assetFactory/textureFragment.h b/assetFactory/textureFragment.h new file mode 100644 index 0000000..52f2591 --- /dev/null +++ b/assetFactory/textureFragment.h @@ -0,0 +1,14 @@ +#pragma once + +#include "persistence.h" +#include "stdTypeDefs.hpp" + +class TextureFragment : public Persistence::Persistable, public StdTypeDefs { +public: + std::string id; + std::string path; + +private: + friend Persistence::SelectionPtrBase; + bool persist(Persistence::PersistenceStore & store) override; +}; -- cgit v1.2.3 From 0ee9b8c6036899f95dfd54f151cb60a03645f87a Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 12 Mar 2023 01:05:18 +0000 Subject: Support loading texture references into faces --- assetFactory/style.cpp | 2 +- assetFactory/style.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'assetFactory') diff --git a/assetFactory/style.cpp b/assetFactory/style.cpp index fc5c34e..5303d96 100644 --- a/assetFactory/style.cpp +++ b/assetFactory/style.cpp @@ -42,5 +42,5 @@ Style::persist(Persistence::PersistenceStore & store) } }; - return STORE_HELPER(colour, ColourParser); + return STORE_HELPER(colour, ColourParser) && STORE_MEMBER(texture) && STORE_MEMBER(textureRotation); } diff --git a/assetFactory/style.h b/assetFactory/style.h index e8fd012..84e5dab 100644 --- a/assetFactory/style.h +++ b/assetFactory/style.h @@ -28,6 +28,8 @@ public: } ColourAlpha colour {}; + std::string texture; + std::string textureRotation; // Multiples of 90deg, no int/enum support protected: bool persist(Persistence::PersistenceStore & store); -- cgit v1.2.3 From 0d5b57f31e17b8e46979d8c29b5a3205fbdbd44b Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 12 Mar 2023 01:29:38 +0000 Subject: Dedupe looking up the style stack for colour --- assetFactory/style.cpp | 20 ++++++++++---------- assetFactory/style.h | 2 ++ 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/style.cpp b/assetFactory/style.cpp index 5303d96..fa585ac 100644 --- a/assetFactory/style.cpp +++ b/assetFactory/style.cpp @@ -4,11 +4,7 @@ void Style::applyStyle(ModelFactoryMesh & mesh, const StyleStack & parents, const Shape::CreatedFaces & faces) const { - if (const auto effectiveColour = getProperty(parents, &Style::colour, - [](auto && style) { - return style->colour.a > 0; - }); - effectiveColour.has_value()) { + if (const auto effectiveColour = getColour(parents); effectiveColour.has_value()) { for (const auto & face : faces) { mesh.set_color(face.second, effectiveColour->get()); } @@ -18,15 +14,19 @@ Style::applyStyle(ModelFactoryMesh & mesh, const StyleStack & parents, const Sha void Style::applyStyle(ModelFactoryMesh & mesh, const StyleStack & parents, const ModelFactoryMesh::FaceHandle & face) const { - if (const auto effectiveColour = getProperty(parents, &Style::colour, - [](auto && style) { - return style->colour.a > 0; - }); - effectiveColour.has_value()) { + if (const auto effectiveColour = getColour(parents); effectiveColour.has_value()) { mesh.set_color(face, effectiveColour->get()); } } +std::optional> +Style::getColour(const StyleStack & parents) +{ + return getProperty(parents, &Style::colour, [](auto && style) { + return style->colour.a > 0; + }); +} + bool Style::persist(Persistence::PersistenceStore & store) { diff --git a/assetFactory/style.h b/assetFactory/style.h index 84e5dab..8c64276 100644 --- a/assetFactory/style.h +++ b/assetFactory/style.h @@ -27,6 +27,8 @@ public: return {}; } + static std::optional> getColour(const StyleStack & parents); + ColourAlpha colour {}; std::string texture; std::string textureRotation; // Multiples of 90deg, no int/enum support -- cgit v1.2.3 From 7bf24d23a7db872f7bd13060da9817a9ee5f816c Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 12 Mar 2023 01:36:50 +0000 Subject: Dedupe applying style to a face --- assetFactory/style.cpp | 17 +++++++++++------ assetFactory/style.h | 4 +++- 2 files changed, 14 insertions(+), 7 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/style.cpp b/assetFactory/style.cpp index fa585ac..b5ddcf1 100644 --- a/assetFactory/style.cpp +++ b/assetFactory/style.cpp @@ -4,22 +4,27 @@ void Style::applyStyle(ModelFactoryMesh & mesh, const StyleStack & parents, const Shape::CreatedFaces & faces) const { - if (const auto effectiveColour = getColour(parents); effectiveColour.has_value()) { - for (const auto & face : faces) { - mesh.set_color(face.second, effectiveColour->get()); - } + for (const auto & face : faces) { + applyStyle(mesh, face.second, getColour(parents)); } } void Style::applyStyle(ModelFactoryMesh & mesh, const StyleStack & parents, const ModelFactoryMesh::FaceHandle & face) const { - if (const auto effectiveColour = getColour(parents); effectiveColour.has_value()) { + applyStyle(mesh, face, getColour(parents)); +} + +void +Style::applyStyle( + ModelFactoryMesh & mesh, const ModelFactoryMesh::FaceHandle & face, EffectiveColour effectiveColour) const +{ + if (effectiveColour.has_value()) { mesh.set_color(face, effectiveColour->get()); } } -std::optional> +Style::EffectiveColour Style::getColour(const StyleStack & parents) { return getProperty(parents, &Style::colour, [](auto && style) { diff --git a/assetFactory/style.h b/assetFactory/style.h index 8c64276..f3bc707 100644 --- a/assetFactory/style.h +++ b/assetFactory/style.h @@ -12,6 +12,7 @@ public: using StyleStack = std::vector; using Colour = glm::vec3; using ColourAlpha = glm::vec4; + using EffectiveColour = std::optional>; void applyStyle(ModelFactoryMesh &, const StyleStack & parents, const Shape::CreatedFaces &) const; void applyStyle(ModelFactoryMesh &, const StyleStack & parents, const ModelFactoryMesh::FaceHandle &) const; @@ -27,7 +28,7 @@ public: return {}; } - static std::optional> getColour(const StyleStack & parents); + static EffectiveColour getColour(const StyleStack & parents); ColourAlpha colour {}; std::string texture; @@ -35,4 +36,5 @@ public: protected: bool persist(Persistence::PersistenceStore & store); + void applyStyle(ModelFactoryMesh &, const ModelFactoryMesh::FaceHandle &, EffectiveColour) const; }; -- cgit v1.2.3 From 3fea21a2d8f2aa67fd212837fe7e09e4f29ad515 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 14 Mar 2023 19:16:57 +0000 Subject: Support creating a super texture from fragments Currently makes wild assumptions about vertices and doesn't actually populate the texture, it's just grey --- assetFactory/asset.cpp | 10 +++++++ assetFactory/asset.h | 6 ++++ assetFactory/assetFactory.cpp | 62 ++++++++++++++++++++++++++++++++++++++++- assetFactory/assetFactory.h | 10 +++++++ assetFactory/factoryMesh.cpp | 6 ++-- assetFactory/modelFactoryMesh.h | 4 ++- assetFactory/style.cpp | 17 +++++++++-- 7 files changed, 107 insertions(+), 8 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/asset.cpp b/assetFactory/asset.cpp index 3ab2f1c..e3f5feb 100644 --- a/assetFactory/asset.cpp +++ b/assetFactory/asset.cpp @@ -1,4 +1,5 @@ #include "asset.h" +#include "assetFactory.h" bool Asset::persist(Persistence::PersistenceStore & store) @@ -6,6 +7,15 @@ Asset::persist(Persistence::PersistenceStore & store) return STORE_MEMBER(id) && STORE_MEMBER(name); } +Asset::TexturePtr +Asset::getTexture() const +{ + if (auto mf = Persistence::ParseBase::getShared("assetFactory")) { + return mf->getTexture(); + } + return nullptr; +} + Asset::MeshConstruct::MeshConstruct(Mesh::Ptr & m) : Persistence::SelectionPtrBase {fmesh}, out {m} { } diff --git a/assetFactory/asset.h b/assetFactory/asset.h index e3318e4..30f40cd 100644 --- a/assetFactory/asset.h +++ b/assetFactory/asset.h @@ -4,12 +4,18 @@ #include "persistence.h" #include +class Texture; + class Asset : public Persistence::Persistable, public StdTypeDefs { public: + using TexturePtr = std::shared_ptr; + std::string id; std::string name; protected: + TexturePtr getTexture() const; + struct MeshConstruct : public Persistence::SelectionPtrBase { using Persistence::SelectionPtrBase::setValue; diff --git a/assetFactory/assetFactory.cpp b/assetFactory/assetFactory.cpp index de13579..276c258 100644 --- a/assetFactory/assetFactory.cpp +++ b/assetFactory/assetFactory.cpp @@ -2,11 +2,16 @@ #include "collections.hpp" #include "cuboid.h" #include "cylinder.h" +#include "filesystem.h" +#include "gfx/image.h" +#include "gfx/models/texture.h" #include "modelFactoryMesh_fwd.h" #include "object.h" #include "plane.h" +#include "resource.h" #include "saxParse-persistence.h" -#include +#include "texturePacker.h" +#include AssetFactory::AssetFactory() : shapes { @@ -76,6 +81,61 @@ AssetFactory::parseColour(std::string_view in) const throw std::runtime_error("No such asset factory colour"); } +AssetFactory::TextureFragmentCoords +AssetFactory::getTextureCoords(std::string_view id) const +{ + createTexutre(); + const auto & fragmentUV = textureFragmentPositions.at(id); + return { + fragmentUV.xy(), + fragmentUV.zy(), + fragmentUV.zw(), + fragmentUV.xw(), + }; +} + +Asset::TexturePtr +AssetFactory::getTexture() const +{ + createTexutre(); + return texture; +} + +void +AssetFactory::createTexutre() const +{ + if (!textureFragments.empty() && (!texture || textureFragmentPositions.empty())) { + // * load images + std::vector> images; + std::transform( + textureFragments.begin(), textureFragments.end(), std::back_inserter(images), [](const auto & tf) { + return std::make_unique(Resource::mapPath(tf.second->path), STBI_rgb_alpha); + }); + // * layout images + std::vector imageSizes; + std::transform(images.begin(), images.end(), std::back_inserter(imageSizes), [](const auto & image) { + return TexturePacker::Image {image->width, image->height}; + }); + const auto [layout, outSize] = TexturePacker {imageSizes}.pack(); + // * create texture + std::vector textureData(TexturePacker::area(outSize), {127, 127, 127, 255}); + std::transform(textureFragments.begin(), textureFragments.end(), + std::inserter(textureFragmentPositions, textureFragmentPositions.end()), + [position = layout.begin(), size = imageSizes.begin(), outSize = outSize](const auto & tf) mutable { + const glm::vec4 positionFraction { + static_cast(position->x) / static_cast(outSize.x), + static_cast(position->y) / static_cast(outSize.y), + static_cast(position->x + size->x) / static_cast(outSize.x), + static_cast(position->y + size->y) / static_cast(outSize.y), + }; + position++; + size++; + return decltype(textureFragmentPositions)::value_type {tf.first, positionFraction}; + }); + texture = std::make_shared(outSize.x, outSize.y, textureData.data()); + } +} + bool AssetFactory::persist(Persistence::PersistenceStore & store) { diff --git a/assetFactory/assetFactory.h b/assetFactory/assetFactory.h index 3d52f7f..52692c4 100644 --- a/assetFactory/assetFactory.h +++ b/assetFactory/assetFactory.h @@ -6,6 +6,8 @@ #include "textureFragment.h" #include +class Texture; + class AssetFactory : public Persistence::Persistable { public: using Shapes = std::map>; @@ -14,10 +16,13 @@ public: using Colour = glm::vec3; using ColourAlpha = glm::vec4; using Colours = std::map>; + using TextureFragmentCoords = std::array; AssetFactory(); [[nodiscard]] static std::shared_ptr loadXML(const std::filesystem::path &); [[nodiscard]] ColourAlpha parseColour(std::string_view) const; + [[nodiscard]] TextureFragmentCoords getTextureCoords(std::string_view) const; + [[nodiscard]] Asset::TexturePtr getTexture() const; Shapes shapes; Assets assets; @@ -30,4 +35,9 @@ public: private: friend Persistence::SelectionPtrBase>; bool persist(Persistence::PersistenceStore & store) override; + + void createTexutre() const; + + mutable Asset::TexturePtr texture; + mutable std::map> textureFragmentPositions; }; diff --git a/assetFactory/factoryMesh.cpp b/assetFactory/factoryMesh.cpp index 1665b90..c47e80e 100644 --- a/assetFactory/factoryMesh.cpp +++ b/assetFactory/factoryMesh.cpp @@ -2,13 +2,10 @@ #include "collections.hpp" #include "gfx/models/vertex.hpp" #include "modelFactoryMesh.h" -#include Mesh::Ptr FactoryMesh::createMesh() const { - constexpr glm::vec2 NullUV {}; - ModelFactoryMesh mesh; for (const auto & use : uses) { use->createMesh(mesh, 1); @@ -23,7 +20,8 @@ FactoryMesh::createMesh() const const auto smooth = mesh.property(mesh.smoothFaceProperty, face); const auto colour = mesh.color(face); for (const auto & vertex : mesh.fv_range(face)) { - vertices.emplace_back(mesh.point(vertex), NullUV, + const auto textureUV = mesh.texcoord2D(vertex); + vertices.emplace_back(mesh.point(vertex), textureUV, smooth ? mesh.property(mesh.vertex_normals_pph(), vertex) : mesh.property(mesh.face_normals_pph(), face), colour); diff --git a/assetFactory/modelFactoryMesh.h b/assetFactory/modelFactoryMesh.h index 149ff1a..493ce1b 100644 --- a/assetFactory/modelFactoryMesh.h +++ b/assetFactory/modelFactoryMesh.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -34,10 +35,11 @@ namespace OpenMesh { struct ModelFactoryTraits : public OpenMesh::DefaultTraits { FaceAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status | OpenMesh::Attributes::Color); EdgeAttributes(OpenMesh::Attributes::Status); - VertexAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status); + VertexAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status | OpenMesh::Attributes::TexCoord2D); using Point = glm::vec3; using Normal = glm::vec3; using Color = glm::vec4; + using TexCoord2D = glm::vec2; }; struct ModelFactoryMesh : public OpenMesh::PolyMesh_ArrayKernelT { diff --git a/assetFactory/style.cpp b/assetFactory/style.cpp index b5ddcf1..8aecc71 100644 --- a/assetFactory/style.cpp +++ b/assetFactory/style.cpp @@ -19,8 +19,21 @@ void Style::applyStyle( ModelFactoryMesh & mesh, const ModelFactoryMesh::FaceHandle & face, EffectiveColour effectiveColour) const { - if (effectiveColour.has_value()) { - mesh.set_color(face, effectiveColour->get()); + if (texture.empty()) { + if (effectiveColour.has_value()) { + mesh.set_color(face, effectiveColour->get()); + } + } + else { + mesh.set_color(face, {}); + if (auto mf = Persistence::ParseBase::getShared("assetFactory")) { + auto coords = mf->getTextureCoords(texture); + auto coord = coords.begin(); + // Wild assumption that face is a quad and the texture should apply linearly + for (const auto & vh : mesh.fv_range(face)) { + mesh.set_texcoord2D(vh, *coord++); + } + } } } -- cgit v1.2.3 From ac90f8e60b1c971c342cdd98769388563e157557 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Wed, 15 Mar 2023 02:10:31 +0000 Subject: Populate super texture with fragments This is kinda buggy due to TexturePacker sorting its input array and the client having no idea the order of the results. --- assetFactory/assetFactory.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/assetFactory.cpp b/assetFactory/assetFactory.cpp index 276c258..77dd554 100644 --- a/assetFactory/assetFactory.cpp +++ b/assetFactory/assetFactory.cpp @@ -118,21 +118,25 @@ AssetFactory::createTexutre() const }); const auto [layout, outSize] = TexturePacker {imageSizes}.pack(); // * create texture - std::vector textureData(TexturePacker::area(outSize), {127, 127, 127, 255}); + texture = std::make_shared(outSize.x, outSize.y, TextureOptions {.wrap = GL_CLAMP_TO_EDGE}); std::transform(textureFragments.begin(), textureFragments.end(), std::inserter(textureFragmentPositions, textureFragmentPositions.end()), - [position = layout.begin(), size = imageSizes.begin(), outSize = outSize](const auto & tf) mutable { - const glm::vec4 positionFraction { - static_cast(position->x) / static_cast(outSize.x), - static_cast(position->y) / static_cast(outSize.y), - static_cast(position->x + size->x) / static_cast(outSize.x), - static_cast(position->y + size->y) / static_cast(outSize.y), + [position = layout.begin(), image = images.begin(), size = imageSizes.begin(), + outSize = glm::vec2 {outSize}](const auto & tf) mutable { + glm::vec4 positionFraction { + static_cast(position->x) / outSize.x, + static_cast(position->y) / outSize.y, + static_cast(position->x + size->x) / outSize.x, + static_cast(position->y + size->y) / outSize.y, }; + glTexSubImage2D(GL_TEXTURE_2D, 0, static_cast(position->x), static_cast(position->y), + static_cast(size->x), static_cast(size->y), GL_RGBA, GL_UNSIGNED_BYTE, + image->get()->data.data()); position++; + image++; size++; return decltype(textureFragmentPositions)::value_type {tf.first, positionFraction}; }); - texture = std::make_shared(outSize.x, outSize.y, textureData.data()); } } -- cgit v1.2.3 From 07dc690837f6a665490e370e8a07410e970384d7 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 16 Mar 2023 23:23:04 +0000 Subject: Simplify calculation of texture position fraction --- assetFactory/assetFactory.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/assetFactory.cpp b/assetFactory/assetFactory.cpp index 77dd554..ed1af58 100644 --- a/assetFactory/assetFactory.cpp +++ b/assetFactory/assetFactory.cpp @@ -123,12 +123,7 @@ AssetFactory::createTexutre() const std::inserter(textureFragmentPositions, textureFragmentPositions.end()), [position = layout.begin(), image = images.begin(), size = imageSizes.begin(), outSize = glm::vec2 {outSize}](const auto & tf) mutable { - glm::vec4 positionFraction { - static_cast(position->x) / outSize.x, - static_cast(position->y) / outSize.y, - static_cast(position->x + size->x) / outSize.x, - static_cast(position->y + size->y) / outSize.y, - }; + const auto positionFraction = glm::vec4 {*position, *position + *size} / outSize.xyxy(); glTexSubImage2D(GL_TEXTURE_2D, 0, static_cast(position->x), static_cast(position->y), static_cast(size->x), static_cast(size->y), GL_RGBA, GL_UNSIGNED_BYTE, image->get()->data.data()); -- cgit v1.2.3 From c915f1bcd46144578fad464e52b5a6013dc98de8 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 17 Mar 2023 02:05:42 +0000 Subject: Fix texture packer return value so positions match inputs --- assetFactory/texturePacker.cpp | 15 +++++++++------ assetFactory/texturePacker.h | 5 +++-- 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/texturePacker.cpp b/assetFactory/texturePacker.cpp index 31c9a0e..68a6010 100644 --- a/assetFactory/texturePacker.cpp +++ b/assetFactory/texturePacker.cpp @@ -1,14 +1,16 @@ #include "texturePacker.h" +#include "collections.hpp" #include #include #include #include #include -TexturePacker::TexturePacker(std::vector in) : inputImages {std::move(in)} +TexturePacker::TexturePacker(std::span in) : + inputImages {std::move(in)}, sortedIndexes {vectorOfN(inputImages.size(), size_t {})} { - std::sort(inputImages.rbegin(), inputImages.rend(), [](const auto & a, const auto & b) { - return area(a) < area(b); + std::sort(sortedIndexes.rbegin(), sortedIndexes.rend(), [this](const auto a, const auto b) { + return area(inputImages[a]) < area(inputImages[b]); }); } @@ -24,15 +26,16 @@ TexturePacker::pack(Size size) const using Spaces = std::set; Spaces spaces {{{}, size}}; - Positions result; - for (const auto & image : inputImages) { + Positions result(inputImages.size()); + for (const auto & idx : sortedIndexes) { + const auto & image = inputImages[idx]; if (const auto spaceItr = std::find_if(spaces.begin(), spaces.end(), [image](const Space & s) { return image.x <= s.size.x && image.y <= s.size.y; }); spaceItr != spaces.end()) { auto space = *spaceItr; - result.push_back(space.position); + result[idx] = space.position; spaces.erase(spaceItr); if (space.size.x > image.x) { spaces.emplace(Position {space.position.x + image.x, space.position.y}, diff --git a/assetFactory/texturePacker.h b/assetFactory/texturePacker.h index 8e2061b..7e00f1a 100644 --- a/assetFactory/texturePacker.h +++ b/assetFactory/texturePacker.h @@ -23,7 +23,7 @@ public: using Positions = std::vector; using Result = std::pair; - TexturePacker(std::vector); + TexturePacker(std::span); Result pack(Size) const; Result pack() const; @@ -32,5 +32,6 @@ public: static decltype(Size::x) area(const Size & size); private: - std::vector inputImages; + std::span inputImages; + std::vector sortedIndexes; }; -- cgit v1.2.3 From f412b04cc367168b1a6f921dfa1171a17e1353fc Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 18 Mar 2023 02:12:21 +0000 Subject: Use indices instead of triangulation --- assetFactory/factoryMesh.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/factoryMesh.cpp b/assetFactory/factoryMesh.cpp index c47e80e..59b390f 100644 --- a/assetFactory/factoryMesh.cpp +++ b/assetFactory/factoryMesh.cpp @@ -10,24 +10,31 @@ FactoryMesh::createMesh() const for (const auto & use : uses) { use->createMesh(mesh, 1); } - mesh.garbage_collection(); - mesh.triangulate(); mesh.update_face_normals(); mesh.update_vertex_normals(); std::vector vertices; + std::vector indices; for (const auto & face : mesh.faces()) { const auto smooth = mesh.property(mesh.smoothFaceProperty, face); const auto colour = mesh.color(face); - for (const auto & vertex : mesh.fv_range(face)) { + auto vrange = mesh.fv_range(face); + const unsigned int start = static_cast(vertices.size()); + for (const auto & vertex : vrange) { const auto textureUV = mesh.texcoord2D(vertex); vertices.emplace_back(mesh.point(vertex), textureUV, smooth ? mesh.property(mesh.vertex_normals_pph(), vertex) : mesh.property(mesh.face_normals_pph(), face), colour); } + const auto vcount = std::distance(vrange.begin(), vrange.end()); + for (unsigned int i = 2; i < vcount; i++) { + indices.push_back(start); + indices.push_back(start + i - 1); + indices.push_back(start + i); + } } - return std::make_shared(vertices, vectorOfN(vertices.size())); + return std::make_shared(vertices, indices); } bool -- cgit v1.2.3 From 51f0f60bd24a3d7ed77cf713f846bc49c2f1aed5 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 18 Mar 2023 02:44:00 +0000 Subject: Use halfedge for texture coordinates More unique than vertex as it is also per face, allowing for a different texture on adjacent faces --- assetFactory/factoryMesh.cpp | 9 +++++---- assetFactory/modelFactoryMesh.h | 3 ++- assetFactory/style.cpp | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/factoryMesh.cpp b/assetFactory/factoryMesh.cpp index 59b390f..6cca388 100644 --- a/assetFactory/factoryMesh.cpp +++ b/assetFactory/factoryMesh.cpp @@ -18,16 +18,17 @@ FactoryMesh::createMesh() const for (const auto & face : mesh.faces()) { const auto smooth = mesh.property(mesh.smoothFaceProperty, face); const auto colour = mesh.color(face); - auto vrange = mesh.fv_range(face); + auto hrange = mesh.fh_range(face); const unsigned int start = static_cast(vertices.size()); - for (const auto & vertex : vrange) { - const auto textureUV = mesh.texcoord2D(vertex); + for (const auto & heh : hrange) { + const auto & vertex = mesh.to_vertex_handle(heh); + const auto textureUV = mesh.texcoord2D(heh); vertices.emplace_back(mesh.point(vertex), textureUV, smooth ? mesh.property(mesh.vertex_normals_pph(), vertex) : mesh.property(mesh.face_normals_pph(), face), colour); } - const auto vcount = std::distance(vrange.begin(), vrange.end()); + const auto vcount = std::distance(hrange.begin(), hrange.end()); for (unsigned int i = 2; i < vcount; i++) { indices.push_back(start); indices.push_back(start + i - 1); diff --git a/assetFactory/modelFactoryMesh.h b/assetFactory/modelFactoryMesh.h index 493ce1b..a862dc1 100644 --- a/assetFactory/modelFactoryMesh.h +++ b/assetFactory/modelFactoryMesh.h @@ -35,7 +35,8 @@ namespace OpenMesh { struct ModelFactoryTraits : public OpenMesh::DefaultTraits { FaceAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status | OpenMesh::Attributes::Color); EdgeAttributes(OpenMesh::Attributes::Status); - VertexAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status | OpenMesh::Attributes::TexCoord2D); + VertexAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status); + HalfedgeAttributes(OpenMesh::Attributes::TexCoord2D); using Point = glm::vec3; using Normal = glm::vec3; using Color = glm::vec4; diff --git a/assetFactory/style.cpp b/assetFactory/style.cpp index 8aecc71..d1d4adc 100644 --- a/assetFactory/style.cpp +++ b/assetFactory/style.cpp @@ -30,8 +30,8 @@ Style::applyStyle( auto coords = mf->getTextureCoords(texture); auto coord = coords.begin(); // Wild assumption that face is a quad and the texture should apply linearly - for (const auto & vh : mesh.fv_range(face)) { - mesh.set_texcoord2D(vh, *coord++); + for (const auto & heh : mesh.fh_range(face)) { + mesh.set_texcoord2D(heh, *coord++); } } } -- cgit v1.2.3 From 60ca9a1cdec3685e1b8496bd9c9dc7c9486157e7 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 19 Mar 2023 23:28:56 +0000 Subject: Add aggregrate constructor to TexturePacker::Area as required --- assetFactory/texturePacker.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'assetFactory') diff --git a/assetFactory/texturePacker.h b/assetFactory/texturePacker.h index 7e00f1a..ca0d67a 100644 --- a/assetFactory/texturePacker.h +++ b/assetFactory/texturePacker.h @@ -10,6 +10,10 @@ public: using Size = glm::uvec2; struct Area { +#ifndef __cpp_aggregate_paren_init + constexpr Area(Position p, Size s) : position {std::move(p)}, size {std::move(s)} { } +#endif + Position position; Size size; bool -- cgit v1.2.3 From 40cc01f79c6308b2e4b64fab73cb27d4221a648e Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 19 Mar 2023 23:32:47 +0000 Subject: Dedupe vertices during asset factory mesh build This calls Vertex::== far too many times, but it's not (yet) enough to be a problem --- assetFactory/factoryMesh.cpp | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/factoryMesh.cpp b/assetFactory/factoryMesh.cpp index 6cca388..8869efd 100644 --- a/assetFactory/factoryMesh.cpp +++ b/assetFactory/factoryMesh.cpp @@ -16,23 +16,31 @@ FactoryMesh::createMesh() const std::vector vertices; std::vector indices; for (const auto & face : mesh.faces()) { - const auto smooth = mesh.property(mesh.smoothFaceProperty, face); - const auto colour = mesh.color(face); - auto hrange = mesh.fh_range(face); - const unsigned int start = static_cast(vertices.size()); - for (const auto & heh : hrange) { + const auto & smooth = mesh.property(mesh.smoothFaceProperty, face); + const auto & colour = mesh.color(face); + + std::vector faceIndices; + for (const auto & heh : mesh.fh_range(face)) { const auto & vertex = mesh.to_vertex_handle(heh); - const auto textureUV = mesh.texcoord2D(heh); - vertices.emplace_back(mesh.point(vertex), textureUV, - smooth ? mesh.property(mesh.vertex_normals_pph(), vertex) - : mesh.property(mesh.face_normals_pph(), face), - colour); + const auto & textureUV = mesh.texcoord2D(heh); + const auto & point = mesh.point(vertex); + const auto & normal = smooth ? mesh.property(mesh.vertex_normals_pph(), vertex) + : mesh.property(mesh.face_normals_pph(), face); + Vertex outVertex {point, textureUV, normal, colour}; + if (const auto existingItr = std::find(vertices.rbegin(), vertices.rend(), outVertex); + existingItr != vertices.rend()) { + faceIndices.push_back(static_cast(std::distance(existingItr, vertices.rend()) - 1)); + } + else { + faceIndices.push_back(static_cast(vertices.size())); + vertices.emplace_back(outVertex); + } } - const auto vcount = std::distance(hrange.begin(), hrange.end()); - for (unsigned int i = 2; i < vcount; i++) { - indices.push_back(start); - indices.push_back(start + i - 1); - indices.push_back(start + i); + + for (unsigned int i = 2; i < faceIndices.size(); i++) { + indices.push_back(faceIndices[0]); + indices.push_back(faceIndices[i - 1]); + indices.push_back(faceIndices[i]); } } return std::make_shared(vertices, indices); -- cgit v1.2.3 From d862385c8956b9cc1002323feddf0b65a777a1c1 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 19 Mar 2023 23:52:22 +0000 Subject: Use OpenMesh built-in to calculate face centre --- assetFactory/faceController.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/faceController.cpp b/assetFactory/faceController.cpp index 1ec1467..2fb0412 100644 --- a/assetFactory/faceController.cpp +++ b/assetFactory/faceController.cpp @@ -33,8 +33,7 @@ FaceController::apply(ModelFactoryMesh & mesh, const StyleStack & parents, const return std::move(out); }); const auto vertexCount = points.size(); - const auto centre - = std::accumulate(points.begin(), points.end(), glm::vec3 {}) / static_cast(vertexCount); + const auto centre = mesh.calc_face_centroid(cf.second); if (type == "extrude") { Shape::CreatedFaces newFaces; // mutate points -- cgit v1.2.3 From 5f0fbcef6dbc1421ea2b538c7f839b2f37c6e36e Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 20 Mar 2023 00:11:43 +0000 Subject: Fix some name shadowing in FaceController --- assetFactory/faceController.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/faceController.cpp b/assetFactory/faceController.cpp index 2fb0412..1e563b2 100644 --- a/assetFactory/faceController.cpp +++ b/assetFactory/faceController.cpp @@ -52,9 +52,9 @@ FaceController::apply(ModelFactoryMesh & mesh, const StyleStack & parents, const const auto next = (idx + 1) % vertexCount; const auto newFace = mesh.add_face({baseVertices[idx], baseVertices[next], vertices[next], vertices[idx]}); - auto & name = mesh.property(mesh.nameFaceProperty, newFace); - name = getAdjacentFaceName(ofrange, newFace); - newFaces.emplace(name, newFace); + auto & newFaceName = mesh.property(mesh.nameFaceProperty, newFace); + newFaceName = getAdjacentFaceName(ofrange, newFace); + newFaces.emplace(newFaceName, newFace); } newFaces.emplace(name, mesh.add_face(vertices)); if (smooth) { @@ -63,8 +63,8 @@ FaceController::apply(ModelFactoryMesh & mesh, const StyleStack & parents, const } } applyStyle(mesh, parents + this, newFaces); - for (const auto & [name, faceController] : faceControllers) { - faceController->apply(mesh, parents + this, name, newFaces); + for (const auto & [subFaceName, faceController] : faceControllers) { + faceController->apply(mesh, parents + this, subFaceName, newFaces); } faces.merge(std::move(newFaces)); } -- cgit v1.2.3 From 3687243d2412b0923d2a81a0c13e25ed7f45a893 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 20 Mar 2023 01:07:57 +0000 Subject: Fix left/right swap of cuboid face names --- assetFactory/cuboid.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/cuboid.cpp b/assetFactory/cuboid.cpp index f200258..a8ddcd9 100644 --- a/assetFactory/cuboid.cpp +++ b/assetFactory/cuboid.cpp @@ -21,8 +21,8 @@ Cuboid::createMesh(ModelFactoryMesh & mesh, float) const return { mesh.add_namedFace("top", vhs[4], vhs[5], vhs[6], vhs[7]), mesh.add_namedFace("bottom", vhs[0], vhs[1], vhs[2], vhs[3]), - mesh.add_namedFace("left", vhs[0], vhs[7], vhs[6], vhs[1]), - mesh.add_namedFace("right", vhs[2], vhs[5], vhs[4], vhs[3]), + mesh.add_namedFace("right", vhs[0], vhs[7], vhs[6], vhs[1]), + mesh.add_namedFace("left", vhs[2], vhs[5], vhs[4], vhs[3]), mesh.add_namedFace("front", vhs[0], vhs[3], vhs[4], vhs[7]), mesh.add_namedFace("back", vhs[2], vhs[1], vhs[6], vhs[5]), }; -- cgit v1.2.3 From b5db39e7de50cff669920ab1f279df223d257a51 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 20 Mar 2023 00:26:16 +0000 Subject: Support applying a single face controller to multiple faces --- assetFactory/faceController.cpp | 13 ++++++++++++- assetFactory/faceController.h | 5 ++++- 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/faceController.cpp b/assetFactory/faceController.cpp index 1e563b2..6493300 100644 --- a/assetFactory/faceController.cpp +++ b/assetFactory/faceController.cpp @@ -4,7 +4,18 @@ #include "modelFactoryMesh.h" void -FaceController::apply(ModelFactoryMesh & mesh, const StyleStack & parents, const std::string & name, +FaceController::apply(ModelFactoryMesh & mesh, const StyleStack & parents, const std::string & names, + Shape::CreatedFaces & faces) const +{ + std::stringstream nameStream {names}; + std::for_each(std::istream_iterator(nameStream), std::istream_iterator {}, + [&](const auto & name) { + applySingle(mesh, parents, name, faces); + }); +} + +void +FaceController::applySingle(ModelFactoryMesh & mesh, const StyleStack & parents, const std::string & name, Shape::CreatedFaces & faces) const { const auto getAdjacentFaceName = [&mesh](const auto & ofrange, OpenMesh::FaceHandle nf) -> std::string { diff --git a/assetFactory/faceController.h b/assetFactory/faceController.h index 10a226a..890aafa 100644 --- a/assetFactory/faceController.h +++ b/assetFactory/faceController.h @@ -12,7 +12,7 @@ class FaceController : public Mutation, public Style, public Persistence::Persis public: using FaceControllers = std::map>; - void apply(ModelFactoryMesh & mesh, const Style::StyleStack & parents, const std::string & name, + void apply(ModelFactoryMesh & mesh, const Style::StyleStack & parents, const std::string & names, Shape::CreatedFaces & faces) const; std::string id; @@ -28,4 +28,7 @@ private: { return {}; }; + + void applySingle(ModelFactoryMesh & mesh, const Style::StyleStack & parents, const std::string & name, + Shape::CreatedFaces & faces) const; }; -- cgit v1.2.3 From fe1913b3f3742077763d7a6fc9fcac219900a4ae Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 20 Mar 2023 18:55:44 +0000 Subject: Slightly tidier FaceController? It's still a mess --- assetFactory/faceController.cpp | 126 +++++++++++++++++++++------------------- assetFactory/faceController.h | 3 + 2 files changed, 68 insertions(+), 61 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/faceController.cpp b/assetFactory/faceController.cpp index 6493300..bafbee2 100644 --- a/assetFactory/faceController.cpp +++ b/assetFactory/faceController.cpp @@ -14,82 +14,86 @@ FaceController::apply(ModelFactoryMesh & mesh, const StyleStack & parents, const }); } +std::string +FaceController::getAdjacentFaceName( + const ModelFactoryMesh & mesh, const std::span ofrange, OpenMesh::FaceHandle nf) +{ + const auto nfrange = mesh.ff_range(nf); + if (const auto target = std::find_first_of(ofrange.begin(), ofrange.end(), nfrange.begin(), nfrange.end()); + target != ofrange.end()) { + return mesh.property(mesh.nameFaceProperty, *target); + }; + return {}; +}; + void FaceController::applySingle(ModelFactoryMesh & mesh, const StyleStack & parents, const std::string & name, Shape::CreatedFaces & faces) const { - const auto getAdjacentFaceName = [&mesh](const auto & ofrange, OpenMesh::FaceHandle nf) -> std::string { - const auto nfrange = mesh.ff_range(nf); - if (const auto target = std::find_first_of(ofrange.begin(), ofrange.end(), nfrange.begin(), nfrange.end()); - target != ofrange.end()) { - return mesh.property(mesh.nameFaceProperty, *target); - }; - return {}; - }; - const auto controlledFaces {materializeRange(faces.equal_range(name))}; if (controlledFaces.empty()) { throw std::runtime_error("Named face(s) do not exist: " + name); } if (!type.empty()) { - const auto mutation = getMatrix(); faces.erase(name); - for (const auto & cf : controlledFaces) { - // get points - const auto baseVertices {materializeRange(mesh.fv_range(cf.second))}; - auto points = std::accumulate(baseVertices.begin(), baseVertices.end(), std::vector {}, - [&mesh](auto && out, auto && v) { - out.push_back(mesh.point(v)); - return std::move(out); - }); - const auto vertexCount = points.size(); - const auto centre = mesh.calc_face_centroid(cf.second); - if (type == "extrude") { - Shape::CreatedFaces newFaces; - // mutate points - std::for_each(points.begin(), points.end(), [&mutation, ¢re](auto && p) { - p = centre + ((p - centre) % mutation); - }); - // create new vertices - std::vector vertices; - std::transform(points.begin(), points.end(), std::back_inserter(vertices), [&mesh](auto && p) { - return mesh.add_vertex(p); - }); - // create new faces - const auto ofrange = materializeRange(mesh.ff_range(cf.second)); - mesh.delete_face(cf.second); - for (size_t idx {}; idx < vertexCount; ++idx) { - const auto next = (idx + 1) % vertexCount; - const auto newFace - = mesh.add_face({baseVertices[idx], baseVertices[next], vertices[next], vertices[idx]}); - auto & newFaceName = mesh.property(mesh.nameFaceProperty, newFace); - newFaceName = getAdjacentFaceName(ofrange, newFace); - newFaces.emplace(newFaceName, newFace); - } - newFaces.emplace(name, mesh.add_face(vertices)); - if (smooth) { - for (const auto & [name, face] : newFaces) { - mesh.property(mesh.smoothFaceProperty, face) = true; - } - } - applyStyle(mesh, parents + this, newFaces); - for (const auto & [subFaceName, faceController] : faceControllers) { - faceController->apply(mesh, parents + this, subFaceName, newFaces); - } - faces.merge(std::move(newFaces)); - } - else { - mesh.property(mesh.smoothFaceProperty, cf.second) = smooth; - applyStyle(mesh, parents + this, cf.second); + } + for (const auto & [faceName, faceHandle] : controlledFaces) { + if (type == "extrude") { + auto newFaces = extrude(mesh, faceName, faceHandle); + applyStyle(mesh, parents + this, newFaces); + for (const auto & [subFaceName, faceController] : faceControllers) { + faceController->apply(mesh, parents + this, subFaceName, newFaces); } + faces.merge(std::move(newFaces)); } - } - else { - for (const auto & cf : controlledFaces) { - applyStyle(mesh, parents + this, cf.second); + else { + mesh.property(mesh.smoothFaceProperty, faceHandle) = smooth; + applyStyle(mesh, parents + this, faceHandle); } } + for (const auto & [faceName, faceHandle] : controlledFaces) { + mesh.property(mesh.smoothFaceProperty, faceHandle) = smooth; + applyStyle(mesh, parents + this, faceHandle); + } +} + +Shape::CreatedFaces +FaceController::extrude(ModelFactoryMesh & mesh, const std::string & faceName, OpenMesh::FaceHandle faceHandle) const +{ + // get points + const auto baseVertices {materializeRange(mesh.fv_range(faceHandle))}; + auto points = std::accumulate( + baseVertices.begin(), baseVertices.end(), std::vector {}, [&mesh](auto && out, auto && v) { + out.push_back(mesh.point(v)); + return std::move(out); + }); + const auto vertexCount = points.size(); + const auto centre = mesh.calc_face_centroid(faceHandle); + Shape::CreatedFaces newFaces; + // mutate points + std::for_each(points.begin(), points.end(), [mutation = getMatrix(), ¢re](auto && p) { + p = centre + ((p - centre) % mutation); + }); + // create new vertices + std::vector vertices; + std::transform(points.begin(), points.end(), std::back_inserter(vertices), [&mesh](auto && p) { + return mesh.add_vertex(p); + }); + // create new faces + const auto ofrange = materializeRange(mesh.ff_range(faceHandle)); + mesh.delete_face(faceHandle); + for (size_t idx {}; idx < vertexCount; ++idx) { + const auto next = (idx + 1) % vertexCount; + const auto newFace = mesh.add_face({baseVertices[idx], baseVertices[next], vertices[next], vertices[idx]}); + auto & newFaceName = mesh.property(mesh.nameFaceProperty, newFace); + newFaceName = getAdjacentFaceName(mesh, ofrange, newFace); + newFaces.emplace(newFaceName, newFace); + mesh.property(mesh.smoothFaceProperty, newFace) = smooth; + } + mesh.property(mesh.smoothFaceProperty, newFaces.emplace(faceName, mesh.add_face(vertices))->second) = smooth; + + return newFaces; } bool diff --git a/assetFactory/faceController.h b/assetFactory/faceController.h index 890aafa..962a516 100644 --- a/assetFactory/faceController.h +++ b/assetFactory/faceController.h @@ -31,4 +31,7 @@ private: void applySingle(ModelFactoryMesh & mesh, const Style::StyleStack & parents, const std::string & name, Shape::CreatedFaces & faces) const; + static std::string getAdjacentFaceName(const ModelFactoryMesh & mesh, + const std::span ofrange, OpenMesh::FaceHandle nf); + Shape::CreatedFaces extrude(ModelFactoryMesh & mesh, const std::string & faceName, OpenMesh::FaceHandle) const; }; -- cgit v1.2.3 From 2508112e2853e1a6c012b19c7232aa09f98d3969 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 20 Mar 2023 23:30:21 +0000 Subject: Move smooth property into Style and make it optional This allows it to cascade down as faces are created and also be overridden as required --- assetFactory/faceController.cpp | 8 ++------ assetFactory/faceController.h | 1 - assetFactory/style.cpp | 6 +++++- assetFactory/style.h | 1 + 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/faceController.cpp b/assetFactory/faceController.cpp index bafbee2..2367f8d 100644 --- a/assetFactory/faceController.cpp +++ b/assetFactory/faceController.cpp @@ -48,12 +48,10 @@ FaceController::applySingle(ModelFactoryMesh & mesh, const StyleStack & parents, faces.merge(std::move(newFaces)); } else { - mesh.property(mesh.smoothFaceProperty, faceHandle) = smooth; applyStyle(mesh, parents + this, faceHandle); } } for (const auto & [faceName, faceHandle] : controlledFaces) { - mesh.property(mesh.smoothFaceProperty, faceHandle) = smooth; applyStyle(mesh, parents + this, faceHandle); } } @@ -89,9 +87,8 @@ FaceController::extrude(ModelFactoryMesh & mesh, const std::string & faceName, O auto & newFaceName = mesh.property(mesh.nameFaceProperty, newFace); newFaceName = getAdjacentFaceName(mesh, ofrange, newFace); newFaces.emplace(newFaceName, newFace); - mesh.property(mesh.smoothFaceProperty, newFace) = smooth; } - mesh.property(mesh.smoothFaceProperty, newFaces.emplace(faceName, mesh.add_face(vertices))->second) = smooth; + newFaces.emplace(faceName, mesh.add_face(vertices)); return newFaces; } @@ -99,7 +96,6 @@ FaceController::extrude(ModelFactoryMesh & mesh, const std::string & faceName, O bool FaceController::persist(Persistence::PersistenceStore & store) { - return STORE_TYPE && STORE_MEMBER(id) && Style::persist(store) && STORE_MEMBER(type) && STORE_MEMBER(smooth) - && Mutation::persist(store) + return STORE_TYPE && STORE_MEMBER(id) && Style::persist(store) && STORE_MEMBER(type) && Mutation::persist(store) && STORE_NAME_HELPER("face", faceControllers, Persistence::MapByMember); } diff --git a/assetFactory/faceController.h b/assetFactory/faceController.h index 962a516..851292a 100644 --- a/assetFactory/faceController.h +++ b/assetFactory/faceController.h @@ -17,7 +17,6 @@ public: std::string id; std::string type; - bool smooth {false}; FaceControllers faceControllers; private: diff --git a/assetFactory/style.cpp b/assetFactory/style.cpp index d1d4adc..12346a6 100644 --- a/assetFactory/style.cpp +++ b/assetFactory/style.cpp @@ -19,6 +19,9 @@ void Style::applyStyle( ModelFactoryMesh & mesh, const ModelFactoryMesh::FaceHandle & face, EffectiveColour effectiveColour) const { + if (smooth.has_value()) { + mesh.property(mesh.smoothFaceProperty, face) = smooth.value(); + } if (texture.empty()) { if (effectiveColour.has_value()) { mesh.set_color(face, effectiveColour->get()); @@ -60,5 +63,6 @@ Style::persist(Persistence::PersistenceStore & store) } }; - return STORE_HELPER(colour, ColourParser) && STORE_MEMBER(texture) && STORE_MEMBER(textureRotation); + return STORE_HELPER(colour, ColourParser) && STORE_MEMBER(smooth) && STORE_MEMBER(texture) + && STORE_MEMBER(textureRotation); } diff --git a/assetFactory/style.h b/assetFactory/style.h index f3bc707..d931f98 100644 --- a/assetFactory/style.h +++ b/assetFactory/style.h @@ -31,6 +31,7 @@ public: static EffectiveColour getColour(const StyleStack & parents); ColourAlpha colour {}; + std::optional smooth; std::string texture; std::string textureRotation; // Multiples of 90deg, no int/enum support -- cgit v1.2.3 From 37e39b6c00834f4711576c7f77cb0b7b5d558956 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 21 Mar 2023 00:18:25 +0000 Subject: Apply styles in first loop over controlled faces --- assetFactory/faceController.cpp | 5 ----- 1 file changed, 5 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/faceController.cpp b/assetFactory/faceController.cpp index 2367f8d..25bf833 100644 --- a/assetFactory/faceController.cpp +++ b/assetFactory/faceController.cpp @@ -47,11 +47,6 @@ FaceController::applySingle(ModelFactoryMesh & mesh, const StyleStack & parents, } faces.merge(std::move(newFaces)); } - else { - applyStyle(mesh, parents + this, faceHandle); - } - } - for (const auto & [faceName, faceHandle] : controlledFaces) { applyStyle(mesh, parents + this, faceHandle); } } -- cgit v1.2.3 From 2bcbb86db4061e32005adea8806e4ac552691bcf Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 7 Apr 2023 23:55:09 +0100 Subject: Extend face controller to support splitting a face along a plane Individual parts of the splits faces can then be styled separately --- assetFactory/faceController.cpp | 83 +++++++++++++++++++++++++++++++++++++---- assetFactory/faceController.h | 18 +++++++++ 2 files changed, 93 insertions(+), 8 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/faceController.cpp b/assetFactory/faceController.cpp index 25bf833..28812d8 100644 --- a/assetFactory/faceController.cpp +++ b/assetFactory/faceController.cpp @@ -2,6 +2,7 @@ #include "collections.hpp" #include "maths.h" #include "modelFactoryMesh.h" +#include void FaceController::apply(ModelFactoryMesh & mesh, const StyleStack & parents, const std::string & names, @@ -30,24 +31,29 @@ void FaceController::applySingle(ModelFactoryMesh & mesh, const StyleStack & parents, const std::string & name, Shape::CreatedFaces & faces) const { - const auto controlledFaces {materializeRange(faces.equal_range(name))}; - if (controlledFaces.empty()) { - throw std::runtime_error("Named face(s) do not exist: " + name); - } + auto controlledFaces {materializeRange(faces.equal_range(name))}; - if (!type.empty()) { + if (!type.empty() || !splits.empty()) { faces.erase(name); } - for (const auto & [faceName, faceHandle] : controlledFaces) { + for (auto & [faceName, faceHandle] : controlledFaces) { + Shape::CreatedFaces newFaces; + for (const auto & [newFaceSuffix, splitDef] : splits) { + newFaces.merge(split(mesh, name + newFaceSuffix, faceHandle, *splitDef)); + } if (type == "extrude") { - auto newFaces = extrude(mesh, faceName, faceHandle); + newFaces.merge(extrude(mesh, name, faceHandle)); + } + if (!newFaces.empty()) { applyStyle(mesh, parents + this, newFaces); for (const auto & [subFaceName, faceController] : faceControllers) { faceController->apply(mesh, parents + this, subFaceName, newFaces); } faces.merge(std::move(newFaces)); } - applyStyle(mesh, parents + this, faceHandle); + else { + applyStyle(mesh, parents + this, faceHandle); + } } } @@ -88,9 +94,70 @@ FaceController::extrude(ModelFactoryMesh & mesh, const std::string & faceName, O return newFaces; } +enum class PlaneRelation { Above, Below, On }; +Shape::CreatedFaces +FaceController::split( + ModelFactoryMesh & mesh, const std::string & name, OpenMesh::FaceHandle & fh, const Split & split) const +{ + // Map face vertex handles to their relationship to the split plane + const auto vertices = materializeRange(mesh.fv_range(fh)); + auto vertexRelations = vertices * [&split, &mesh](OpenMesh::VertexHandle vh) { + const auto d = glm::dot(split.normal, mesh.point(vh) - split.origin); + return std::make_pair(vh, d < 0.f ? PlaneRelation::Below : d > 0.f ? PlaneRelation::Above : PlaneRelation::On); + }; + // Insert new vertices where half edges intersect the split plane + for (size_t curIdx = 0; curIdx < vertexRelations.size(); ++curIdx) { + const size_t nextIdx = (curIdx + 1) % vertexRelations.size(); + const auto ¤t = vertexRelations[curIdx], next = vertexRelations[nextIdx]; + if ((current.second == PlaneRelation::Above && next.second == PlaneRelation::Below) + || (current.second == PlaneRelation::Below && next.second == PlaneRelation::Above)) { + const auto origin = mesh.point(current.first), dir = glm::normalize(mesh.point(next.first) - origin); + + float dist {}; + glm::intersectRayPlane(origin, dir, split.origin, split.normal, dist); + const auto newv = mesh.add_vertex(origin + (dir * dist)); + auto where = vertexRelations.begin(); + ++curIdx; + std::advance(where, curIdx); + vertexRelations.emplace(where, newv, PlaneRelation::On); + } + } + // Create vertex vectors + std::array, 2> out; + auto filterVertices = [&vertexRelations](auto & out, auto notRelation) { + for (const auto & vhr : vertexRelations) { + if (vhr.second != notRelation) { + out.emplace_back(vhr.first); + } + } + }; + filterVertices(out.front(), PlaneRelation::Above); + filterVertices(out.back(), PlaneRelation::Below); + + if (out.back().size() > 2) { + Shape::CreatedFaces newFaces; + const auto oldName = mesh.property(mesh.nameFaceProperty, fh); + mesh.delete_face(fh); + const auto newf1 = newFaces.insert(mesh.add_namedFace(oldName, out.front()))->second; + const auto newf2 = newFaces.insert(mesh.add_namedFace(name, out.back()))->second; + mesh.copy_property(mesh.smoothFaceProperty, fh, newf1); + mesh.copy_property(mesh.smoothFaceProperty, fh, newf2); + fh = newf1; + return newFaces; + } + return {}; +} + bool FaceController::persist(Persistence::PersistenceStore & store) { return STORE_TYPE && STORE_MEMBER(id) && Style::persist(store) && STORE_MEMBER(type) && Mutation::persist(store) + && STORE_NAME_HELPER("split", splits, Persistence::MapByMember) && STORE_NAME_HELPER("face", faceControllers, Persistence::MapByMember); } + +bool +FaceController::Split::persist(Persistence::PersistenceStore & store) +{ + return STORE_TYPE && STORE_MEMBER(id) && STORE_MEMBER(origin) && STORE_MEMBER(normal); +} diff --git a/assetFactory/faceController.h b/assetFactory/faceController.h index 851292a..91860f4 100644 --- a/assetFactory/faceController.h +++ b/assetFactory/faceController.h @@ -10,7 +10,22 @@ class FaceController : public Mutation, public Style, public Persistence::Persistable { public: + class Split : public Persistable { + public: + std::string id; + glm::vec3 origin, normal; + + private: + friend Persistence::SelectionPtrBase>; + bool persist(Persistence::PersistenceStore & store) override; + std::string + getId() const override + { + return {}; + }; + }; using FaceControllers = std::map>; + using Splits = std::map>; void apply(ModelFactoryMesh & mesh, const Style::StyleStack & parents, const std::string & names, Shape::CreatedFaces & faces) const; @@ -18,6 +33,7 @@ public: std::string id; std::string type; FaceControllers faceControllers; + Splits splits; private: friend Persistence::SelectionPtrBase>; @@ -33,4 +49,6 @@ private: static std::string getAdjacentFaceName(const ModelFactoryMesh & mesh, const std::span ofrange, OpenMesh::FaceHandle nf); Shape::CreatedFaces extrude(ModelFactoryMesh & mesh, const std::string & faceName, OpenMesh::FaceHandle) const; + Shape::CreatedFaces split( + ModelFactoryMesh & mesh, const std::string & faceName, OpenMesh::FaceHandle &, const Split &) const; }; -- cgit v1.2.3 From 7f9e28e4e91ac757680fef56e771122cde14c9db Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 8 Apr 2023 11:42:43 +0100 Subject: Remember the name of the adjacent face of each halfedge of each named face Used when extruding to remember what the new face name will be, even after the adjacent face has been removed/replaced/split/etc --- assetFactory/modelFactoryMesh.cpp | 16 ++++++++++++++++ assetFactory/modelFactoryMesh.h | 8 ++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/modelFactoryMesh.cpp b/assetFactory/modelFactoryMesh.cpp index 806ac3b..e640502 100644 --- a/assetFactory/modelFactoryMesh.cpp +++ b/assetFactory/modelFactoryMesh.cpp @@ -4,4 +4,20 @@ ModelFactoryMesh::ModelFactoryMesh() { add_property(smoothFaceProperty); add_property(nameFaceProperty); + add_property(nameAdjFaceProperty); +} + +void +ModelFactoryMesh::configNamedFace(const std::string & name, OpenMesh::FaceHandle handle) +{ + property(nameFaceProperty, handle) = name; + const auto halfEdges = fh_range(handle); + for (const auto & he : halfEdges) { + if (auto ofh = opposite_face_handle(he); ofh.is_valid()) { + property(nameAdjFaceProperty, he) = property(nameFaceProperty, ofh); + } + if (auto oheh = opposite_halfedge_handle(he); oheh.is_valid()) { + property(nameAdjFaceProperty, oheh) = name; + } + } } diff --git a/assetFactory/modelFactoryMesh.h b/assetFactory/modelFactoryMesh.h index a862dc1..8ac2edd 100644 --- a/assetFactory/modelFactoryMesh.h +++ b/assetFactory/modelFactoryMesh.h @@ -48,13 +48,17 @@ struct ModelFactoryMesh : public OpenMesh::PolyMesh_ArrayKernelT smoothFaceProperty; OpenMesh::FPropHandleT nameFaceProperty; + OpenMesh::HPropHandleT nameAdjFaceProperty; template std::pair add_namedFace(std::string name, Vs &&... vs) { const auto handle = add_face(std::forward(vs)...); - property(nameFaceProperty, handle) = name; - return std::make_pair(name, handle); + configNamedFace(name, handle); + return {std::move(name), handle}; } + +private: + void configNamedFace(const std::string & name, OpenMesh::FaceHandle); }; -- cgit v1.2.3 From 5ffac39b0edfe04c081191b399cadcd69ad3ccd2 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 8 Apr 2023 11:46:51 +0100 Subject: Generate extrusion face names from halfedge adjacent face names --- assetFactory/faceController.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/faceController.cpp b/assetFactory/faceController.cpp index 28812d8..92cc8d2 100644 --- a/assetFactory/faceController.cpp +++ b/assetFactory/faceController.cpp @@ -69,7 +69,6 @@ FaceController::extrude(ModelFactoryMesh & mesh, const std::string & faceName, O }); const auto vertexCount = points.size(); const auto centre = mesh.calc_face_centroid(faceHandle); - Shape::CreatedFaces newFaces; // mutate points std::for_each(points.begin(), points.end(), [mutation = getMatrix(), ¢re](auto && p) { p = centre + ((p - centre) % mutation); @@ -79,17 +78,22 @@ FaceController::extrude(ModelFactoryMesh & mesh, const std::string & faceName, O std::transform(points.begin(), points.end(), std::back_inserter(vertices), [&mesh](auto && p) { return mesh.add_vertex(p); }); + // get new faces names + std::vector faceNames; + for (size_t idx {}; idx < vertexCount; ++idx) { + const auto next = (idx + 1) % vertexCount; + const auto existingEdge = mesh.find_halfedge(baseVertices[idx], baseVertices[next]); + faceNames.push_back(mesh.property(mesh.nameAdjFaceProperty, existingEdge)); + } // create new faces - const auto ofrange = materializeRange(mesh.ff_range(faceHandle)); mesh.delete_face(faceHandle); + Shape::CreatedFaces newFaces; for (size_t idx {}; idx < vertexCount; ++idx) { const auto next = (idx + 1) % vertexCount; - const auto newFace = mesh.add_face({baseVertices[idx], baseVertices[next], vertices[next], vertices[idx]}); - auto & newFaceName = mesh.property(mesh.nameFaceProperty, newFace); - newFaceName = getAdjacentFaceName(mesh, ofrange, newFace); - newFaces.emplace(newFaceName, newFace); + newFaces.emplace(mesh.add_namedFace( + faceNames[idx], baseVertices[idx], baseVertices[next], vertices[next], vertices[idx])); } - newFaces.emplace(faceName, mesh.add_face(vertices)); + newFaces.emplace(mesh.add_namedFace(faceName, vertices)); return newFaces; } -- cgit v1.2.3 From 144f9b57295f7fee9306ee1a4480c165a834e6ca Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 8 Apr 2023 11:48:17 +0100 Subject: Remove no longer required getAdjacentFaceName --- assetFactory/faceController.cpp | 12 ------------ assetFactory/faceController.h | 2 -- 2 files changed, 14 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/faceController.cpp b/assetFactory/faceController.cpp index 92cc8d2..7e4b0e1 100644 --- a/assetFactory/faceController.cpp +++ b/assetFactory/faceController.cpp @@ -15,18 +15,6 @@ FaceController::apply(ModelFactoryMesh & mesh, const StyleStack & parents, const }); } -std::string -FaceController::getAdjacentFaceName( - const ModelFactoryMesh & mesh, const std::span ofrange, OpenMesh::FaceHandle nf) -{ - const auto nfrange = mesh.ff_range(nf); - if (const auto target = std::find_first_of(ofrange.begin(), ofrange.end(), nfrange.begin(), nfrange.end()); - target != ofrange.end()) { - return mesh.property(mesh.nameFaceProperty, *target); - }; - return {}; -}; - void FaceController::applySingle(ModelFactoryMesh & mesh, const StyleStack & parents, const std::string & name, Shape::CreatedFaces & faces) const diff --git a/assetFactory/faceController.h b/assetFactory/faceController.h index 91860f4..8d30dc6 100644 --- a/assetFactory/faceController.h +++ b/assetFactory/faceController.h @@ -46,8 +46,6 @@ private: void applySingle(ModelFactoryMesh & mesh, const Style::StyleStack & parents, const std::string & name, Shape::CreatedFaces & faces) const; - static std::string getAdjacentFaceName(const ModelFactoryMesh & mesh, - const std::span ofrange, OpenMesh::FaceHandle nf); Shape::CreatedFaces extrude(ModelFactoryMesh & mesh, const std::string & faceName, OpenMesh::FaceHandle) const; Shape::CreatedFaces split( ModelFactoryMesh & mesh, const std::string & faceName, OpenMesh::FaceHandle &, const Split &) const; -- cgit v1.2.3 From fe5a06851823ac6da841a513cf59140c63ff69f3 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 8 Apr 2023 14:08:25 +0100 Subject: Simplify extruding --- assetFactory/faceController.cpp | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/faceController.cpp b/assetFactory/faceController.cpp index 7e4b0e1..7992fba 100644 --- a/assetFactory/faceController.cpp +++ b/assetFactory/faceController.cpp @@ -50,23 +50,13 @@ FaceController::extrude(ModelFactoryMesh & mesh, const std::string & faceName, O { // get points const auto baseVertices {materializeRange(mesh.fv_range(faceHandle))}; - auto points = std::accumulate( - baseVertices.begin(), baseVertices.end(), std::vector {}, [&mesh](auto && out, auto && v) { - out.push_back(mesh.point(v)); - return std::move(out); - }); - const auto vertexCount = points.size(); - const auto centre = mesh.calc_face_centroid(faceHandle); - // mutate points - std::for_each(points.begin(), points.end(), [mutation = getMatrix(), ¢re](auto && p) { - p = centre + ((p - centre) % mutation); - }); // create new vertices - std::vector vertices; - std::transform(points.begin(), points.end(), std::back_inserter(vertices), [&mesh](auto && p) { - return mesh.add_vertex(p); - }); + const auto vertices + = baseVertices * [&mesh, mutation = getMatrix(), centre = mesh.calc_face_centroid(faceHandle)](auto && v) { + return mesh.add_vertex(centre + ((mesh.point(v) - centre) % mutation)); + }; // get new faces names + const auto vertexCount = baseVertices.size(); std::vector faceNames; for (size_t idx {}; idx < vertexCount; ++idx) { const auto next = (idx + 1) % vertexCount; -- cgit v1.2.3 From b222c21715384efc2eaa53d3ba295fb34da5b599 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 9 Apr 2023 12:24:55 +0100 Subject: Start to factor out geometric place from face controller split --- assetFactory/faceController.cpp | 16 ++++++++-------- assetFactory/faceController.h | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/faceController.cpp b/assetFactory/faceController.cpp index 7992fba..37aaa4c 100644 --- a/assetFactory/faceController.cpp +++ b/assetFactory/faceController.cpp @@ -76,7 +76,6 @@ FaceController::extrude(ModelFactoryMesh & mesh, const std::string & faceName, O return newFaces; } -enum class PlaneRelation { Above, Below, On }; Shape::CreatedFaces FaceController::split( ModelFactoryMesh & mesh, const std::string & name, OpenMesh::FaceHandle & fh, const Split & split) const @@ -84,15 +83,16 @@ FaceController::split( // Map face vertex handles to their relationship to the split plane const auto vertices = materializeRange(mesh.fv_range(fh)); auto vertexRelations = vertices * [&split, &mesh](OpenMesh::VertexHandle vh) { - const auto d = glm::dot(split.normal, mesh.point(vh) - split.origin); - return std::make_pair(vh, d < 0.f ? PlaneRelation::Below : d > 0.f ? PlaneRelation::Above : PlaneRelation::On); + return std::make_pair(vh, split.getRelation(mesh.point(vh))); }; // Insert new vertices where half edges intersect the split plane for (size_t curIdx = 0; curIdx < vertexRelations.size(); ++curIdx) { const size_t nextIdx = (curIdx + 1) % vertexRelations.size(); const auto ¤t = vertexRelations[curIdx], next = vertexRelations[nextIdx]; - if ((current.second == PlaneRelation::Above && next.second == PlaneRelation::Below) - || (current.second == PlaneRelation::Below && next.second == PlaneRelation::Above)) { + if ((current.second == GeometricPlane::PlaneRelation::Above + && next.second == GeometricPlane::PlaneRelation::Below) + || (current.second == GeometricPlane::PlaneRelation::Below + && next.second == GeometricPlane::PlaneRelation::Above)) { const auto origin = mesh.point(current.first), dir = glm::normalize(mesh.point(next.first) - origin); float dist {}; @@ -101,7 +101,7 @@ FaceController::split( auto where = vertexRelations.begin(); ++curIdx; std::advance(where, curIdx); - vertexRelations.emplace(where, newv, PlaneRelation::On); + vertexRelations.emplace(where, newv, GeometricPlane::PlaneRelation::On); } } // Create vertex vectors @@ -113,8 +113,8 @@ FaceController::split( } } }; - filterVertices(out.front(), PlaneRelation::Above); - filterVertices(out.back(), PlaneRelation::Below); + filterVertices(out.front(), GeometricPlane::PlaneRelation::Above); + filterVertices(out.back(), GeometricPlane::PlaneRelation::Below); if (out.back().size() > 2) { Shape::CreatedFaces newFaces; diff --git a/assetFactory/faceController.h b/assetFactory/faceController.h index 8d30dc6..0376241 100644 --- a/assetFactory/faceController.h +++ b/assetFactory/faceController.h @@ -1,5 +1,6 @@ #pragma once +#include "geometricPlane.h" #include "modelFactoryMesh_fwd.h" #include "mutation.h" #include "persistence.h" @@ -10,10 +11,9 @@ class FaceController : public Mutation, public Style, public Persistence::Persistable { public: - class Split : public Persistable { + class Split : public Persistable, public GeometricPlane { public: std::string id; - glm::vec3 origin, normal; private: friend Persistence::SelectionPtrBase>; -- cgit v1.2.3 From a74ee2960bd8c930b91dbc897c27d134f5f2c2f0 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 9 Apr 2023 15:51:47 +0100 Subject: Move remaining split/plane functions to use library --- assetFactory/faceController.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'assetFactory') diff --git a/assetFactory/faceController.cpp b/assetFactory/faceController.cpp index 37aaa4c..b305f1c 100644 --- a/assetFactory/faceController.cpp +++ b/assetFactory/faceController.cpp @@ -2,7 +2,7 @@ #include "collections.hpp" #include "maths.h" #include "modelFactoryMesh.h" -#include +#include "ray.hpp" void FaceController::apply(ModelFactoryMesh & mesh, const StyleStack & parents, const std::string & names, @@ -89,15 +89,11 @@ FaceController::split( for (size_t curIdx = 0; curIdx < vertexRelations.size(); ++curIdx) { const size_t nextIdx = (curIdx + 1) % vertexRelations.size(); const auto ¤t = vertexRelations[curIdx], next = vertexRelations[nextIdx]; - if ((current.second == GeometricPlane::PlaneRelation::Above - && next.second == GeometricPlane::PlaneRelation::Below) - || (current.second == GeometricPlane::PlaneRelation::Below - && next.second == GeometricPlane::PlaneRelation::Above)) { - const auto origin = mesh.point(current.first), dir = glm::normalize(mesh.point(next.first) - origin); - - float dist {}; - glm::intersectRayPlane(origin, dir, split.origin, split.normal, dist); - const auto newv = mesh.add_vertex(origin + (dir * dist)); + if (GeometricPlane::isIntersect(current.second, next.second)) { + const auto ray = Ray::fromPoints(mesh.point(current.first), mesh.point(next.first)); + const auto intersect = split.getRayIntersectPosition(ray); + assert(intersect); + const auto newv = mesh.add_vertex(intersect->position); auto where = vertexRelations.begin(); ++curIdx; std::advance(where, curIdx); -- cgit v1.2.3