From 51b649914deef24af240cd279bd667c6bdcf2c6d Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 9 Apr 2023 17:45:16 +0100 Subject: Include assimp library --- Jamroot.jam | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Jamroot.jam b/Jamroot.jam index e2075cf..ebe97a6 100644 --- a/Jamroot.jam +++ b/Jamroot.jam @@ -13,6 +13,7 @@ pkg-config.import glew ; pkg-config.import freetype2 ; pkg-config.import glib-2.0 ; pkg-config.import mxml ; +pkg-config.import assimp ; lib pthread ; lib OpenMeshCore ; @@ -115,6 +116,7 @@ lib ilt : freetype2 glib-2.0 mxml + assimp pthread OpenMeshCore : : -- cgit v1.2.3 From d4177ecd85dddcc16c6254619020a64d9b5ad6b5 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 9 Apr 2023 17:45:47 +0100 Subject: Add low poly tree collection Thanks https://www.turbosquid.com/3d-models/3d-shapespark-low-poly-plants-kit-1826978 --- res/shapespark-low-poly-plants-kit.fbx | Bin 0 -> 20264540 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 res/shapespark-low-poly-plants-kit.fbx diff --git a/res/shapespark-low-poly-plants-kit.fbx b/res/shapespark-low-poly-plants-kit.fbx new file mode 100644 index 0000000..fe87c0c Binary files /dev/null and b/res/shapespark-low-poly-plants-kit.fbx differ -- cgit v1.2.3 From f5a213f621f012e8e4ea541cad409e3cfa1ccaa6 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 10 Apr 2023 01:59:11 +0100 Subject: One OpenMesh instance per top level Use in createMesh --- assetFactory/factoryMesh.cpp | 60 +++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/assetFactory/factoryMesh.cpp b/assetFactory/factoryMesh.cpp index 8869efd..4922936 100644 --- a/assetFactory/factoryMesh.cpp +++ b/assetFactory/factoryMesh.cpp @@ -6,43 +6,45 @@ Mesh::Ptr FactoryMesh::createMesh() const { - ModelFactoryMesh mesh; + std::vector vertices; + std::vector indices; + for (const auto & use : uses) { + ModelFactoryMesh mesh; use->createMesh(mesh, 1); - } - 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); + mesh.update_face_normals(); + mesh.update_vertex_normals(); + for (const auto & face : mesh.faces()) { + 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); - 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); + 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); + 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); + } } - } - 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]); + 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 38fc122b84fce3a0e6299069524e80a73818d928 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 10 Apr 2023 13:19:19 +0100 Subject: Constraint operator* collection helper to IterableCollections --- lib/collections.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/collections.hpp b/lib/collections.hpp index 59cec6f..4df622e 100644 --- a/lib/collections.hpp +++ b/lib/collections.hpp @@ -65,10 +65,11 @@ operator*=(IterableCollection auto & in, auto && f) } template typename C, typename... T> + requires IterableCollection> [[nodiscard]] constexpr auto operator*(const C & in, auto && f) { - C out; + C out; std::transform(in.begin(), in.end(), std::inserter(out, out.end()), f); return out; -- cgit v1.2.3 From a5a0ad3634c512afb1686a2ec8940843e7f0eb63 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 10 Apr 2023 13:20:49 +0100 Subject: operator* collection helper reserves target space when possible --- lib/collections.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/collections.hpp b/lib/collections.hpp index 4df622e..b51d18e 100644 --- a/lib/collections.hpp +++ b/lib/collections.hpp @@ -70,6 +70,9 @@ template typename C, typename... T> operator*(const C & in, auto && f) { C out; + if constexpr (requires { out.reserve(in.size()); }) { + out.reserve(in.size()); + } std::transform(in.begin(), in.end(), std::inserter(out, out.end()), f); return out; -- cgit v1.2.3 From e428f2145ac3b05345d42e3518a22d429ad0970e Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 10 Apr 2023 14:33:54 +0100 Subject: Add the plant/foliage game item concepts --- game/scenary/foliage.cpp | 33 +++++++++++++++++++++++++++++++++ game/scenary/foliage.h | 21 +++++++++++++++++++++ game/scenary/plant.cpp | 13 +++++++++++++ game/scenary/plant.h | 16 ++++++++++++++++ 4 files changed, 83 insertions(+) create mode 100644 game/scenary/foliage.cpp create mode 100644 game/scenary/foliage.h create mode 100644 game/scenary/plant.cpp create mode 100644 game/scenary/plant.h diff --git a/game/scenary/foliage.cpp b/game/scenary/foliage.cpp new file mode 100644 index 0000000..d39d500 --- /dev/null +++ b/game/scenary/foliage.cpp @@ -0,0 +1,33 @@ +#include "foliage.h" +#include "gfx/gl/sceneShader.h" +#include "gfx/gl/shadowMapper.h" +#include "gfx/models/texture.h" + +bool +Foliage::persist(Persistence::PersistenceStore & store) +{ + return STORE_TYPE && STORE_HELPER(bodyMesh, Asset::MeshConstruct) && Asset::persist(store); +} + +void +Foliage::postLoad() +{ + texture = getTexture(); +} + +void +Foliage::render(const SceneShader & shader, const Location & loc) const +{ + shader.basic.use(loc); + if (texture) { + texture->bind(); + } + bodyMesh->Draw(); +} + +void +Foliage::shadows(const ShadowMapper & mapper, const Location & loc) const +{ + mapper.dynamicPoint.use(loc); + bodyMesh->Draw(); +} diff --git a/game/scenary/foliage.h b/game/scenary/foliage.h new file mode 100644 index 0000000..229bccb --- /dev/null +++ b/game/scenary/foliage.h @@ -0,0 +1,21 @@ +#pragma once + +#include "assetFactory/asset.h" + +class SceneShader; +class ShadowMapper; +class Location; + +class Foliage : public Asset, public StdTypeDefs { + Mesh::Ptr bodyMesh; + std::shared_ptr texture; + +public: + void render(const SceneShader &, const Location &) const; + void shadows(const ShadowMapper &, const Location &) const; + +protected: + friend Persistence::SelectionPtrBase>; + bool persist(Persistence::PersistenceStore & store) override; + void postLoad() override; +}; diff --git a/game/scenary/plant.cpp b/game/scenary/plant.cpp new file mode 100644 index 0000000..2b01bee --- /dev/null +++ b/game/scenary/plant.cpp @@ -0,0 +1,13 @@ +#include "plant.h" + +void +Plant::render(const SceneShader & shader) const +{ + type->render(shader, position); +} + +void +Plant::shadows(const ShadowMapper & mapper) const +{ + type->shadows(mapper, position); +} diff --git a/game/scenary/plant.h b/game/scenary/plant.h new file mode 100644 index 0000000..7f964eb --- /dev/null +++ b/game/scenary/plant.h @@ -0,0 +1,16 @@ +#pragma once + +#include "foliage.h" +#include "gfx/renderable.h" +#include "location.hpp" + +class Plant : public Renderable { + std::shared_ptr type; + Location position; + + void render(const SceneShader & shader) const override; + void shadows(const ShadowMapper & shadowMapper) const override; + +public: + Plant(std::shared_ptr type, Location position) : type(std::move(type)), position(position) { } +}; -- cgit v1.2.3 From e7d946aadebfdf49cc96e6a518c1af1ef7f5c71c Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 10 Apr 2023 14:34:56 +0100 Subject: Add operator* helper specialised for std::span --- lib/collections.hpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lib/collections.hpp b/lib/collections.hpp index b51d18e..8f5a43d 100644 --- a/lib/collections.hpp +++ b/lib/collections.hpp @@ -78,6 +78,27 @@ operator*(const C & in, auto && f) return out; } +template +[[nodiscard]] constexpr auto +operator*(const std::span in, auto && f) +{ + std::array())), N> out; + + std::transform(in.begin(), in.end(), out.begin(), f); + return out; +} + +template +[[nodiscard]] constexpr auto +operator*(const std::span in, auto && f) +{ + std::vector()))> out; + + out.reserve(in.size()); + std::transform(in.begin(), in.end(), std::inserter(out, out.end()), f); + return out; +} + template constexpr auto & operator+=(std::vector & in, std::vector && src) -- cgit v1.2.3 From 48a891316490fd8bc8574aafbd390eb96011ee40 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 10 Apr 2023 14:35:56 +0100 Subject: test-assetFactory depends on all resource files --- test/Jamfile.jam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Jamfile.jam b/test/Jamfile.jam index bf1c408..390880d 100644 --- a/test/Jamfile.jam +++ b/test/Jamfile.jam @@ -54,7 +54,7 @@ run test-text.cpp ; run test-enumDetails.cpp ; run test-render.cpp : : : test ; run test-glContextBhvr.cpp ; -run test-assetFactory.cpp : -- : [ sequence.insertion-sort [ glob-tree $(res) : *.xml *.png ] fixtures/rgb.txt ] : test ; +run test-assetFactory.cpp : -- : [ sequence.insertion-sort [ glob-tree $(res) : *.* ] fixtures/rgb.txt ] : test ; run perf-assetFactory.cpp : : : benchmark test test-assetFactory ; run perf-persistence.cpp : : : benchmark test test-persistence ; compile test-static-enumDetails.cpp ; -- cgit v1.2.3 From 989b10986f1626d1a50fceb8a33174108c03da93 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 10 Apr 2023 14:46:18 +0100 Subject: Load texture fragment images as we go, make the image a member --- assetFactory/assetFactory.cpp | 19 ++++++------------- assetFactory/textureFragment.cpp | 8 ++++++++ assetFactory/textureFragment.h | 3 +++ 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/assetFactory/assetFactory.cpp b/assetFactory/assetFactory.cpp index ed1af58..ec0e19f 100644 --- a/assetFactory/assetFactory.cpp +++ b/assetFactory/assetFactory.cpp @@ -11,7 +11,6 @@ #include "resource.h" #include "saxParse-persistence.h" #include "texturePacker.h" -#include AssetFactory::AssetFactory() : shapes { @@ -105,30 +104,24 @@ 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}; + std::transform( + textureFragments.begin(), textureFragments.end(), std::back_inserter(imageSizes), [](const auto & tf) { + return TexturePacker::Image {tf.second->image->width, tf.second->image->height}; }); const auto [layout, outSize] = TexturePacker {imageSizes}.pack(); // * create texture 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(), image = images.begin(), size = imageSizes.begin(), - outSize = glm::vec2 {outSize}](const auto & tf) mutable { + [position = layout.begin(), size = imageSizes.begin(), outSize = glm::vec2 {outSize}]( + const auto & tf) mutable { 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()); + tf.second->image->data.data()); position++; - image++; size++; return decltype(textureFragmentPositions)::value_type {tf.first, positionFraction}; }); diff --git a/assetFactory/textureFragment.cpp b/assetFactory/textureFragment.cpp index 72107a5..d153688 100644 --- a/assetFactory/textureFragment.cpp +++ b/assetFactory/textureFragment.cpp @@ -1,7 +1,15 @@ #include "textureFragment.h" +#include "resource.h" +#include bool TextureFragment::persist(Persistence::PersistenceStore & store) { return STORE_TYPE && STORE_MEMBER(id) && STORE_MEMBER(path); } + +void +TextureFragment::postLoad() +{ + image = std::make_unique(Resource::mapPath(path), STBI_rgb_alpha); +} diff --git a/assetFactory/textureFragment.h b/assetFactory/textureFragment.h index 52f2591..d03affd 100644 --- a/assetFactory/textureFragment.h +++ b/assetFactory/textureFragment.h @@ -1,5 +1,6 @@ #pragma once +#include "gfx/image.h" #include "persistence.h" #include "stdTypeDefs.hpp" @@ -7,8 +8,10 @@ class TextureFragment : public Persistence::Persistable, public StdTypeDefs image; private: friend Persistence::SelectionPtrBase; bool persist(Persistence::PersistenceStore & store) override; + void postLoad() override; }; -- cgit v1.2.3 From 5215c297280e5440881bcc495ef75a86a5708b03 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 10 Apr 2023 18:31:57 +0100 Subject: Plants are world objects --- game/scenary/plant.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/game/scenary/plant.h b/game/scenary/plant.h index 7f964eb..55acca1 100644 --- a/game/scenary/plant.h +++ b/game/scenary/plant.h @@ -1,16 +1,22 @@ #pragma once #include "foliage.h" +#include "game/worldobject.h" #include "gfx/renderable.h" #include "location.hpp" -class Plant : public Renderable { +class Plant : public Renderable, public WorldObject { std::shared_ptr type; Location position; void render(const SceneShader & shader) const override; void shadows(const ShadowMapper & shadowMapper) const override; + void + tick(TickDuration) override + { + } + public: Plant(std::shared_ptr type, Location position) : type(std::move(type)), position(position) { } }; -- cgit v1.2.3 From 9aa09c55b0af4b8c4c14a4ac50fcb21f7eba492d Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 10 Apr 2023 18:36:53 +0100 Subject: Support loading textures from an in memory buffer --- gfx/image.cpp | 16 ++++++++++++++++ gfx/image.h | 1 + 2 files changed, 17 insertions(+) diff --git a/gfx/image.cpp b/gfx/image.cpp index e3e3b01..fb86cb6 100644 --- a/gfx/image.cpp +++ b/gfx/image.cpp @@ -19,6 +19,22 @@ Image::Image(const char * fileName, int flags) : width {}, height {}, numCompone data = {bytes, static_cast(width * height * numComponents)}; } +Image::Image(std::span buffer, int flags) +{ + stbi_set_flip_vertically_on_load(1); + int w, h, nc; + unsigned char * bytes = stbi_load_from_memory(buffer.data(), static_cast(buffer.size()), &w, &h, &nc, flags); + width = static_cast(w); + height = static_cast(h); + numComponents = static_cast(nc); + + if (!bytes) { + throw std::runtime_error {"Unable to load image from memory buffer "}; + } + + data = {bytes, static_cast(width * height * numComponents)}; +} + Image::~Image() { stbi_image_free(data.data()); diff --git a/gfx/image.h b/gfx/image.h index 47437ca..97c2731 100644 --- a/gfx/image.h +++ b/gfx/image.h @@ -8,6 +8,7 @@ class Image { public: Image(const char * fileName, int flags); Image(const std::string & fileName, int flags) : Image(fileName.c_str(), flags) { } + Image(std::span data, int flags); ~Image(); NO_COPY(Image); -- cgit v1.2.3 From b25bc3cc32c5a9057c66ad282fa1cdfe0ed6094a Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 10 Apr 2023 18:45:13 +0100 Subject: First cut loading assets using assimp This is far from perfect, specifically the created texture atlas is not compatibile with wrapping texture UVs --- assetFactory/assetFactory.cpp | 5 +- assetFactory/assetFactory.h | 3 ++ assetFactory/assimp.cpp | 119 ++++++++++++++++++++++++++++++++++++++++++ assetFactory/assimp.h | 14 +++++ res/foliage.xml | 9 ++++ test/perf-assetFactory.cpp | 11 ++++ test/test-assetFactory.cpp | 17 ++++++ 7 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 assetFactory/assimp.cpp create mode 100644 assetFactory/assimp.h create mode 100644 res/foliage.xml diff --git a/assetFactory/assetFactory.cpp b/assetFactory/assetFactory.cpp index ec0e19f..917edfe 100644 --- a/assetFactory/assetFactory.cpp +++ b/assetFactory/assetFactory.cpp @@ -109,7 +109,7 @@ AssetFactory::createTexutre() const std::transform( textureFragments.begin(), textureFragments.end(), std::back_inserter(imageSizes), [](const auto & tf) { return TexturePacker::Image {tf.second->image->width, tf.second->image->height}; - }); + }); const auto [layout, outSize] = TexturePacker {imageSizes}.pack(); // * create texture texture = std::make_shared(outSize.x, outSize.y, TextureOptions {.wrap = GL_CLAMP_TO_EDGE}); @@ -134,7 +134,8 @@ AssetFactory::persist(Persistence::PersistenceStore & store) using MapObjects = Persistence::MapByMember>; using MapAssets = Persistence::MapByMember; using MapTextureFragments = Persistence::MapByMember; + using MapAssImp = Persistence::MapByMember, &AssImp::path>; return STORE_TYPE && STORE_NAME_HELPER("object", shapes, MapObjects) && STORE_NAME_HELPER("textureFragment", textureFragments, MapTextureFragments) - && STORE_NAME_HELPER("asset", assets, MapAssets); + && STORE_NAME_HELPER("assimp", assimps, MapAssImp) && STORE_NAME_HELPER("asset", assets, MapAssets); } diff --git a/assetFactory/assetFactory.h b/assetFactory/assetFactory.h index 52692c4..7843d44 100644 --- a/assetFactory/assetFactory.h +++ b/assetFactory/assetFactory.h @@ -1,6 +1,7 @@ #pragma once #include "asset.h" +#include "assimp.h" #include "persistence.h" #include "shape.h" #include "textureFragment.h" @@ -12,6 +13,7 @@ class AssetFactory : public Persistence::Persistable { public: using Shapes = std::map>; using Assets = std::map>; + using AssImps = std::map>; using TextureFragments = std::map>; using Colour = glm::vec3; using ColourAlpha = glm::vec4; @@ -26,6 +28,7 @@ public: Shapes shapes; Assets assets; + AssImps assimps; Colours colours; TextureFragments textureFragments; diff --git a/assetFactory/assimp.cpp b/assetFactory/assimp.cpp new file mode 100644 index 0000000..55090f4 --- /dev/null +++ b/assetFactory/assimp.cpp @@ -0,0 +1,119 @@ +#include "assimp.h" +#include "assetFactory.h" +#include "collections.hpp" +#include "ptr.hpp" +#include "resource.h" +#include +#include +#include +#include + +template +glm::vec<3, T> +operator*(const aiVector3t & v) +{ + return {v.x, v.y, v.z}; +} + +template +glm::vec<2, T> +operator!(const aiVector3t & v) +{ + return {v.x, v.y}; +} + +#define AIRANGE(parent, member) \ + std::span \ + { \ + (parent)->m##member, (parent)->mNum##member \ + } + +using ScemeCPtr = std::shared_ptr; +class AssImpNode : public Shape { +public: + AssImpNode(ScemeCPtr scene, const aiNode * node) : scene(std::move(scene)), node(node) { } + + ScemeCPtr scene; + const aiNode * node; + + CreatedFaces + createMesh(ModelFactoryMesh & mesh, float) const + { + CreatedFaces faces; + addMesh(faces, mesh, node); + return faces; + } + + void + addMesh(CreatedFaces & faces, ModelFactoryMesh & mesh, const aiNode * node) const + { + for (const auto & m : AIRANGE(node, Meshes)) { + addMesh(faces, mesh, scene->mMeshes[m]); + } + for (const auto & n : AIRANGE(node, Children)) { + addMesh(faces, mesh, n); + } + } + + void + addMesh(CreatedFaces & faces, ModelFactoryMesh & mesh, const aiMesh * amesh) const + { + const auto vhs = AIRANGE(amesh, Vertices) * [&mesh](auto && v) { + return mesh.add_vertex(*v); + }; + const auto & m = *scene->mMaterials[amesh->mMaterialIndex]; + + AssetFactory::TextureFragmentCoords tfc; + if (auto mf = Persistence::ParseBase::getShared("assetFactory")) { + aiString path; + m.Get(AI_MATKEY_TEXTURE_DIFFUSE(0), path); + tfc = mf->getTextureCoords(path.C_Str()); + } + + for (const auto & f : AIRANGE(amesh, Faces)) { + const auto fvhs = AIRANGE(&f, Indices) * [&vhs](auto && i) { + return vhs[i]; + }; + const auto fh = faces.emplace(mesh.add_namedFace(amesh->mName.C_Str(), fvhs))->second; + if (amesh->HasTextureCoords(0)) { + for (auto idx = f.mIndices; const auto fheh : mesh.fh_range(fh)) { + const auto ouv = !amesh->mTextureCoords[0][*idx++]; + const auto uv = glm::mix(tfc[0], tfc[2], ouv); + mesh.set_texcoord2D(fheh, uv); + } + } + } + } +}; + +void +AssImp::postLoad() +{ + ScemeCPtr scene { + aiImportFile(Resource::mapPath(path).c_str(), aiProcess_RemoveRedundantMaterials), &aiReleaseImport}; + if (!scene) { + throw std::runtime_error("Failed to load asset library: " + path); + } + if (auto mf = Persistence::ParseBase::getShared("assetFactory")) { + const auto root = AIRANGE(scene->mRootNode, Children); + std::transform( + root.begin(), root.end(), std::inserter(mf->shapes, mf->shapes.end()), [&scene](const aiNode * m) { + return AssetFactory::Shapes::value_type {m->mName.C_Str(), std::make_shared(scene, m)}; + }); + const auto textures = AIRANGE(scene, Textures); + std::transform(textures.begin(), textures.end(), + std::inserter(mf->textureFragments, mf->textureFragments.end()), [](const aiTexture * t) { + auto texture = std::make_shared(); + texture->id = texture->path = t->mFilename.C_Str(); + texture->image = std::make_unique( + std::span {reinterpret_cast(t->pcData), t->mWidth}, STBI_rgb_alpha); + return AssetFactory::TextureFragments::value_type {texture->id, texture}; + }); + } +} + +bool +AssImp::persist(Persistence::PersistenceStore & store) +{ + return STORE_TYPE && STORE_MEMBER(path); +} diff --git a/assetFactory/assimp.h b/assetFactory/assimp.h new file mode 100644 index 0000000..55b551d --- /dev/null +++ b/assetFactory/assimp.h @@ -0,0 +1,14 @@ +#pragma once + +#include "persistence.h" + +class AssImp : public Persistence::Persistable { +public: + using Ptr = std::shared_ptr; + + void postLoad() override; + + bool persist(Persistence::PersistenceStore & store) override; + + std::string path; +}; diff --git a/res/foliage.xml b/res/foliage.xml new file mode 100644 index 0000000..1b0a1aa --- /dev/null +++ b/res/foliage.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/test/perf-assetFactory.cpp b/test/perf-assetFactory.cpp index c90ac52..147e4ba 100644 --- a/test/perf-assetFactory.cpp +++ b/test/perf-assetFactory.cpp @@ -14,6 +14,17 @@ brush47xml_load(benchmark::State & state) } } +static void +foliagexml_load(benchmark::State & state) +{ + TestMainWindow window; + + for (auto _ : state) { + benchmark::DoNotOptimize(AssetFactory::loadXML(RESDIR "/foliage.xml")); + } +} + BENCHMARK(brush47xml_load); +BENCHMARK(foliagexml_load); BENCHMARK_MAIN(); diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp index 54168aa..dd458ca 100644 --- a/test/test-assetFactory.cpp +++ b/test/test-assetFactory.cpp @@ -8,6 +8,8 @@ #include "assetFactory/assetFactory.h" #include "assetFactory/object.h" #include "assetFactory/texturePacker.h" +#include "game/scenary/foliage.h" +#include "game/scenary/plant.h" #include "game/vehicles/railVehicle.h" #include "game/vehicles/railVehicleClass.h" #include "gfx/gl/sceneRenderer.h" @@ -96,6 +98,21 @@ BOOST_AUTO_TEST_CASE(brush47xml, *boost::unit_test::timeout(5)) render(); } + +BOOST_AUTO_TEST_CASE(foliage, *boost::unit_test::timeout(5)) +{ + auto mf = AssetFactory::loadXML(RESDIR "/foliage.xml"); + BOOST_REQUIRE(mf); + auto tree_01_1 = mf->assets.at("Tree-01-1"); + BOOST_REQUIRE(tree_01_1); + auto tree_01_1_f = std::dynamic_pointer_cast(tree_01_1); + BOOST_REQUIRE(tree_01_1_f); + + auto plant = std::make_shared(tree_01_1_f, Location {}); + objects.objects.push_back(plant); + + render(); +} BOOST_AUTO_TEST_SUITE_END(); template using InOut = std::tuple; -- cgit v1.2.3 From 3cd6bc2d9eebbdd575164816110717241d9e22db Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 10 Apr 2023 19:48:07 +0100 Subject: Load assimp textures in parallel --- assetFactory/assimp.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/assetFactory/assimp.cpp b/assetFactory/assimp.cpp index 55090f4..0c6cb86 100644 --- a/assetFactory/assimp.cpp +++ b/assetFactory/assimp.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include template @@ -101,12 +102,18 @@ AssImp::postLoad() return AssetFactory::Shapes::value_type {m->mName.C_Str(), std::make_shared(scene, m)}; }); const auto textures = AIRANGE(scene, Textures); - std::transform(textures.begin(), textures.end(), - std::inserter(mf->textureFragments, mf->textureFragments.end()), [](const aiTexture * t) { - auto texture = std::make_shared(); - texture->id = texture->path = t->mFilename.C_Str(); - texture->image = std::make_unique( - std::span {reinterpret_cast(t->pcData), t->mWidth}, STBI_rgb_alpha); + auto textureFutures = textures * [](const aiTexture * t) { + return std::async(std::launch::async, [t]() { + auto texture = std::make_shared(); + texture->id = texture->path = t->mFilename.C_Str(); + texture->image = std::make_unique( + std::span {reinterpret_cast(t->pcData), t->mWidth}, STBI_rgb_alpha); + return texture; + }); + }; + std::transform(textureFutures.begin(), textureFutures.end(), + std::inserter(mf->textureFragments, mf->textureFragments.end()), [](auto && textureFuture) { + auto texture = textureFuture.get(); return AssetFactory::TextureFragments::value_type {texture->id, texture}; }); } -- cgit v1.2.3 From e2edd9f141699ce4be1664f590438369db9573e6 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 11 Apr 2023 18:36:41 +0100 Subject: Split out the glsl embedding jam rules --- Jamroot.jam | 24 +----------------------- glsl.jam | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 23 deletions(-) create mode 100644 glsl.jam diff --git a/Jamroot.jam b/Jamroot.jam index ebe97a6..2275dd6 100644 --- a/Jamroot.jam +++ b/Jamroot.jam @@ -1,12 +1,10 @@ using gcc ; using pkg-config ; import pkg-config ; -import type : register ; -import type : type ; -import generators : register-standard ; import testing ; import lex ; import sequence ; +import glsl ; pkg-config.import sdl2 ; pkg-config.import glew ; @@ -50,26 +48,6 @@ project : requirements tidy:TIDY ; -type.register GL_VERTEX_SHADER : vs ; -type.register GL_GEOMETRY_SHADER : gs ; -type.register GL_FRAGMENT_SHADER : fs ; - -generators.register-standard embed.glsl : GL_VERTEX_SHADER : CPP(vs-%) H(vs-%) ; -generators.register-standard embed.glsl : GL_GEOMETRY_SHADER : CPP(gs-%) H(gs-%) ; -generators.register-standard embed.glsl : GL_FRAGMENT_SHADER : CPP(fs-%) H(fs-%) ; - -actions embed.glsl -{ - m4 -DNAME=$(2:B) -DTYPE=$(2:S) > $(1[2]) lib/embed-glsl.h.m4 - m4 -DSOURCE=$(2) -DNAME=$(2:B) -DTYPE=$(2:S) -DGLTYPE=$(OPTIONS) > $(1[1]) lib/embed-glsl.cpp.m4 -} -rule embed.glsl ( targets * : sources * : properties * ) -{ - DEPENDS $(targets) : lib/embed-glsl.h.m4 lib/embed-glsl.cpp.m4 ; - OPTIONS on $(targets) = [ type.type $(sources) ] ; -} -IMPORT $(__name__) : embed.glsl : : embed.glsl ; - exe iliketrains : application/main.cpp : diff --git a/glsl.jam b/glsl.jam new file mode 100644 index 0000000..03e93e9 --- /dev/null +++ b/glsl.jam @@ -0,0 +1,23 @@ +import type : register ; +import type : type ; +import generators : register-standard ; + +type.register GL_VERTEX_SHADER : vs ; +type.register GL_GEOMETRY_SHADER : gs ; +type.register GL_FRAGMENT_SHADER : fs ; + +generators.register-standard glsl.embed : GL_VERTEX_SHADER : CPP(vs-%) H(vs-%) ; +generators.register-standard glsl.embed : GL_GEOMETRY_SHADER : CPP(gs-%) H(gs-%) ; +generators.register-standard glsl.embed : GL_FRAGMENT_SHADER : CPP(fs-%) H(fs-%) ; + +actions glsl.embed +{ + m4 -DNAME=$(2:B) -DTYPE=$(2:S) > $(1[2]) lib/embed-glsl.h.m4 + m4 -DSOURCE=$(2) -DNAME=$(2:B) -DTYPE=$(2:S) -DGLTYPE=$(OPTIONS) > $(1[1]) lib/embed-glsl.cpp.m4 +} + +rule glsl.embed ( targets * : sources * : properties * ) +{ + DEPENDS $(targets) : lib/embed-glsl.h.m4 lib/embed-glsl.cpp.m4 ; + OPTIONS on $(targets) = [ type.type $(sources) ] ; +} -- cgit v1.2.3 From 4d569af26d3bab55e27b3bb9ada14ef088e23f35 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 11 Apr 2023 18:40:18 +0100 Subject: Support m4 includes as a Jam scanner --- glsl.jam | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/glsl.jam b/glsl.jam index 03e93e9..87dee61 100644 --- a/glsl.jam +++ b/glsl.jam @@ -1,6 +1,7 @@ import type : register ; import type : type ; import generators : register-standard ; +import scanner : register ; type.register GL_VERTEX_SHADER : vs ; type.register GL_GEOMETRY_SHADER : gs ; @@ -10,10 +11,22 @@ generators.register-standard glsl.embed : GL_VERTEX_SHADER : CPP(vs-%) H(vs-%) ; generators.register-standard glsl.embed : GL_GEOMETRY_SHADER : CPP(gs-%) H(gs-%) ; generators.register-standard glsl.embed : GL_FRAGMENT_SHADER : CPP(fs-%) H(fs-%) ; +class m4-scanner : common-scanner { + rule pattern ( ) { + return "s?include\\(`([^']*)'\\)" ; + } +} + +scanner.register m4-scanner : include ; + +type.set-scanner GL_VERTEX_SHADER : m4-scanner ; +type.set-scanner GL_GEOMETRY_SHADER : m4-scanner ; +type.set-scanner GL_FRAGMENT_SHADER : m4-scanner ; + actions glsl.embed { - m4 -DNAME=$(2:B) -DTYPE=$(2:S) > $(1[2]) lib/embed-glsl.h.m4 - m4 -DSOURCE=$(2) -DNAME=$(2:B) -DTYPE=$(2:S) -DGLTYPE=$(OPTIONS) > $(1[1]) lib/embed-glsl.cpp.m4 + m4 -I$(2:D) -DNAME=$(2:B) -DTYPE=$(2:S) > $(1[2]) lib/embed-glsl.h.m4 + m4 -I$(2:D) -DSOURCE=$(2) -DNAME=$(2:B) -DTYPE=$(2:S) -DGLTYPE=$(OPTIONS) > $(1[1]) lib/embed-glsl.cpp.m4 } rule glsl.embed ( targets * : sources * : properties * ) -- cgit v1.2.3 From 43d8fdb3f6aeb88762c68179d7bb1dc58507bb60 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 11 Apr 2023 18:54:41 +0100 Subject: Move lots of common glsl interface to include files --- gfx/gl/shaders/basicShader.fs | 5 +---- gfx/gl/shaders/basicShader.vs | 6 +----- gfx/gl/shaders/geometryOut.glsl | 3 +++ gfx/gl/shaders/landmassShader.fs | 5 +---- gfx/gl/shaders/landmassShader.vs | 6 +----- gfx/gl/shaders/meshIn.glsl | 4 ++++ gfx/gl/shaders/shadowDynamicPoint.vs | 2 +- gfx/gl/shaders/shadowFixedPoint.vs | 2 +- gfx/gl/shaders/waterShader.fs | 5 +---- gfx/gl/shaders/waterShader.vs | 5 +---- 10 files changed, 15 insertions(+), 28 deletions(-) create mode 100644 gfx/gl/shaders/geometryOut.glsl create mode 100644 gfx/gl/shaders/meshIn.glsl diff --git a/gfx/gl/shaders/basicShader.fs b/gfx/gl/shaders/basicShader.fs index 24b2791..0d0b904 100644 --- a/gfx/gl/shaders/basicShader.fs +++ b/gfx/gl/shaders/basicShader.fs @@ -4,10 +4,7 @@ in vec3 FragPos; in vec2 TexCoords; in vec3 Normal; in vec4 Colour; - -out vec4 gPosition; -out vec4 gNormal; -out vec4 gAlbedoSpec; +include(`geometryOut.glsl') uniform sampler2D texture0; diff --git a/gfx/gl/shaders/basicShader.vs b/gfx/gl/shaders/basicShader.vs index ff9a401..a96d478 100644 --- a/gfx/gl/shaders/basicShader.vs +++ b/gfx/gl/shaders/basicShader.vs @@ -1,10 +1,6 @@ #version 330 core -in vec3 position; -in vec2 texCoord; -in vec3 normal; -in vec4 colour; - +include(`meshIn.glsl') out vec3 FragPos; out vec2 TexCoords; out vec3 Normal; diff --git a/gfx/gl/shaders/geometryOut.glsl b/gfx/gl/shaders/geometryOut.glsl new file mode 100644 index 0000000..dc5f8e8 --- /dev/null +++ b/gfx/gl/shaders/geometryOut.glsl @@ -0,0 +1,3 @@ +layout(location = 0) out vec4 gPosition; +layout(location = 1) out vec4 gNormal; +layout(location = 2) out vec4 gAlbedoSpec; diff --git a/gfx/gl/shaders/landmassShader.fs b/gfx/gl/shaders/landmassShader.fs index 7c08e8e..5daeeb6 100644 --- a/gfx/gl/shaders/landmassShader.fs +++ b/gfx/gl/shaders/landmassShader.fs @@ -3,10 +3,7 @@ in vec3 FragPos; in vec2 TexCoords; in vec3 Normal; - -layout(location = 0) out vec4 gPosition; -layout(location = 1) out vec4 gNormal; -layout(location = 2) out vec4 gAlbedoSpec; +include(`geometryOut.glsl') uniform sampler2D texture0; diff --git a/gfx/gl/shaders/landmassShader.vs b/gfx/gl/shaders/landmassShader.vs index 30c4ef4..3eb9aa3 100644 --- a/gfx/gl/shaders/landmassShader.vs +++ b/gfx/gl/shaders/landmassShader.vs @@ -1,10 +1,6 @@ #version 330 core -in vec3 position; -in vec2 texCoord; -in vec3 normal; -in vec4 colour; - +include(`meshIn.glsl') out vec3 FragPos; out vec2 TexCoords; out vec3 Normal; diff --git a/gfx/gl/shaders/meshIn.glsl b/gfx/gl/shaders/meshIn.glsl new file mode 100644 index 0000000..2b244c1 --- /dev/null +++ b/gfx/gl/shaders/meshIn.glsl @@ -0,0 +1,4 @@ +layout(location = 0) in vec3 position; +layout(location = 1) in vec2 texCoord; +layout(location = 2) in vec3 normal; +layout(location = 3) in vec4 colour; diff --git a/gfx/gl/shaders/shadowDynamicPoint.vs b/gfx/gl/shaders/shadowDynamicPoint.vs index 6ea352f..531d8de 100644 --- a/gfx/gl/shaders/shadowDynamicPoint.vs +++ b/gfx/gl/shaders/shadowDynamicPoint.vs @@ -1,6 +1,6 @@ #version 330 core -in vec3 position; +include(`meshIn.glsl') uniform mat4 viewProjection; uniform mat4 model; diff --git a/gfx/gl/shaders/shadowFixedPoint.vs b/gfx/gl/shaders/shadowFixedPoint.vs index 246890c..c9fa19b 100644 --- a/gfx/gl/shaders/shadowFixedPoint.vs +++ b/gfx/gl/shaders/shadowFixedPoint.vs @@ -1,6 +1,6 @@ #version 330 core -layout(location = 0) in vec3 position; +include(`meshIn.glsl') uniform mat4 viewProjection; diff --git a/gfx/gl/shaders/waterShader.fs b/gfx/gl/shaders/waterShader.fs index d242566..d457f27 100644 --- a/gfx/gl/shaders/waterShader.fs +++ b/gfx/gl/shaders/waterShader.fs @@ -4,10 +4,7 @@ in vec3 FragPos; in vec2 TexCoords; in vec3 Normal; - -out vec4 gPosition; -out vec4 gNormal; -out vec4 gAlbedoSpec; +include(`geometryOut.glsl') uniform sampler2D texture0; uniform vec3 waves; diff --git a/gfx/gl/shaders/waterShader.vs b/gfx/gl/shaders/waterShader.vs index fe9206f..6f96c19 100644 --- a/gfx/gl/shaders/waterShader.vs +++ b/gfx/gl/shaders/waterShader.vs @@ -1,9 +1,6 @@ #version 330 core -in vec3 position; -in vec2 texCoord; -in vec3 normal; - +include(`meshIn.glsl') out vec3 FragPos; out vec2 TexCoords; out vec3 Normal; -- cgit v1.2.3 From d0186d81127056ac2647807dcf05b454e234a7cb Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 11 Apr 2023 22:54:44 +0100 Subject: Move the vertex/fragment shader interface for materials into an include --- gfx/gl/shaders/basicShader.fs | 5 +---- gfx/gl/shaders/basicShader.vs | 5 +---- gfx/gl/shaders/landmassShader.fs | 4 +--- gfx/gl/shaders/landmassShader.vs | 5 +---- gfx/gl/shaders/materialInterface.glsl | 4 ++++ gfx/gl/shaders/waterShader.fs | 4 +--- gfx/gl/shaders/waterShader.vs | 4 +--- 7 files changed, 10 insertions(+), 21 deletions(-) create mode 100644 gfx/gl/shaders/materialInterface.glsl diff --git a/gfx/gl/shaders/basicShader.fs b/gfx/gl/shaders/basicShader.fs index 0d0b904..8bb6350 100644 --- a/gfx/gl/shaders/basicShader.fs +++ b/gfx/gl/shaders/basicShader.fs @@ -1,9 +1,6 @@ #version 330 core -in vec3 FragPos; -in vec2 TexCoords; -in vec3 Normal; -in vec4 Colour; +include(`materialInterface.glsl') include(`geometryOut.glsl') uniform sampler2D texture0; diff --git a/gfx/gl/shaders/basicShader.vs b/gfx/gl/shaders/basicShader.vs index a96d478..4d648f3 100644 --- a/gfx/gl/shaders/basicShader.vs +++ b/gfx/gl/shaders/basicShader.vs @@ -1,10 +1,7 @@ #version 330 core include(`meshIn.glsl') -out vec3 FragPos; -out vec2 TexCoords; -out vec3 Normal; -out vec4 Colour; +include(`materialInterface.glsl') uniform mat4 viewProjection; uniform mat4 model; diff --git a/gfx/gl/shaders/landmassShader.fs b/gfx/gl/shaders/landmassShader.fs index 5daeeb6..f3cc3e8 100644 --- a/gfx/gl/shaders/landmassShader.fs +++ b/gfx/gl/shaders/landmassShader.fs @@ -1,8 +1,6 @@ #version 330 core -in vec3 FragPos; -in vec2 TexCoords; -in vec3 Normal; +include(`materialInterface.glsl') include(`geometryOut.glsl') uniform sampler2D texture0; diff --git a/gfx/gl/shaders/landmassShader.vs b/gfx/gl/shaders/landmassShader.vs index 3eb9aa3..cabe39f 100644 --- a/gfx/gl/shaders/landmassShader.vs +++ b/gfx/gl/shaders/landmassShader.vs @@ -1,10 +1,7 @@ #version 330 core include(`meshIn.glsl') -out vec3 FragPos; -out vec2 TexCoords; -out vec3 Normal; -out vec4 Colour; +include(`materialInterface.glsl') uniform mat4 viewProjection; diff --git a/gfx/gl/shaders/materialInterface.glsl b/gfx/gl/shaders/materialInterface.glsl new file mode 100644 index 0000000..3e09c85 --- /dev/null +++ b/gfx/gl/shaders/materialInterface.glsl @@ -0,0 +1,4 @@ +ifelse(TYPE, .fs, in, out) vec3 FragPos; +ifelse(TYPE, .fs, in, out) vec2 TexCoords; +ifelse(TYPE, .fs, in, out) vec3 Normal; +ifelse(TYPE, .fs, in, out) vec4 Colour; diff --git a/gfx/gl/shaders/waterShader.fs b/gfx/gl/shaders/waterShader.fs index d457f27..5936da4 100644 --- a/gfx/gl/shaders/waterShader.fs +++ b/gfx/gl/shaders/waterShader.fs @@ -1,9 +1,7 @@ #version 330 core #extension GL_ARB_shading_language_420pack : enable -in vec3 FragPos; -in vec2 TexCoords; -in vec3 Normal; +include(`materialInterface.glsl') include(`geometryOut.glsl') uniform sampler2D texture0; diff --git a/gfx/gl/shaders/waterShader.vs b/gfx/gl/shaders/waterShader.vs index 6f96c19..a21b49f 100644 --- a/gfx/gl/shaders/waterShader.vs +++ b/gfx/gl/shaders/waterShader.vs @@ -1,9 +1,7 @@ #version 330 core include(`meshIn.glsl') -out vec3 FragPos; -out vec2 TexCoords; -out vec3 Normal; +include(`materialInterface.glsl') uniform mat4 viewProjection; uniform vec3 waves; -- cgit v1.2.3 From 936f54e86f71d8e4af4784ebb32b6518c6fc3a01 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 13 Apr 2023 00:44:20 +0100 Subject: Fix submitting of integer values via vertex arrays --- gfx/gl/shaders/lightingShader.vs | 2 +- gfx/gl/vertexArrayObject.hpp | 2 +- lib/gl_traits.hpp | 45 ++++++++++++++++++++++++++-------------- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/gfx/gl/shaders/lightingShader.vs b/gfx/gl/shaders/lightingShader.vs index 2271d2e..e07cd0a 100644 --- a/gfx/gl/shaders/lightingShader.vs +++ b/gfx/gl/shaders/lightingShader.vs @@ -1,6 +1,6 @@ #version 330 core -in vec4 position; +in ivec4 position; out vec2 TexCoords; diff --git a/gfx/gl/vertexArrayObject.hpp b/gfx/gl/vertexArrayObject.hpp index c0273c0..5b9fc60 100644 --- a/gfx/gl/vertexArrayObject.hpp +++ b/gfx/gl/vertexArrayObject.hpp @@ -61,7 +61,7 @@ private: { glEnableVertexAttribArray(vertexArrayId); using traits = gl_traits; - glVertexAttribPointer(vertexArrayId, traits::size, traits::type, GL_FALSE, sizeof(Vertex), ptr); + traits::vertexAttribFunc(vertexArrayId, traits::size, traits::type, sizeof(Vertex), ptr); } template diff --git a/lib/gl_traits.hpp b/lib/gl_traits.hpp index d140de9..e2e689d 100644 --- a/lib/gl_traits.hpp +++ b/lib/gl_traits.hpp @@ -6,37 +6,50 @@ #include template struct gl_traits; -template<> struct gl_traits { - static constexpr GLenum type {GL_FLOAT}; +struct gl_traits_base { static constexpr GLint size {1}; }; -template<> struct gl_traits { +struct gl_traits_float : public gl_traits_base { + static constexpr auto vertexAttribFunc { + [](GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer) { + glVertexAttribPointer(index, size, type, GL_FALSE, stride, pointer); + }}; +}; +struct gl_traits_longfloat : public gl_traits_base { + static constexpr auto vertexAttribFunc { + [](GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer) { + glVertexAttribLPointer(index, size, type, stride, pointer); + }}; +}; +struct gl_traits_integer : public gl_traits_base { + static constexpr auto vertexAttribFunc { + [](GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer) { + glVertexAttribIPointer(index, size, type, stride, pointer); + }}; +}; +template<> struct gl_traits : public gl_traits_float { + static constexpr GLenum type {GL_FLOAT}; +}; +template<> struct gl_traits : public gl_traits_longfloat { static constexpr GLenum type {GL_DOUBLE}; - static constexpr GLint size {1}; }; -template<> struct gl_traits { +template<> struct gl_traits : public gl_traits_integer { static constexpr GLenum type {GL_BYTE}; - static constexpr GLint size {1}; }; -template<> struct gl_traits { +template<> struct gl_traits : public gl_traits_integer { static constexpr GLenum type {GL_SHORT}; - static constexpr GLint size {1}; }; -template<> struct gl_traits { +template<> struct gl_traits : public gl_traits_integer { static constexpr GLenum type {GL_INT}; - static constexpr GLint size {1}; }; -template<> struct gl_traits { +template<> struct gl_traits : public gl_traits_integer { static constexpr GLenum type {GL_UNSIGNED_BYTE}; - static constexpr GLint size {1}; }; -template<> struct gl_traits { +template<> struct gl_traits : public gl_traits_integer { static constexpr GLenum type {GL_UNSIGNED_SHORT}; - static constexpr GLint size {1}; }; -template<> struct gl_traits { +template<> struct gl_traits : public gl_traits_integer { static constexpr GLenum type {GL_UNSIGNED_INT}; - static constexpr GLint size {1}; }; template struct gl_traits> : public gl_traits { -- cgit v1.2.3 From 1529d37d585ec38aee475519e444d2718a81fda5 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 13 Apr 2023 02:10:44 +0100 Subject: Add TextureAtlas class as an extension of Texture --- gfx/models/texture.cpp | 32 ++++++++++++++++++++++++++++++++ gfx/models/texture.h | 19 +++++++++++++++++-- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/gfx/models/texture.cpp b/gfx/models/texture.cpp index efc76e1..a500fed 100644 --- a/gfx/models/texture.cpp +++ b/gfx/models/texture.cpp @@ -85,3 +85,35 @@ Texture::saveNormal(const glTexture & texture, const glm::ivec2 & size, const ch { save(texture, GL_BGR, GL_BYTE, size, 3, path, 2); } + +TextureAtlas::TextureAtlas(GLsizei width, GLsizei height, GLuint count) : Texture(width, height, nullptr, {}) +{ + glBindTexture(GL_TEXTURE_RECTANGLE, m_atlas); + + glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA16UI, 2, static_cast(count), 0, GL_RGBA_INTEGER, + GL_UNSIGNED_BYTE, nullptr); +} + +void +TextureAtlas::bind(GLenum unit) const +{ + Texture::bind(unit); + glActiveTexture(unit + 1); + glBindTexture(GL_TEXTURE_RECTANGLE, m_atlas); +} + +GLuint +TextureAtlas::add(glm::ivec2 position, glm::ivec2 size, void * data, TextureOptions) +{ + glTextureSubImage2D(m_texture, 0, position.x, position.y, size.x, size.y, GL_RGBA, GL_UNSIGNED_BYTE, data); + struct Material { + glm::vec<2, uint16_t> position, size, unused1 {}, unused2 {}; + } material {position, size}; + glTextureSubImage2D(m_atlas, 0, 0, static_cast(used), 2, 1, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, &material); + return ++used; +} diff --git a/gfx/models/texture.h b/gfx/models/texture.h index ffc9a4a..7900f17 100644 --- a/gfx/models/texture.h +++ b/gfx/models/texture.h @@ -16,6 +16,9 @@ struct TextureOptions { class Texture { public: + virtual ~Texture() = default; + DEFAULT_MOVE_NO_COPY(Texture); + explicit Texture(const std::filesystem::path & fileName, TextureOptions = {}); explicit Texture(const Image & image, TextureOptions = {}); explicit Texture(GLsizei width, GLsizei height, TextureOptions = {}); @@ -23,17 +26,29 @@ public: static Cache cachedTexture; - void bind(GLenum unit = GL_TEXTURE0) const; + virtual void bind(GLenum unit = GL_TEXTURE0) const; void save(const glm::ivec2 & size, const char * path) const; static void save(const glTexture &, const glm::ivec2 & size, const char * path); static void saveDepth(const glTexture &, const glm::ivec2 & size, const char * path); static void saveNormal(const glTexture &, const glm::ivec2 & size, const char * path); -private: +protected: static void save(const glTexture &, GLenum, GLenum, const glm::ivec2 & size, unsigned short channels, const char * path, short tgaFormat); glTexture m_texture; GLenum type; }; + +class TextureAtlas : public Texture { +public: + TextureAtlas(GLsizei width, GLsizei height, GLuint count); + + void bind(GLenum unit = GL_TEXTURE0) const override; + GLuint add(glm::ivec2 position, glm::ivec2 size, void * data, TextureOptions = {}); + +private: + glTexture m_atlas; + GLuint used {}; +}; -- cgit v1.2.3 From 259444e842ac4ec546948a8e828b62bec734f659 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 13 Apr 2023 02:13:20 +0100 Subject: Add material field to vertex and configure it in mesh --- gfx/models/mesh.cpp | 3 ++- gfx/models/vertex.hpp | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/gfx/models/mesh.cpp b/gfx/models/mesh.cpp index 3db1ad5..2719211 100644 --- a/gfx/models/mesh.cpp +++ b/gfx/models/mesh.cpp @@ -7,7 +7,8 @@ Mesh::Mesh(const std::span vertices, const std::span indices, GLenum m) : m_numIndices {static_cast(indices.size())}, mode {m} { - VertexArrayObject::configure<&Vertex::pos, &Vertex::texCoord, &Vertex::normal, &Vertex::colour>( + VertexArrayObject::configure<&Vertex::pos, &Vertex::texCoord, &Vertex::normal, &Vertex::colour, + &Vertex::material>( m_vertexArrayObject, m_vertexArrayBuffers[0], m_vertexArrayBuffers[1], vertices, indices); } diff --git a/gfx/models/vertex.hpp b/gfx/models/vertex.hpp index 64ec3d0..181e7e7 100644 --- a/gfx/models/vertex.hpp +++ b/gfx/models/vertex.hpp @@ -1,12 +1,14 @@ #pragma once +#include #include class Vertex { public: #ifndef __cpp_aggregate_paren_init - constexpr Vertex(glm::vec3 pos, glm::vec2 texCoord, glm::vec3 normal, glm::vec4 colour = {}) : - pos {std::move(pos)}, texCoord {std::move(texCoord)}, normal {std::move(normal)}, colour {std::move(colour)} + constexpr Vertex(glm::vec3 pos, glm::vec2 texCoord, glm::vec3 normal, glm::vec4 colour = {}, GLuint material = 0) : + pos {std::move(pos)}, texCoord {std::move(texCoord)}, normal {std::move(normal)}, colour {std::move(colour)}, + material {material} { } #endif @@ -16,5 +18,6 @@ public: glm::vec3 pos; glm::vec2 texCoord; glm::vec3 normal; - glm::vec4 colour; + glm::vec4 colour {}; + GLuint material {}; }; -- cgit v1.2.3 From f16a7df6135262c91fee2a2f6c46ad2f3caa7157 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 13 Apr 2023 02:15:41 +0100 Subject: Update shaders to use material to conditionally lookup sub-texture in the atlas --- gfx/gl/shaders/basicShader.fs | 16 ++++++++++++++-- gfx/gl/shaders/basicShader.vs | 1 + gfx/gl/shaders/landmassShader.vs | 1 + gfx/gl/shaders/materialInterface.glsl | 3 +++ gfx/gl/shaders/meshIn.glsl | 1 + 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/gfx/gl/shaders/basicShader.fs b/gfx/gl/shaders/basicShader.fs index 8bb6350..ab5e58b 100644 --- a/gfx/gl/shaders/basicShader.fs +++ b/gfx/gl/shaders/basicShader.fs @@ -1,14 +1,26 @@ #version 330 core +#extension GL_ARB_shading_language_420pack : enable include(`materialInterface.glsl') include(`geometryOut.glsl') -uniform sampler2D texture0; +layout(binding = 0) uniform sampler2D texture0; +layout(binding = 1) uniform usampler2DRect material; + +vec4 getTextureColour(uint midx, vec2 uv) +{ + if (midx > 0u) { + const vec2 tSize = textureSize(texture0, 0); + const vec4 sPosSize = texture(material, uvec2(0, midx - 1u)); + uv = (sPosSize.xy + sPosSize.zw * fract(uv)) / tSize; + } + return texture(texture0, uv); +} void main() { - vec4 textureColour = texture(texture0, TexCoords); + vec4 textureColour = getTextureColour(Material, TexCoords); float clear = round(mix(textureColour.a, 1, Colour.a)); gPosition = vec4(FragPos, clear); gNormal = vec4(Normal, clear); diff --git a/gfx/gl/shaders/basicShader.vs b/gfx/gl/shaders/basicShader.vs index 4d648f3..e1701ed 100644 --- a/gfx/gl/shaders/basicShader.vs +++ b/gfx/gl/shaders/basicShader.vs @@ -15,6 +15,7 @@ main() TexCoords = texCoord; Normal = (model * vec4(normal, 0.0)).xyz; Colour = colour; + Material = material; gl_Position = viewProjection * worldPos; } diff --git a/gfx/gl/shaders/landmassShader.vs b/gfx/gl/shaders/landmassShader.vs index cabe39f..0cc8153 100644 --- a/gfx/gl/shaders/landmassShader.vs +++ b/gfx/gl/shaders/landmassShader.vs @@ -12,6 +12,7 @@ main() TexCoords = texCoord; Normal = normal; Colour = colour; + Material = material; gl_Position = viewProjection * vec4(position, 1.0); } diff --git a/gfx/gl/shaders/materialInterface.glsl b/gfx/gl/shaders/materialInterface.glsl index 3e09c85..5735cf9 100644 --- a/gfx/gl/shaders/materialInterface.glsl +++ b/gfx/gl/shaders/materialInterface.glsl @@ -2,3 +2,6 @@ ifelse(TYPE, .fs, in, out) vec3 FragPos; ifelse(TYPE, .fs, in, out) vec2 TexCoords; ifelse(TYPE, .fs, in, out) vec3 Normal; ifelse(TYPE, .fs, in, out) vec4 Colour; +flat +ifelse(TYPE, .fs, in, out) +uint Material; diff --git a/gfx/gl/shaders/meshIn.glsl b/gfx/gl/shaders/meshIn.glsl index 2b244c1..dd84a10 100644 --- a/gfx/gl/shaders/meshIn.glsl +++ b/gfx/gl/shaders/meshIn.glsl @@ -2,3 +2,4 @@ layout(location = 0) in vec3 position; layout(location = 1) in vec2 texCoord; layout(location = 2) in vec3 normal; layout(location = 3) in vec4 colour; +layout(location = 4) in uint material; -- cgit v1.2.3 From f709098cd7a5fb7e88b96de18e609a2aebd56644 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 13 Apr 2023 02:16:39 +0100 Subject: Add missing forward declaration --- game/scenary/foliage.h | 1 + 1 file changed, 1 insertion(+) diff --git a/game/scenary/foliage.h b/game/scenary/foliage.h index 229bccb..b85aab2 100644 --- a/game/scenary/foliage.h +++ b/game/scenary/foliage.h @@ -5,6 +5,7 @@ class SceneShader; class ShadowMapper; class Location; +class Texture; class Foliage : public Asset, public StdTypeDefs { Mesh::Ptr bodyMesh; -- cgit v1.2.3 From 1b97b7b4cb126c8b60ac1acbd7e72274f0ddf21f Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 13 Apr 2023 02:20:50 +0100 Subject: Use texture atlas for asset factory --- assetFactory/asset.h | 4 ++-- assetFactory/assetFactory.cpp | 26 ++++++++------------------ assetFactory/assetFactory.h | 4 ++-- assetFactory/assimp.cpp | 8 ++++---- assetFactory/factoryMesh.cpp | 3 ++- assetFactory/modelFactoryMesh.cpp | 1 + assetFactory/modelFactoryMesh.h | 2 ++ assetFactory/style.cpp | 9 ++++++++- 8 files changed, 29 insertions(+), 28 deletions(-) diff --git a/assetFactory/asset.h b/assetFactory/asset.h index 30f40cd..dba4974 100644 --- a/assetFactory/asset.h +++ b/assetFactory/asset.h @@ -4,11 +4,11 @@ #include "persistence.h" #include -class Texture; +class TextureAtlas; class Asset : public Persistence::Persistable, public StdTypeDefs { public: - using TexturePtr = std::shared_ptr; + using TexturePtr = std::shared_ptr; std::string id; std::string name; diff --git a/assetFactory/assetFactory.cpp b/assetFactory/assetFactory.cpp index 917edfe..46b4642 100644 --- a/assetFactory/assetFactory.cpp +++ b/assetFactory/assetFactory.cpp @@ -80,17 +80,11 @@ 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 +GLuint +AssetFactory::getMaterialIndex(std::string_view id) const { createTexutre(); - const auto & fragmentUV = textureFragmentPositions.at(id); - return { - fragmentUV.xy(), - fragmentUV.zy(), - fragmentUV.zw(), - fragmentUV.xw(), - }; + return textureFragmentPositions.at(id); } Asset::TexturePtr @@ -103,7 +97,7 @@ AssetFactory::getTexture() const void AssetFactory::createTexutre() const { - if (!textureFragments.empty() && (!texture || textureFragmentPositions.empty())) { + if (!textureFragments.empty() && !texture) { // * layout images std::vector imageSizes; std::transform( @@ -112,18 +106,14 @@ AssetFactory::createTexutre() const }); const auto [layout, outSize] = TexturePacker {imageSizes}.pack(); // * create texture - texture = std::make_shared(outSize.x, outSize.y, TextureOptions {.wrap = GL_CLAMP_TO_EDGE}); + texture = std::make_shared(outSize.x, outSize.y, layout.size()); std::transform(textureFragments.begin(), textureFragments.end(), std::inserter(textureFragmentPositions, textureFragmentPositions.end()), - [position = layout.begin(), size = imageSizes.begin(), outSize = glm::vec2 {outSize}]( - const auto & tf) mutable { - 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, - tf.second->image->data.data()); + [position = layout.begin(), size = imageSizes.begin(), this](const auto & tf) mutable { + const auto m = texture->add(*position, *size, tf.second->image->data.data()); position++; size++; - return decltype(textureFragmentPositions)::value_type {tf.first, positionFraction}; + return decltype(textureFragmentPositions)::value_type {tf.first, m}; }); } } diff --git a/assetFactory/assetFactory.h b/assetFactory/assetFactory.h index 7843d44..9e5d205 100644 --- a/assetFactory/assetFactory.h +++ b/assetFactory/assetFactory.h @@ -23,7 +23,7 @@ public: 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]] GLuint getMaterialIndex(std::string_view) const; [[nodiscard]] Asset::TexturePtr getTexture() const; Shapes shapes; @@ -42,5 +42,5 @@ private: void createTexutre() const; mutable Asset::TexturePtr texture; - mutable std::map> textureFragmentPositions; + mutable std::map> textureFragmentPositions; }; diff --git a/assetFactory/assimp.cpp b/assetFactory/assimp.cpp index 0c6cb86..dd82105 100644 --- a/assetFactory/assimp.cpp +++ b/assetFactory/assimp.cpp @@ -64,11 +64,11 @@ public: }; const auto & m = *scene->mMaterials[amesh->mMaterialIndex]; - AssetFactory::TextureFragmentCoords tfc; + GLuint material {}; if (auto mf = Persistence::ParseBase::getShared("assetFactory")) { aiString path; m.Get(AI_MATKEY_TEXTURE_DIFFUSE(0), path); - tfc = mf->getTextureCoords(path.C_Str()); + material = mf->getMaterialIndex(path.C_Str()); } for (const auto & f : AIRANGE(amesh, Faces)) { @@ -79,8 +79,8 @@ public: if (amesh->HasTextureCoords(0)) { for (auto idx = f.mIndices; const auto fheh : mesh.fh_range(fh)) { const auto ouv = !amesh->mTextureCoords[0][*idx++]; - const auto uv = glm::mix(tfc[0], tfc[2], ouv); - mesh.set_texcoord2D(fheh, uv); + mesh.set_texcoord2D(fheh, ouv); + mesh.property(mesh.materialFaceProperty, fh) = material; } } } diff --git a/assetFactory/factoryMesh.cpp b/assetFactory/factoryMesh.cpp index 4922936..f7bc7c8 100644 --- a/assetFactory/factoryMesh.cpp +++ b/assetFactory/factoryMesh.cpp @@ -18,6 +18,7 @@ FactoryMesh::createMesh() const for (const auto & face : mesh.faces()) { const auto & smooth = mesh.property(mesh.smoothFaceProperty, face); const auto & colour = mesh.color(face); + const auto & material = mesh.property(mesh.materialFaceProperty, face); std::vector faceIndices; for (const auto & heh : mesh.fh_range(face)) { @@ -26,7 +27,7 @@ FactoryMesh::createMesh() const 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}; + Vertex outVertex {point, textureUV, normal, colour, material}; 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)); diff --git a/assetFactory/modelFactoryMesh.cpp b/assetFactory/modelFactoryMesh.cpp index e640502..3d4b5f3 100644 --- a/assetFactory/modelFactoryMesh.cpp +++ b/assetFactory/modelFactoryMesh.cpp @@ -3,6 +3,7 @@ ModelFactoryMesh::ModelFactoryMesh() { add_property(smoothFaceProperty); + add_property(materialFaceProperty); add_property(nameFaceProperty); add_property(nameAdjFaceProperty); } diff --git a/assetFactory/modelFactoryMesh.h b/assetFactory/modelFactoryMesh.h index 8ac2edd..4eac7ee 100644 --- a/assetFactory/modelFactoryMesh.h +++ b/assetFactory/modelFactoryMesh.h @@ -1,6 +1,7 @@ #pragma once #include "modelFactoryMesh_fwd.h" +#include #include #include #include @@ -47,6 +48,7 @@ struct ModelFactoryMesh : public OpenMesh::PolyMesh_ArrayKernelT smoothFaceProperty; + OpenMesh::FPropHandleT materialFaceProperty; OpenMesh::FPropHandleT nameFaceProperty; OpenMesh::HPropHandleT nameAdjFaceProperty; diff --git a/assetFactory/style.cpp b/assetFactory/style.cpp index 12346a6..ea67fc2 100644 --- a/assetFactory/style.cpp +++ b/assetFactory/style.cpp @@ -30,7 +30,14 @@ Style::applyStyle( else { mesh.set_color(face, {}); if (auto mf = Persistence::ParseBase::getShared("assetFactory")) { - auto coords = mf->getTextureCoords(texture); + const auto material = mf->getMaterialIndex(texture); + mesh.property(mesh.materialFaceProperty, face) = material; + static constexpr std::array coords {{ + {0.f, 0.f}, + {1.f, 0.f}, + {1.f, 1.f}, + {0.f, 1.f}, + }}; auto coord = coords.begin(); // Wild assumption that face is a quad and the texture should apply linearly for (const auto & heh : mesh.fh_range(face)) { -- cgit v1.2.3 From 2f5a53d9dfec54bd33609dbe5a0af44c565d8069 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 13 Apr 2023 17:53:38 +0100 Subject: Adjust gl_FragDepth according to texel opacity --- gfx/gl/shaders/basicShader.fs | 1 + 1 file changed, 1 insertion(+) diff --git a/gfx/gl/shaders/basicShader.fs b/gfx/gl/shaders/basicShader.fs index ab5e58b..ff1c822 100644 --- a/gfx/gl/shaders/basicShader.fs +++ b/gfx/gl/shaders/basicShader.fs @@ -24,5 +24,6 @@ main() float clear = round(mix(textureColour.a, 1, Colour.a)); gPosition = vec4(FragPos, clear); gNormal = vec4(Normal, clear); + gl_FragDepth = mix(1.0, gl_FragCoord.z, clear); gAlbedoSpec = mix(textureColour, vec4(Colour.rgb, 1), Colour.a); } -- cgit v1.2.3 From 31e2bd9b5738498be3d13dc96cc78f48825a8601 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 13 Apr 2023 18:02:28 +0100 Subject: Rename clear to opaque as its 1 for solid --- gfx/gl/shaders/basicShader.fs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gfx/gl/shaders/basicShader.fs b/gfx/gl/shaders/basicShader.fs index ff1c822..8a72e6d 100644 --- a/gfx/gl/shaders/basicShader.fs +++ b/gfx/gl/shaders/basicShader.fs @@ -21,9 +21,9 @@ void main() { vec4 textureColour = getTextureColour(Material, TexCoords); - float clear = round(mix(textureColour.a, 1, Colour.a)); - gPosition = vec4(FragPos, clear); - gNormal = vec4(Normal, clear); - gl_FragDepth = mix(1.0, gl_FragCoord.z, clear); + float opaque = step(0.5, mix(textureColour.a, 1, Colour.a)); + gPosition = vec4(FragPos, opaque); + gNormal = vec4(Normal, opaque); + gl_FragDepth = mix(1.0, gl_FragCoord.z, opaque); gAlbedoSpec = mix(textureColour, vec4(Colour.rgb, 1), Colour.a); } -- cgit v1.2.3 From c51c4c0ca3b19e47d6e75ce4be247a28d412a04c Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 13 Apr 2023 20:03:13 +0100 Subject: Fix typo in name SceneCPtr --- assetFactory/assimp.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/assetFactory/assimp.cpp b/assetFactory/assimp.cpp index dd82105..878e7e7 100644 --- a/assetFactory/assimp.cpp +++ b/assetFactory/assimp.cpp @@ -29,12 +29,12 @@ operator!(const aiVector3t & v) (parent)->m##member, (parent)->mNum##member \ } -using ScemeCPtr = std::shared_ptr; +using SceneCPtr = std::shared_ptr; class AssImpNode : public Shape { public: - AssImpNode(ScemeCPtr scene, const aiNode * node) : scene(std::move(scene)), node(node) { } + AssImpNode(SceneCPtr scene, const aiNode * node) : scene(std::move(scene)), node(node) { } - ScemeCPtr scene; + SceneCPtr scene; const aiNode * node; CreatedFaces @@ -90,7 +90,7 @@ public: void AssImp::postLoad() { - ScemeCPtr scene { + SceneCPtr scene { aiImportFile(Resource::mapPath(path).c_str(), aiProcess_RemoveRedundantMaterials), &aiReleaseImport}; if (!scene) { throw std::runtime_error("Failed to load asset library: " + path); -- cgit v1.2.3 From 79506d6072ad7482ace521cc3a60671e78fd1597 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 01:04:38 +0100 Subject: Reduce texture size determined by packer if non-pot sizes are supported --- assetFactory/texturePacker.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/assetFactory/texturePacker.cpp b/assetFactory/texturePacker.cpp index 68a6010..30f1c37 100644 --- a/assetFactory/texturePacker.cpp +++ b/assetFactory/texturePacker.cpp @@ -1,7 +1,9 @@ #include "texturePacker.h" #include "collections.hpp" +#include #include #include +#include #include #include #include @@ -55,6 +57,17 @@ TexturePacker::pack(Size size) const } } } + if (GLEW_ARB_texture_non_power_of_two) { + // Crop the size back to minimum size + size = std::transform_reduce( + result.begin(), result.end(), inputImages.begin(), Size {}, + [](auto && max, auto && limit) { + return glm::max(max, limit); + }, + [](auto && pos, auto && size) { + return pos + size; + }); + } return {result, size}; } -- cgit v1.2.3 From 2b3df2889369aa22b6a1c782bb7fed658720c341 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 01:06:31 +0100 Subject: Have texture packer search harder for a solution, stopping at the reported texture size limit --- assetFactory/texturePacker.cpp | 16 ++++++++++++---- assetFactory/texturePacker.h | 1 + 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/assetFactory/texturePacker.cpp b/assetFactory/texturePacker.cpp index 30f1c37..fcc935f 100644 --- a/assetFactory/texturePacker.cpp +++ b/assetFactory/texturePacker.cpp @@ -14,6 +14,9 @@ TexturePacker::TexturePacker(std::span in) : std::sort(sortedIndexes.rbegin(), sortedIndexes.rend(), [this](const auto a, const auto b) { return area(inputImages[a]) < area(inputImages[b]); }); + int mts; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mts); + maxTextureSize = static_cast(mts); } TexturePacker::Result @@ -25,6 +28,9 @@ TexturePacker::pack() const TexturePacker::Result TexturePacker::pack(Size size) const { + if (size.x > maxTextureSize || size.y > maxTextureSize) { + return {}; + } using Spaces = std::set; Spaces spaces {{{}, size}}; @@ -49,12 +55,14 @@ TexturePacker::pack(Size size) const } } else { - if (size.x < size.y) { - return pack({size.x * 2, size.y}); + const auto x = pack({size.x * 2, size.y}), y = pack({size.x, size.y * 2}); + if (!x.first.empty() && (y.first.empty() || area(x.second) < area(y.second))) { + return x; } - else { - return pack({size.x, size.y * 2}); + else if (!y.first.empty()) { + return y; } + return {}; } } if (GLEW_ARB_texture_non_power_of_two) { diff --git a/assetFactory/texturePacker.h b/assetFactory/texturePacker.h index ca0d67a..a1b270b 100644 --- a/assetFactory/texturePacker.h +++ b/assetFactory/texturePacker.h @@ -38,4 +38,5 @@ public: private: std::span inputImages; std::vector sortedIndexes; + unsigned int maxTextureSize; }; -- cgit v1.2.3 From 1efd1c0cabb19c0d305b64d6e8aa1df3ab2150da Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 01:40:28 +0100 Subject: Extend timeout... this can be a bit slow now --- test/test-assetFactory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp index dd458ca..4fde5ed 100644 --- a/test/test-assetFactory.cpp +++ b/test/test-assetFactory.cpp @@ -174,7 +174,7 @@ BOOST_AUTO_TEST_CASE(texturePacker_many, *boost::unit_test::timeout(5)) BOOST_CHECK_EQUAL(totalSize, TexturePacker::area(result.second)); } -BOOST_AUTO_TEST_CASE(texturePacker_many_random, *boost::unit_test::timeout(5)) +BOOST_AUTO_TEST_CASE(texturePacker_many_random, *boost::unit_test::timeout(15)) { std::vector images(2048); std::mt19937 gen(std::random_device {}()); -- cgit v1.2.3 From 0638aaaf2a60efae95a1b404d7eee29e894047bc Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 01:54:19 +0100 Subject: No need to pass size around, we can get it back from the texture --- gfx/models/texture.cpp | 30 ++++++++++++++++++++---------- gfx/models/texture.h | 12 ++++++------ test/test-assetFactory.cpp | 2 +- test/test-render.cpp | 6 +++--- 4 files changed, 30 insertions(+), 20 deletions(-) diff --git a/gfx/models/texture.cpp b/gfx/models/texture.cpp index a500fed..ab256d5 100644 --- a/gfx/models/texture.cpp +++ b/gfx/models/texture.cpp @@ -44,12 +44,22 @@ Texture::bind(GLenum unit) const glBindTexture(type, m_texture); } +glm::ivec2 +Texture::getSize(const glTexture & texture) +{ + glm::ivec2 size; + glGetTextureLevelParameteriv(texture, 0, GL_TEXTURE_WIDTH, &size.x); + glGetTextureLevelParameteriv(texture, 0, GL_TEXTURE_HEIGHT, &size.y); + return size; +} + void -Texture::save(const glTexture & texture, GLenum format, GLenum type, const glm::ivec2 & size, unsigned short channels, - const char * path, short tgaFormat) +Texture::save(const glTexture & texture, GLenum format, GLenum type, unsigned short channels, const char * path, + short tgaFormat) { using TGAHead = std::array; + const auto size = getSize(texture); const size_t dataSize = (static_cast(size.x * size.y * channels)); const size_t fileSize = dataSize + sizeof(TGAHead); @@ -63,27 +73,27 @@ Texture::save(const glTexture & texture, GLenum format, GLenum type, const glm:: } void -Texture::save(const glm::ivec2 & size, const char * path) const +Texture::save(const char * path) const { - save(m_texture, GL_BGR, GL_UNSIGNED_BYTE, size, 3, path, 2); + save(m_texture, GL_BGR, GL_UNSIGNED_BYTE, 3, path, 2); } void -Texture::save(const glTexture & texture, const glm::ivec2 & size, const char * path) +Texture::save(const glTexture & texture, const char * path) { - save(texture, GL_BGR, GL_UNSIGNED_BYTE, size, 3, path, 2); + save(texture, GL_BGR, GL_UNSIGNED_BYTE, 3, path, 2); } void -Texture::saveDepth(const glTexture & texture, const glm::ivec2 & size, const char * path) +Texture::saveDepth(const glTexture & texture, const char * path) { - save(texture, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, size, 1, path, 3); + save(texture, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 1, path, 3); } void -Texture::saveNormal(const glTexture & texture, const glm::ivec2 & size, const char * path) +Texture::saveNormal(const glTexture & texture, const char * path) { - save(texture, GL_BGR, GL_BYTE, size, 3, path, 2); + save(texture, GL_BGR, GL_BYTE, 3, path, 2); } TextureAtlas::TextureAtlas(GLsizei width, GLsizei height, GLuint count) : Texture(width, height, nullptr, {}) diff --git a/gfx/models/texture.h b/gfx/models/texture.h index 7900f17..f4e1476 100644 --- a/gfx/models/texture.h +++ b/gfx/models/texture.h @@ -28,14 +28,14 @@ public: virtual void bind(GLenum unit = GL_TEXTURE0) const; - void save(const glm::ivec2 & size, const char * path) const; - static void save(const glTexture &, const glm::ivec2 & size, const char * path); - static void saveDepth(const glTexture &, const glm::ivec2 & size, const char * path); - static void saveNormal(const glTexture &, const glm::ivec2 & size, const char * path); + void save(const char * path) const; + static void save(const glTexture &, const char * path); + static void saveDepth(const glTexture &, const char * path); + static void saveNormal(const glTexture &, const char * path); protected: - static void save(const glTexture &, GLenum, GLenum, const glm::ivec2 & size, unsigned short channels, - const char * path, short tgaFormat); + static void save(const glTexture &, GLenum, GLenum, unsigned short channels, const char * path, short tgaFormat); + static glm::ivec2 getSize(const glTexture &); glTexture m_texture; GLenum type; diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp index 4fde5ed..59dc40d 100644 --- a/test/test-assetFactory.cpp +++ b/test/test-assetFactory.cpp @@ -32,7 +32,7 @@ public: 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()); + Texture::save(outImage, outpath.c_str()); } void content(const SceneShader & shader) const override diff --git a/test/test-render.cpp b/test/test-render.cpp index 7771760..8c6b31c 100644 --- a/test/test-render.cpp +++ b/test/test-render.cpp @@ -73,7 +73,7 @@ BOOST_AUTO_TEST_CASE(basic) const TestScene scene; ss.render(scene); glDisable(GL_DEBUG_OUTPUT); - Texture::save(outImage, size, "/tmp/basic.tga"); + Texture::save(outImage, "/tmp/basic.tga"); } BOOST_AUTO_TEST_CASE(pointlight) @@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(pointlight) const PointLightScene scene; ss.render(scene); glDisable(GL_DEBUG_OUTPUT); - Texture::save(outImage, size, "/tmp/pointlight.tga"); + Texture::save(outImage, "/tmp/pointlight.tga"); } BOOST_AUTO_TEST_CASE(spotlight) @@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE(spotlight) const PointLightScene scene; ss.render(scene); glDisable(GL_DEBUG_OUTPUT); - Texture::save(outImage, size, "/tmp/spotlight.tga"); + Texture::save(outImage, "/tmp/spotlight.tga"); } BOOST_AUTO_TEST_SUITE_END(); -- cgit v1.2.3 From c44e7537d027cba66abe564b247549040426ebfe Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 02:56:33 +0100 Subject: Externalise a neater definition of TGAHead --- gfx/models/texture.cpp | 14 ++++++++------ gfx/models/texture.h | 2 +- gfx/models/tga.h | 14 ++++++++++++++ 3 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 gfx/models/tga.h diff --git a/gfx/models/texture.cpp b/gfx/models/texture.cpp index ab256d5..3b27e77 100644 --- a/gfx/models/texture.cpp +++ b/gfx/models/texture.cpp @@ -1,5 +1,6 @@ #include "texture.h" #include "glArrays.h" +#include "tga.h" #include #include #include @@ -54,11 +55,9 @@ Texture::getSize(const glTexture & texture) } void -Texture::save(const glTexture & texture, GLenum format, GLenum type, unsigned short channels, const char * path, - short tgaFormat) +Texture::save( + const glTexture & texture, GLenum format, GLenum type, uint8_t channels, const char * path, uint8_t tgaFormat) { - using TGAHead = std::array; - const auto size = getSize(texture); const size_t dataSize = (static_cast(size.x * size.y * channels)); const size_t fileSize = dataSize + sizeof(TGAHead); @@ -66,8 +65,11 @@ Texture::save(const glTexture & texture, GLenum format, GLenum type, unsigned sh filesystem::fh out {path, O_RDWR | O_CREAT, 0660}; out.truncate(fileSize); auto tga = out.mmap(fileSize, 0, PROT_WRITE, MAP_SHARED); - *tga.get() = {0, tgaFormat, 0, 0, 0, 0, static_cast(size.x), static_cast(size.y), - static_cast(8 * channels)}; + *tga.get() = { + .format = tgaFormat, + .size = size, + .pixelDepth = static_cast(8 * channels), + }; glGetTextureImage(texture, 0, format, type, static_cast(dataSize), tga.get() + 1); tga.msync(MS_ASYNC); } diff --git a/gfx/models/texture.h b/gfx/models/texture.h index f4e1476..68ec649 100644 --- a/gfx/models/texture.h +++ b/gfx/models/texture.h @@ -34,7 +34,7 @@ public: static void saveNormal(const glTexture &, const char * path); protected: - static void save(const glTexture &, GLenum, GLenum, unsigned short channels, const char * path, short tgaFormat); + static void save(const glTexture &, GLenum, GLenum, uint8_t channels, const char * path, uint8_t tgaFormat); static glm::ivec2 getSize(const glTexture &); glTexture m_texture; diff --git a/gfx/models/tga.h b/gfx/models/tga.h new file mode 100644 index 0000000..1f400ef --- /dev/null +++ b/gfx/models/tga.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +struct TGAHead { + uint8_t idLength {}, colorMapType {}, format {}; + uint16_t __attribute__((packed)) colorMapFirst {}, colorMapLength {}; + uint8_t colorMapEntrySize {}; + glm::vec<2, uint16_t> origin {}, size {}; + uint8_t pixelDepth {}; + uint8_t descriptor {}; +}; +static_assert(sizeof(TGAHead) == 18); -- cgit v1.2.3 From 4bf94458d5d7abafb154e914620dc758d26719c2 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 10:24:10 +0100 Subject: Global worker instance --- lib/worker.cpp | 12 ++++++------ lib/worker.h | 35 ++++++++++------------------------- test/Jamfile.jam | 1 + test/test-worker.cpp | 7 +++++++ 4 files changed, 24 insertions(+), 31 deletions(-) create mode 100644 test/test-worker.cpp diff --git a/lib/worker.cpp b/lib/worker.cpp index fd255c7..cf59f56 100644 --- a/lib/worker.cpp +++ b/lib/worker.cpp @@ -1,9 +1,10 @@ #include "worker.h" -#if __cpp_lib_semaphore -# include "work.h" -# include -# include -# include +#include "work.h" +#include +#include +#include + +Worker Worker::instance; Worker::Worker() : todoLen {0} { @@ -45,4 +46,3 @@ Worker::worker() j->doWork(); } } -#endif diff --git a/lib/worker.h b/lib/worker.h index 7cd06f9..136c50e 100644 --- a/lib/worker.h +++ b/lib/worker.h @@ -1,19 +1,17 @@ #pragma once +#include +#include +#include +#include +#include +#include #include -class Work; - -#if __cpp_lib_semaphore -# include -# include -# include -# include -# include -# include -# include +#include +class Work; class Worker { -public: +private: Worker(); ~Worker(); @@ -42,19 +40,6 @@ private: ToDo todo; std::counting_semaphore<16> todoLen; std::mutex todoMutex; -}; - -#else -class Worker { -public: - template - void - addWork(Params &&... params) - requires std::is_base_of_v - { - T(std::forward(params)...).doWork(); - } + static Worker instance; }; - -#endif diff --git a/test/Jamfile.jam b/test/Jamfile.jam index 390880d..482b388 100644 --- a/test/Jamfile.jam +++ b/test/Jamfile.jam @@ -57,6 +57,7 @@ run test-glContextBhvr.cpp ; run test-assetFactory.cpp : -- : [ sequence.insertion-sort [ glob-tree $(res) : *.* ] fixtures/rgb.txt ] : test ; run perf-assetFactory.cpp : : : benchmark test test-assetFactory ; run perf-persistence.cpp : : : benchmark test test-persistence ; +run test-worker.cpp ; compile test-static-enumDetails.cpp ; compile test-static-stream_support.cpp ; explicit perf-assetFactory ; diff --git a/test/test-worker.cpp b/test/test-worker.cpp new file mode 100644 index 0000000..3c5ed7e --- /dev/null +++ b/test/test-worker.cpp @@ -0,0 +1,7 @@ +#define BOOST_TEST_MODULE test_worker + +#include "testHelpers.h" +#include +#include + +BOOST_AUTO_TEST_CASE(exists) { } -- cgit v1.2.3 From 1cbf18ff8463946aa5a09ccf1d6873b222b912b6 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 10:26:51 +0100 Subject: Simplify worker with jthread Moves thread collection to bottom of class so threads are joined before job storage is destroyed. --- lib/work.h | 12 ------------ lib/worker.cpp | 5 +---- lib/worker.h | 4 ++-- 3 files changed, 3 insertions(+), 18 deletions(-) delete mode 100644 lib/work.h diff --git a/lib/work.h b/lib/work.h deleted file mode 100644 index c780e13..0000000 --- a/lib/work.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include - -class Work { -public: - virtual ~Work() = default; - NO_COPY(Work); - NO_MOVE(Work); - - virtual void doWork() = 0; -}; diff --git a/lib/worker.cpp b/lib/worker.cpp index cf59f56..4f1352d 100644 --- a/lib/worker.cpp +++ b/lib/worker.cpp @@ -9,16 +9,13 @@ Worker Worker::instance; Worker::Worker() : todoLen {0} { std::generate_n(std::back_inserter(threads), std::thread::hardware_concurrency(), [this]() { - return std::thread {&Worker::worker, this}; + return std::jthread {&Worker::worker, this}; }); } Worker::~Worker() { todoLen.release(std::thread::hardware_concurrency()); - std::for_each(threads.begin(), threads.end(), [](auto & th) { - th.join(); - }); } void diff --git a/lib/worker.h b/lib/worker.h index 136c50e..96593d9 100644 --- a/lib/worker.h +++ b/lib/worker.h @@ -33,13 +33,13 @@ private: private: void worker(); - using Threads = std::vector; + using Threads = std::vector; using ToDo = std::deque; - Threads threads; ToDo todo; std::counting_semaphore<16> todoLen; std::mutex todoMutex; + Threads threads; static Worker instance; }; -- cgit v1.2.3 From aa77548bd637ffd1a7461136e6206906dc4c61c7 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 11:54:45 +0100 Subject: New WorkItem/job/promise/future based interface --- lib/worker.cpp | 3 +- lib/worker.h | 87 ++++++++++++++++++++++++++++++++++++++++++++++------ test/test-worker.cpp | 39 ++++++++++++++++++++++- 3 files changed, 116 insertions(+), 13 deletions(-) diff --git a/lib/worker.cpp b/lib/worker.cpp index 4f1352d..7e7f296 100644 --- a/lib/worker.cpp +++ b/lib/worker.cpp @@ -1,5 +1,4 @@ #include "worker.h" -#include "work.h" #include #include #include @@ -19,7 +18,7 @@ Worker::~Worker() } void -Worker::addWork(WorkPtr j) +Worker::addWorkPtr(WorkPtr j) { std::lock_guard lck {todoMutex}; todoLen.release(); diff --git a/lib/worker.h b/lib/worker.h index 96593d9..5356606 100644 --- a/lib/worker.h +++ b/lib/worker.h @@ -1,6 +1,8 @@ #pragma once #include +#include +#include #include #include #include @@ -9,28 +11,93 @@ #include #include -class Work; class Worker { +public: + class WorkItem { + public: + WorkItem() = default; + virtual ~WorkItem() = default; + NO_MOVE(WorkItem); + NO_COPY(WorkItem); + + virtual void doWork() = 0; + }; + + template class WorkItemT : public WorkItem { + public: + T + get() + { + return future.get(); + } + + protected: + std::promise promise; + std::future future {promise.get_future()}; + friend Worker; + }; + + template + static auto + addWork(Params &&... params) + { + return instance.addWorkImpl(std::forward(params)...); + } + template using WorkPtrT = std::shared_ptr>; + private: + template class WorkItemTImpl : public WorkItemT { + public: + WorkItemTImpl(Params &&... params) : params {std::forward(params)...} { } + + private: + void + doWork() override + { + try { + if constexpr (std::is_void_v) { + std::apply( + [](auto &&... p) { + return std::invoke(p...); + }, + params); + WorkItemT::promise.set_value(); + } + else { + WorkItemT::promise.set_value(std::apply( + [](auto &&... p) { + return std::invoke(p...); + }, + params)); + } + } + catch (...) { + WorkItemT::promise.set_exception(std::current_exception()); + } + } + + std::tuple params; + }; + Worker(); ~Worker(); NO_COPY(Worker); NO_MOVE(Worker); - using WorkPtr = std::unique_ptr; + using WorkPtr = std::shared_ptr; - template - void - addWork(Params &&... params) - requires std::is_base_of_v + template + auto + addWorkImpl(Params &&... params) { - addWork(std::make_unique(std::forward(params)...)); + using T = decltype(std::invoke(std::forward(params)...)); + auto work = std::make_shared>(std::forward(params)...); + addWorkPtr(work); + return work; } - void addWork(WorkPtr w); - -private: + void addWorkPtr(WorkPtr w); void worker(); using Threads = std::vector; diff --git a/test/test-worker.cpp b/test/test-worker.cpp index 3c5ed7e..c542020 100644 --- a/test/test-worker.cpp +++ b/test/test-worker.cpp @@ -2,6 +2,43 @@ #include "testHelpers.h" #include +#include #include +#include -BOOST_AUTO_TEST_CASE(exists) { } +uint32_t +workCounter() +{ + static std::atomic_uint32_t n; + usleep(1000); + return n++; +} + +BOOST_AUTO_TEST_CASE(basic_slow_counter) +{ + std::vector> ps; + for (int i {}; i < 30; ++i) { + ps.push_back(Worker::addWork(workCounter)); + } + std::set out; + std::transform(ps.begin(), ps.end(), std::inserter(out, out.end()), [](auto && p) { + return p->get(); + }); + BOOST_REQUIRE_EQUAL(out.size(), ps.size()); + BOOST_CHECK_EQUAL(*out.begin(), 0); + BOOST_CHECK_EQUAL(*out.rbegin(), ps.size() - 1); +} + +BOOST_AUTO_TEST_CASE(basic_error_handler) +{ + auto workitem = Worker::addWork([]() { + throw std::runtime_error {"test"}; + }); + BOOST_CHECK_THROW(workitem->get(), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(basic_void_work) +{ + auto workitem = Worker::addWork([]() {}); + BOOST_CHECK_NO_THROW(workitem->get()); +} -- cgit v1.2.3 From e671adba5a57e1d4e848eb4d6de0f480e7b3709a Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 12:29:24 +0100 Subject: Simplify doWork, add tests for various interface uses --- lib/worker.h | 12 ++---------- test/test-worker.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/lib/worker.h b/lib/worker.h index 5356606..1bc7c14 100644 --- a/lib/worker.h +++ b/lib/worker.h @@ -56,19 +56,11 @@ private: { try { if constexpr (std::is_void_v) { - std::apply( - [](auto &&... p) { - return std::invoke(p...); - }, - params); + std::apply(std::invoke, params); WorkItemT::promise.set_value(); } else { - WorkItemT::promise.set_value(std::apply( - [](auto &&... p) { - return std::invoke(p...); - }, - params)); + WorkItemT::promise.set_value(std::apply(std::invoke, params)); } } catch (...) { diff --git a/test/test-worker.cpp b/test/test-worker.cpp index c542020..319261b 100644 --- a/test/test-worker.cpp +++ b/test/test-worker.cpp @@ -14,6 +14,19 @@ workCounter() return n++; } +void +workVoid() +{ + usleep(1000); +} + +void +workFail() +{ + usleep(1000); + throw std::runtime_error {"test"}; +} + BOOST_AUTO_TEST_CASE(basic_slow_counter) { std::vector> ps; @@ -31,14 +44,40 @@ BOOST_AUTO_TEST_CASE(basic_slow_counter) BOOST_AUTO_TEST_CASE(basic_error_handler) { - auto workitem = Worker::addWork([]() { - throw std::runtime_error {"test"}; - }); + auto workitem = Worker::addWork(workFail); BOOST_CHECK_THROW(workitem->get(), std::runtime_error); } BOOST_AUTO_TEST_CASE(basic_void_work) { - auto workitem = Worker::addWork([]() {}); + auto workitem = Worker::addWork(workVoid); BOOST_CHECK_NO_THROW(workitem->get()); } + +BOOST_AUTO_TEST_CASE(lambda_void) +{ + BOOST_CHECK_NO_THROW(Worker::addWork([]() {})->get()); + BOOST_CHECK_NO_THROW(Worker::addWork([](int) {}, 0)->get()); + BOOST_CHECK_NO_THROW(Worker::addWork([](int, int) {}, 0, 0)->get()); +} + +BOOST_AUTO_TEST_CASE(lambda_value) +{ + BOOST_CHECK_EQUAL(1, Worker::addWork([]() { + return 1; + })->get()); + BOOST_CHECK_EQUAL(2, + Worker::addWork( + [](int i) { + return i; + }, + 2) + ->get()); + BOOST_CHECK_EQUAL(3, + Worker::addWork( + [](int i, int j) { + return i + j; + }, + 1, 2) + ->get()); +} -- cgit v1.2.3 From f8ee56f6dc8cf7e92c4bfc5930d32b14f634141c Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 13:13:47 +0100 Subject: Current thread partakes in work effort while waiting This will prevent deadlock if the work pool is otherwise busy by ensuring work is always being done --- lib/worker.cpp | 21 +++++++++++++++++++++ lib/worker.h | 26 ++++++++++++++++++++++---- test/test-worker.cpp | 21 +++++++++++++++++++++ 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/lib/worker.cpp b/lib/worker.cpp index 7e7f296..45fb6df 100644 --- a/lib/worker.cpp +++ b/lib/worker.cpp @@ -42,3 +42,24 @@ Worker::worker() j->doWork(); } } + +void +Worker::assist() +{ + auto job = [this]() { + using namespace std::chrono_literals; + if (todoLen.try_acquire_for(100us)) { + if (std::lock_guard lck {todoMutex}; todo.size()) { + WorkPtr x = std::move(todo.front()); + if (x) { + todo.pop_front(); + } + return x; + } + } + return WorkPtr {}; + }; + if (auto j = job()) { + j->doWork(); + } +} diff --git a/lib/worker.h b/lib/worker.h index 1bc7c14..d9a5a6f 100644 --- a/lib/worker.h +++ b/lib/worker.h @@ -14,12 +14,20 @@ class Worker { public: class WorkItem { - public: - WorkItem() = default; + protected: + WorkItem(Worker * worker) : worker {worker} { } virtual ~WorkItem() = default; NO_MOVE(WorkItem); NO_COPY(WorkItem); + void + assist() const + { + worker->assist(); + } + Worker * worker; + + public: virtual void doWork() = 0; }; @@ -28,10 +36,16 @@ public: T get() { + using namespace std::chrono_literals; + while (future.wait_for(0s) == std::future_status::timeout) { + assist(); + } return future.get(); } protected: + WorkItemT(Worker * worker) : WorkItem {worker} { } + std::promise promise; std::future future {promise.get_future()}; friend Worker; @@ -48,7 +62,10 @@ public: private: template class WorkItemTImpl : public WorkItemT { public: - WorkItemTImpl(Params &&... params) : params {std::forward(params)...} { } + WorkItemTImpl(Worker * worker, Params &&... params) : + WorkItemT {worker}, params {std::forward(params)...} + { + } private: void @@ -84,13 +101,14 @@ private: addWorkImpl(Params &&... params) { using T = decltype(std::invoke(std::forward(params)...)); - auto work = std::make_shared>(std::forward(params)...); + auto work = std::make_shared>(this, std::forward(params)...); addWorkPtr(work); return work; } void addWorkPtr(WorkPtr w); void worker(); + void assist(); using Threads = std::vector; using ToDo = std::deque; diff --git a/test/test-worker.cpp b/test/test-worker.cpp index 319261b..76b7138 100644 --- a/test/test-worker.cpp +++ b/test/test-worker.cpp @@ -81,3 +81,24 @@ BOOST_AUTO_TEST_CASE(lambda_value) 1, 2) ->get()); } + +BOOST_AUTO_TEST_CASE(recursive, *boost::unit_test::timeout(5)) +{ + auto recurse = []() { + std::vector> ps; + for (int i {}; i < 30; ++i) { + ps.push_back(Worker::addWork(workCounter)); + } + return std::accumulate(ps.begin(), ps.end(), 0U, [](auto && out, auto && p) { + return out += p->get(); + }); + }; + std::vector> ps; + for (int i {}; i < 30; ++i) { + ps.push_back(Worker::addWork(recurse)); + } + std::set out; + std::transform(ps.begin(), ps.end(), std::inserter(out, out.end()), [](auto && p) { + return p->get(); + }); +} -- cgit v1.2.3 From 1cdd7753d37bcf8f626298c3df97a02cc73f266c Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 14:48:59 +0100 Subject: Load texture images in Worker --- assetFactory/assetFactory.cpp | 18 +++++++++++------- assetFactory/assimp.cpp | 20 ++++++++------------ assetFactory/textureFragment.cpp | 4 +++- assetFactory/textureFragment.h | 3 ++- 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/assetFactory/assetFactory.cpp b/assetFactory/assetFactory.cpp index 46b4642..e27e575 100644 --- a/assetFactory/assetFactory.cpp +++ b/assetFactory/assetFactory.cpp @@ -99,21 +99,25 @@ AssetFactory::createTexutre() const { if (!textureFragments.empty() && !texture) { // * layout images - std::vector imageSizes; + std::map> images; std::transform( - textureFragments.begin(), textureFragments.end(), std::back_inserter(imageSizes), [](const auto & tf) { - return TexturePacker::Image {tf.second->image->width, tf.second->image->height}; + textureFragments.begin(), textureFragments.end(), std::inserter(images, images.end()), [](auto && tf) { + return decltype(images)::value_type {tf.first, tf.second->image->get()}; }); + std::vector imageSizes; + std::transform(images.begin(), images.end(), std::back_inserter(imageSizes), [](const auto & i) { + return TexturePacker::Image {i.second->width, i.second->height}; + }); const auto [layout, outSize] = TexturePacker {imageSizes}.pack(); // * create texture texture = std::make_shared(outSize.x, outSize.y, layout.size()); - std::transform(textureFragments.begin(), textureFragments.end(), + std::transform(images.begin(), images.end(), std::inserter(textureFragmentPositions, textureFragmentPositions.end()), - [position = layout.begin(), size = imageSizes.begin(), this](const auto & tf) mutable { - const auto m = texture->add(*position, *size, tf.second->image->data.data()); + [position = layout.begin(), size = imageSizes.begin(), this](const auto & i) mutable { + const auto m = texture->add(*position, *size, i.second->data.data()); position++; size++; - return decltype(textureFragmentPositions)::value_type {tf.first, m}; + return decltype(textureFragmentPositions)::value_type {i.first, m}; }); } } diff --git a/assetFactory/assimp.cpp b/assetFactory/assimp.cpp index 878e7e7..bab052e 100644 --- a/assetFactory/assimp.cpp +++ b/assetFactory/assimp.cpp @@ -102,18 +102,14 @@ AssImp::postLoad() return AssetFactory::Shapes::value_type {m->mName.C_Str(), std::make_shared(scene, m)}; }); const auto textures = AIRANGE(scene, Textures); - auto textureFutures = textures * [](const aiTexture * t) { - return std::async(std::launch::async, [t]() { - auto texture = std::make_shared(); - texture->id = texture->path = t->mFilename.C_Str(); - texture->image = std::make_unique( - std::span {reinterpret_cast(t->pcData), t->mWidth}, STBI_rgb_alpha); - return texture; - }); - }; - std::transform(textureFutures.begin(), textureFutures.end(), - std::inserter(mf->textureFragments, mf->textureFragments.end()), [](auto && textureFuture) { - auto texture = textureFuture.get(); + std::transform(textures.begin(), textures.end(), + std::inserter(mf->textureFragments, mf->textureFragments.end()), [](auto && t) { + auto texture = std::make_shared(); + texture->id = texture->path = t->mFilename.C_Str(); + texture->image = Worker::addWork([t]() { + return std::make_unique( + std::span {reinterpret_cast(t->pcData), t->mWidth}, STBI_rgb_alpha); + }); return AssetFactory::TextureFragments::value_type {texture->id, texture}; }); } diff --git a/assetFactory/textureFragment.cpp b/assetFactory/textureFragment.cpp index d153688..0a4ec1d 100644 --- a/assetFactory/textureFragment.cpp +++ b/assetFactory/textureFragment.cpp @@ -11,5 +11,7 @@ TextureFragment::persist(Persistence::PersistenceStore & store) void TextureFragment::postLoad() { - image = std::make_unique(Resource::mapPath(path), STBI_rgb_alpha); + image = Worker::addWork([this]() { + return std::make_unique(Resource::mapPath(path), STBI_rgb_alpha); + }); } diff --git a/assetFactory/textureFragment.h b/assetFactory/textureFragment.h index d03affd..75fe96e 100644 --- a/assetFactory/textureFragment.h +++ b/assetFactory/textureFragment.h @@ -3,12 +3,13 @@ #include "gfx/image.h" #include "persistence.h" #include "stdTypeDefs.hpp" +#include "worker.h" class TextureFragment : public Persistence::Persistable, public StdTypeDefs { public: std::string id; std::string path; - std::unique_ptr image; + Worker::WorkPtrT> image; private: friend Persistence::SelectionPtrBase; -- cgit v1.2.3 From 59733c3c3de7aa6dee5fde8e2a60b80b4c706583 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 15:21:36 +0100 Subject: Set GL_PACK_ALIGNMENT before saving texture to fit buffer correctly --- gfx/models/texture.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/gfx/models/texture.cpp b/gfx/models/texture.cpp index 3b27e77..6319eb8 100644 --- a/gfx/models/texture.cpp +++ b/gfx/models/texture.cpp @@ -70,6 +70,7 @@ Texture::save( .size = size, .pixelDepth = static_cast(8 * channels), }; + glPixelStorei(GL_PACK_ALIGNMENT, 1); glGetTextureImage(texture, 0, format, type, static_cast(dataSize), tga.get() + 1); tga.msync(MS_ASYNC); } -- cgit v1.2.3 From 3e97b30a194907cede7a230e618f82ffb516b329 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 15:25:38 +0100 Subject: Create texture fragments from materials --- assetFactory/assimp.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/assetFactory/assimp.cpp b/assetFactory/assimp.cpp index bab052e..9a49717 100644 --- a/assetFactory/assimp.cpp +++ b/assetFactory/assimp.cpp @@ -62,13 +62,11 @@ public: const auto vhs = AIRANGE(amesh, Vertices) * [&mesh](auto && v) { return mesh.add_vertex(*v); }; - const auto & m = *scene->mMaterials[amesh->mMaterialIndex]; + const auto & m = scene->mMaterials[amesh->mMaterialIndex]->GetName(); GLuint material {}; if (auto mf = Persistence::ParseBase::getShared("assetFactory")) { - aiString path; - m.Get(AI_MATKEY_TEXTURE_DIFFUSE(0), path); - material = mf->getMaterialIndex(path.C_Str()); + material = mf->getMaterialIndex(m.C_Str()); } for (const auto & f : AIRANGE(amesh, Faces)) { @@ -101,12 +99,15 @@ AssImp::postLoad() root.begin(), root.end(), std::inserter(mf->shapes, mf->shapes.end()), [&scene](const aiNode * m) { return AssetFactory::Shapes::value_type {m->mName.C_Str(), std::make_shared(scene, m)}; }); - const auto textures = AIRANGE(scene, Textures); - std::transform(textures.begin(), textures.end(), - std::inserter(mf->textureFragments, mf->textureFragments.end()), [](auto && t) { + const auto materials = AIRANGE(scene, Materials); + std::transform(materials.begin(), materials.end(), + std::inserter(mf->textureFragments, mf->textureFragments.end()), [&scene](const aiMaterial * m) { + aiString path; + m->Get(AI_MATKEY_TEXTURE_DIFFUSE(0), path); auto texture = std::make_shared(); - texture->id = texture->path = t->mFilename.C_Str(); - texture->image = Worker::addWork([t]() { + texture->id = m->GetName().C_Str(); + texture->path = path.C_Str(); + texture->image = Worker::addWork([t = scene->GetEmbeddedTexture(path.C_Str())]() { return std::make_unique( std::span {reinterpret_cast(t->pcData), t->mWidth}, STBI_rgb_alpha); }); -- cgit v1.2.3 From b4ede2fd89d0effb44ebae15862427de9a147476 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 16:34:56 +0100 Subject: Define our own enum for texture mapmode --- gfx/models/texture.cpp | 19 +++++++++++++++++-- gfx/models/texture.h | 9 ++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/gfx/models/texture.cpp b/gfx/models/texture.cpp index 6319eb8..e29fd6c 100644 --- a/gfx/models/texture.cpp +++ b/gfx/models/texture.cpp @@ -13,6 +13,21 @@ Cache Texture::cachedTexture; +GLint +TextureOptions::glMapMode(TextureOptions::MapMode mm) +{ + switch (mm) { + case MapMode::Repeat: + return GL_REPEAT; + case MapMode::Clamp: + return GL_CLAMP_TO_EDGE; + case MapMode::Mirror: + return GL_MIRRORED_REPEAT; + default: + throw std::domain_error("Invalid MapMode value"); + } +} + Texture::Texture(const std::filesystem::path & fileName, TextureOptions to) : Texture {Image {Resource::mapPath(fileName).c_str(), STBI_rgb_alpha}, to} { @@ -30,8 +45,8 @@ Texture::Texture(GLsizei width, GLsizei height, const void * data, TextureOption glBindTexture(type, m_texture); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexParameteri(type, GL_TEXTURE_WRAP_S, to.wrap); - glTexParameteri(type, GL_TEXTURE_WRAP_T, to.wrap); + glTexParameteri(type, GL_TEXTURE_WRAP_S, TextureOptions::glMapMode(to.wrapU)); + glTexParameteri(type, GL_TEXTURE_WRAP_T, TextureOptions::glMapMode(to.wrapV)); glTexParameteri(type, GL_TEXTURE_MIN_FILTER, to.minFilter); glTexParameteri(type, GL_TEXTURE_MAG_FILTER, to.magFilter); diff --git a/gfx/models/texture.h b/gfx/models/texture.h index 68ec649..86e76a0 100644 --- a/gfx/models/texture.h +++ b/gfx/models/texture.h @@ -9,9 +9,16 @@ class Image; struct TextureOptions { - GLint wrap {GL_REPEAT}; + enum class MapMode { + Repeat, + Clamp, + Mirror, + Decal, + }; + MapMode wrapU {MapMode::Repeat}, wrapV {MapMode::Repeat}; GLint minFilter {GL_LINEAR}, magFilter {GL_LINEAR}; GLenum type {GL_TEXTURE_2D}; + static GLint glMapMode(MapMode); }; class Texture { -- cgit v1.2.3 From 32a2da41e0946c1d6d364b7763d1829bfa8b74db Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 16:36:22 +0100 Subject: Configure texture fragment mapmode from material --- assetFactory/assimp.cpp | 7 +++++++ assetFactory/textureFragment.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/assetFactory/assimp.cpp b/assetFactory/assimp.cpp index 9a49717..840c5a9 100644 --- a/assetFactory/assimp.cpp +++ b/assetFactory/assimp.cpp @@ -85,6 +85,11 @@ public: } }; +static_assert(TextureOptions::MapMode::Repeat == static_cast(aiTextureMapMode_Wrap)); +static_assert(TextureOptions::MapMode::Clamp == static_cast(aiTextureMapMode_Clamp)); +static_assert(TextureOptions::MapMode::Decal == static_cast(aiTextureMapMode_Decal)); +static_assert(TextureOptions::MapMode::Mirror == static_cast(aiTextureMapMode_Mirror)); + void AssImp::postLoad() { @@ -107,6 +112,8 @@ AssImp::postLoad() auto texture = std::make_shared(); texture->id = m->GetName().C_Str(); texture->path = path.C_Str(); + m->Get(AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0), texture->mapmodeU); + m->Get(AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0), texture->mapmodeV); texture->image = Worker::addWork([t = scene->GetEmbeddedTexture(path.C_Str())]() { return std::make_unique( std::span {reinterpret_cast(t->pcData), t->mWidth}, STBI_rgb_alpha); diff --git a/assetFactory/textureFragment.h b/assetFactory/textureFragment.h index 75fe96e..e6f07f3 100644 --- a/assetFactory/textureFragment.h +++ b/assetFactory/textureFragment.h @@ -1,6 +1,7 @@ #pragma once #include "gfx/image.h" +#include "gfx/models/texture.h" #include "persistence.h" #include "stdTypeDefs.hpp" #include "worker.h" @@ -9,6 +10,7 @@ class TextureFragment : public Persistence::Persistable, public StdTypeDefs> image; private: -- cgit v1.2.3 From 41b6cc54a739ef1776c4e827a0e82c33438f1c14 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 16:37:04 +0100 Subject: Adjust test render view to get a closer view of our tree --- test/test-assetFactory.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp index 59dc40d..c425e71 100644 --- a/test/test-assetFactory.cpp +++ b/test/test-assetFactory.cpp @@ -108,10 +108,10 @@ BOOST_AUTO_TEST_CASE(foliage, *boost::unit_test::timeout(5)) auto tree_01_1_f = std::dynamic_pointer_cast(tree_01_1); BOOST_REQUIRE(tree_01_1_f); - auto plant = std::make_shared(tree_01_1_f, Location {}); + auto plant = std::make_shared(tree_01_1_f, Location {{-2, 2, 0}, {}}); objects.objects.push_back(plant); - render(); + render(5); } BOOST_AUTO_TEST_SUITE_END(); -- cgit v1.2.3 From 70c3268225bbb985079ec6715ae598dce5605a4e Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 16:38:05 +0100 Subject: Pass texture fragment mapmode to texture atlas --- assetFactory/assetFactory.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/assetFactory/assetFactory.cpp b/assetFactory/assetFactory.cpp index e27e575..05f0634 100644 --- a/assetFactory/assetFactory.cpp +++ b/assetFactory/assetFactory.cpp @@ -99,10 +99,10 @@ AssetFactory::createTexutre() const { if (!textureFragments.empty() && !texture) { // * layout images - std::map> images; + std::map> images; std::transform( textureFragments.begin(), textureFragments.end(), std::inserter(images, images.end()), [](auto && tf) { - return decltype(images)::value_type {tf.first, tf.second->image->get()}; + return decltype(images)::value_type {tf.second.get(), tf.second->image->get()}; }); std::vector imageSizes; std::transform(images.begin(), images.end(), std::back_inserter(imageSizes), [](const auto & i) { @@ -114,10 +114,14 @@ AssetFactory::createTexutre() const std::transform(images.begin(), images.end(), std::inserter(textureFragmentPositions, textureFragmentPositions.end()), [position = layout.begin(), size = imageSizes.begin(), this](const auto & i) mutable { - const auto m = texture->add(*position, *size, i.second->data.data()); + const auto m = texture->add(*position, *size, i.second->data.data(), + { + .wrapU = i.first->mapmodeU, + .wrapV = i.first->mapmodeV, + }); position++; size++; - return decltype(textureFragmentPositions)::value_type {i.first, m}; + return decltype(textureFragmentPositions)::value_type {i.first->id, m}; }); } } -- cgit v1.2.3 From be9a796e68a25f7567b7c16e00d9b42f5e0d9528 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 16:39:27 +0100 Subject: Write applicable Texture Options into texture atlas texture data --- gfx/models/texture.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/gfx/models/texture.cpp b/gfx/models/texture.cpp index e29fd6c..e014f80 100644 --- a/gfx/models/texture.cpp +++ b/gfx/models/texture.cpp @@ -136,12 +136,15 @@ TextureAtlas::bind(GLenum unit) const } GLuint -TextureAtlas::add(glm::ivec2 position, glm::ivec2 size, void * data, TextureOptions) +TextureAtlas::add(glm::ivec2 position, glm::ivec2 size, void * data, TextureOptions to) { glTextureSubImage2D(m_texture, 0, position.x, position.y, size.x, size.y, GL_RGBA, GL_UNSIGNED_BYTE, data); struct Material { - glm::vec<2, uint16_t> position, size, unused1 {}, unused2 {}; - } material {position, size}; + glm::vec<2, uint16_t> position, size; + TextureOptions::MapMode wrapU; + TextureOptions::MapMode wrapV; + } material {position, size, to.wrapU, to.wrapV}; + static_assert(sizeof(Material) <= 32); glTextureSubImage2D(m_atlas, 0, 0, static_cast(used), 2, 1, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, &material); return ++used; } -- cgit v1.2.3 From 4a7cff8f634122314d0bb4766795ea2d1e652ed4 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 16:39:57 +0100 Subject: Handle different mapmodes in basic shader --- gfx/gl/shaders/basicShader.fs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/gfx/gl/shaders/basicShader.fs b/gfx/gl/shaders/basicShader.fs index 8a72e6d..57eaba2 100644 --- a/gfx/gl/shaders/basicShader.fs +++ b/gfx/gl/shaders/basicShader.fs @@ -7,12 +7,37 @@ include(`geometryOut.glsl') layout(binding = 0) uniform sampler2D texture0; layout(binding = 1) uniform usampler2DRect material; +float map(uint mapmode, float value) +{ + switch (mapmode) { + case 0u: // Repeat + return fract(value); + case 1u: // Clamp to edge + return clamp(0.0, 1.0, value); + case 2u: // Mirror + discard; + case 3u: // Decal + if (value != clamp(0.0, 1.0, value)) { + discard; + } + } + return 0; +} + +vec2 map(uint mapmodeU, uint mapmodeV, vec2 value) +{ + return vec2(map(mapmodeU, value.x), map(mapmodeV, value.y)); +} + vec4 getTextureColour(uint midx, vec2 uv) { if (midx > 0u) { const vec2 tSize = textureSize(texture0, 0); const vec4 sPosSize = texture(material, uvec2(0, midx - 1u)); - uv = (sPosSize.xy + sPosSize.zw * fract(uv)) / tSize; + const uvec4 sMode = texture(material, uvec2(1, midx - 1u)); + const uint mapmodeU = sMode.x & 0xFu; + const uint mapmodeV = (sMode.x & 0xF0u) >> 1; + uv = (sPosSize.xy + sPosSize.zw * map(mapmodeU, mapmodeV, uv)) / tSize; } return texture(texture0, uv); } -- cgit v1.2.3 From 7c2977ee4de2cfd967871a0927443f24361944b1 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 17:07:40 +0100 Subject: Use asset factory models in test-render --- test/Jamfile.jam | 6 +++--- test/test-render.cpp | 24 +++++++++++++++++++----- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/test/Jamfile.jam b/test/Jamfile.jam index 482b388..d91af1d 100644 --- a/test/Jamfile.jam +++ b/test/Jamfile.jam @@ -52,11 +52,11 @@ run test-network.cpp ; run test-persistence.cpp : -- : [ sequence.insertion-sort [ glob-tree fixtures : *.json ] ] : test ; run test-text.cpp ; run test-enumDetails.cpp ; -run test-render.cpp : : : test ; +run test-render.cpp : -- : test-assetFactory : test ; run test-glContextBhvr.cpp ; run test-assetFactory.cpp : -- : [ sequence.insertion-sort [ glob-tree $(res) : *.* ] fixtures/rgb.txt ] : test ; -run perf-assetFactory.cpp : : : benchmark test test-assetFactory ; -run perf-persistence.cpp : : : benchmark test test-persistence ; +run perf-assetFactory.cpp : -- : test-assetFactory : benchmark test ; +run perf-persistence.cpp : -- : test-persistence : benchmark test ; run test-worker.cpp ; compile test-static-enumDetails.cpp ; compile test-static-stream_support.cpp ; diff --git a/test/test-render.cpp b/test/test-render.cpp index 8c6b31c..45acab5 100644 --- a/test/test-render.cpp +++ b/test/test-render.cpp @@ -6,8 +6,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -19,18 +21,30 @@ #include class TestScene : public SceneProvider { - RailVehicleClass train {"brush47"}; + std::shared_ptr train1, train2; + Terrain terrain {[]() { auto gd = std::make_shared(GeoData::Limits {{0, 0}, {100, 100}}); gd->generateRandom(); return gd; }()}; + +public: + TestScene() + { + const auto assetFactory = AssetFactory::loadXML(RESDIR "/brush47.xml"); + const auto brush47rvc = std::dynamic_pointer_cast(assetFactory->assets.at("brush-47")); + train1 = std::make_shared(brush47rvc); + train1->location.pos = {52, 50, 2}; + train2 = std::make_shared(brush47rvc); + train2->location.pos = {52, 30, 2}; + } void content(const SceneShader & shader) const override { terrain.render(shader); - train.render(shader, Location {{52, 50, 2}}, {Location {{52, 56, 2}}, Location {{52, 44, 2}}}); - train.render(shader, Location {{52, 30, 2}}, {Location {{52, 36, 2}}, Location {{52, 24, 2}}}); + train1->render(shader); + train2->render(shader); } void lights(const SceneShader &) const override @@ -40,8 +54,8 @@ class TestScene : public SceneProvider { shadows(const ShadowMapper & shadowMapper) const override { terrain.shadows(shadowMapper); - train.shadows(shadowMapper, Location {{52, 50, 2}}, {Location {{52, 56, 2}}, Location {{52, 44, 2}}}); - train.shadows(shadowMapper, Location {{52, 30, 2}}, {Location {{52, 36, 2}}, Location {{52, 24, 2}}}); + train1->shadows(shadowMapper); + train2->shadows(shadowMapper); } }; -- cgit v1.2.3 From 47cd9d863fb09acb82d2428f881d61242f8ab437 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 17:33:02 +0100 Subject: Load all assets in red dir with asset factory --- application/main.cpp | 9 ++++++++- assetFactory/assetFactory.cpp | 13 +++++++++++++ assetFactory/assetFactory.h | 1 + test/test-assetFactory.cpp | 7 +++++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/application/main.cpp b/application/main.cpp index 1f91dab..aea3d2e 100644 --- a/application/main.cpp +++ b/application/main.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -11,6 +12,8 @@ #include #include #include +#include +#include #include #include #include @@ -43,6 +46,7 @@ public: world.create(geoData); { + const auto assets = AssetFactory::loadAll("res"); auto rl = world.create(); const glm::vec3 j {-1120, -1100, 3}, k {-1100, -1000, 15}, l {-1000, -800, 20}, m {-900, -600, 30}, n {-600, -500, 32}, o {-500, -800, 30}, p {-600, -900, 25}, q {-1025, -1175, 10}, @@ -66,13 +70,16 @@ public: rl->addLinksBetween(t, u); rl->addLinksBetween(u, m); const std::shared_ptr train = world.create(l3); - auto b47 = std::make_shared("brush47"); + auto b47 = std::dynamic_pointer_cast(assets.at("brush-47")); for (int N = 0; N < 6; N++) { train->create(b47); } train->orders.removeAll(); train->orders.create(&train->orders, l3->ends[1], l3->length, rl->findNodeAt({-1100, -450, 15})); train->currentActivity = train->orders.current()->createActivity(); + + auto foliage = std::dynamic_pointer_cast(assets.at("Tree-01-1")); + world.create(foliage, Location {{-1100, -1100, 0}}); } auto t_start = std::chrono::high_resolution_clock::now(); diff --git a/assetFactory/assetFactory.cpp b/assetFactory/assetFactory.cpp index 05f0634..af0cd54 100644 --- a/assetFactory/assetFactory.cpp +++ b/assetFactory/assetFactory.cpp @@ -11,6 +11,7 @@ #include "resource.h" #include "saxParse-persistence.h" #include "texturePacker.h" +#include AssetFactory::AssetFactory() : shapes { @@ -29,6 +30,18 @@ AssetFactory::loadXML(const std::filesystem::path & filename) return Persistence::SAXParsePersistence {}.loadState>(file); } +AssetFactory::Assets +AssetFactory::loadAll(const std::filesystem::path & root) +{ + return std::accumulate(std::filesystem::recursive_directory_iterator {root}, + std::filesystem::recursive_directory_iterator {}, Assets {}, [](auto && out, auto && path) { + if (path.path().extension() == ".xml") { + out.merge(loadXML(path)->assets); + } + return std::move(out); + }); +} + AssetFactory::Colours AssetFactory::parseX11RGB(const char * path) { diff --git a/assetFactory/assetFactory.h b/assetFactory/assetFactory.h index 9e5d205..e449ce2 100644 --- a/assetFactory/assetFactory.h +++ b/assetFactory/assetFactory.h @@ -22,6 +22,7 @@ public: AssetFactory(); [[nodiscard]] static std::shared_ptr loadXML(const std::filesystem::path &); + [[nodiscard]] static Assets loadAll(const std::filesystem::path &); [[nodiscard]] ColourAlpha parseColour(std::string_view) const; [[nodiscard]] GLuint getMaterialIndex(std::string_view) const; [[nodiscard]] Asset::TexturePtr getTexture() const; diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp index c425e71..3d79213 100644 --- a/test/test-assetFactory.cpp +++ b/test/test-assetFactory.cpp @@ -115,6 +115,13 @@ BOOST_AUTO_TEST_CASE(foliage, *boost::unit_test::timeout(5)) } BOOST_AUTO_TEST_SUITE_END(); +BOOST_AUTO_TEST_CASE(loadall) +{ + const auto assets = AssetFactory::loadAll(RESDIR); + BOOST_CHECK(assets.at("brush-47")); + BOOST_CHECK(assets.at("Tree-01-1")); +} + template using InOut = std::tuple; BOOST_DATA_TEST_CASE(normalizeColourName, boost::unit_test::data::make>({ -- cgit v1.2.3 From 66da4f83c1b5bb6f3ceda880820e01c2f8e23e43 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 17:45:31 +0100 Subject: Remove the old .obj load, assets and supporting stuff --- Jamroot.jam | 1 - game/vehicles/railVehicleClass.cpp | 53 -------- game/vehicles/railVehicleClass.h | 9 -- gfx/models/obj.h | 38 ------ gfx/models/obj.impl.cpp | 77 ----------- gfx/models/obj.ll | 116 ----------------- res/brush47.mtl | 13 -- res/brush47.obj | 260 ------------------------------------- res/brush47.png | Bin 111263 -> 0 bytes test/Jamfile.jam | 1 - test/test-obj.cpp | 39 ------ 11 files changed, 607 deletions(-) delete mode 100644 gfx/models/obj.h delete mode 100644 gfx/models/obj.impl.cpp delete mode 100644 gfx/models/obj.ll delete mode 100644 res/brush47.mtl delete mode 100644 res/brush47.obj delete mode 100644 res/brush47.png delete mode 100644 test/test-obj.cpp diff --git a/Jamroot.jam b/Jamroot.jam index 2275dd6..35b48ea 100644 --- a/Jamroot.jam +++ b/Jamroot.jam @@ -22,7 +22,6 @@ project : requirements profile:on coverage:on tidy:all - tidy:bin/link-static/gfx/models/obj.cpp tidy:bin/link-static/lib/jsonParse.cpp tidy:boost-* tidy:bugprone-* diff --git a/game/vehicles/railVehicleClass.cpp b/game/vehicles/railVehicleClass.cpp index 4e9263c..b7a3b1e 100644 --- a/game/vehicles/railVehicleClass.cpp +++ b/game/vehicles/railVehicleClass.cpp @@ -2,7 +2,6 @@ #include "gfx/gl/sceneShader.h" #include "gfx/gl/shadowMapper.h" #include "gfx/models/mesh.h" -#include "gfx/models/obj.h" #include "gfx/models/texture.h" #include #include @@ -22,25 +21,6 @@ #include #include -RailVehicleClass::RailVehicleClass(const std::string & name) : - RailVehicleClass {std::make_unique(Resource::mapPath(name + ".obj")), - Texture::cachedTexture.get(Resource::mapPath(name + ".png"))} -{ -} - -RailVehicleClass::RailVehicleClass(std::unique_ptr o, std::shared_ptr t) : - texture {std::move(t)}, maxSpeed(95._mph) -{ - wheelBase = bogieOffset(*o); - length = objectLength(*o); - const auto m = o->createMeshes(); - bodyMesh = m.at("Body"); - bogies[0] = m.at("Bogie1"); - bogies[1] = m.at("Bogie2"); -} - -RailVehicleClass::RailVehicleClass() { } - bool RailVehicleClass::persist(Persistence::PersistenceStore & store) { @@ -80,36 +60,3 @@ RailVehicleClass::shadows( bogies[b]->Draw(); } } - -float -RailVehicleClass::bogieOffset(ObjParser & o) -{ - float wheelBase {0}; - // offset bogie positions so they can be set directly - for (auto & object : o.objects) { // bogie object index - if (!object.first.starts_with("Bogie")) { - continue; - } - std::set> vertexIds; - for (const auto & face : object.second) { - for (const auto & faceElement : face) { - vertexIds.emplace(o.vertices[faceElement.x - 1].y, faceElement.x - 1); - } - } - const auto offset = (vertexIds.begin()->first + vertexIds.rbegin()->first) / 2; - for (const auto & v : vertexIds) { - o.vertices[v.second].y -= offset; - } - wheelBase += std::abs(offset); - } - return wheelBase; -} - -float -RailVehicleClass::objectLength(ObjParser & o) -{ - const auto mme = std::minmax_element(o.vertices.begin(), o.vertices.end(), [](const auto & v1, const auto & v2) { - return v1.y < v2.y; - }); - return mme.second->y - mme.first->y; -} diff --git a/game/vehicles/railVehicleClass.h b/game/vehicles/railVehicleClass.h index 61ec4ec..1a52e2b 100644 --- a/game/vehicles/railVehicleClass.h +++ b/game/vehicles/railVehicleClass.h @@ -9,14 +9,10 @@ class SceneShader; class ShadowMapper; class Texture; -class ObjParser; class Location; class RailVehicleClass : public Asset { public: - explicit RailVehicleClass(const std::string & name); - RailVehicleClass(); - void render(const SceneShader &, const Location &, const std::array &) const; void shadows(const ShadowMapper &, const Location &, const std::array &) const; @@ -31,10 +27,5 @@ protected: friend Persistence::SelectionPtrBase>; bool persist(Persistence::PersistenceStore & store) override; void postLoad() override; - -private: - RailVehicleClass(std::unique_ptr obj, std::shared_ptr); - static float bogieOffset(ObjParser & o); - static float objectLength(ObjParser & o); }; using RailVehicleClassPtr = std::shared_ptr; diff --git a/gfx/models/obj.h b/gfx/models/obj.h deleted file mode 100644 index e28f7de..0000000 --- a/gfx/models/obj.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#ifndef yyFlexLexer -# define yyFlexLexer objbaseFlexLexer -# include -#endif -#include -#include -#include -#include -#include -#include - -class Mesh; -class Vertex; - -class ObjParser : yyFlexLexer { -public: - explicit ObjParser(const std::filesystem::path & fileName); - explicit ObjParser(std::unique_ptr in); - - int yylex() override; - - std::vector vertices; - std::vector texCoords; - std::vector normals; - using FaceElement = glm::vec<3, unsigned int>; - using Face = std::vector; - using Faces = std::vector; - using Object = std::pair; - std::vector objects; - glm::length_t axis {0}; - - using NamedMeshesData = std::map, std::vector>>; - [[nodiscard]] NamedMeshesData createMeshData() const; - using NamedMeshes = std::map>; - [[nodiscard]] NamedMeshes createMeshes() const; -}; diff --git a/gfx/models/obj.impl.cpp b/gfx/models/obj.impl.cpp deleted file mode 100644 index 205abc8..0000000 --- a/gfx/models/obj.impl.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "obj.h" -#include -#include -#include -#include -#include // IWYU pragma: keep -#include -#include -#include -#include -#include -#include -#include - -ObjParser::ObjParser(const std::filesystem::path & fileName) : ObjParser {std::make_unique(fileName)} { } - -ObjParser::ObjParser(std::unique_ptr in) : yyFlexLexer(in.get()) -{ - assert(in); - ObjParser::yylex(); - assert(in->good()); - constexpr const glm::mat4 obj2ilt { - -1, 0, 0, 0, // x - 0, 0, 1, 0, // y - 0, 1, 0, 0, // z - 0, 0, 0, 0, // w - }; - std::for_each(vertices.begin(), vertices.end(), [&obj2ilt](auto & v) { - v = v * obj2ilt; - }); - std::for_each(normals.begin(), normals.end(), [&obj2ilt](auto & v) { - v = glm::vec4 {v, 0} * obj2ilt; - }); -} - -ObjParser::NamedMeshes -ObjParser::createMeshes() const -{ - NamedMeshes out; - const auto data {createMeshData()}; - std::transform(data.begin(), data.end(), std::inserter(out, out.end()), [](auto && obj) { - return std::make_pair(obj.first, std::make_shared(obj.second.first, obj.second.second)); - }); - return out; -} - -ObjParser::NamedMeshesData -ObjParser::createMeshData() const -{ - NamedMeshesData out; - std::transform(objects.begin(), objects.end(), std::inserter(out, out.end()), [this](auto && obj) { - std::vector overtices; - std::vector vertexOrder; - std::vector indices; - for (const auto & face : obj.second) { - for (auto idx = 2U; idx < face.size(); idx += 1) { - auto f = [&](auto idx) { - const auto & fe {face[idx]}; - if (const auto existing = std::find(vertexOrder.begin(), vertexOrder.end(), fe); - existing != vertexOrder.end()) { - indices.push_back(static_cast(std::distance(vertexOrder.begin(), existing))); - } - else { - indices.push_back(static_cast(overtices.size())); - overtices.emplace_back(vertices[fe.x - 1], texCoords[fe.y - 1], -normals[fe.z - 1]); - vertexOrder.emplace_back(fe); - } - }; - f(0U); - f(idx); - f(idx - 1); - } - } - return std::make_pair(obj.first, std::make_pair(overtices, indices)); - }); - return out; -} diff --git a/gfx/models/obj.ll b/gfx/models/obj.ll deleted file mode 100644 index 84884fe..0000000 --- a/gfx/models/obj.ll +++ /dev/null @@ -1,116 +0,0 @@ -%option batch -%option c++ -%option noyywrap -%option 8bit -%option stack -%option yyclass="ObjParser" -%option prefix="objbase" - -%{ -#include -#include -#include -#include -#include -class objbaseFlexLexer; -%} - -comment #.* -float -?[0-9.]+ -index -?[0-9]+ -linestring [^\r\n]* -truthy (1|on) -falsey (0|off) - -%x FACE -%x MTLLIB -%x OBJECT -%x SMOOTH -%x USEMTL -%x VERTEX -%x NORMAL -%x TEXCOORD - -%% - -{comment} { - // fprintf(stderr, "COMMENT %s\n", YYText()); -} -"f " { - BEGIN(FACE); - objects.back().second.emplace_back(); - objects.back().second.back().emplace_back(); - axis = 0; -} -"mtllib " { - BEGIN(MTLLIB); -} -"o " { - BEGIN(OBJECT); -} -"s " { - BEGIN(SMOOTH); -} -"usemtl " { - BEGIN(USEMTL); -} -"v " { - BEGIN(VERTEX); - vertices.emplace_back(0, 0, 0, 1); - axis = 0; -} -"vn " { - BEGIN(NORMAL); - normals.emplace_back(0, 0, 0); - axis = 0; -} -"vt " { - BEGIN(TEXCOORD); - texCoords.emplace_back(0, 1, 1); - axis = 0; -} -{linestring} { - // fprintf(stderr, "USEMTL <%s>\n", YYText()); -} -{linestring} { - // fprintf(stderr, "MTLLIB <%s>\n", YYText()); -} -{linestring} { - objects.emplace_back(YYText(), Faces{}); -} -{truthy} { - // fprintf(stderr, "Set smooth\n"); -} -{falsey} { - // fprintf(stderr, "Set flat\n"); -} -{float} { - vertices.back()[axis++] = std::stof(YYText()); -} -{float} { - normals.back()[axis++] = std::stof(YYText()); -} -{float} { - texCoords.back()[axis++] = std::stof(YYText()); -} -{index} { - objects.back().second.back().back()[axis] = std::stoi(YYText()); -} -\/ { - axis++; -} -[ \t] { - objects.back().second.back().emplace_back(); - axis = 0; -} - -<*>[ \t] { -} -<*>[\r\n\f] { - BEGIN(INITIAL); -} - -%% - -// Make iwyu think unistd.h is required -[[maybe_unused]]static auto x=getpid; diff --git a/res/brush47.mtl b/res/brush47.mtl deleted file mode 100644 index a4ba512..0000000 --- a/res/brush47.mtl +++ /dev/null @@ -1,13 +0,0 @@ -# Blender MTL File: 'brush47.blend' -# Material Count: 1 - -newmtl Brush47 -Ns 225.000000 -Ka 1.000000 1.000000 1.000000 -Kd 0.800000 0.800000 0.800000 -Ks 0.500000 0.500000 0.500000 -Ke 0.000000 0.000000 0.000000 -Ni 1.450000 -d 1.000000 -illum 2 -map_Kd brush47.png diff --git a/res/brush47.obj b/res/brush47.obj deleted file mode 100644 index 8fcb2b1..0000000 --- a/res/brush47.obj +++ /dev/null @@ -1,260 +0,0 @@ -# Blender v2.91.0 OBJ File: 'brush47.blend' -# www.blender.org -mtllib brush47.mtl -o Body -v -1.345000 1.200000 -9.690000 -v -1.345000 1.200000 9.690000 -v 1.345000 1.200000 -9.690000 -v 1.345000 1.200000 9.690000 -v -0.991447 3.900000 -8.536446 -v -1.345000 3.546447 -9.440000 -v -0.991447 3.900000 8.536446 -v -1.345000 3.546447 9.440000 -v 0.991447 3.900000 -8.536446 -v 1.345000 3.546447 -9.440000 -v 0.991447 3.900000 8.536446 -v 1.345000 3.546447 9.440000 -v -1.345000 2.723224 9.690000 -v 1.345000 2.723224 9.690000 -v 1.345000 2.723224 -9.690000 -v -1.345000 2.723224 -9.690000 -v 1.340000 0.500000 9.600000 -v -1.340000 0.500000 9.600000 -v -1.340000 1.200000 9.690000 -v -1.340000 0.500000 -9.600000 -v 1.340000 0.500000 -9.600000 -v -1.300000 0.200000 -2.250000 -v -1.300000 1.200000 -2.250000 -v -1.300000 0.200000 2.250000 -v -1.300000 1.200000 2.250000 -v 1.300000 0.200000 -2.250000 -v 1.300000 1.200000 -2.250000 -v 1.300000 0.200000 2.250000 -v 1.300000 1.200000 2.250000 -v 1.345000 1.200000 8.236500 -v 1.345000 1.200000 -8.236500 -v -1.345000 1.200000 -8.236500 -v -1.345000 1.200000 8.236500 -vt 0.025174 0.662500 -vt 0.025174 0.831250 -vt 0.037326 0.925000 -vt 0.957465 0.927083 -vt 0.971354 0.833333 -vt 0.971354 0.662500 -vt 0.900391 0.662500 -vt 0.096137 0.662500 -vt 0.025174 0.662500 -vt 0.025174 0.831250 -vt 0.037326 0.925000 -vt 0.957465 0.927083 -vt 0.971354 0.833333 -vt 0.971354 0.662500 -vt 0.900391 0.662500 -vt 0.096137 0.662500 -vt 0.605035 0.456250 -vt 0.605035 0.581250 -vt 0.359375 0.581250 -vt 0.359375 0.456250 -vt 0.605035 0.581250 -vt 0.605035 0.456250 -vt 0.359375 0.581250 -vt 0.359375 0.456250 -vt 0.026042 0.593750 -vt 0.971354 0.593750 -vt 0.026042 0.593750 -vt 0.971354 0.593750 -vt 0.088542 0.089583 -vt 0.088542 0.206250 -vt 0.918403 0.206250 -vt 0.918403 0.089583 -vt 0.926215 0.527083 -vt 0.926215 0.612500 -vt 0.834201 0.612500 -vt 0.834201 0.527083 -vt 0.083333 0.989583 -vt 0.913194 0.989583 -vt 0.037326 0.927083 -vt 0.152778 0.364583 -vt 0.197049 0.364583 -vt 0.204861 0.310417 -vt 0.144965 0.310417 -vt 0.083333 0.989583 -vt 0.913194 0.989583 -vt 0.037326 0.927083 -vt 0.152778 0.364583 -vt 0.197049 0.364583 -vt 0.204861 0.310417 -vt 0.144965 0.310417 -vt 0.834201 0.527083 -vt 0.834201 0.612500 -vt 0.927083 0.612500 -vt 0.927083 0.527083 -vt 0.114583 0.293750 -vt 0.114583 0.414583 -vt 0.010417 0.414583 -vt 0.010417 0.293750 -vt 0.010417 0.293750 -vt 0.010417 0.414583 -vt 0.114583 0.414583 -vt 0.114583 0.293750 -vt 0.043403 0.014583 -vt 0.002604 0.014583 -vt 0.002604 0.081250 -vt 0.043403 0.081250 -vt 0.043403 0.014583 -vt 0.002604 0.014583 -vt 0.002604 0.081250 -vt 0.043403 0.081250 -vn -1.0000 0.0000 0.0000 -vn 1.0000 0.0000 0.0000 -vn 0.0000 0.0000 -1.0000 -vn 0.0000 0.0000 1.0000 -vn -1.0000 0.0071 0.0000 -vn 1.0000 0.0071 -0.0000 -vn -0.3335 -0.9344 -0.1252 -vn 0.3335 -0.9344 -0.1252 -vn 0.3335 -0.9344 0.1252 -vn -0.3335 -0.9344 0.1252 -vn 0.6755 -0.1083 -0.7294 -vn 0.6276 -0.5509 -0.5500 -vn -0.6276 -0.5509 -0.5500 -vn -0.6755 -0.1083 -0.7294 -vn 0.6276 -0.5509 0.5500 -vn -0.6276 -0.5509 0.5500 -vn -0.6755 -0.1083 0.7294 -vn 0.6755 -0.1083 0.7294 -vn 0.8867 0.0030 -0.4622 -vn -0.6937 0.0482 -0.7186 -vn -0.6937 0.0482 0.7186 -vn 0.6937 0.0482 0.7186 -vn -0.6128 0.1051 -0.7832 -vn 0.6145 0.1049 -0.7819 -vn 0.0000 0.1275 -0.9918 -vn 0.6128 0.1051 0.7832 -vn -0.6128 0.1051 0.7832 -usemtl Brush47 -s off -f 4/1/1 14/2/1 12/3/1 10/4/1 15/5/1 3/6/1 31/7/1 30/8/1 -f 1/9/2 16/10/2 6/11/2 8/12/2 13/13/2 2/14/2 33/15/2 32/16/2 -f 22/17/2 23/18/2 25/19/2 24/20/2 -f 24/20/3 25/19/3 29/21/3 28/22/3 -f 28/22/1 29/21/1 27/23/1 26/24/1 -f 26/24/4 27/23/4 23/18/4 22/17/4 -f 4/1/5 30/8/5 17/25/5 -f 31/7/5 3/6/5 21/26/5 -f 1/9/6 32/16/6 20/27/6 -f 33/15/6 2/14/6 18/28/6 -s 1 -f 11/29/7 7/30/8 5/31/9 9/32/10 -f 13/33/11 8/34/12 12/35/13 14/36/14 -f 5/37/9 7/38/8 8/12/12 6/39/15 -f 7/40/8 11/41/7 12/42/13 8/43/12 -f 11/44/7 9/45/10 10/4/16 12/46/13 -f 9/47/10 5/48/9 6/49/15 10/50/16 -f 15/51/17 10/52/16 6/53/15 16/54/18 -f 2/55/19 13/56/11 14/57/14 4/58/20 -f 3/59/21 15/60/17 16/61/18 1/62/22 -f 17/63/23 18/64/24 19/65/25 4/66/20 -f 20/67/26 21/68/27 3/69/21 1/70/22 -o Bogie2 -v -0.717500 0.000000 -2.700000 -v -0.717500 0.000000 -9.300000 -v -0.717500 1.200000 -2.700000 -v 0.717500 1.200000 -2.700000 -v 0.717500 0.000000 -2.700000 -v 0.717500 0.000000 -9.300000 -v 1.017500 1.200000 -2.700000 -v 1.017500 0.000000 -2.700000 -v 1.017500 0.000000 -9.300000 -v -1.017500 0.000000 -9.300000 -v -1.017501 0.000000 -2.700000 -v -1.017501 1.200000 -2.700000 -v -0.717500 0.654015 -9.300000 -v -0.717500 1.200000 -8.236500 -v -0.717500 0.661560 -9.285304 -v 0.717500 1.200000 -8.236500 -v 0.717500 0.654015 -9.300000 -v 1.017500 1.200000 -8.236500 -v 1.017500 0.654015 -9.300000 -v -1.017500 0.654015 -9.300000 -v -1.017500 1.200000 -8.236500 -vt 0.342014 0.591667 -vt 0.342014 0.435417 -vt 0.006076 0.435417 -vt 0.006076 0.520575 -vt 0.006824 0.521557 -vt 0.060208 0.591667 -vt 0.006076 0.435417 -vt 0.342014 0.435417 -vt 0.342014 0.591667 -vt 0.060208 0.591667 -vt 0.006076 0.520575 -vt 0.217014 0.270833 -vt 0.552951 0.270833 -vt 0.552951 0.427083 -vt 0.271146 0.427083 -vt 0.217014 0.355992 -vt 0.552083 0.429167 -vt 0.552083 0.272917 -vt 0.216146 0.272917 -vt 0.216146 0.358075 -vt 0.270278 0.429167 -vn 1.0000 0.0000 -0.0000 -vn -1.0000 0.0000 0.0000 -usemtl Brush47 -s off -f 36/71/28 34/72/28 35/73/28 46/74/28 48/75/28 47/76/28 -f 39/77/29 38/78/29 37/79/29 49/80/29 50/81/29 -f 42/82/29 41/83/29 40/84/29 51/85/29 52/86/29 -f 45/87/28 44/88/28 43/89/28 53/90/28 54/91/28 -o Bogie1 -v 0.717500 0.000000 2.700000 -v 0.717500 1.200000 2.700000 -v 0.717500 0.000000 9.300000 -v -0.717500 0.000000 2.700000 -v -0.717500 1.200000 2.700000 -v -0.717500 0.000000 9.300000 -v 1.017500 0.000000 2.700001 -v 1.017500 1.200000 2.700001 -v 1.017500 0.000000 9.300000 -v -1.017500 0.000000 2.700000 -v -1.017500 1.200000 2.700000 -v -1.017500 0.000000 9.300000 -v 0.717500 0.654015 9.300000 -v 0.717500 1.200000 8.236500 -v 1.017500 0.654015 9.300000 -v 1.017500 1.200000 8.236500 -v -0.717500 1.200000 8.236500 -v -0.717500 0.661372 9.285670 -v -0.717500 0.654015 9.300000 -v -1.017500 1.200000 8.236500 -v -1.017500 0.654015 9.300000 -vt 0.342014 0.435417 -vt 0.006076 0.435417 -vt 0.006076 0.520575 -vt 0.060208 0.591667 -vt 0.342014 0.591667 -vt 0.006076 0.520575 -vt 0.006076 0.435417 -vt 0.342014 0.435417 -vt 0.342014 0.591667 -vt 0.060208 0.591667 -vt 0.006806 0.521533 -vt 0.552083 0.270833 -vt 0.216146 0.270833 -vt 0.216146 0.355992 -vt 0.270278 0.427083 -vt 0.552083 0.427083 -vt 0.215278 0.355992 -vt 0.215278 0.270833 -vt 0.552083 0.270833 -vt 0.552083 0.427083 -vt 0.269549 0.427083 -vn -1.0000 0.0000 -0.0000 -vn 1.0000 -0.0000 0.0000 -usemtl Brush47 -s off -f 55/92/30 57/93/30 67/94/30 68/95/30 56/96/30 -f 73/97/31 60/98/31 58/99/31 59/100/31 71/101/31 72/102/31 -f 61/103/30 63/104/30 69/105/30 70/106/30 62/107/30 -f 75/108/31 66/109/31 64/110/31 65/111/31 74/112/31 diff --git a/res/brush47.png b/res/brush47.png deleted file mode 100644 index 3d435d6..0000000 Binary files a/res/brush47.png and /dev/null differ diff --git a/test/Jamfile.jam b/test/Jamfile.jam index d91af1d..b0eed5e 100644 --- a/test/Jamfile.jam +++ b/test/Jamfile.jam @@ -44,7 +44,6 @@ project : requirements lib test : [ glob *.cpp : test-*.cpp perf-*.cpp ] ; run test-collection.cpp ; -run test-obj.cpp ; run test-maths.cpp ; run test-lib.cpp ; run test-geo.cpp ; diff --git a/test/test-obj.cpp b/test/test-obj.cpp deleted file mode 100644 index e6e725d..0000000 --- a/test/test-obj.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#define BOOST_TEST_MODULE test_obj - -#include - -#include -#include -#include -#include -#include -#include -#include - -BOOST_AUTO_TEST_CASE(objparse) -{ - const ObjParser op {RESDIR "/brush47.obj"}; - BOOST_CHECK_EQUAL(75, op.vertices.size()); - BOOST_CHECK_EQUAL(112, op.texCoords.size()); - BOOST_CHECK_EQUAL(31, op.normals.size()); - BOOST_CHECK_EQUAL(3, op.objects.size()); - const auto & object {op.objects.front()}; - BOOST_CHECK_EQUAL("Body", object.first); - BOOST_CHECK_EQUAL(21, object.second.size()); - BOOST_CHECK_EQUAL(8, object.second[0].size()); - BOOST_CHECK_EQUAL(8, object.second[1].size()); - BOOST_CHECK_EQUAL(4, object.second[12].size()); -} - -BOOST_AUTO_TEST_CASE(create_meshes) -{ - const ObjParser op {RESDIR "/brush47.obj"}; - const auto ms = op.createMeshData(); - BOOST_REQUIRE_EQUAL(3, ms.size()); - BOOST_REQUIRE_EQUAL("Body", ms.begin()->first); - const auto & o = ms.at("Body"); - BOOST_REQUIRE_EQUAL(88, o.first.size()); - const auto & v = o.first.front(); - BOOST_REQUIRE_CLOSE(-1.345, v.pos.x, 1); - BOOST_REQUIRE_EQUAL(138, o.second.size()); -} -- cgit v1.2.3 From 46784bfd9ca8d500971d2ec43fe83f12bddef117 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 17:59:45 +0100 Subject: Add an asset template and use it to define all the foliage assets in the plants pack --- res/assetTemplate.m4 | 5 ++ res/foliage.xml | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 res/assetTemplate.m4 diff --git a/res/assetTemplate.m4 b/res/assetTemplate.m4 new file mode 100644 index 0000000..8750c42 --- /dev/null +++ b/res/assetTemplate.m4 @@ -0,0 +1,5 @@ + + + + + diff --git a/res/foliage.xml b/res/foliage.xml index 1b0a1aa..5345b39 100644 --- a/res/foliage.xml +++ b/res/foliage.xml @@ -6,4 +6,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3