1#include "MeshReductionManager.h"
4#include "Resources/MeshManager.h"
6#include "../Extensions/GeometryProcessing/GeometryProcessing.h"
8#include "Foundation/Geometry/NormalGenerator.hpp"
9#include "Foundation/Logging/Logger.h"
11#include <rrapi/rrapi.h>
13using namespace Cogs::RationalReducerExtension;
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;
35 void dummyprogress(
float ,
void* )
42 void progress(
float fraction,
void* )
45 LOG_INFO(logger,
"Reduction Progress %d", (
int)(fraction * 100));
51 auto handle = state->rrHandle;
56 state->hasNormals = state->hasNormals || normals.size();
59 auto transverts = rr_add_vertices(handle, (
int)vertices.size(),
reinterpret_cast<const float *
>(vertices.data()));
62 triangleData->meshIndex = index;
63 triangleData->material = material;
65 glm::vec2 * tex =
nullptr;
66 bool textured = state->textured && texcoords.size();
68 tex =
static_cast<glm::vec2*
>(rr_malloc(handle,
static_cast<unsigned int>(
sizeof(glm::vec2) * 3 * state->triangleCount)));
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];
81 tex[t * 3] = texcoords[iA];
82 tex[t * 3 + 1] = texcoords[iB];
83 tex[t * 3 + 2] = texcoords[iC];
86 rr_add_indexed_polygon(handle, 3, indices, transverts, triangleData, textured ?
reinterpret_cast<float *
>(&tex[t * 3]) : NULL, RR_REDUCABLE);
93 rr_bool_t extractPrimitives(
void * ,
void * userdata)
95 auto state =
static_cast<ReductionState *
>(userdata);
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);
108 rr_bool_t stuffPrimitives(
void *handle,
void *userdata)
110 auto state =
static_cast<ReductionState *
>(userdata);
111 const auto numTriangles = rr_get_num_triangles(handle);
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);
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;
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)));
137 auto * tex = rr_triangle_get_texcoords(triangle);
139 for (
unsigned i = 0; i < 3; i++) {
140 T.emplace_back(glm::make_vec2(tex + 2 * i));
144 if (P.size() != T.size() && !T.empty()) {
145 LOG_WARNING(logger,
"Mesh with texture coordinates on only some of the triangles.");
149 std::vector<uint32_t> unique;
150 std::vector<uint32_t> map;
153 if constexpr (
true || T.empty()) {
154 GeometryProcessing::uniqueVertexSubset(state->context, unique, map,
155 (
const float*)P.data(), 3 *
sizeof(
float),
159 std::vector<glm::vec3> P_(unique.size());
160 for (
size_t i = 0; i < unique.size(); i++) {
161 P_[i] = P[unique[i]];
166 assert(P.size() == T.size());
167 GeometryProcessing::uniqueVertexSubset(state->context, unique, map,
168 (
const float*)P.data(), 3 *
sizeof(
float),
170 (
const float*)T.data(), 2 *
sizeof(
float),
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]];
182 auto proxy = state->context->meshManager->createLocked();
184 std::vector<glm::vec3> N;
185 if (state->addNormals) {
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()));
195 std::vector<glm::vec3> P_(remap.size());
196 for (
size_t i = 0; i <P_.size(); i++) {
201 map.swap(newIndices);
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());
222 proxy->setPositions(P);
224 proxy->setTexCoords(T);
227 proxy->setNormals(N);
230 proxy->setBounds(bbox);
231 proxy->setIndexData(std::move(map));
233 state->reduced[l] = proxy.getHandle();
239 float sameTexture(
void * triangle1data,
void * triangle2data,
void * )
243 return tri1->material == tri2->
material ? 0.0f : 1.0f;
246 float sameMaterial(
void* triangle1data,
void* triangle2data,
void* )
250 return tri1->material == tri2->
material ? 0.0f : 1.0f;
253 bool anyTextured(std::vector<Mesh *> meshes)
255 for (
auto & mesh : meshes) {
257 bool textured = num != 0;
258 if (textured)
return true;
269void MeshReductionManager::cleanup()
275std::vector<MeshHandle> MeshReductionManager::reduce(std::vector<Mesh *> meshes, std::vector<MaterialInstance *> materials,
float percent,
float epsilon)
278 size_t numTriangles = 0;
279 for(
auto & mesh : meshes) numTriangles += mesh->getIndexes().size() / 3;
281 std::vector<MeshHandle> reduced(meshes.size());
282 for (
auto & red : reduced) red = context->meshManager->create();
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;
294 for (
auto & m : state.original) state.triangleCount += m->getIndexes().size() / 3;
298 auto & rrHandle = state.rrHandle;
301 rr_set_extract_primitives(rrHandle, extractPrimitives, &state);
302 rr_set_stuff_primitives(rrHandle, stuffPrimitives, &state);
304 rr_set_simple_progress(rrHandle, progress, &state);
307 rr_set_simple_progress(rrHandle, dummyprogress, &state);
310 rr_set_same_texture(rrHandle, sameTexture, &state);
311 rr_set_same_material(rrHandle, sameTexture, &state);
312 rr_set_same_surfaceappearance(rrHandle, sameTexture, &state);
315 rr_set_num_native_triangles(rrHandle, (
int)numTriangles);
316 rr_set_epsilon(rrHandle, epsilon);
317 rr_set_percentage(rrHandle, percent);
320 auto ret = rr_reduce(rrHandle);
321 rr_end(state.rrHandle);
324 LOG_ERROR(logger,
"Reduction error. #Triangles: %d", (
int)numTriangles);
325 return std::vector<MeshHandle>();
327 else if (loglevel > 0) {
328 LOG_INFO(logger,
"Reduction Complete");
331 return state.reduced;
334MeshHandle Cogs::RationalReducerExtension::MeshReductionManager::reduce(
Mesh * mesh,
float percent,
float epsilon)
336 auto meshes = std::vector<Mesh *>();
337 meshes.push_back(mesh);
339 auto materials = std::vector<MaterialInstance *>();
340 materials.push_back(NULL);
342 auto reduced = reduce(meshes, materials, percent, epsilon);
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Log implementation class.
Interface to Rational Reducer for reducing meshes.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
@ Position
Position 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.
Meshes contain streams of vertex data in addition to index data and options defining geometry used fo...
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.
StreamReference getSemanticStream(ElementSemantic semantic, DataFormat format)
Get the data of the stream containing data with the given semantic, format and minimum element size.
@ TriangleList
List of triangles.