Blender V4.3
quadriflow_capi.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2019 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <unordered_map>
6
7#include "MEM_guardedalloc.h"
8
9#include "config.hpp"
10#include "field-math.hpp"
11#include "loader.hpp"
12#include "optimizer.hpp"
13#include "parametrizer.hpp"
14#include "quadriflow_capi.hpp"
15
16using namespace qflow;
17
18struct ObjVertex {
22
24
26 {
27 p = pi;
28 }
29
30 bool operator==(const ObjVertex &v) const
31 {
32 return v.p == p && v.n == n && v.uv == uv;
33 }
34};
35
37 std::size_t operator()(const ObjVertex &v) const
38 {
39 size_t hash = std::hash<uint32_t>()(v.p);
40 hash = hash * 37 + std::hash<uint32_t>()(v.uv);
41 hash = hash * 37 + std::hash<uint32_t>()(v.n);
42 return hash;
43 }
44};
45
46typedef std::unordered_map<ObjVertex, uint32_t, ObjVertexHash> VertexMap;
47
48static int check_if_canceled(float progress,
49 void (*update_cb)(void *, float progress, int *cancel),
50 void *update_cb_data)
51{
52 int cancel = 0;
53 update_cb(update_cb_data, progress, &cancel);
54 return cancel;
55}
56
58 void (*update_cb)(void *, float progress, int *cancel),
59 void *update_cb_data)
60{
61 Parametrizer field;
62 VertexMap vertexMap;
63
64 /* Get remeshing parameters. */
65 int faces = qrd->target_faces;
66
67 if (qrd->preserve_sharp) {
68 field.flag_preserve_sharp = 1;
69 }
70 if (qrd->preserve_boundary) {
71 field.flag_preserve_boundary = 1;
72 }
73 if (qrd->adaptive_scale) {
74 field.flag_adaptive_scale = 1;
75 }
76 if (qrd->minimum_cost_flow) {
77 field.flag_minimum_cost_flow = 1;
78 }
79 if (qrd->aggresive_sat) {
80 field.flag_aggresive_sat = 1;
81 }
82 if (qrd->rng_seed) {
83 field.hierarchy.rng_seed = qrd->rng_seed;
84 }
85
86 if (check_if_canceled(0.0f, update_cb, update_cb_data) != 0) {
87 return;
88 }
89
90 /* Copy mesh to quadriflow data structures. */
91 std::vector<Vector3d> positions;
92 std::vector<uint32_t> indices;
93 std::vector<ObjVertex> vertices;
94
95 for (int i = 0; i < qrd->totverts; i++) {
96 Vector3d v(qrd->verts[i * 3], qrd->verts[i * 3 + 1], qrd->verts[i * 3 + 2]);
97 positions.push_back(v);
98 }
99
100 for (int q = 0; q < qrd->totfaces; q++) {
101 Vector3i f(qrd->faces[q * 3], qrd->faces[q * 3 + 1], qrd->faces[q * 3 + 2]);
102
103 ObjVertex tri[6];
104 int nVertices = 3;
105
106 tri[0] = ObjVertex(f[0]);
107 tri[1] = ObjVertex(f[1]);
108 tri[2] = ObjVertex(f[2]);
109
110 for (int i = 0; i < nVertices; ++i) {
111 const ObjVertex &v = tri[i];
112 VertexMap::const_iterator it = vertexMap.find(v);
113 if (it == vertexMap.end()) {
114 vertexMap[v] = (uint32_t)vertices.size();
115 indices.push_back((uint32_t)vertices.size());
116 vertices.push_back(v);
117 }
118 else {
119 indices.push_back(it->second);
120 }
121 }
122 }
123
124 field.F.resize(3, indices.size() / 3);
125 memcpy(field.F.data(), indices.data(), sizeof(uint32_t) * indices.size());
126
127 field.V.resize(3, vertices.size());
128 for (uint32_t i = 0; i < vertices.size(); ++i) {
129 field.V.col(i) = positions.at(vertices[i].p);
130 }
131
132 if (check_if_canceled(0.1f, update_cb, update_cb_data)) {
133 return;
134 }
135
136 /* Start processing the input mesh data */
137 field.NormalizeMesh();
138 field.Initialize(faces);
139
140 if (check_if_canceled(0.2f, update_cb, update_cb_data)) {
141 return;
142 }
143
144 /* Setup mesh boundary constraints if needed */
145 if (field.flag_preserve_boundary) {
146 Hierarchy &mRes = field.hierarchy;
147 mRes.clearConstraints();
148 for (uint32_t i = 0; i < 3 * mRes.mF.cols(); ++i) {
149 if (mRes.mE2E[i] == -1) {
150 uint32_t i0 = mRes.mF(i % 3, i / 3);
151 uint32_t i1 = mRes.mF((i + 1) % 3, i / 3);
152 Vector3d p0 = mRes.mV[0].col(i0), p1 = mRes.mV[0].col(i1);
153 Vector3d edge = p1 - p0;
154 if (edge.squaredNorm() > 0) {
155 edge.normalize();
156 mRes.mCO[0].col(i0) = p0;
157 mRes.mCO[0].col(i1) = p1;
158 mRes.mCQ[0].col(i0) = mRes.mCQ[0].col(i1) = edge;
159 mRes.mCQw[0][i0] = mRes.mCQw[0][i1] = mRes.mCOw[0][i0] = mRes.mCOw[0][i1] = 1.0;
160 }
161 }
162 }
163 mRes.propagateConstraints();
164 }
165
166 /* Optimize the mesh field orientations (tangental field etc) */
167 Optimizer::optimize_orientations(field.hierarchy);
168 field.ComputeOrientationSingularities();
169
170 if (check_if_canceled(0.3f, update_cb, update_cb_data)) {
171 return;
172 }
173
174 if (field.flag_adaptive_scale == 1) {
175 field.EstimateSlope();
176 }
177
178 if (check_if_canceled(0.4f, update_cb, update_cb_data)) {
179 return;
180 }
181
182 Optimizer::optimize_scale(field.hierarchy, field.rho, field.flag_adaptive_scale);
183 field.flag_adaptive_scale = 1;
184
185 Optimizer::optimize_positions(field.hierarchy, field.flag_adaptive_scale);
186
187 field.ComputePositionSingularities();
188
189 if (check_if_canceled(0.5f, update_cb, update_cb_data)) {
190 return;
191 }
192
193 /* Compute the final quad geomtry using a maxflow solver */
194 field.ComputeIndexMap();
195
196 if (check_if_canceled(0.9f, update_cb, update_cb_data)) {
197 return;
198 }
199
200 /* Get the output mesh data */
201 qrd->out_totverts = field.O_compact.size();
202 qrd->out_totfaces = field.F_compact.size();
203
204 qrd->out_verts = (float *)MEM_malloc_arrayN(qrd->out_totverts, sizeof(float[3]), __func__);
205 qrd->out_faces = (int *)MEM_malloc_arrayN(qrd->out_totfaces, sizeof(int[4]), __func__);
206
207 for (int i = 0; i < qrd->out_totverts; i++) {
208 auto t = field.O_compact[i] * field.normalize_scale + field.normalize_offset;
209 qrd->out_verts[i * 3] = t[0];
210 qrd->out_verts[i * 3 + 1] = t[1];
211 qrd->out_verts[i * 3 + 2] = t[2];
212 }
213
214 for (int i = 0; i < qrd->out_totfaces; i++) {
215 qrd->out_faces[i * 4] = field.F_compact[i][0];
216 qrd->out_faces[i * 4 + 1] = field.F_compact[i][1];
217 qrd->out_faces[i * 4 + 2] = field.F_compact[i][2];
218 qrd->out_faces[i * 4 + 3] = field.F_compact[i][3];
219 }
220}
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert * v
static ushort indices[]
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
#define hash
Definition noise.c:154
void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd, void(*update_cb)(void *, float progress, int *cancel), void *update_cb_data)
static int check_if_canceled(float progress, void(*update_cb)(void *, float progress, int *cancel), void *update_cb_data)
std::unordered_map< ObjVertex, uint32_t, ObjVertexHash > VertexMap
unsigned int uint32_t
Definition stdint.h:80
std::size_t operator()(const ObjVertex &v) const
bool operator==(const ObjVertex &v) const
ObjVertex(uint32_t pi)