Cogs.Core
LoftedCrossSectionsSystemHollow.cpp
1#include <glm/gtc/type_ptr.hpp>
2#include "LoftedCrossSectionsSystem.h"
3#define COGS_TABLE_HOLLOW
4#include "LoftedCrossSectionsSystem_tables.h"
5
6
7using std::vector;
8using glm::vec2;
9using glm::vec3;
10using glm::make_vec2;
11using glm::make_vec3;
12using glm::dot;
13using glm::mix;
14using glm::normalize;
15
16using std::abs;
17
18
19void Cogs::Core::LoftedCrossSectionsSystem::hollowInitialize()
20{
21 hollowCellClassCounts.resize(4 * 256);
22
23 for (int caps = 0; caps < 4; caps++) {
24 for (int code = 0; code < 256; code++) {
25 CellClassCounts counts = { 0, 0, 0, 0 };
26
27 // the rest of cases, determine which table entry to use
28 int N = triangle_table_hollow[256 * caps + code].n;
29 unsigned char* indices = triangle_table_hollow[256 * caps + code].indices;
30
31 // plow through indices.
32 for (int k = 0; k < N; k++) {
33 int ix = indices[k];
34 int a = ix & 0x7;
35 int b = (ix >> 3) & 0x7;
36 switch ((ix >> 6) & 0x3) {
37 case 0: // --- Outer/inner wall ------------------------------------
38 if (a != b) { // corner index
39 counts.newVertices++;
40 }
41 counts.outIndices++;
42 break;
43 case 1: //--- Cap at first cross section ---------------------------
44 if (a != b) {
45 counts.newVertices++;
46 }
47 counts.outIndices++;
48 break;
49 case 2: //--- Cap at last cross section ----------------------------
50 if (a != b) {
51 counts.newVertices++;
52 }
53 counts.outIndices++;
54 break;
55 case 3: // --- Inner face edge index -------------------------------
56 counts.newVertices++;
57 counts.cutIndices++;
58 break;
59 }
60 }
61 hollowCellClassCounts[256 * caps + code] = counts;
62 }
63 }
64
65}
66
67
68void Cogs::Core::LoftedCrossSectionsSystem::hollowOpenAlignedClassifySamples(vector<uint8_t>& inside,
69 const float* pos,
70 const size_t pos_stride,
71 const vector<vec3>& spine,
72 const vec3& viewer,
73 const int slices,
74 const int samples)
75{
76 inside.resize(2 * slices*samples);
77 for (int j = 0; j < slices; j++) {
78 for (int i = 0; i < samples; i++) {
79
80 const vec3 p0 = make_vec3(pos + pos_stride*(2 * (j*samples + i) + 0));
81 inside[2 * (j*samples + i) + 0] = dot(viewer - p0, p0 - spine[j]) <= 0.f;
82
83 const vec3 p1 = make_vec3(pos + pos_stride*(2 * (j*samples + i) + 1));
84 inside[2 * (j*samples + i) + 1] = dot(viewer - p1, p1 - spine[j]) <= 0.f;
85
86 }
87 }
88}
89
90
91void Cogs::Core::LoftedCrossSectionsSystem::hollowOpenAlignedCountCellResources(size_t& newVertices, size_t& outIndices, size_t& cutIndices,
92 vector<uint8_t>& classification,
93 const vector<vec3>& /*spine*/,
94 const vector<uint8_t>& inside,
95 const vec3& /*viewer*/,
96 const int slices, const int samples, const bool doubleSeam)
97{
98 classification.resize(slices*samples);
99 newVertices = 0;
100 outIndices = 0;
101 cutIndices = 0;
102
103 // --- March through slices ------------------------------------------------
104 for (int j = 1; j < slices - 2; j++) {
105
106 // check if we need to employ tables that include end capping.
107 int which_caps = ((j == 1) ? 1 : 0) | ((j == (slices - 3)) ? 2 : 0);
108
109 // --- March along cross section -----------------------------------------
110 for (int i = 0; i < samples - (doubleSeam ? 1 : 0); i++) {
111
112 // closed cross section, wrap-around
113 int ii = (i + 1) % samples;
114
115 // vertex indices of the eight corners of the current cell
116 int crn_vtx_ix[8] = {
117 2 * ((j + 0)*samples + i) + 0, 2 * ((j + 0)*samples + i) + 1,
118 2 * ((j + 0)*samples + ii) + 0, 2 * ((j + 0)*samples + ii) + 1,
119 2 * ((j + 1)*samples + i) + 0, 2 * ((j + 1)*samples + i) + 1,
120 2 * ((j + 1)*samples + ii) + 0, 2 * ((j + 1)*samples + ii) + 1
121 };
122
123 // determine marching cubes-class
124 uint8_t code = (inside[crn_vtx_ix[0]] ? 1 : 0) | (inside[crn_vtx_ix[1]] ? 2 : 0) |
125 (inside[crn_vtx_ix[2]] ? 4 : 0) | (inside[crn_vtx_ix[3]] ? 8 : 0) |
126 (inside[crn_vtx_ix[4]] ? 16 : 0) | (inside[crn_vtx_ix[5]] ? 32 : 0) |
127 (inside[crn_vtx_ix[6]] ? 64 : 0) | (inside[crn_vtx_ix[7]] ? 128 : 0);
128
129 classification[j*samples + i] = code;
130
131 const CellClassCounts& counts = hollowCellClassCounts[256 * which_caps + code];
132 newVertices += counts.newVertices;
133 outIndices += counts.outIndices;
134 cutIndices += counts.cutIndices;
135 }
136 }
137}
138
139void Cogs::Core::LoftedCrossSectionsSystem::hollowOpenAlignedSkin(vector<unsigned int>& outSurface,
140 vector<unsigned int>& cutSurface,
141 float* pos, const size_t pos_stride,
142 float* tex, const size_t tex_stride,
143 float* nrm, const size_t nrm_stride,
144 const vector<uint8_t>& classification,
145 const vector<vec3>& spine,
146 const vec3& viewer,
147 const int slices, const int samples, const bool doubleSeam)
148{
149 unsigned int newVertex = 2 * samples * slices;
150 unsigned int outIndex = 0;
151 unsigned int cutIndex = 0;
152
153 // --- March through slices ------------------------------------------------
154 for (int j = 1; j < slices - 2; j++) {
155
156 // check if we need to employ tables that include end capping.
157 int which_caps = ((j == 1) ? 1 : 0) | ((j == (slices - 3)) ? 2 : 0);
158
159 // --- March along cross section -----------------------------------------
160 for (int i = 0; i < samples - (doubleSeam ? 1 : 0); i++) {
161
162 // closed cross section, wrap-around
163 int ii = (i + 1) % samples;
164
165 // vertex indices of the eight corners of the current cell
166 int crn_vtx_ix[8] = {
167 2 * ((j + 0)*samples + i) + 0, 2 * ((j + 0)*samples + i) + 1,
168 2 * ((j + 0)*samples + ii) + 0, 2 * ((j + 0)*samples + ii) + 1,
169 2 * ((j + 1)*samples + i) + 0, 2 * ((j + 1)*samples + i) + 1,
170 2 * ((j + 1)*samples + ii) + 0, 2 * ((j + 1)*samples + ii) + 1
171 };
172
173 // determine marching cubes-class
174 int code = classification[j*samples + i];
175 int N = triangle_table_hollow[256 * which_caps + code].n;
176 unsigned char* indices = triangle_table_hollow[256 * which_caps + code].indices;
177
178 // plow through indices.
179 for (int k = 0; k < N; k++) {
180 int ix = indices[k];
181 int a = crn_vtx_ix[ix & 0x7];
182 int a_j = j + ((ix & 0x4) == 0 ? 0 : 1);
183 int b = crn_vtx_ix[(ix >> 3) & 0x7];
184 int b_j = j + (((ix >> 3) & 0x4) == 0 ? 0 : 1);
185
186 bool onEdge = false;
187 bool onCut = false;
188 switch ((ix >> 6) & 0x3) {
189 case 0: // --- Outer/inner wall ------------------------------------
190 if (a == b) { // corner index
191 outSurface[outIndex++] = a;
192 }
193 else { // edge index
194 outSurface[outIndex++] = newVertex;
195 onEdge = true;
196 }
197 break;
198 case 1: //--- Cap at first cross section ---------------------------
199 if (a == b) {
200 outSurface[outIndex++] = a - 2 * samples;
201 }
202 else {
203 a = a - 2 * samples; // move to ring 0 with end-facing normals
204 b = b - 2 * samples;
205 outSurface[outIndex++] = newVertex;
206 onEdge = true;
207 }
208 break;
209 case 2: //--- Cap at last cross section ----------------------------
210 if (a == b) {
211 outSurface[outIndex++] = a + 2 * samples;
212 }
213 else {
214 a = a + 2 * samples; // move to last ring with end-facing normals
215 b = b + 2 * samples;
216 outSurface[outIndex++] = newVertex;
217 onEdge = true;
218 }
219 break;
220 case 3: // --- Inner face edge index -------------------------------
221 cutSurface[cutIndex++] = newVertex;
222 onEdge = true;
223 onCut = true;
224 break;
225 }
226
227 // --- Create new vertex if required --------------------------------
228 if (onEdge) {
229 const vec3 ap = make_vec3(pos + pos_stride*a);
230 const vec3 bp = make_vec3(pos + pos_stride*b);
231
232 vec3 va = normalize(viewer - ap);
233 vec3 vb = normalize(viewer - bp);
234 vec3 na = normalize(ap - spine[a_j]);
235 vec3 nb = normalize(bp - spine[b_j]);
236#if 0
237 float fa = std::acos(glm::dot(va, na)) - float(M_PI_2);
238 float fb = std::acos(glm::dot(vb, nb)) - float(M_PI_2);
239#else
240 float fa = dot(va, na);
241 float fb = dot(vb, nb);
242#endif
243 const float t = fa*fb < 0.f ? fa / (fa - fb) : (abs(fa) < abs(fb) ? 0.f : 1.f);
244
245 const vec3 p = mix(ap, bp, t);
246 *reinterpret_cast<vec3*>(pos + pos_stride*newVertex) = p;
247
248 if (tex_stride) {
249 const vec2 at = make_vec2(tex + tex_stride*a);
250 const vec2 bt = make_vec2(tex + tex_stride*b);
251 *reinterpret_cast<vec2*>(tex + tex_stride*newVertex) = mix(at, bt, t);
252 }
253 if (nrm_stride) {
254 if (onCut) {
255 *reinterpret_cast<vec3*>(nrm + nrm_stride*newVertex) = normalize(viewer - p);
256 }
257 else {
258 const vec3 an = make_vec3(nrm + nrm_stride*a);
259 const vec3 bn = make_vec3(nrm + nrm_stride*b);
260 *reinterpret_cast<vec3*>(nrm + nrm_stride*newVertex) = mix(an, bn, t);
261 }
262 }
263
264 newVertex++;
265 }
266 }
267 }
268 }
269}
270
271void Cogs::Core::LoftedCrossSectionsSystem::hollowOpenCountCellResources(size_t& newVertices, size_t& outIndices, size_t& cutIndices,
272 const int slices, const int samples, const bool doubleSeam)
273{
274 const int cN = (samples - (doubleSeam ? 1 : 0)) / 2;
275 newVertices = 8 * (slices - 3);
276 outIndices = cN * 12 * (slices - 3) + cN * 6 + cN * 6;
277 cutIndices = 12 * (slices - 3);
278}
279
280void Cogs::Core::LoftedCrossSectionsSystem::hollowOpenSkin(vector<unsigned int>& outSurface,
281 vector<unsigned int>& cutSurface,
282 float* pos, const size_t pos_stride,
283 float* tex, const size_t tex_stride,
284 float* nrm, const size_t nrm_stride,
285 const int slices, const int samples, const bool doubleSeam)
286{
287 const int cN = (samples - (doubleSeam ? 1 : 0)) / 2;
288 const int cuts[4 * 3] = {
289 2 * 0 + 0, 2 * 2 + 0, 2 * 1 + 0,
290 2 * 1 + 0, 2 * 2 + 0, 2 * 3 + 0,
291 2 * 0 + 1, 2 * 1 + 1, 2 * 2 + 1,
292 2 * 1 + 1, 2 * 3 + 1, 2 * 2 + 1
293 };
294 const int end0[2 * 3] = {
295 2 * 0 + 0, 2 * 0 + 1, 2 * 1 + 0,
296 2 * 0 + 1, 2 * 1 + 1, 2 * 1 + 0
297 };
298 const int end1[2 * 3] = {
299 2 * ((slices - 1)*samples + 0) + 0, 2 * ((slices - 1)*samples + 1) + 0, 2 * ((slices - 1)*samples + 0) + 1,
300 2 * ((slices - 1)*samples + 0) + 1, 2 * ((slices - 1)*samples + 1) + 0, 2 * ((slices - 1)*samples + 1) + 1
301 };
302 const int wall[12] = {
303 2 * (0 * samples + 0) + 0, 2 * (0 * samples + 1) + 0, 2 * (1 * samples + 0) + 0, // Outer skin triangle 1
304 2 * (1 * samples + 1) + 0, 2 * (1 * samples + 0) + 0, 2 * (0 * samples + 1) + 0, // Outer skin triangle 2
305 2 * (0 * samples + 0) + 1, 2 * (1 * samples + 0) + 1, 2 * (0 * samples + 1) + 1, // Inner skin triangle 1
306 2 * (1 * samples + 1) + 1, 2 * (0 * samples + 1) + 1, 2 * (1 * samples + 0) + 1, // Inner skin triangle 2
307 };
308 int cutVtxIx[3 * 2] = {
309 2 * 0, 2 * (samples - (doubleSeam ? 2 : 1)), 2 * 1, // cut geometry at beginning of half-ring
310 2 * cN, 2 * (cN + 1), 2 * (cN - 1) // cut geometry at end of half-ring
311 };
312
313 unsigned int newVertex = 2 * samples * slices;
314 unsigned int outIndex = 0;
315 unsigned int cutIndex = 0;
316 for (int k = 1; k < slices - 2; k++) {
317 for (int i = 0; i < cN; i++) {
318 for (int q = 0; q < 12; q++) {
319 outSurface[outIndex++] = wall[q] + 2 * (i + k*samples);
320 }
321 }
322 int base = newVertex;
323 for (int j = 0; j < 2; j++) {
324 for (int i = 0; i < 2; i++) {
325 for (int q = 0; q < 2; q++) {
326 int a = cutVtxIx[3 * q + 0] + i + 2 * samples*(k + j);
327 int b = cutVtxIx[3 * q + 1] + i + 2 * samples*(k + j);
328 int c = cutVtxIx[3 * q + 2] + i + 2 * samples*(k + j);
329
330 *reinterpret_cast<vec3*>(pos + pos_stride*newVertex) = *reinterpret_cast<vec3*>(pos + pos_stride*a);
331 if (tex_stride) {
332 *reinterpret_cast<vec2*>(tex + tex_stride*newVertex) = *reinterpret_cast<vec2*>(tex + tex_stride*a);
333 }
334 if (nrm_stride) {
335 *reinterpret_cast<vec3*>(nrm + nrm_stride*newVertex) = normalize(*reinterpret_cast<vec3*>(pos + pos_stride*b) - *reinterpret_cast<vec3*>(pos + pos_stride*c));
336 }
337 newVertex++;
338 }
339 }
340 }
341 for (int q = 0; q < 4 * 3; q++) {
342 cutSurface[cutIndex++] = cuts[q] + base;
343 }
344 }
345
346 for (int i = 0; i < cN; i++) {
347 for (int q = 0; q < 2 * 3; q++) {
348 outSurface[outIndex++] = end0[q] + 2 * i;
349 }
350 }
351 for (int i = 0; i < cN; i++) {
352 for (int q = 0; q < 2 * 3; q++) {
353 outSurface[outIndex++] = end1[q] + 2 * i;
354 }
355 }
356}
357
358
359void Cogs::Core::LoftedCrossSectionsSystem::hollowClosedCountCellResources(size_t& newVertices, size_t& outIndices, size_t& cutIndices,
360 const int slices, const int samples, const bool doubleSeam)
361{
362 int Nk = slices - 2 - 1;
363 int Ni = (doubleSeam ? samples - 1 : samples);
364 newVertices = 0;
365 outIndices = 4 * 3 * Ni*Nk + 2 * 3 * Ni + 2 * 3 * Ni;
366 cutIndices = 0;
367}
368
369void Cogs::Core::LoftedCrossSectionsSystem::hollowClosedSkin(std::vector<unsigned int>& outSurface,
370 const int slices, const int samples, const bool doubleSeam)
371{
372 unsigned int outIndex = 0;
373
374 for (int k = 1; k < slices - 2; k++) {
375 for (int i = 0; i < (doubleSeam ? samples - 1 : samples); i++) {
376 int ii = (i + 1) % samples;
377 // Outer skin triangle 1
378 outSurface[outIndex++] = 2 * ((k + 0)*samples + i) + 0;
379 outSurface[outIndex++] = 2 * ((k + 0)*samples + ii) + 0;
380 outSurface[outIndex++] = 2 * ((k + 1)*samples + i) + 0;
381 // Outer skin triangle 2
382 outSurface[outIndex++] = 2 * ((k + 1)*samples + ii) + 0;
383 outSurface[outIndex++] = 2 * ((k + 1)*samples + i) + 0;
384 outSurface[outIndex++] = 2 * ((k + 0)*samples + ii) + 0;
385 // Inner skin triangle 1
386 outSurface[outIndex++] = 2 * ((k + 0)*samples + i) + 1;
387 outSurface[outIndex++] = 2 * ((k + 1)*samples + i) + 1;
388 outSurface[outIndex++] = 2 * ((k + 0)*samples + ii) + 1;
389 // Inner skin triangle 2
390 outSurface[outIndex++] = 2 * ((k + 1)*samples + ii) + 1;
391 outSurface[outIndex++] = 2 * ((k + 0)*samples + ii) + 1;
392 outSurface[outIndex++] = 2 * ((k + 1)*samples + i) + 1;
393 }
394 }
395
396 for (int i = 0; i < (doubleSeam ? samples - 1 : samples); i++) {
397 int k = (i + 1) % samples;
398 outSurface[outIndex++] = 2 * i + 0;
399 outSurface[outIndex++] = 2 * i + 1;
400 outSurface[outIndex++] = 2 * k + 0;
401 outSurface[outIndex++] = 2 * i + 1;
402 outSurface[outIndex++] = 2 * k + 1;
403 outSurface[outIndex++] = 2 * k + 0;
404 }
405
406 for (int i = 0; i < (doubleSeam ? samples - 1 : samples); i++) {
407 int k = (i + 1) % samples;
408 outSurface[outIndex++] = 2 * ((slices - 1)*samples + i) + 0;
409 outSurface[outIndex++] = 2 * ((slices - 1)*samples + k) + 0;
410 outSurface[outIndex++] = 2 * ((slices - 1)*samples + i) + 1;
411 outSurface[outIndex++] = 2 * ((slices - 1)*samples + i) + 1;
412 outSurface[outIndex++] = 2 * ((slices - 1)*samples + k) + 0;
413 outSurface[outIndex++] = 2 * ((slices - 1)*samples + k) + 1;
414 }
415}