summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2023-02-15 02:26:06 +0000
committerDan Goodliffe <dan.goodliffe@octal.co.uk>2023-02-15 11:34:11 +0000
commit715d4879fdd096ac82367984fdb22117d48737a4 (patch)
tree576b0553b10795bb51384ba4c47269d4226bdca6
parentAdd OpenMeshCore library (diff)
downloadilt-715d4879fdd096ac82367984fdb22117d48737a4.tar.bz2
ilt-715d4879fdd096ac82367984fdb22117d48737a4.tar.xz
ilt-715d4879fdd096ac82367984fdb22117d48737a4.zip
First cut of the model factory and the hardcoded Brush 47 model
Requires temporary change to the fragment shader to hardcode some visible colour to the model
-rw-r--r--assetFactory/assetFactoryConfig.h28
-rw-r--r--assetFactory/assetFactoryConfig_fwd.h8
-rw-r--r--assetFactory/cuboid.cpp29
-rw-r--r--assetFactory/cuboid.h8
-rw-r--r--assetFactory/cylinder.cpp43
-rw-r--r--assetFactory/cylinder.h8
-rw-r--r--assetFactory/faceController.cpp53
-rw-r--r--assetFactory/faceController.h20
-rw-r--r--assetFactory/factoryMesh.cpp27
-rw-r--r--assetFactory/factoryMesh.h14
-rw-r--r--assetFactory/modelFactory.cpp14
-rw-r--r--assetFactory/modelFactory.h12
-rw-r--r--assetFactory/mutation.cpp10
-rw-r--r--assetFactory/mutation.h14
-rw-r--r--assetFactory/object.cpp17
-rw-r--r--assetFactory/object.h15
-rw-r--r--assetFactory/plane.cpp15
-rw-r--r--assetFactory/plane.h8
-rw-r--r--assetFactory/shape.cpp17
-rw-r--r--assetFactory/shape.h25
-rw-r--r--assetFactory/use.cpp11
-rw-r--r--assetFactory/use.h17
-rw-r--r--test/Jamfile.jam1
-rw-r--r--test/test-modelFactory.cpp150
24 files changed, 564 insertions, 0 deletions
diff --git a/assetFactory/assetFactoryConfig.h b/assetFactory/assetFactoryConfig.h
new file mode 100644
index 0000000..171b81a
--- /dev/null
+++ b/assetFactory/assetFactoryConfig.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "assetFactoryConfig_fwd.h"
+#include <OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh>
+#include <OpenMesh/Core/Mesh/Traits.hh>
+#include <glm/geometric.hpp>
+#include <glm/vec3.hpp>
+
+namespace OpenMesh {
+ template<typename Scalar, int DIM> struct glmvec : public VectorT<Scalar, DIM> {
+ using VectorT<Scalar, DIM>::VectorT;
+ glmvec(const VectorT<Scalar, DIM> & v) : VectorT<Scalar, DIM> {v} { }
+ operator glm::vec<DIM, Scalar>() const
+ {
+ glm::vec<DIM, Scalar> out;
+ std::copy(this->begin(), this->end(), &out[0]);
+ return out;
+ }
+ };
+}
+
+struct ModelFactoryTraits : public OpenMesh::DefaultTraits {
+ FaceAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status);
+ EdgeAttributes(OpenMesh::Attributes::Status);
+ VertexAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status);
+ using Point = OpenMesh::glmvec<float, 3>;
+ using Normal = OpenMesh::glmvec<float, 3>;
+};
diff --git a/assetFactory/assetFactoryConfig_fwd.h b/assetFactory/assetFactoryConfig_fwd.h
new file mode 100644
index 0000000..28489ff
--- /dev/null
+++ b/assetFactory/assetFactoryConfig_fwd.h
@@ -0,0 +1,8 @@
+#pragma once
+
+namespace OpenMesh {
+ template<typename> class PolyMesh_ArrayKernelT;
+}
+struct ModelFactoryTraits;
+
+using ModelFactoryMesh = OpenMesh::PolyMesh_ArrayKernelT<ModelFactoryTraits>;
diff --git a/assetFactory/cuboid.cpp b/assetFactory/cuboid.cpp
new file mode 100644
index 0000000..90b2108
--- /dev/null
+++ b/assetFactory/cuboid.cpp
@@ -0,0 +1,29 @@
+#include "cuboid.h"
+#include "assetFactoryConfig.h"
+
+Cuboid::CreatedFaces
+Cuboid::createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const
+{
+ static constexpr std::array<glm::vec3, 8> VERTICES {{
+ // bottom
+ {n, n, z},
+ {n, y, z},
+ {y, y, z},
+ {y, n, z},
+ // top
+ {y, n, o},
+ {y, y, o},
+ {n, y, o},
+ {n, n, o},
+ }};
+
+ const auto vhs = addMutatedToMesh(mesh, VERTICES, mutation);
+ return {
+ {"top", mesh.add_face({vhs[4], vhs[5], vhs[6], vhs[7]})},
+ {"bottom", mesh.add_face({vhs[0], vhs[1], vhs[2], vhs[3]})},
+ {"left", mesh.add_face({vhs[0], vhs[7], vhs[6], vhs[1]})},
+ {"right", mesh.add_face({vhs[2], vhs[5], vhs[4], vhs[3]})},
+ {"front", mesh.add_face({vhs[0], vhs[3], vhs[4], vhs[7]})},
+ {"back", mesh.add_face({vhs[2], vhs[1], vhs[6], vhs[5]})},
+ };
+}
diff --git a/assetFactory/cuboid.h b/assetFactory/cuboid.h
new file mode 100644
index 0000000..5a4072a
--- /dev/null
+++ b/assetFactory/cuboid.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "shape.h"
+
+class Cuboid : public Shape {
+public:
+ CreatedFaces createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const override;
+};
diff --git a/assetFactory/cylinder.cpp b/assetFactory/cylinder.cpp
new file mode 100644
index 0000000..66d456d
--- /dev/null
+++ b/assetFactory/cylinder.cpp
@@ -0,0 +1,43 @@
+#include "cylinder.h"
+#include "assetFactoryConfig.h"
+#include "maths.h"
+
+Cylinder::CreatedFaces
+Cylinder::createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const
+{
+ const glm::vec2 scale {std::accumulate(&mutation[0][0], &mutation[0][3], 0.f),
+ std::accumulate(&mutation[1][0], &mutation[1][3], 0.f)};
+ const unsigned int P = static_cast<unsigned int>(std::round(15.F * std::sqrt(glm::length(scale))));
+ std::vector<OpenMesh::VertexHandle> bottom(P), top(P);
+ std::generate_n(bottom.begin(), P, [a = 0.f, step = two_pi / static_cast<float>(P), &mesh, &mutation]() mutable {
+ const auto xy = sincosf(a += step) * .5F;
+ const auto xyz = (xy ^ 0) % mutation;
+ return mesh.add_vertex({xyz.x, xyz.y, xyz.z});
+ });
+ std::generate_n(top.begin(), P, [a = 0.f, step = two_pi / static_cast<float>(P), &mesh, &mutation]() mutable {
+ const auto xy = sincosf(a -= step) * .5F;
+ const auto xyz = (xy ^ 1) % mutation;
+ return mesh.add_vertex({xyz.x, xyz.y, xyz.z});
+ });
+ CreatedFaces surface;
+ std::generate_n(std::inserter(surface, surface.end()), P,
+ [a = 0.f, step = two_pi / static_cast<float>(P), &mesh, &mutation]() mutable {
+ const auto xy1 = sincosf(a) * .5F;
+ const auto xy2 = sincosf(a -= step) * .5F;
+ const auto xyz1b = (xy1 ^ 0) % mutation;
+ const auto xyz2b = (xy2 ^ 0) % mutation;
+ const auto xyz1t = (xy1 ^ 1) % mutation;
+ const auto xyz2t = (xy2 ^ 1) % mutation;
+ return std::make_pair(std::string {"edge"},
+ mesh.add_face({
+ mesh.add_vertex({xyz1b.x, xyz1b.y, xyz1b.z}),
+ mesh.add_vertex({xyz2b.x, xyz2b.y, xyz2b.z}),
+ mesh.add_vertex({xyz2t.x, xyz2t.y, xyz2t.z}),
+ mesh.add_vertex({xyz1t.x, xyz1t.y, xyz1t.z}),
+ }));
+ });
+ surface.emplace("bottom", mesh.add_face(bottom));
+ surface.emplace("top", mesh.add_face(top));
+
+ return surface;
+}
diff --git a/assetFactory/cylinder.h b/assetFactory/cylinder.h
new file mode 100644
index 0000000..65ca5e5
--- /dev/null
+++ b/assetFactory/cylinder.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "shape.h"
+
+class Cylinder : public Shape {
+public:
+ CreatedFaces createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const override;
+};
diff --git a/assetFactory/faceController.cpp b/assetFactory/faceController.cpp
new file mode 100644
index 0000000..bdef74b
--- /dev/null
+++ b/assetFactory/faceController.cpp
@@ -0,0 +1,53 @@
+#include "faceController.h"
+#include "assetFactoryConfig.h"
+#include "maths.h"
+
+void
+FaceController::apply(ModelFactoryMesh & mesh, const std::string & name, Shape::CreatedFaces & faces) const
+{
+ 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
+ const auto faceVertexRange = mesh.fv_range(cf.second);
+ // get points
+ const std::vector baseVertices(faceVertexRange.begin(), faceVertexRange.end());
+ std::vector<glm::vec3> points;
+ std::transform(
+ faceVertexRange.begin(), faceVertexRange.end(), std::back_inserter(points), [&mesh](auto && v) {
+ return mesh.point(v);
+ });
+ const auto vertexCount = points.size();
+ const auto centre
+ = std::accumulate(points.begin(), points.end(), glm::vec3 {}) / static_cast<float>(vertexCount);
+ if (type == "extrude") {
+ Shape::CreatedFaces newFaces;
+ // mutate points
+ std::for_each(points.begin(), points.end(), [&mutation, &centre](auto && p) {
+ p = centre + ((p - centre) % mutation);
+ });
+ // create new vertices
+ std::vector<OpenMesh::VertexHandle> vertices;
+ std::transform(points.begin(), points.end(), std::back_inserter(vertices), [&mesh](auto && p) {
+ 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;
+ newFaces.emplace("extrusion",
+ mesh.add_face({baseVertices[idx], baseVertices[next], vertices[next], vertices[idx]}));
+ }
+ newFaces.emplace(name, mesh.add_face(vertices));
+ for (const auto & [name, faceController] : faceControllers) {
+ faceController.apply(mesh, name, newFaces);
+ }
+ faces.merge(std::move(newFaces));
+ }
+ }
+ }
+}
diff --git a/assetFactory/faceController.h b/assetFactory/faceController.h
new file mode 100644
index 0000000..64c33f3
--- /dev/null
+++ b/assetFactory/faceController.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "assetFactoryConfig_fwd.h"
+#include "mutation.h"
+#include "shape.h"
+#include <map>
+#include <string>
+
+class FaceController : public Mutation {
+public:
+ using FaceControllers = std::map<std::string, FaceController>;
+
+ void apply(ModelFactoryMesh & mesh, 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
new file mode 100644
index 0000000..1b89d14
--- /dev/null
+++ b/assetFactory/factoryMesh.cpp
@@ -0,0 +1,27 @@
+#include "factoryMesh.h"
+#include "assetFactoryConfig.h"
+#include "collections.hpp"
+#include "gfx/models/vertex.hpp"
+#include <glm/ext/matrix_transform.hpp>
+
+Mesh::Ptr
+FactoryMesh::createMesh() const
+{
+ constexpr glm::vec2 NullUV {};
+
+ ModelFactoryMesh mesh;
+ for (const auto & use : uses) {
+ use->createMesh(mesh, glm::identity<Mutation::Matrix>());
+ }
+ mesh.garbage_collection();
+
+ mesh.triangulate();
+ mesh.update_face_normals();
+ std::vector<Vertex> vertices;
+ for (const auto & face : mesh.faces()) {
+ for (const auto & vertex : mesh.fv_range(face)) {
+ vertices.emplace_back(mesh.point(vertex), NullUV, mesh.property(mesh.face_normals_pph(), face));
+ }
+ }
+ return std::make_shared<Mesh>(vertices, vectorOfN(vertices.size()));
+}
diff --git a/assetFactory/factoryMesh.h b/assetFactory/factoryMesh.h
new file mode 100644
index 0000000..f850893
--- /dev/null
+++ b/assetFactory/factoryMesh.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "gfx/models/mesh.h"
+#include "stdTypeDefs.hpp"
+#include "use.h"
+
+class FactoryMesh : public StdTypeDefs<FactoryMesh> {
+public:
+ Mesh::Ptr createMesh() const;
+
+ std::string id;
+ glm::vec3 size;
+ Use::Collection uses;
+};
diff --git a/assetFactory/modelFactory.cpp b/assetFactory/modelFactory.cpp
new file mode 100644
index 0000000..3a89157
--- /dev/null
+++ b/assetFactory/modelFactory.cpp
@@ -0,0 +1,14 @@
+#include "modelFactory.h"
+#include "assetFactoryConfig.h"
+#include "cuboid.h"
+#include "cylinder.h"
+#include "plane.h"
+
+ModelFactory::ModelFactory() :
+ shapes {
+ {"plane", std::make_shared<Plane>()},
+ {"cuboid", std::make_shared<Cuboid>()},
+ {"cylinder", std::make_shared<Cylinder>()},
+ }
+{
+}
diff --git a/assetFactory/modelFactory.h b/assetFactory/modelFactory.h
new file mode 100644
index 0000000..f2b1b48
--- /dev/null
+++ b/assetFactory/modelFactory.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "shape.h"
+
+class ModelFactory {
+public:
+ using Shapes = std::map<std::string, Shape::CPtr, std::less<>>;
+
+ ModelFactory();
+
+ Shapes shapes;
+};
diff --git a/assetFactory/mutation.cpp b/assetFactory/mutation.cpp
new file mode 100644
index 0000000..21d2a24
--- /dev/null
+++ b/assetFactory/mutation.cpp
@@ -0,0 +1,10 @@
+#include "mutation.h"
+#include <glm/gtx/transform.hpp>
+#include <maths.h>
+
+Mutation::Matrix
+Mutation::getMatrix() const
+{
+ return glm::translate(glm::identity<Matrix>(), position) * rotate_ypr(rotation)
+ * glm::scale(glm::identity<Matrix>(), scale);
+}
diff --git a/assetFactory/mutation.h b/assetFactory/mutation.h
new file mode 100644
index 0000000..440fab0
--- /dev/null
+++ b/assetFactory/mutation.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <glm/mat4x4.hpp>
+#include <glm/vec3.hpp>
+
+struct Mutation {
+ using Matrix = glm::mat4;
+
+ Matrix getMatrix() const;
+
+ glm::vec3 position {};
+ glm::vec3 rotation {};
+ glm::vec3 scale {1};
+};
diff --git a/assetFactory/object.cpp b/assetFactory/object.cpp
new file mode 100644
index 0000000..8b70676
--- /dev/null
+++ b/assetFactory/object.cpp
@@ -0,0 +1,17 @@
+#include "object.h"
+#include <algorithm>
+
+Object::Object(std::string i) : id {std::move(i)} { }
+
+Object::CreatedFaces
+Object::createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const
+{
+ CreatedFaces faces;
+ for (const auto & use : uses) {
+ auto useFaces = use->createMesh(mesh, mutation);
+ std::transform(useFaces.begin(), useFaces.end(), std::inserter(faces, faces.end()), [this](auto && face) {
+ return std::make_pair(id + ":" + face.first, std::move(face.second));
+ });
+ }
+ return faces;
+}
diff --git a/assetFactory/object.h b/assetFactory/object.h
new file mode 100644
index 0000000..f48b78a
--- /dev/null
+++ b/assetFactory/object.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "shape.h"
+#include "stdTypeDefs.hpp"
+#include "use.h"
+
+class Object : public StdTypeDefs<Object>, public Shape {
+public:
+ Object(std::string i);
+
+ CreatedFaces createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const;
+
+ Use::Collection uses;
+ std::string id;
+};
diff --git a/assetFactory/plane.cpp b/assetFactory/plane.cpp
new file mode 100644
index 0000000..1e522ad
--- /dev/null
+++ b/assetFactory/plane.cpp
@@ -0,0 +1,15 @@
+#include "plane.h"
+#include "assetFactoryConfig.h"
+
+Plane::CreatedFaces
+Plane::createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const
+{
+ static constexpr std::array<glm::vec3, 4> VERTICES {{
+ {n, n, z},
+ {y, n, z},
+ {y, y, z},
+ {n, y, z},
+ }};
+
+ return {{"plane", mesh.add_face(addMutatedToMesh(mesh, VERTICES, mutation))}};
+}
diff --git a/assetFactory/plane.h b/assetFactory/plane.h
new file mode 100644
index 0000000..5e93ee4
--- /dev/null
+++ b/assetFactory/plane.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "shape.h"
+
+class Plane : public Shape {
+public:
+ CreatedFaces createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const override;
+};
diff --git a/assetFactory/shape.cpp b/assetFactory/shape.cpp
new file mode 100644
index 0000000..0994898
--- /dev/null
+++ b/assetFactory/shape.cpp
@@ -0,0 +1,17 @@
+#include "shape.h"
+#include "assetFactoryConfig.h"
+#include "gfx/models/vertex.hpp"
+#include "maths.h"
+#include "shape.h"
+
+std::vector<OpenMesh::VertexHandle>
+Shape::addMutatedToMesh(
+ ModelFactoryMesh & mesh, const std::span<const glm::vec3> vertices, const Mutation::Matrix & mutation)
+{
+ std::vector<OpenMesh::VertexHandle> vhs;
+ std::transform(vertices.begin(), vertices.end(), std::back_inserter(vhs), [&mesh, &mutation](const auto & v) {
+ const auto p = v % mutation;
+ return mesh.add_vertex({p.x, p.y, p.z});
+ });
+ return vhs;
+}
diff --git a/assetFactory/shape.h b/assetFactory/shape.h
new file mode 100644
index 0000000..9510538
--- /dev/null
+++ b/assetFactory/shape.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "assetFactoryConfig_fwd.h"
+#include "mutation.h"
+#include "stdTypeDefs.hpp"
+#include <OpenMesh/Core/Mesh/Handles.hh>
+#include <map>
+#include <span>
+#include <string>
+
+class Vertex;
+
+class Shape : public StdTypeDefs<Shape> {
+public:
+ using CreatedFaces = std::multimap<std::string, OpenMesh::FaceHandle>;
+
+ static constexpr float z {}, y {.5}, n {-y}, o {1};
+
+ virtual ~Shape() = default;
+
+ virtual CreatedFaces createMesh(ModelFactoryMesh &, const Mutation::Matrix & mutation) const = 0;
+
+ static std::vector<OpenMesh::VertexHandle> addMutatedToMesh(
+ ModelFactoryMesh & mesh, const std::span<const glm::vec3> vertices, const Mutation::Matrix & mutation);
+};
diff --git a/assetFactory/use.cpp b/assetFactory/use.cpp
new file mode 100644
index 0000000..d191329
--- /dev/null
+++ b/assetFactory/use.cpp
@@ -0,0 +1,11 @@
+#include "use.h"
+
+Shape::CreatedFaces
+Use::createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const
+{
+ auto faces = type->createMesh(mesh, mutation * getMatrix());
+ for (const auto & [name, faceController] : faceControllers) {
+ faceController.apply(mesh, name, faces);
+ }
+ return faces;
+}
diff --git a/assetFactory/use.h b/assetFactory/use.h
new file mode 100644
index 0000000..4bfce97
--- /dev/null
+++ b/assetFactory/use.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "assetFactoryConfig_fwd.h"
+#include "faceController.h"
+#include "shape.h"
+#include "stdTypeDefs.hpp"
+
+class Use : public StdTypeDefs<Use>, public Mutation {
+public:
+ using FaceControllers = std::map<std::string, FaceController>;
+
+ Shape::CreatedFaces createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const;
+
+ Shape::CPtr type;
+ std::string colour;
+ FaceControllers faceControllers;
+};
diff --git a/test/Jamfile.jam b/test/Jamfile.jam
index cefad7b..d802975 100644
--- a/test/Jamfile.jam
+++ b/test/Jamfile.jam
@@ -52,5 +52,6 @@ run test-text.cpp ;
run test-enumDetails.cpp ;
run test-render.cpp : : : <library>test ;
run test-glContextBhvr.cpp ;
+run test-modelFactory.cpp : : : <library>test ;
compile test-static-enumDetails.cpp ;
compile test-static-stream_support.cpp ;
diff --git a/test/test-modelFactory.cpp b/test/test-modelFactory.cpp
new file mode 100644
index 0000000..39362f5
--- /dev/null
+++ b/test/test-modelFactory.cpp
@@ -0,0 +1,150 @@
+#define BOOST_TEST_MODULE test_model_factory
+
+#include "testHelpers.h"
+#include "testRenderOutput.h"
+#include <boost/test/data/test_case.hpp>
+#include <boost/test/unit_test.hpp>
+
+#include "assetFactory/factoryMesh.h"
+#include "assetFactory/modelFactory.h"
+#include "assetFactory/object.h"
+#include "gfx/gl/sceneRenderer.h"
+#include "lib/collection.hpp"
+#include "lib/location.hpp"
+#include "testMainWindow.h"
+#include "ui/applicationBase.h"
+
+BOOST_GLOBAL_FIXTURE(ApplicationBase);
+BOOST_GLOBAL_FIXTURE(TestMainWindow);
+
+const std::filesystem::path TMP {"/tmp"};
+class FactoryFixture : public TestRenderOutputSize<glm::ivec2 {2048, 2048}>, public SceneProvider {
+public:
+ FactoryFixture() : sceneRenderer {size, output} { }
+ ~FactoryFixture()
+ {
+ glDisable(GL_DEBUG_OUTPUT);
+ auto outpath = (TMP / boost::unit_test::framework::current_test_case().full_name()).replace_extension(".tga");
+ std::filesystem::create_directories(outpath.parent_path());
+ Texture::save(outImage, size, outpath.c_str());
+ }
+ void
+ content(const SceneShader & shader) const override
+ {
+ shader.basic.use(Location {{0, 0, 0}, {0, 0, 0}});
+ meshes.apply(&Mesh::Draw);
+ }
+ void
+ lights(const SceneShader & shader) const override
+ {
+ shader.pointLight.add({-3, 1, 5}, {1, 1, 1}, .1F);
+ }
+ void
+ environment(const SceneShader &, const SceneRenderer & sceneRenderer) const override
+ {
+ sceneRenderer.setAmbientLight({.2, .2, .2});
+ sceneRenderer.setDirectionalLight({.3, .3, .3}, east + south + south + down, *this);
+ }
+ void
+ shadows(const ShadowMapper & mapper) const override
+ {
+ mapper.dynamicPoint.use(Location {{0, 0, 0}, {0, 0, 0}});
+ meshes.apply(&Mesh::Draw);
+ }
+ void
+ render(float dist = 10.f)
+ {
+ sceneRenderer.camera.setView({dist, dist, dist}, south + west + down);
+ sceneRenderer.render(*this);
+ }
+ Collection<const Mesh> meshes;
+
+private:
+ SceneRenderer sceneRenderer;
+};
+
+BOOST_FIXTURE_TEST_SUITE(m, FactoryFixture);
+BOOST_AUTO_TEST_CASE(brush47)
+{
+ ModelFactory modelFactory;
+ {
+ auto wheel = std::make_shared<Object>("wheel");
+ {
+ auto wheelCylinder = wheel->uses.emplace_back(std::make_shared<Use>());
+ wheelCylinder->type = modelFactory.shapes.at("cylinder");
+ wheelCylinder->position = {0, 0, 0.571};
+ wheelCylinder->scale = {1.142, 1.142, 0.07};
+ wheelCylinder->rotation = {0, 0, half_pi};
+ wheelCylinder->colour = "#2C3539";
+ }
+ modelFactory.shapes.emplace(wheel->id, wheel);
+ }
+ {
+ auto axel = std::make_shared<Object>("axel");
+ for (float x : {-1.f, 1.f}) {
+ auto wheel = axel->uses.emplace_back(std::make_shared<Use>());
+ wheel->type = modelFactory.shapes.at("wheel");
+ wheel->position = {x * 0.717f, 0, 0};
+ wheel->rotation = {0, x == 1.f ? pi : 0.f, 0};
+ }
+ modelFactory.shapes.emplace(axel->id, axel);
+ }
+ {
+ auto bogey = std::make_shared<Object>("bogey");
+ for (float y : {-2.f, 0.f, 2.f}) {
+ auto axel = bogey->uses.emplace_back(std::make_shared<Use>());
+ axel->type = modelFactory.shapes.at("axel");
+ axel->position = {0, y, 0};
+ }
+ modelFactory.shapes.emplace(bogey->id, bogey);
+ }
+ FactoryMesh::Collection factoryMeshes;
+ {
+ unsigned short b {0};
+ for (float y : {-6.f, 6.f}) {
+ auto bogey = factoryMeshes.emplace_back(std::make_shared<FactoryMesh>());
+ bogey->id = "bogey" + std::to_string(b);
+ auto bogeyUse = bogey->uses.emplace_back(std::make_shared<Use>());
+ bogeyUse->type = modelFactory.shapes.at("bogey");
+ bogeyUse->position = {0, y, 0};
+ bogeyUse->rotation = {0, b * pi, 0};
+ b++;
+ }
+ }
+ {
+ auto body = factoryMeshes.emplace_back(std::make_shared<FactoryMesh>());
+ body->id = "body";
+ body->size = {2.69f, 19.38f, 3.9f};
+ {
+ auto bodyLower = body->uses.emplace_back(std::make_shared<Use>());
+ bodyLower->type = modelFactory.shapes.at("cuboid");
+ bodyLower->position = {0, 0, 1.2};
+ bodyLower->scale = {2.69, 19.38, 1.5};
+ bodyLower->colour = "#1111DD";
+ bodyLower->faceControllers["bottom"].colour = "#2C3539";
+ auto & bodyUpper = bodyLower->faceControllers["top"];
+ bodyUpper.type = "extrude";
+ bodyUpper.scale = {1, .95f, 1};
+ bodyUpper.position = {0, 0, 1.0};
+ auto & roof = bodyUpper.faceControllers["top"];
+ roof.type = "extrude";
+ roof.scale = {.6f, .9f, 0};
+ roof.position = {0, 0, 0.2};
+ roof.smooth = true;
+ }
+ {
+ auto batteryBox = body->uses.emplace_back(std::make_shared<Use>());
+ batteryBox->type = modelFactory.shapes.at("cuboid");
+ batteryBox->position = {0, 0, .2};
+ batteryBox->scale = {2.6, 4.5, 1};
+ batteryBox->colour = "#2C3539";
+ }
+ }
+ std::transform(factoryMeshes.begin(), factoryMeshes.end(), std::back_inserter(meshes.objects),
+ [](const FactoryMesh::CPtr & factoryMesh) -> Mesh::Ptr {
+ return factoryMesh->createMesh();
+ });
+
+ render(20);
+}
+BOOST_AUTO_TEST_SUITE_END();