diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2023-02-24 19:30:30 +0000 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2023-02-24 19:30:30 +0000 |
commit | 7d0decccaac3aa564b549d91a36279e7aca0814e (patch) | |
tree | 749ceff26556ed201a055b8d8a70636b50c562f7 | |
parent | Support for model colours mixed with textures (diff) | |
download | ilt-7d0decccaac3aa564b549d91a36279e7aca0814e.tar.bz2 ilt-7d0decccaac3aa564b549d91a36279e7aca0814e.tar.xz ilt-7d0decccaac3aa564b549d91a36279e7aca0814e.zip |
Support for recursive colouring of asset factory faces
Updates colours in sample model.
-rw-r--r-- | assetFactory/faceController.cpp | 29 | ||||
-rw-r--r-- | assetFactory/faceController.h | 7 | ||||
-rw-r--r-- | assetFactory/factoryMesh.cpp | 4 | ||||
-rw-r--r-- | assetFactory/modelFactoryMesh.h | 3 | ||||
-rw-r--r-- | assetFactory/style.cpp | 59 | ||||
-rw-r--r-- | assetFactory/style.h | 22 | ||||
-rw-r--r-- | assetFactory/use.cpp | 5 | ||||
-rw-r--r-- | assetFactory/use.h | 4 | ||||
-rw-r--r-- | res/brush47.xml | 16 |
9 files changed, 124 insertions, 25 deletions
diff --git a/assetFactory/faceController.cpp b/assetFactory/faceController.cpp index 499f7e4..9f057da 100644 --- a/assetFactory/faceController.cpp +++ b/assetFactory/faceController.cpp @@ -1,14 +1,19 @@ #include "faceController.h" +#include "collections.hpp" #include "maths.h" #include "modelFactoryMesh.h" void -FaceController::apply(ModelFactoryMesh & mesh, const std::string & name, Shape::CreatedFaces & faces) const +FaceController::apply(ModelFactoryMesh & mesh, const StyleStack & parents, const std::string & name, + Shape::CreatedFaces & faces) const { + const auto controlledFacesRange = faces.equal_range(name); + const std::vector controlledFaces(controlledFacesRange.first, controlledFacesRange.second); + if (controlledFaces.empty()) { + throw std::runtime_error("Named face(s) do not exist: " + name); + } if (!type.empty()) { const auto mutation = getMatrix(); - const auto controlledFacesRange = faces.equal_range(name); - const std::vector controlledFaces(controlledFacesRange.first, controlledFacesRange.second); faces.erase(name); for (const auto & cf : controlledFaces) { // get face vertices @@ -23,9 +28,6 @@ FaceController::apply(ModelFactoryMesh & mesh, const std::string & name, Shape:: const auto vertexCount = points.size(); const auto centre = std::accumulate(points.begin(), points.end(), glm::vec3 {}) / static_cast<float>(vertexCount); - if (smooth) { - mesh.property(mesh.smoothFaceProperty, cf.second) = true; - } if (type == "extrude") { Shape::CreatedFaces newFaces; // mutate points @@ -38,7 +40,6 @@ FaceController::apply(ModelFactoryMesh & mesh, const std::string & name, Shape:: return mesh.add_vertex({p.x, p.y, p.z}); }); // create new faces - mesh.delete_face(cf.second); for (size_t idx {}; idx < vertexCount; ++idx) { const auto next = (idx + 1) % vertexCount; @@ -51,11 +52,21 @@ FaceController::apply(ModelFactoryMesh & mesh, const std::string & name, Shape:: mesh.property(mesh.smoothFaceProperty, face) = true; } } + applyStyle(mesh, parents + this, newFaces); for (const auto & [name, faceController] : faceControllers) { - faceController->apply(mesh, name, newFaces); + faceController->apply(mesh, parents + this, name, newFaces); } faces.merge(std::move(newFaces)); } + else { + mesh.property(mesh.smoothFaceProperty, cf.second) = smooth; + applyStyle(mesh, parents + this, cf.second); + } + } + } + else { + for (const auto & cf : controlledFaces) { + applyStyle(mesh, parents + this, cf.second); } } } @@ -63,7 +74,7 @@ FaceController::apply(ModelFactoryMesh & mesh, const std::string & name, Shape:: bool FaceController::persist(Persistence::PersistenceStore & store) { - return STORE_TYPE && STORE_MEMBER(id) && STORE_MEMBER(colour) && STORE_MEMBER(type) && STORE_MEMBER(smooth) + return STORE_TYPE && STORE_MEMBER(id) && Style::persist(store) && STORE_MEMBER(type) && STORE_MEMBER(smooth) && STORE_MEMBER(scale) && STORE_MEMBER(position) && STORE_MEMBER(rotation) && STORE_NAME_HELPER("face", faceControllers, Persistence::MapByMember<FaceControllers>); } diff --git a/assetFactory/faceController.h b/assetFactory/faceController.h index 296210d..0618388 100644 --- a/assetFactory/faceController.h +++ b/assetFactory/faceController.h @@ -4,17 +4,18 @@ #include "mutation.h" #include "persistence.h" #include "shape.h" +#include "style.h" #include <map> #include <string> -class FaceController : public Mutation, public Persistence::Persistable { +class FaceController : public Mutation, public Style, public Persistence::Persistable { public: using FaceControllers = std::map<std::string, std::unique_ptr<FaceController>>; - void apply(ModelFactoryMesh & mesh, const std::string & name, Shape::CreatedFaces & faces) const; + void apply(ModelFactoryMesh & mesh, const Style::StyleStack & parents, const std::string & name, + Shape::CreatedFaces & faces) const; std::string id; - std::string colour; std::string type; bool smooth {false}; FaceControllers faceControllers; diff --git a/assetFactory/factoryMesh.cpp b/assetFactory/factoryMesh.cpp index 0fb72ad..0cfed85 100644 --- a/assetFactory/factoryMesh.cpp +++ b/assetFactory/factoryMesh.cpp @@ -21,10 +21,12 @@ FactoryMesh::createMesh() const std::vector<Vertex> vertices; 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)) { vertices.emplace_back(mesh.point(vertex), NullUV, smooth ? mesh.property(mesh.vertex_normals_pph(), vertex) - : mesh.property(mesh.face_normals_pph(), face)); + : mesh.property(mesh.face_normals_pph(), face), + colour); } } return std::make_shared<Mesh>(vertices, vectorOfN(vertices.size())); diff --git a/assetFactory/modelFactoryMesh.h b/assetFactory/modelFactoryMesh.h index d0ffc26..7d222f5 100644 --- a/assetFactory/modelFactoryMesh.h +++ b/assetFactory/modelFactoryMesh.h @@ -20,11 +20,12 @@ namespace OpenMesh { } struct ModelFactoryTraits : public OpenMesh::DefaultTraits { - FaceAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status); + FaceAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status | OpenMesh::Attributes::Color); EdgeAttributes(OpenMesh::Attributes::Status); VertexAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status); using Point = OpenMesh::glmvec<float, 3>; using Normal = OpenMesh::glmvec<float, 3>; + using Color = OpenMesh::glmvec<float, 4>; }; struct ModelFactoryMesh : public OpenMesh::PolyMesh_ArrayKernelT<ModelFactoryTraits> { diff --git a/assetFactory/style.cpp b/assetFactory/style.cpp new file mode 100644 index 0000000..099d81a --- /dev/null +++ b/assetFactory/style.cpp @@ -0,0 +1,59 @@ +#include "style.h" + +ModelFactoryMesh::Color +Style::parseColour(const std::string_view & in) +{ + if (in.empty()) { + return {}; + } + if (in[0] == '#') { + ModelFactoryMesh::Color out {0, 0, 0, 1}; + std::generate_n(out.begin(), (in.length() - 1) / 2, [in = in.data() + 1]() mutable { + uint8_t channel; + std::from_chars(in, in + 2, channel, 16); + in += 2; + return static_cast<float>(channel) / 256.F; + }); + return out; + } + return {}; +} + +void +Style::applyStyle(ModelFactoryMesh & mesh, const StyleStack & parents, const Shape::CreatedFaces & faces) const +{ + if (const auto effectiveColour = getProperty(parents, &Style::colour); !effectiveColour.empty()) { + const auto parsedColour = parseColour(effectiveColour); + for (const auto & face : faces) { + mesh.set_color(face.second, parsedColour); + } + } +} + +void +Style::applyStyle(ModelFactoryMesh & mesh, const StyleStack & parents, const ModelFactoryMesh::FaceHandle & face) const +{ + if (const auto effectiveColour = getProperty(parents, &Style::colour); !effectiveColour.empty()) { + const auto parsedColour = parseColour(effectiveColour); + mesh.set_color(face, parsedColour); + } +} + +std::string_view +Style::getProperty(const StyleStack & parents, std::string Style::*member) +{ + if (const auto itr = std::find_if(parents.rbegin(), parents.rend(), + [&member](auto && s) { + return !(s->*member).empty(); + }); + itr != parents.rend()) { + return (*itr)->*member; + } + return {}; +} + +bool +Style::persist(Persistence::PersistenceStore & store) +{ + return STORE_MEMBER(colour); +} diff --git a/assetFactory/style.h b/assetFactory/style.h new file mode 100644 index 0000000..0c7ad5a --- /dev/null +++ b/assetFactory/style.h @@ -0,0 +1,22 @@ +#pragma once + +#include "modelFactoryMesh.h" +#include "persistence.h" +#include "shape.h" +#include <string> + +class Style { +public: + using StyleStack = std::vector<const Style *>; + + static ModelFactoryMesh::Color parseColour(const std::string_view &); + void applyStyle(ModelFactoryMesh &, const StyleStack & parents, const Shape::CreatedFaces &) const; + void applyStyle(ModelFactoryMesh &, const StyleStack & parents, const ModelFactoryMesh::FaceHandle &) const; + + static std::string_view getProperty(const StyleStack & parents, std::string Style::*member); + + std::string colour; + +protected: + bool persist(Persistence::PersistenceStore & store); +}; diff --git a/assetFactory/use.cpp b/assetFactory/use.cpp index 1f28332..a6fac5c 100644 --- a/assetFactory/use.cpp +++ b/assetFactory/use.cpp @@ -5,8 +5,9 @@ Shape::CreatedFaces Use::createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const { auto faces = type->createMesh(mesh, mutation * getMatrix()); + applyStyle(mesh, {this}, faces); for (const auto & [name, faceController] : faceControllers) { - faceController->apply(mesh, name, faces); + faceController->apply(mesh, {this}, name, faces); } return faces; } @@ -27,6 +28,6 @@ bool Use::persist(Persistence::PersistenceStore & store) { return STORE_TYPE && STORE_HELPER(type, Lookup) && STORE_MEMBER(position) && STORE_MEMBER(scale) - && STORE_MEMBER(rotation) && STORE_MEMBER(colour) + && STORE_MEMBER(rotation) && Style::persist(store) && STORE_NAME_HELPER("face", faceControllers, Persistence::MapByMember<FaceControllers>); } diff --git a/assetFactory/use.h b/assetFactory/use.h index 853af23..5b61eca 100644 --- a/assetFactory/use.h +++ b/assetFactory/use.h @@ -5,15 +5,15 @@ #include "persistence.h" #include "shape.h" #include "stdTypeDefs.hpp" +#include "style.h" -class Use : public StdTypeDefs<Use>, public Mutation, public Persistence::Persistable { +class Use : public StdTypeDefs<Use>, public Mutation, public Style, public Persistence::Persistable { public: using FaceControllers = std::map<std::string, std::unique_ptr<FaceController>>; Shape::CreatedFaces createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const; Shape::CPtr type; - std::string colour; FaceControllers faceControllers; private: diff --git a/res/brush47.xml b/res/brush47.xml index 9fd4fe2..fe3d114 100644 --- a/res/brush47.xml +++ b/res/brush47.xml @@ -14,19 +14,21 @@ </object> <asset id="brush-47" name="Brush 47"> <mesh id="body" size="2.69,19.38,3.9"> - <use type="cuboid" position="0,0,1.2" scale="2.69,19.38,1.5" colour="#1111dd"> - <face id="bottom" colour="#2C3539"/> - <face id="top" type="extrude" scale="1,0.95,1" position="0,0,1.0"> - <face id="top" type="extrude" scale="0.6,0.9,0" position="0,0,0.2" smooth="true"/> + <use type="cuboid" position="0,0,1.2" scale="2.69,19.38,1.5" colour="#2c4f5a"> + <face id="bottom" colour="#2c3539"/> + <face id="front" colour="#fbc32f"/> + <face id="back" colour="#fbc32f"/> + <face id="top" type="extrude" scale="1,0.95,1" position="0,0,0.8"> + <face id="top" type="extrude" scale="0.5,0.8,0" position="0,0,0.4" smooth="true" colour="#aeb0b0"/> </face> </use> - <use type="cuboid" position="0,0,0.2" scale="2.6,4.5,1" colour="#2C3539"/> + <use type="cuboid" position="0,0,0.2" scale="2.6,4.5,1" colour="#413b3a"/> </mesh> <mesh id="bogie1"> - <use type="bogie" position="0,6,0"/> + <use type="bogie" position="0,6,0" colour="#413b3a"/> </mesh> <mesh id="bogie2"> - <use type="bogie" position="0,-6,0" rotation="0,3.14159,0"/> + <use type="bogie" position="0,-6,0" rotation="0,3.14159,0" colour="#413b3a"/> </mesh> </asset> </ilt> |