1#include "MeshOpCommands.h"
2#include "Rendering/Common.h"
4#include "Platform/Instrumentation.h"
5#include "../Extensions/GeometryProcessing/GeometryProcessing.h"
11 items.transforms.clear();
13 getMeshItems(context, items, state->selected, ~0u);
14 if (items.meshes.empty())
return;
16 unpackMeshItems(context, originalMeshes, meshes, items, opts);
18 packMeshItems(context, originalMeshes, meshes, items,
true);
23 items.transforms.clear();
25 getMeshItems(context, items, state->selected, ~0u);
26 if (items.meshes.empty())
return;
28 unpackMeshItems(context, originalMeshes, meshes, items, opts);
41 ImGui::OpenPopup(
"No operation");
42 if (ImGui::BeginPopupModal(
"No operation",
nullptr)) {
43 if (ImGui::Button(
"OK", ImVec2(120, 0))) { modal =
false; ImGui::CloseCurrentPopup(); }
46 if (ImGui::Button(
"Cancel", ImVec2(120, 0))) { cancel =
true; modal =
false; ImGui::CloseCurrentPopup(); }
51 packMeshItems(context, originalMeshes, meshes, items, cancel ==
false);
55void Cogs::Core::NoOpModalCommand::undo()
57 packMeshItems(context, originalMeshes, meshes, items,
false);
67 items.transforms.clear();
69 getMeshItems(context, items, state->selected, primitiveMask);
70 if (items.meshes.empty())
return;
72 unpackMeshItems(context, originalMeshes, meshes, items, opts);
73 newMeshes.resize(meshes.size());
81 if (running ==
false) {
83 context->taskManager->wait(task);
85 packMeshItems(context, originalMeshes, newMeshes, items, cancel ==
false);
87 if (modal && !cancel && dirty) {
97void Cogs::Core::AbstractLiveUpdateCommand::undo()
99 packMeshItems(context, originalMeshes, newMeshes, items,
false);
106 if (task.isValid()) {
107 context->taskManager->wait(task);
109 packMeshItems(context, originalMeshes, newMeshes, items, cancel ==
false);
112 packMeshItems(context, originalMeshes, newMeshes, items,
false);
121Cogs::Core::GenerateNormalsCommand::GenerateNormalsCommand(
EditorState * state)
124 opts.discardNormals =
true;
125 opts.discardTexCoords =
true;
126 opts.forceIndexed =
true;
132 for (
auto & option : options) {
133 if (option.key ==
"featureAngle") option.asFloat(featureAngle);
134 else if (option.key ==
"protrusionAngle") option.asFloat(protrusionAngle);
135 else if (option.key ==
"flip") option.asBool(flip);
138 items.transforms.clear();
139 items.meshes.clear();
140 getMeshItems(context, items, state->selected, primitiveMask);
141 if (items.meshes.empty())
return;
143 unpackMeshItems(context, originalMeshes, meshes, items, opts);
144 newMeshes.resize(meshes.size());
145 if (issueTask() && task.isValid()) {
146 context->taskManager->wait(task);
148 packMeshItems(context, originalMeshes, newMeshes, items,
true);
157 ImGui::OpenPopup(
"Generate normals");
158 if (ImGui::BeginPopupModal(
"Generate normals",
nullptr)) {
160 if (ImGui::SliderAngle(
"Feature angle", &featureAngle, 0.f, 180.f)) {
164 if (ImGui::SliderAngle(
"Protrusion angle", &protrusionAngle, 0.f, 180.f)) {
168 if (ImGui::Checkbox(
"Flip normals", &flip)) {
174 if (ImGui::Button(
"OK", ImVec2(120, 0))) { modal =
false; ImGui::CloseCurrentPopup(); }
177 if (ImGui::Button(
"Cancel", ImVec2(120, 0))) { cancel =
true; modal =
false; ImGui::CloseCurrentPopup(); }
183bool Cogs::Core::GenerateNormalsCommand::issueTask()
186 task = context->taskManager->enqueue(context->taskManager->GlobalQueue,
187 [that =
this, fa = featureAngle, pa = protrusionAngle, fl =flip]()
189 CpuInstrumentationScope(SCOPE_EDITOR_COMMAND,
"MeshOpCmd::GenNrmTask");
191 for (size_t i = 0; i<that->meshes.size(); i++) {
192 auto & mesh = that->newMeshes[i];
193 mesh.copy(that->meshes[i]);
195 std::vector<uint32_t> remap;
196 std::vector<uint32_t> newIndices;
197 std::vector<glm::vec3> N;
199 GeometryProcessing::normalsFromIndexedTriangles(that->context,
200 N, remap, newIndices,
201 reinterpret_cast<const float*>(mesh.positions.data()), 3 * sizeof(float), static_cast<uint32_t>(mesh.positions.size()),
202 mesh.indices.data(), static_cast<uint32_t>(mesh.indices.size()), fa, pa, fl);
203 assert(N.size() == remap.size());
205 remapVertices(that->context, mesh, remap);
207 mesh.indices.resize(newIndices.size());
208 std::memcpy(mesh.indices.data(), newIndices.data(), sizeof(uint32_t)*newIndices.size());
210 mesh.normals.resize(remap.size(), false);
211 std::memcpy(mesh.normals.data(), N.data(), mesh.normals.byteSize());
213 that->running =
false;
221Cogs::Core::UniqueVerticesCommand::UniqueVerticesCommand(EditorState * state)
222 : AbstractLiveUpdateCommand(state)
224 opts.forceIndexed =
true;
230 for (
auto & option : options) {
231 if (option.key ==
"keepNormals") option.asBool(keepNormals);
232 else if (option.key ==
"keepTexCoords") option.asBool(keepTexCoords);
233 else if (option.key ==
"keepTangents") option.asBool(keepTangents);
236 items.transforms.clear();
237 items.meshes.clear();
238 getMeshItems(context, items, state->selected, primitiveMask);
239 if (items.meshes.empty())
return;
241 unpackMeshItems(context, originalMeshes, meshes, items, opts);
242 newMeshes.resize(meshes.size());
243 if (issueTask() && task.isValid()) {
244 context->taskManager->wait(task);
246 packMeshItems(context, originalMeshes, newMeshes, items,
true);
255 ImGui::OpenPopup(
"Remove duplicate vertices");
256 if (ImGui::BeginPopupModal(
"Remove duplicate vertices", NULL)) {
258 if (ImGui::InputFloat(
"Epsilon", &epsilon)) { dirty =
true; }
259 if (hasNormals && ImGui::Checkbox(
"Keep normals", &keepNormals)) { dirty =
true; }
260 if (hasTexCoords && ImGui::Checkbox(
"Keep texcoords", &keepTexCoords)) { dirty =
true; }
261 if (hasTangents && ImGui::Checkbox(
"Keep tangents", &keepTangents)) { dirty =
true; }
265 if (ImGui::Button(
"OK", ImVec2(120, 0))) { modal =
false; ImGui::CloseCurrentPopup(); }
268 if (ImGui::Button(
"Cancel", ImVec2(120, 0))) { cancel =
true; modal =
false; ImGui::CloseCurrentPopup(); }
274bool Cogs::Core::UniqueVerticesCommand::issueTask()
277 hasTexCoords =
false;
279 for (
auto & mesh : meshes) {
280 hasNormals = hasNormals || mesh.normals.size();
281 hasTexCoords = hasTexCoords || mesh.texcoords.size();
282 hasTangents = hasTangents || mesh.tangents.size();
285 task = context->taskManager->enqueue(context->taskManager->GlobalQueue,
286 [that =
this, keepN = keepNormals, keepTC = keepTexCoords, keepT = keepTangents, e = epsilon]()
288 CpuInstrumentationScope(SCOPE_EDITOR_COMMAND,
"MeshOpCmd::UniqVtxTask");
290 for (size_t i = 0; i < that->meshes.size(); i++) {
291 auto & mesh = that->newMeshes[i];
292 mesh.copy(that->meshes[i]);
294 if (!keepN) mesh.normals.clear();
295 if (!keepTC) mesh.texcoords.clear();
296 if (!keepT) mesh.tangents.clear();
298 std::vector<uint32_t> unique;
299 std::vector<uint32_t> map;
300 GeometryProcessing::uniqueVertexSubset(that->context, unique, map,
301 (float*)mesh.positions.data(),
303 mesh.normals.size() ? (float*)mesh.normals.data() : nullptr,
305 mesh.texcoords.size() ? (float*)mesh.texcoords.data() : nullptr,
307 static_cast<uint32_t>(mesh.positions.size()), e);
309 remapVertices(that->context, mesh, unique);
310 remapIndices(that->context, mesh, map);
312 that->running =
false;
Contains all Cogs related functionality.
void beginModal() override
Called when the command is initiated.
bool continueModal() override
Shall return true while the GUI should still be shown. False when.
void showGui() override
Display custom ImGUI.
void showGui() override
Display custom ImGUI.
void apply() override
Run the command.
bool continueModal() override
Shall return true while the GUI should still be shown. False when.
void beginModal() override
Called when the command is initiated.
void apply() override
Run the command.
void showGui() override
Display custom ImGUI.
void apply() override
Run the command.
void showGui() override
Display custom ImGUI.
Primitive types for interpreting vertex data sent to the graphics pipeline.