1#include "MergeCommand.h"
3#include "Systems/Core/SceneSystem.h"
4#include "Systems/Core/MeshSystem.h"
5#include "Systems/Core/TransformSystem.h"
6#include "Systems/Core/RenderSystem.h"
8#include "Resources/MeshManager.h"
10#include "Foundation/Logging/Logger.h"
21 bool canMerge(SceneComponent * sc)
23 if (sc->children.empty())
return false;
25 for (
auto & c : sc->children) {
26 auto childSc = c->getComponent<SceneComponent>();
28 if (!childSc->children.empty())
return false;
30 auto meshComponent = c->getComponent<MeshComponent>();
32 if (!meshComponent)
return false;
38 template<
typename Container>
41 auto & stream = mesh->getStream(dataType);
43 auto pData = (
const typename Container::value_type *)stream.data();
45 container.insert(container.end(), pData, pData + stream.numElements);
48 MeshHandle createMesh(Context * context, SceneComponent * sc)
50 auto mesh = context->meshManager->create();
52 std::vector<glm::vec3> positions;
53 std::vector<glm::vec3> normals;
54 std::vector<glm::vec2> texCoords;
55 std::vector<glm::vec3> tangents;
57 std::vector<uint32_t> indexes;
59 for (
auto & c : sc->children) {
60 if (c->getName().size() && c->getName()[0] ==
'/')
continue;
62 auto meshComponent = c->getComponent<MeshComponent>();
64 uint32_t offset = (uint32_t)positions.size();
66 auto childMesh = meshComponent->meshHandle.resolve();
68 copyStream(childMesh, VertexDataType::Positions, positions);
69 if (childMesh->hasStream(VertexDataType::Normals)) copyStream(childMesh, VertexDataType::Normals, normals);
70 if (childMesh->hasStream(VertexDataType::TexCoords0)) copyStream(childMesh, VertexDataType::TexCoords0, texCoords);
71 if (childMesh->hasStream(VertexDataType::Tangents)) copyStream(childMesh, VertexDataType::Tangents, tangents);
73 auto meshIndexes = childMesh->getIndexes();
74 for (
auto i : meshIndexes) {
75 indexes.emplace_back(i + offset);
79 mesh->setPositions(positions);
80 if (!normals.empty()) mesh->setNormals(normals);
81 if (!texCoords.empty()) mesh->setTexCoords(texCoords);
82 if (!tangents.empty()) mesh->setTangents(tangents);
83 if (!indexes.empty()) mesh->setIndexes(indexes);
91 void traverse(Context * context,
Entity * entity,
const std::regex & matchRegex)
96 auto mesh = createMesh(context, sc);
97 auto material = sc->children.front()->getComponent<MeshRenderComponent>()->material;
99 if (!mesh->getCount())
return;
101 auto oldChildren = sc->children;
102 sc->children.clear();
104 for (
auto & oldChild : oldChildren) {
106 const std::string & name = oldChild->getName();
107 if (std::regex_match(name, matchRegex)) {
108 sc->children.emplace_back(oldChild);
112 const size_t numMerged = oldChildren.size() - sc->children.size();
114 LOG_TRACE(logger,
"Merged %zd children up the hierarchy.", numMerged);
116 auto existingMc = entity->
getComponent<MeshComponent>();
119 auto mc = context->meshSystem->createComponent();
120 auto mrc = context->renderSystem->createComponent();
125 mc.resolveComponent<MeshComponent>()->meshHandle = mesh;
126 mrc.resolveComponent<MeshRenderComponent>()->material = material;
128 auto newChild = context->store->createChildEntity(
"MeshPart", entity,
"MergedChild");
130 auto mc = newChild->getComponent<MeshComponent>();
132 mc->meshHandle = mesh;
135 auto mrc = newChild->getComponent<MeshRenderComponent>();
137 mrc->material = material;
141 for (
auto & child : sc->children) {
142 traverse(context, child.get(), matchRegex);
151 const std::regex matchRegex = std::regex(
getOption(
options,
"matchRegex",
"^/[^/]*$").to_string(), std::regex_constants::ECMAScript);
153 for (
auto &
id : entityIds) {
154 auto entity = context->store->getEntityPtr(
id);
156 traverse(context, entity, matchRegex);
160void Cogs::Core::MergeCommand::undo()
176 std::vector<MergeInstance> instances;
178 uint32_t signature = 0;
180 size_t vertexCountThreshold = 100000;
183 uint32_t getMeshSignature(
const Mesh * mesh)
185 uint32_t signature = 0;
186 for (
size_t i = 0; i < 11; ++i) {
192 for (
size_t i = 11; i < 15; ++i) {
194 signature = (uint32_t)-1;
201 void closeMergeState(Context * context, MergeMeshState & state)
203 if (state.instances.empty())
return;
205 if (state.instances.size() >= 2) {
206 auto mesh = context->meshManager->create();
208 std::vector<glm::vec3> positions;
209 std::vector<glm::vec3> normals;
210 std::vector<glm::vec2> texCoords;
211 std::vector<glm::vec3> tangents;
213 std::vector<uint32_t> indexes;
215 for (
auto & instance : state.instances) {
216 instance.meshComponent->meshHandle = mesh;
217 instance.meshComponent->setChanged();
219 uint32_t offset = (uint32_t)positions.size();
221 auto childMesh = instance.mesh;
223 copyStream(childMesh, VertexDataType::Positions, positions);
224 if (childMesh->hasStream(VertexDataType::Normals)) copyStream(childMesh, VertexDataType::Normals, normals);
225 if (childMesh->hasStream(VertexDataType::TexCoords0)) copyStream(childMesh, VertexDataType::TexCoords0, texCoords);
226 if (childMesh->hasStream(VertexDataType::Tangents)) copyStream(childMesh, VertexDataType::Tangents, tangents);
228 auto meshIndexes = childMesh->getIndexes();
229 for (
auto i : meshIndexes) {
230 indexes.emplace_back(i + offset);
233 instance.meshRenderComponent->startIndex = offset;
234 instance.meshRenderComponent->vertexCount = (uint32_t)meshIndexes.size();
235 auto localBounds = context->renderSystem->getLocalBounds(instance.meshRenderComponent);
236 context->renderSystem->setLocalBounds(instance.meshRenderComponent, localBounds);
237 instance.meshRenderComponent->setChanged();
241 if (!normals.empty()) mesh->
setNormals(normals);
243 if (!tangents.empty()) mesh->
setTangents(tangents);
244 if (!indexes.empty()) mesh->
setIndexes(indexes);
248 LOG_TRACE(logger,
"Merged %zd meshes with %zd verts.", state.instances.size(), state.size);
250 LOG_TRACE(logger,
"Skipped %zd mesh(es) with %zd verts.", state.instances.size(), state.size);
253 state.instances = {};
257 void traverseMerge(Context * context,
Entity * entity, MergeMeshState & state)
260 auto meshComponent = entity->
getComponent<MeshComponent>();
261 auto meshRenderComponent = entity->
getComponent<MeshRenderComponent>();
264 auto meshSignature = getMeshSignature(meshComponent->meshHandle.resolve());
266 if (meshSignature != state.signature) {
267 closeMergeState(context, state);
268 }
else if (state.size > state.vertexCountThreshold) {
269 closeMergeState(context, state);
272 state.signature = meshSignature;
274 state.instances.emplace_back(MergeInstance
276 meshComponent->meshHandle.resolve(),
281 state.size += meshComponent->meshHandle->getCount();
284 for (
auto & child : sc->children) {
285 traverseMerge(context, child.get(), state);
289 void traverseScale(Context * context,
Entity * entity, MergeMeshState & state)
292 auto meshComponent = entity->
getComponent<MeshComponent>();
293 auto meshRenderComponent = entity->
getComponent<MeshRenderComponent>();
296 auto mesh = meshComponent->getMesh(context);
298 assert(pStride ==
sizeof(glm::vec3));
299 auto positions = (glm::vec3 *)pData;
301 printf(
"Scaling mesh resource %u...\n", pSize);
303 for (
size_t i = 0; i < pSize; ++i) {
304 positions[i] = positions[i] * 0.001f;
307 mesh->
unmap(VertexDataType::Positions);
313 context->renderSystem->setLocalBounds(meshRenderComponent, bounds);
316 for (
auto & child : sc->children) {
317 traverseScale(context, child.get(), state);
326 state.vertexCountThreshold =
getOption(options,
"vertexCountThreshold", state.vertexCountThreshold);
328 for (
auto &
id : entityIds) {
329 auto entity = context->store->getEntityPtr(
id);
331 traverseMerge(context, entity, state);
333 if (state.instances.size()) closeMergeState(context, state);
337void Cogs::Core::MergeMeshCommand::undo()
347 state.vertexCountThreshold =
getOption(options,
"vertexCountThreshold", state.vertexCountThreshold);
350 for (
auto &
id : entityIds) {
351 printf(
"Scaling mesh entity...\n");
353 auto entity = context->store->getEntityPtr(
id);
355 traverseScale(context, entity, state);
357 if (state.instances.size()) closeMergeState(context, state);
361void Cogs::Core::ScaleMeshCommand::undo()
Container for components, providing composition of dynamic entities.
T * getComponent() const
Get a pointer to the first component implementing the given type in the entity.
void addComponent(ComponentHandle component)
Contains a handle to a Mesh resource to use when rendering using the MeshRenderComponent.
Renders the contents of a MeshComponent using the given materials.
Log implementation class.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
Cogs::Geometry::BoundingBox COGSCORE_DLL_API calculateBounds(Mesh *mesh)
Calculate a bounding box for the given mesh.
StringView getOption(const std::vector< ParsedValue > &options, const StringView &key, const StringView &defaultValue="")
Find and get value of option in vector as a string. Return default if not found.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
std::vector< ParsedValue > options
Options passed to the command when running in batch mode.
void apply() override
Run the command.
void apply() override
Run the command.
@ BoundingBoxSet
Custom bounding box set, no automatic calculation of bounds should be performed.
@ ClockwiseWinding
The mesh uses clockwise winding order for it's triangles as opposed to the counter-clockwise default.
Meshes contain streams of vertex data in addition to index data and options defining geometry used fo...
void unmap(VertexDataType::EVertexDataType type)
Unmap the stream with the given vertex data type index.
void setTangents(std::span< const glm::vec3 > tangents)
Set the tangent data of the Mesh.
void setIndexes(std::span< const uint32_t > collection)
Set the index data to the collection given.
void setTexCoords(std::span< const glm::vec2 > texCoords)
Set the texture coordinate data of the Mesh.
StreamReference getPositionStream()
Get the data of the stream containing positions.
void setBounds(Geometry::BoundingBox box)
Set custom bounds for the mesh.
void setNormals(std::span< const glm::vec3 > normals)
Set the normal data of the Mesh.
void unsetMeshFlag(MeshFlags::EMeshFlags flag)
Unset the given mesh flag.
static constexpr int NoStream
Used to indicate no stream.
void setMeshFlag(MeshFlags::EMeshFlags flag)
Set the given mesh flag.
void setPositions(std::span< const glm::vec3 > positions)
Set the position data of the Mesh.
void apply() override
Run the command.
EVertexDataType
Contains data types.