Cogs.Core
MeshReductionManager.cpp
1#include "MeshReductionManager.h"
2
3#include "Context.h"
4#include "Resources/MeshManager.h"
5
6#include "../Extensions/GeometryProcessing/GeometryProcessing.h"
7
8#include "Foundation/Geometry/NormalGenerator.hpp"
9#include "Foundation/Logging/Logger.h"
10
11#include <rrapi/rrapi.h>
12
13using namespace Cogs::RationalReducerExtension;
14
15namespace
16{
17 Cogs::Logging::Log logger = Cogs::Logging::getLogger("RR::MeshReductionManager");
18
19
20 struct ReductionState
21 {
22 Context* context = nullptr;
23 size_t triangleCount = 0;
24 size_t reducedCount = 0;
25 std::vector<Mesh *> original;
26 std::vector<MeshHandle> reduced;
27 std::vector<MaterialInstance *> materials;
28 void * rrHandle = nullptr;
29 bool textured = false;
30 bool hasNormals = false;
31 bool addNormals = true;
32 class MeshReductionManager * manager = nullptr;
33 };
34
35 void dummyprogress(float /*fraction*/, void* /*userdata*/)
36 {
37 }
38
39 /*
40 * Write progress info Logging system.
41 */
42 void progress(float fraction, void* /*userdata*/)
43 {
44 //auto state = static_cast<ReductionState *>(userdata);
45 LOG_INFO(logger, "Reduction Progress %d", (int)(fraction * 100));
46 }
47
48 //Add a single mesh to RR
49 void addMesh(ReductionState * state, Mesh * mesh, MaterialInstance * material, int index)
50 {
51 auto handle = state->rrHandle;
52
53 auto vertices = mesh->copyData<glm::vec3>(Cogs::ElementSemantic::Position, Cogs::DataFormat::X32Y32Z32_FLOAT);
54 auto texcoords = mesh->copyData<glm::vec2>(Cogs::ElementSemantic::TextureCoordinate, Cogs::DataFormat::X32Y32_FLOAT);
55 auto normals = mesh->copyData<glm::vec3>(Cogs::ElementSemantic::Normal, Cogs::DataFormat::X32Y32Z32_FLOAT);
56 state->hasNormals = state->hasNormals || normals.size();
57
58 //Add all vertices to RR
59 auto transverts = rr_add_vertices(handle, (int)vertices.size(), reinterpret_cast<const float *>(vertices.data()));
60
61 auto triangleData = static_cast<TriangleData*>(rr_malloc(handle, static_cast<unsigned int>(sizeof(TriangleData))));
62 triangleData->meshIndex = index;
63 triangleData->material = material;
64
65 glm::vec2 * tex = nullptr;
66 bool textured = state->textured && texcoords.size();
67 if (textured) {
68 tex = static_cast<glm::vec2*>(rr_malloc(handle, static_cast<unsigned int>(sizeof(glm::vec2) * 3 * state->triangleCount)));
69 }
70
71 //FIXME: Assumes indexed triangle set
72 int indices[3];
73 auto indexes = mesh->getIndexes();
74 for (size_t t = 0; t < indexes.size() / 3; t++) {
75 auto iA = indices[0] = indexes[t * 3];
76 auto iB = indices[1] = indexes[t * 3 + 1];
77 auto iC = indices[2] = indexes[t * 3 + 2];
78
79
80 if (textured) {
81 tex[t * 3] = texcoords[iA];
82 tex[t * 3 + 1] = texcoords[iB];
83 tex[t * 3 + 2] = texcoords[iC];
84 }
85
86 rr_add_indexed_polygon(handle, 3, indices, transverts, triangleData, textured ? reinterpret_cast<float *>(&tex[t * 3]) : NULL, RR_REDUCABLE);
87 }
88 }
89
90 /*
91 * Extraction callback.
92 */
93 rr_bool_t extractPrimitives(void * /*handle*/, void * userdata)
94 {
95 auto state = static_cast<ReductionState *>(userdata);
96
97 for (int i = 0, s = static_cast<int>(state->original.size()); i < s; i++) {
98 addMesh(state, state->original[i], state->materials[i], i);
99 }
100
101 /* Everything is OK */
102 return TRUE;
103 }
104
105 /*
106 * Stuffing callback.
107 */
108 rr_bool_t stuffPrimitives(void *handle, void *userdata)
109 {
110 auto state = static_cast<ReductionState *>(userdata);
111 const auto numTriangles = rr_get_num_triangles(handle);
112 //const auto numVertices = rr_get_num_vertices(handle);
113
114 // Group triangles by mesh
115 std::vector<std::vector<rr_triangle_t*>> groupedTriangles(state->original.size());
116 for (int i = 0; i < numTriangles; i++) {
117 auto rr_triangle = rr_get_triangle(handle, i);
118 auto * triangleData = static_cast<TriangleData*>(rr_triangle_get_data(rr_triangle));
119 groupedTriangles[triangleData->meshIndex].push_back(rr_triangle);
120 }
121
122 // Process triangles mesh by mesh.
123 state->reduced.resize(state->original.size());
124 for (size_t l = 0; l < groupedTriangles.size(); l++) {
125 auto & triangles = groupedTriangles[l];
126 if (triangles.empty()) continue;
127
128 auto bbox = Cogs::Geometry::makeEmptyBoundingBox<Cogs::Geometry::BoundingBox>();
129 std::vector<glm::vec3> P; P.reserve(triangles.size());
130 std::vector<glm::vec2> T; T.reserve(triangles.size());
131 for (auto & triangle : triangles) {
132 for (unsigned i = 0; i < 3; i++) {
133 auto * vertex = rr_triangle_get_vertex(triangle, i);
134 P.emplace_back(glm::make_vec3(rr_vertex_get_coord(vertex)));
135 bbox += P.back();
136 }
137 auto * tex = rr_triangle_get_texcoords(triangle);
138 if (tex) {
139 for (unsigned i = 0; i < 3; i++) {
140 T.emplace_back(glm::make_vec2(tex + 2 * i));
141 }
142 }
143 }
144 if (P.size() != T.size() && !T.empty()) {
145 LOG_WARNING(logger, "Mesh with texture coordinates on only some of the triangles.");
146 T.clear();
147 }
148
149 std::vector<uint32_t> unique;
150 std::vector<uint32_t> map;
151
152
153 if constexpr (true || T.empty()) {
154 GeometryProcessing::uniqueVertexSubset(state->context, unique, map,
155 (const float*)P.data(), 3 * sizeof(float),
156 nullptr, 0,
157 nullptr, 0,
158 (uint32_t)P.size());
159 std::vector<glm::vec3> P_(unique.size());
160 for (size_t i = 0; i < unique.size(); i++) {
161 P_[i] = P[unique[i]];
162 }
163 P.swap(P_);
164 }
165 else {
166 assert(P.size() == T.size());
167 GeometryProcessing::uniqueVertexSubset(state->context, unique, map,
168 (const float*)P.data(), 3 * sizeof(float),
169 nullptr, 0,
170 (const float*)T.data(), 2 * sizeof(float),
171 (uint32_t)P.size());
172 std::vector<glm::vec3> P_(unique.size());
173 std::vector<glm::vec2> T_(unique.size());
174 for (size_t i = 0; i < unique.size(); i++) {
175 P_[i] = P[unique[i]];
176 T_[i] = T[unique[i]];
177 }
178 P.swap(P_);
179 T.swap(T_);
180 }
181
182 auto proxy = state->context->meshManager->createLocked();
183
184 std::vector<glm::vec3> N;
185 if (state->addNormals) {
186#if 1
187 T.clear();
188 std::vector<uint32_t> remap;
189 std::vector<uint32_t> newIndices;
190 GeometryProcessing::normalsFromIndexedTriangles(state->context,
191 N, remap, newIndices,
192 reinterpret_cast<const float*>(P.data()), 3 * sizeof(float), static_cast<uint32_t>(P.size()),
193 map.data(), static_cast<uint32_t>(map.size()));
194
195 std::vector<glm::vec3> P_(remap.size());
196 for (size_t i = 0; i <P_.size(); i++) {
197 P_[i] = P[remap[i]];
198 }
199 P.swap(P_);
200
201 map.swap(newIndices);
202
203#else
204 N.resize(P.size());
205 Cogs::Core::normalsFromIndexedTriangles(state->context,
206 reinterpret_cast<float*>(N.data()), 3,
207 reinterpret_cast<const float*>(P.data()), 3, P.size(),
208 map.data(), map.size());
209
210 for (auto & n : N) {
211 n = -n;
212 }
213#endif
214 }
215 if (state->original[l]->isMeshFlagSet(MeshFlags::ClockwiseWinding)) {
216 proxy->setMeshFlag(MeshFlags::ClockwiseWinding);
217 }
218 else {
219 proxy->unsetMeshFlag(MeshFlags::ClockwiseWinding);
220 }
221
222 proxy->setPositions(P);
223 if (!T.empty()) {
224 proxy->setTexCoords(T);
225 }
226 if (!N.empty()) {
227 proxy->setNormals(N);
228 }
229
230 proxy->setBounds(bbox);
231 proxy->setIndexData(std::move(map));
232 proxy->primitiveType = Cogs::PrimitiveType::TriangleList;
233 state->reduced[l] = proxy.getHandle();
234 }
235
236 return TRUE;
237 }
238
239 float sameTexture(void * triangle1data, void * triangle2data, void * /*userdata*/)
240 {
241 auto tri1 = static_cast<TriangleData *>(triangle1data);
242 auto tri2 = static_cast<TriangleData *>(triangle2data);
243 return tri1->material == tri2->material ? 0.0f : 1.0f; //FIXME: for now, assume different material pointer means different texture
244 }
245
246 float sameMaterial(void* triangle1data, void* triangle2data, void* /*userdata*/)
247 {
248 auto tri1 = static_cast<TriangleData*>(triangle1data);
249 auto tri2 = static_cast<TriangleData*>(triangle2data);
250 return tri1->material == tri2->material ? 0.0f : 1.0f; //FIXME: for now, assume different material pointer means different material
251 }
252
253 bool anyTextured(std::vector<Mesh *> meshes)
254 {
255 for (auto & mesh : meshes) {
256 auto[_, num, __] = mesh->getSemanticStream(Cogs::ElementSemantic::TextureCoordinate, Cogs::DataFormat::X32Y32_FLOAT);
257 bool textured = num != 0;
258 if (textured) return true;
259 }
260 return false;
261 }
262
263}
264
265
266
267
268
269void MeshReductionManager::cleanup()
270{
271
272}
273
274
275std::vector<MeshHandle> MeshReductionManager::reduce(std::vector<Mesh *> meshes, std::vector<MaterialInstance *> materials, float percent, float epsilon)
276{
277 /* Let RR know how many triangles we've got. */
278 size_t numTriangles = 0;
279 for(auto & mesh : meshes) numTriangles += mesh->getIndexes().size() / 3; //FIXME: Assumes indexed triangle set
280
281 std::vector<MeshHandle> reduced(meshes.size());
282 for (auto & red : reduced) red = context->meshManager->create();
283
284 ReductionState state;
285 state.context = context;
286 state.textured = anyTextured(meshes);
287 state.addNormals = addNormals;
288 state.rrHandle = rr_init(state.textured);
289 state.original = meshes;
290 state.materials = materials;
291 state.manager = this;
292 //state.reduced.resize(meshes.size());
293 //for (auto & r : state.reduced) r = context->meshManager->create();
294 for (auto & m : state.original) state.triangleCount += m->getIndexes().size() / 3;
295
296 //ReductionState state(meshes, reduced, materials, this, numTriangles, anyTextured(meshes));
297
298 auto & rrHandle = state.rrHandle;
299
300 //Register our functions
301 rr_set_extract_primitives(rrHandle, extractPrimitives, &state);
302 rr_set_stuff_primitives(rrHandle, stuffPrimitives, &state);
303 if (loglevel > 1) {
304 rr_set_simple_progress(rrHandle, progress, &state);
305 }
306 else {
307 rr_set_simple_progress(rrHandle, dummyprogress, &state);
308 }
309
310 rr_set_same_texture(rrHandle, sameTexture, &state);
311 rr_set_same_material(rrHandle, sameTexture, &state);
312 rr_set_same_surfaceappearance(rrHandle, sameTexture, &state);
313
314 //Set options
315 rr_set_num_native_triangles(rrHandle, (int)numTriangles);
316 rr_set_epsilon(rrHandle, epsilon);
317 rr_set_percentage(rrHandle, percent);
318
319 /* Reduce! */
320 auto ret = rr_reduce(rrHandle);
321 rr_end(state.rrHandle);
322
323 if (ret != RR_OK) {
324 LOG_ERROR(logger, "Reduction error. #Triangles: %d", (int)numTriangles);
325 return std::vector<MeshHandle>();
326 }
327 else if (loglevel > 0) {
328 LOG_INFO(logger, "Reduction Complete");
329 }
330
331 return state.reduced;
332}
333
334MeshHandle Cogs::RationalReducerExtension::MeshReductionManager::reduce(Mesh * mesh, float percent, float epsilon)
335{
336 auto meshes = std::vector<Mesh *>();
337 meshes.push_back(mesh);
338
339 auto materials = std::vector<MaterialInstance *>();
340 materials.push_back(NULL);
341
342 auto reduced = reduce(meshes, materials, percent, epsilon);
343 return reduced[0];
344}
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
Log implementation class.
Definition: LogManager.h:139
Interface to Rational Reducer for reducing meshes.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
@ Position
Position semantic.
@ Normal
Normal semantic.
@ TextureCoordinate
Texture coordinate semantic.
Material instances represent a specialized Material combined with state for all its buffers and prope...
Material * material
Material resource this MaterialInstance is created from.
@ ClockwiseWinding
The mesh uses clockwise winding order for it's triangles as opposed to the counter-clockwise default.
Definition: Mesh.h:63
Meshes contain streams of vertex data in addition to index data and options defining geometry used fo...
Definition: Mesh.h:265
Cogs::Memory::TypedBuffer< Datatype > copyData(Cogs::ElementSemantic semantic, DataFormat format)
Return a vector with all elements of the given semantic data as a continous buffer.
Definition: Mesh.h:1045
StreamReference getSemanticStream(ElementSemantic semantic, DataFormat format)
Get the data of the stream containing data with the given semantic, format and minimum element size.
Definition: Mesh.cpp:144
@ TriangleList
List of triangles.
Definition: Common.h:116