summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--assetFactory/assetFactory.cpp5
-rw-r--r--assetFactory/assetFactory.h3
-rw-r--r--assetFactory/assimp.cpp119
-rw-r--r--assetFactory/assimp.h14
-rw-r--r--res/foliage.xml9
-rw-r--r--test/perf-assetFactory.cpp11
-rw-r--r--test/test-assetFactory.cpp17
7 files changed, 176 insertions, 2 deletions
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<Texture>(outSize.x, outSize.y, TextureOptions {.wrap = GL_CLAMP_TO_EDGE});
@@ -134,7 +134,8 @@ AssetFactory::persist(Persistence::PersistenceStore & store)
using MapObjects = Persistence::MapByMember<Shapes, std::shared_ptr<Object>>;
using MapAssets = Persistence::MapByMember<Assets>;
using MapTextureFragments = Persistence::MapByMember<TextureFragments>;
+ using MapAssImp = Persistence::MapByMember<AssImps, std::shared_ptr<AssImp>, &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<std::string, Shape::Ptr, std::less<>>;
using Assets = std::map<std::string, Asset::Ptr, std::less<>>;
+ using AssImps = std::map<std::string, AssImp::Ptr, std::less<>>;
using TextureFragments = std::map<std::string, TextureFragment::Ptr, std::less<>>;
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 <assimp/cimport.h>
+#include <assimp/postprocess.h>
+#include <assimp/scene.h>
+#include <stb/stb_image.h>
+
+template<typename T>
+glm::vec<3, T>
+operator*(const aiVector3t<T> & v)
+{
+ return {v.x, v.y, v.z};
+}
+
+template<typename T>
+glm::vec<2, T>
+operator!(const aiVector3t<T> & v)
+{
+ return {v.x, v.y};
+}
+
+#define AIRANGE(parent, member) \
+ std::span \
+ { \
+ (parent)->m##member, (parent)->mNum##member \
+ }
+
+using ScemeCPtr = std::shared_ptr<const aiScene>;
+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>("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>("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<AssImpNode>(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<TextureFragment>();
+ texture->id = texture->path = t->mFilename.C_Str();
+ texture->image = std::make_unique<Image>(
+ std::span {reinterpret_cast<unsigned char *>(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<AssImp>;
+
+ 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 @@
+<?xml version="1.0"?>
+<ilt p.id="assetFactory">
+ <assimp path="shapespark-low-poly-plants-kit.fbx"/>
+ <asset p.typeid="Foliage" id="Tree-01-1" name="Tree-01-1">
+ <bodyMesh id="body">
+ <use type="Tree-01-1"/>
+ </bodyMesh>
+ </asset>
+</ilt>
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<Foliage>(tree_01_1);
+ BOOST_REQUIRE(tree_01_1_f);
+
+ auto plant = std::make_shared<Plant>(tree_01_1_f, Location {});
+ objects.objects.push_back(plant);
+
+ render();
+}
BOOST_AUTO_TEST_SUITE_END();
template<typename T> using InOut = std::tuple<T, T>;