Cogs.Core
RRSaveAllLodCommand.cpp
1#include "imgui.h"
2#include "Commands/CommandHelpers.h"
3#include "Commands/CommandParseHelpers.h"
4#include "Commands/ExportCommand.h"
5#include "EditorState.h"
6#include "Editor/Editor.h"
7
8#include "Context.h"
9#include "Renderer/IRenderer.h"
10#include "Renderer/InspectorGui/InspectorGuiRenderer.h"
11
12#include "Components/Core/LodComponent.h"
13#include "Components/Core/SceneComponent.h"
14
15#include "RRSaveAllLodCommand.h"
16#include "RRSaveAllLodCommand.h"
17#include "Rendering/Common.h"
18
19#include "Platform/Instrumentation.h"
20
21#include "Scene/GetBounds.h"
22
23#include "Foundation/Logging/Logger.h"
24#include "Foundation/Platform/IO.h"
25
26#define _SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING
27#include "rapidjson/document.h"
28#include "rapidjson/stringbuffer.h"
29#include "rapidjson/prettywriter.h"
30#undef _SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING
31
32#include <cassert>
33#include <fstream>
34
35using namespace rapidjson;
36
37namespace {
38 Cogs::Logging::Log logger = Cogs::Logging::getLogger("RRSaveAllLodCommand");
39
40 const char * label1 = "RR LOD Save All";
41
42 uint64_t getModelSizeEstimate(const std::string & filename)
43 {
44 auto fh = Cogs::IO::openFile(filename, Cogs::FileHandle::OpenMode::Open, Cogs::FileHandle::AccessMode::Read);
45 uint64_t size = Cogs::IO::fileSize(fh);
46 return size;
47 }
48
50 void storeLodSidecarfile(std::string path,
51 const std::string & sourcePath,
52 const float threshold,
53 const std::vector<Cogs::Core::ParsedValue> & options,
54 Cogs::Geometry::BoundingBox bbox)
55 {
56 path = Cogs::Core::replaceFileMacros(path, options);
57 auto jsonpath = path + ".json";
58 const auto filename = Cogs::IO::fileName(jsonpath);
59 Document doc;
60 doc.SetObject();
61 auto & alloc = doc.GetAllocator();
62 doc.AddMember("error", Value().SetFloat(threshold), alloc);
63 doc.AddMember("byteSize", Value().SetUint64(getModelSizeEstimate(path)), alloc);
64 doc.AddMember("path", Value().SetString(filename.c_str(), alloc), alloc);
65 doc.AddMember("offset", Value().SetUint(0), alloc);
66 doc.AddMember("source", Value().SetString(sourcePath.c_str(), alloc), alloc);
67
68 Value box(kArrayType);
69 box.PushBack(Value().SetFloat(bbox.min.x), alloc);
70 box.PushBack(Value().SetFloat(bbox.min.y), alloc);
71 box.PushBack(Value().SetFloat(bbox.min.z), alloc);
72 box.PushBack(Value().SetFloat(bbox.max.x), alloc);
73 box.PushBack(Value().SetFloat(bbox.max.y), alloc);
74 box.PushBack(Value().SetFloat(bbox.max.z), alloc);
75 doc.AddMember("bbox", box, alloc);
76
77 StringBuffer buffer;
78 PrettyWriter<StringBuffer> writer(buffer);
79 doc.Accept(writer);
80
81 LOG_DEBUG(logger, "Writing JSon sidecar: '%s'.", jsonpath.c_str());
82 std::ofstream file(jsonpath.c_str());
83 file.write(buffer.GetString(), buffer.GetSize());
84 file.close();
85 }
86}
87
88namespace Cogs::Core
89{
90 RRSaveAllLodCommand::RRSaveAllLodCommand(EditorState * state)
91 : ModalEditorCommand(state)
92 {
93 path.resize(128, '\0');
94 }
95
96 void RRSaveAllLodCommand::apply()
97 {
98 bool hasStem = false;
99 bool hasExtension = false;
100 std::string batchSource;
101 for (auto & option : options) {
102
103 if (option.key == "path")
104 {
105 path.resize(0);
106 path.insert(path.begin(), std::begin(option.value), std::end(option.value));
107 }
108 else if (option.key == "source") {
109 batchSource = option.value;
110 }
111 else if (option.key == "stem") {
112 hasStem = true;
113 }
114 else if (option.key == "extension") {
115 hasExtension = true;
116 }
117 }
118
119 if (!hasStem) {
120 auto fileName = IO::fileName(batchSource);
121 auto stem = IO::stem(fileName);
122
123 auto & stemValue = options.emplace_back();
124 stemValue.key = "stem";
125 stemValue.value = stem;
126 }
127 if (!hasExtension) {
128 auto fileName = IO::fileName(batchSource);
129 auto extension = IO::extension(batchSource);
130
131 auto & extensionValue = options.emplace_back();
132 extensionValue.key = "extension";
133 extensionValue.value = extension;
134 }
135
136 // Run the task and wait for completion
137 issueTask();
138 }
139
140
141 void RRSaveAllLodCommand::beginModal()
142 {
143 modal = true;
144 }
145
146 void RRSaveAllLodCommand::showGui()
147 {
148 if (modal) {
149 // Config gui
150 ImGui::OpenPopup(label1);
151 if (ImGui::BeginPopupModal(label1, nullptr)) {
152
153 if (ImGui::InputText("Path", path.data(), path.size())) {
154
155 ImguiRenderer* guiRenderer = context->renderer->getGuiRenderer();
156 if (guiRenderer) {
157 guiRenderer->addTextToGlyphBuilder(path.data());
158 }
159
160 }
161
162 ImGui::Separator();
163
164 if (ImGui::Button("Save", ImVec2(120, 0))) {
165 modal = issueTask();
166 ImGui::CloseCurrentPopup();
167 }
168
169 ImGui::EndPopup();
170 }
171 }
172 }
173
174 bool RRSaveAllLodCommand::continueModal()
175 {
176 return modal;
177 }
178
179 void RRSaveAllLodCommand::runTask()
180 {
181 while (!path.empty() && path.back() == ' ')
182 path.resize(path.size() - 1);
183
184 auto entity = state->getSelected();
185 if (entity == nullptr) {
186 LOG_ERROR(logger, "No Selected entity.");
187 return;
188 }
189
190 auto lodComp = entity->getComponent<LodComponent>();
191 if (lodComp == nullptr) {
192 LOG_ERROR(logger, "No LodComponent in entity to save.");
193 return;
194 }
195
196 auto sourcePath = getOption(options, "source", "");
197 auto sceneComponent = entity->getComponent<SceneComponent>();
198
199 Cogs::Geometry::BoundingBox bb;
200 bb = state->context->bounds->getBounds(context, state->getSelected(), true);
201
202 size_t index = 0;
203 for (auto threshold : lodComp->thresholds)
204 {
205 EntityPtr child = sceneComponent->children[index];
206
207 SelectCommand select(state, child->getId());
208 select.apply();
209
210 ExportCommand cmd(state, child->getId());
211 cmd.options = options;
212 auto & opt = cmd.options.emplace_back();
213 opt.key = "fileName";
214 opt.value = std::string(path.empty() ? "" : path.data()) + "_" + std::to_string(threshold) + ".cogsbin";
215 opt.type = ParsedDataType::String;
216 cmd.apply();
217
218 auto outputPath = opt.value;
219 if (IO::isRelative(outputPath)) {
220 auto destination = getOption(options, "destination").to_string();
221 outputPath = IO::combine(destination, outputPath);
222 }
223
224 storeLodSidecarfile(outputPath, sourcePath.to_string(), threshold, options, bb);
225
226 index++;
227 }
228
229 // Select old entity.
230 SelectCommand select(state, entity->getId());
231 select.apply();
232 }
233
234 bool RRSaveAllLodCommand::issueTask()
235 {
236 runTask();
237 running = false;
238
239 // Value of modal is returned.
240 return false;
241 }
242}
Log implementation class.
Definition: LogManager.h:139
std::string to_string() const
String conversion method.
Definition: StringView.cpp:9
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
std::string replaceFileMacros(std::string outputName, const std::vector< ParsedValue > &options)
Replace common macroes for file name generation. I.e.: "A/$Filename" etc.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180