Cogs.Core
LoftedCrossSectionsSystemSolid.cpp
1#include <glm/gtc/type_ptr.hpp>
2#include "LoftedCrossSectionsSystem.h"
3#define COGS_TABLE_SOLID
4#include "LoftedCrossSectionsSystem_tables.h"
5
6using std::vector;
7using glm::vec2;
8using glm::vec3;
9using glm::make_vec2;
10using glm::make_vec3;
11using glm::dot;
12using glm::mix;
13using glm::normalize;
14
15using std::abs;
16
17void Cogs::Core::LoftedCrossSectionsSystem::solidInitialize()
18{
19 solidCellClassCounts.resize(4 * 256);
20
21 for (int caps = 0; caps < 4; caps++) {
22 for (int code = 0; code < 256; code++) {
23 CellClassCounts counts = { 0, 0, 0, 0 };
24
25
26 int N = triangle_table_solid[256 * caps + code].n;
27 unsigned char* indices = triangle_table_solid[256 * caps + code].indices;
28 for (int k = 0; k < N; k++) {
29
30 int ix = indices[k];
31 int ix_a = ix & 0x7;
32 int ix_b = (ix >> 3) & 0x7;
33
34 switch ((ix >> 6) & 0x3) {
35 case 0: // Outer wall
36 if (ix_a == ix_b) {
37 counts.outIndices++;
38 }
39 else {
40 counts.outIndices++;
41 counts.newVertices++;
42 }
43 break;
44
45 case 1: // End at first cross section
46 if (ix_a == ix_b) {
47 if ((ix_a & 0x1) == 0) {
48 counts.outIndices++;
49 }
50 else { // on center-axis
51 counts.outIndices++;
52 counts.newVertices++;
53 }
54 }
55 else { // edge intersection
56 counts.outIndices++;
57 counts.newVertices++;
58 }
59 break;
60
61 case 2: // End at last cross section
62 {
63 if (ix_a == ix_b) {
64 if ((ix_a & 0x1) == 0) {
65 counts.outIndices++;
66 }
67 else { // on center-axis
68 counts.outIndices++;
69 counts.newVertices++;
70 }
71 }
72 else { // edge intersection
73 counts.outIndices++;
74 counts.newVertices++;
75 }
76 break;
77 }
78
79 case 3:
80 counts.outIndices++;
81 counts.newVertices++;
82 break;
83
84 default:
85 break;
86 }
87 }
88
89 solidCellClassCounts[256 * caps + code] = counts;
90 }
91 }
92}
93
94
95
96void Cogs::Core::LoftedCrossSectionsSystem::solidOpenAlignedClassifySamples(std::vector<uint8_t>& inside,
97 const float* pos, const size_t pos_stride,
98 const std::vector<glm::vec3>& spine,
99 const glm::vec3& viewer,
100 const int slices,
101 const int samples)
102{
103 inside.resize(2*slices*samples);
104 for (int j = 0; j < slices; j++) {
105 for (int i = 0; i < samples; i++) {
106 const vec3 p = make_vec3(pos + pos_stride*(j*samples + i));
107 const glm::vec3 n = p - spine[j];
108 inside[2 * (j*samples + i) + 0] = glm::dot(viewer - p, n) <= 0.0f;
109 inside[2 * (j*samples + i) + 1] = glm::dot(viewer - spine[j], n) <= 0.0f;
110 }
111 }
112}
113
114void Cogs::Core::LoftedCrossSectionsSystem::solidOpenAlignedCountCellResources(size_t& newVertices, size_t& outIndices, size_t& cutIndices,
115 std::vector<uint8_t>& classification,
116 const std::vector<glm::vec3>& /*spine*/,
117 const std::vector<uint8_t>& inside,
118 const glm::vec3& /*viewer*/,
119 const int slices, const int samples, const bool doubleSeam)
120{
121 classification.resize(samples*slices);
122 newVertices = 0;
123 outIndices = 0;
124 cutIndices = 0;
125
126 for (int j = 1; j < slices - 2; j++) {
127 int which_caps = (j == 1 ? 1 : 0) | (j == (slices - 3) ? 2 : 0);
128
129 for (int i = 0; i < samples - (doubleSeam ? 1 : 0); i++) {
130 int ii = (i + 1) % samples;
131 int crn_vtx_ix[4] = {
132 (j + 0)*samples + i, (j + 0)*samples + ii,
133 (j + 1)*samples + i, (j + 1)*samples + ii,
134 };
135
136 uint8_t code = (inside[2 * crn_vtx_ix[0] + 0] ? 1 : 0) |
137 (inside[2 * crn_vtx_ix[0] + 1] ? 2 : 0) |
138 (inside[2 * crn_vtx_ix[1] + 0] ? 4 : 0) |
139 (inside[2 * crn_vtx_ix[1] + 1] ? 8 : 0) |
140 (inside[2 * crn_vtx_ix[2] + 0] ? 16 : 0) |
141 (inside[2 * crn_vtx_ix[2] + 1] ? 32 : 0) |
142 (inside[2 * crn_vtx_ix[3] + 0] ? 64 : 0) |
143 (inside[2 * crn_vtx_ix[3] + 1] ? 128 : 0);
144
145 classification[j*samples + i] = code;
146
147 const CellClassCounts& counts = solidCellClassCounts[256 * which_caps + code];
148 newVertices += counts.newVertices;
149 outIndices += counts.outIndices;
150 cutIndices += counts.cutIndices;
151 }
152 }
153}
154
155
156
157void Cogs::Core::LoftedCrossSectionsSystem::solidOpenAlignedSkin(std::vector<unsigned int>& outSurface,
158 std::vector<unsigned int>& /*cutSurface*/,
159 float* pos, const size_t pos_stride,
160 float* tex, const size_t tex_stride,
161 float* nrm, const size_t nrm_stride,
162 const std::vector<uint8_t>& classification,
163 const std::vector<glm::vec3>& spine,
164 const glm::vec3& viewer,
165 const int slices, const int samples, const bool doubleSeam)
166{
167 unsigned int newVertex = samples * slices;
168 unsigned int outIndex = 0;
169
170 // --- March through slices ------------------------------------------------
171 for (int j = 1; j < slices - 2; j++) {
172 // check if we need to employ tables that include end capping.
173 int which_caps = (j == 1 ? 1 : 0) | (j == (slices - 3) ? 2 : 0);
174
175 // --- March along cross section -----------------------------------------
176 for (int i = 0; i < samples - (doubleSeam ? 1 : 0); i++) {
177
178 // closed cross section, wrap-around
179 int ii = (i + 1) % samples;
180
181 int crn_vtx_ix[4] = {
182 (j + 0)*samples + i, (j + 0)*samples + ii,
183 (j + 1)*samples + i, (j + 1)*samples + ii,
184 };
185
186 int code = classification[j*samples + i];
187
188 int N = triangle_table_solid[256 * which_caps + code].n;
189 unsigned char* indices = triangle_table_solid[256 * which_caps + code].indices;
190 for (int k = 0; k < N; k++) {
191 int ix = indices[k];
192 int ix_a = ix & 0x7;
193 int ix_b = (ix >> 3) & 0x7;
194
195 int a = crn_vtx_ix[ix_a >> 1];
196 int a_j = j + ((ix & 0x4) == 0 ? 0 : 1);
197 int b = crn_vtx_ix[ix_b >> 1];
198 int b_j = j + (((ix >> 3) & 0x4) == 0 ? 0 : 1);
199
200 const float* paPtr = pos + pos_stride*a;
201 const float* pbPtr = pos + pos_stride*b;
202
203 bool createVertex = false;
204 bool onCut = false;
205 vec3 na, nb;
206 switch ((ix >> 6) & 0x3) {
207
208 case 0: // Outer wall
209 if (ix_a == ix_b) {
210 outSurface[outIndex++] = a;
211 }
212 else {
213 na = make_vec3(paPtr) - spine[a_j];
214 nb = make_vec3(paPtr) - spine[b_j];
215 createVertex = true;
216 }
217 break;
218
219 case 1: // End at first cross section
220 a = a - samples;
221 if (ix_a == ix_b) {
222 if ((ix_a & 0x1) == 0) {
223 outSurface[outIndex++] = a;
224 }
225 else { // on center-axis
226 paPtr = reinterpret_cast<const float*>(spine.data() + 0);
227 b = a;
228 createVertex = true;
229 }
230 }
231 else { // edge intersection
232 b = b - samples;
233 paPtr = pos + pos_stride*a;
234 pbPtr = pos + pos_stride*b;
235 na = make_vec3(paPtr) - spine[0];
236 nb = make_vec3(pbPtr) - spine[0];
237 if (ix_a & 0x1) { paPtr = reinterpret_cast<const float*>(spine.data() + 0); }
238 if (ix_b & 0x1) { pbPtr = reinterpret_cast<const float*>(spine.data() + 0); }
239 createVertex = true;
240 }
241 break;
242
243 case 2: // End at last cross section
244 a = a + samples;
245 if (ix_a == ix_b) {
246 if ((ix_a & 0x1) == 0) {
247 outSurface[outIndex++] = a;
248 }
249 else { // on center-axis
250 paPtr = reinterpret_cast<const float*>(spine.data() + slices - 1);
251 b = a;
252 createVertex = true;
253 }
254 }
255 else { // edge intersection
256 b = b + samples;
257 paPtr = pos + pos_stride*a;
258 pbPtr = pos + pos_stride*b;
259 na = make_vec3(paPtr) - spine[slices - 1];
260 nb = make_vec3(pbPtr) - spine[slices - 1];
261 if (ix_a & 0x1) { paPtr = reinterpret_cast<const float*>(spine.data() + slices - 1); }
262 if (ix_b & 0x1) { pbPtr = reinterpret_cast<const float*>(spine.data() + slices - 1); }
263 createVertex = true;
264 }
265 break;
266
267 case 3: // Intersection face
268 na = make_vec3(paPtr) - spine[j + (ix_a >> 2)];
269 nb = make_vec3(pbPtr) - spine[j + (ix_b >> 2)];
270 if (ix_a & 0x1) { paPtr = reinterpret_cast<const float*>(spine.data() + j + (ix_a >> 2)); }
271 if (ix_b & 0x1) { pbPtr = reinterpret_cast<const float*>(spine.data() + j + (ix_b >> 2)); }
272 createVertex = true;
273 onCut = true;
274 break;
275
276 default:
277 break;
278 }
279
280
281 if (createVertex) {
282 vec3 pa = make_vec3(paPtr);
283 float t = 0.0f;
284 if (a != b) {
285 vec3 pb = make_vec3(pbPtr);
286#if 0
287 float fa = std::acos(dot(normalize(viewer - pa), normalize(na))) - float(M_PI_2);
288 float fb = std::acos(dot(normalize(viewer - pb), normalize(nb))) - float(M_PI_2);
289#else
290 float fa = dot(normalize(viewer - pa), normalize(na));
291 float fb = dot(normalize(viewer - pb), normalize(nb));
292#endif
293 t = fa*fb < 0.f ? fa / (fa - fb) : (abs(fa) < abs(fb) ? 0.f : 1.f);
294 pa = mix(pa, pb, t);
295 }
296 *reinterpret_cast<vec3*>(pos + pos_stride*newVertex) = pa;
297
298 if (tex_stride) {
299 vec2 vt = make_vec2(tex + tex_stride*a);
300 if (a != b) {
301 vt = mix(vt, make_vec2(tex + tex_stride*b), t);
302 }
303 *reinterpret_cast<vec2*>(tex + tex_stride*newVertex) = vt;
304 }
305 if (nrm_stride) {
306 if (onCut) {
307 *reinterpret_cast<vec3*>(nrm + nrm_stride*newVertex) = normalize(viewer - pa);
308 }
309 else {
310 vec3 vn = make_vec3(nrm + nrm_stride*a);
311 if (a != b) {
312 vn = mix(vn, make_vec3(nrm + nrm_stride*b), t);
313 }
314 *reinterpret_cast<vec3*>(nrm + nrm_stride*newVertex) = vn;
315 }
316 }
317
318 outSurface[outIndex++] = newVertex;
319 newVertex++;
320 }
321
322 }
323 }
324 }
325}
326
327
328void Cogs::Core::LoftedCrossSectionsSystem::solidOpenCountCellResources(size_t& newVertices, size_t& outIndices, size_t& cutIndices,
329 const int slices, const int samples, const bool doubleSeam)
330{
331 int cN = (samples - (doubleSeam ? 1 : 0)) / 2;
332 newVertices = 4 * slices + 2 * (cN + 1) + 2 * (cN + 1);
333 outIndices = 6 * cN*(slices - 2 - 1) + 3 * cN + 3 * cN;
334 cutIndices = 4 * 3 * (slices - 2 - 1);
335}
336
337
338void Cogs::Core::LoftedCrossSectionsSystem::solidOpenSkin(vector<unsigned int>& outSurface, vector<unsigned int>& cutSurface,
339 float* pos, const size_t pos_stride,
340 float* tex, const size_t tex_stride,
341 float* nrm, const size_t nrm_stride,
342 const vector<vec3>& spine,
343 const int slices, const int samples, const bool doubleSeam)
344{
345 const int doubleSeamCut[4 * 3] = {
346 4 * 0 + 0, 4 * 1 + 0, 4 * 0 + 1,
347 4 * 1 + 0, 4 * 1 + 1, 4 * 0 + 1,
348 4 * 0 + 2, 4 * 1 + 2, 4 * 0 + 3,
349 4 * 1 + 2, 4 * 1 + 3, 4 * 0 + 3
350 };
351
352 int cN = (samples - (doubleSeam ? 1 : 0)) / 2;
353
354 unsigned int newVertex = samples * slices;
355 unsigned int outIndex = 0;
356 unsigned int cutIndex = 0;
357
358 for (int k = 1; k < slices - 2; k++) {
359 for (int i = 0; i < cN; i++) {
360 int ii = (i + 1) % samples;
361
362 outSurface[outIndex++] = (k + 0)*samples + i; // Outer skin triangle 1
363 outSurface[outIndex++] = (k + 0)*samples + ii;
364 outSurface[outIndex++] = (k + 1)*samples + i;
365
366 outSurface[outIndex++] = (k + 1)*samples + ii; // Outer skin triangle 2
367 outSurface[outIndex++] = (k + 1)*samples + i;
368 outSurface[outIndex++] = (k + 0)*samples + ii;
369 }
370 }
371
372 // cut surface
373 for (int k = 1; k < slices - 2; k++) {
374 for (int q = 0; q < 4 * 3; q++) {
375 cutSurface[cutIndex++] = doubleSeamCut[q] + 4 * k + newVertex;
376 }
377 }
378
379 for (int j = 0; j < slices; j++) {
380 const vec3 q0 = make_vec3(pos + pos_stride*(j*samples + samples - 1));
381 const vec3 p0 = make_vec3(pos + pos_stride*(j*samples + 0));
382 const vec3 l0 = make_vec3(pos + pos_stride*(j*samples + 1));
383 const vec3 n0 = normalize(q0 - l0);
384
385 const vec3 q2 = make_vec3(pos + pos_stride*(j*samples + cN + 1));
386 const vec3 p2 = make_vec3(pos + pos_stride*(j*samples + cN));
387 const vec3 l2 = make_vec3(pos + pos_stride*(j*samples + cN - 1));
388 const vec3 n2 = normalize(q2 - l2);
389
390 const vec3& p1 = spine[j];
391 const vec3 n1 = normalize(n0 + n2);
392
393 *reinterpret_cast<vec3*>(pos + pos_stride*(newVertex + 0)) = p0;
394 *reinterpret_cast<vec3*>(pos + pos_stride*(newVertex + 1)) = p1;
395 *reinterpret_cast<vec3*>(pos + pos_stride*(newVertex + 2)) = p1;
396 *reinterpret_cast<vec3*>(pos + pos_stride*(newVertex + 3)) = p2;
397 if (tex_stride) {
398 const vec2 t0 = make_vec2(tex + tex_stride*(j*samples + 0));
399 const vec2 t2 = make_vec2(tex + tex_stride*(j*samples + cN));
400 *reinterpret_cast<vec2*>(tex + tex_stride*(newVertex + 0)) = t0;
401 *reinterpret_cast<vec2*>(tex + tex_stride*(newVertex + 1)) = t0;
402 *reinterpret_cast<vec2*>(tex + tex_stride*(newVertex + 2)) = t2;
403 *reinterpret_cast<vec2*>(tex + tex_stride*(newVertex + 3)) = t2;
404 }
405 if (nrm_stride) {
406 *reinterpret_cast<vec3*>(nrm + nrm_stride*(newVertex + 0)) = n0;
407 *reinterpret_cast<vec3*>(nrm + nrm_stride*(newVertex + 1)) = n1;
408 *reinterpret_cast<vec3*>(nrm + nrm_stride*(newVertex + 2)) = n1;
409 *reinterpret_cast<vec3*>(nrm + nrm_stride*(newVertex + 3)) = n2;
410 }
411 newVertex += 4;
412 }
413
414 // cap at 0
415 for (int i = 0; i < cN; i++) {
416 int k = i + 1;
417 outSurface[outIndex++] = newVertex + 2 * k + 0;
418 outSurface[outIndex++] = newVertex + 2 * i + 0;
419 outSurface[outIndex++] = newVertex + 2 * i + 1;
420 }
421
422 for (int i = 0; i <= cN; i++) {
423 *reinterpret_cast<vec3*>(pos + pos_stride*(newVertex + 2 * i + 0)) = make_vec3(pos + pos_stride*i);
424 *reinterpret_cast<vec3*>(pos + pos_stride*(newVertex + 2 * i + 1)) = spine[0];
425 }
426 if (nrm_stride) {
427 const vec3 n = normalize(spine[0] - spine[2]);
428 for (int i = 0; i <= cN; i++) {
429 *reinterpret_cast<vec3*>(nrm + nrm_stride*(newVertex + 2 * i + 0)) = n;
430 *reinterpret_cast<vec3*>(nrm + nrm_stride*(newVertex + 2 * i + 1)) = n;
431 }
432 }
433 if (tex_stride) {
434 for (int i = 0; i <= cN; i++) {
435 const vec2 t = make_vec2(tex + tex_stride*i);
436 *reinterpret_cast<vec2*>(tex + tex_stride*(newVertex + 2 * i + 0)) = t;
437 *reinterpret_cast<vec2*>(tex + tex_stride*(newVertex + 2 * i + 1)) = t;
438 }
439 }
440 newVertex += 2 * (cN + 1);
441
442 // cap at 1
443 for (int i = 0; i < cN; i++) {
444 int k = i + 1;
445 outSurface[outIndex++] = newVertex + 2 * i + 0;
446 outSurface[outIndex++] = newVertex + 2 * k + 0;
447 outSurface[outIndex++] = newVertex + 2 * i + 1;
448 }
449
450 for (int i = 0; i <= cN; i++) {
451 *reinterpret_cast<vec3*>(pos + pos_stride*(newVertex + 2 * i + 0)) = make_vec3(pos + pos_stride*((slices - 1)*samples + i));
452 *reinterpret_cast<vec3*>(pos + pos_stride*(newVertex + 2 * i + 1)) = spine[slices - 1];
453 }
454 if (nrm_stride) {
455 const vec3 n = normalize(spine[slices - 1] - spine[slices - 3]);
456 for (int i = 0; i <= cN; i++) {
457 *reinterpret_cast<vec3*>(nrm + nrm_stride*(newVertex + 2 * i + 0)) = n;
458 *reinterpret_cast<vec3*>(nrm + nrm_stride*(newVertex + 2 * i + 1)) = n;
459 }
460 }
461 if (tex_stride) {
462 for (int i = 0; i <= cN; i++) {
463 const vec2 t = make_vec2(tex + tex_stride*((slices - 1)*samples + i));
464 *reinterpret_cast<vec2*>(tex + tex_stride*(newVertex + 2 * i + 0)) = t;
465 *reinterpret_cast<vec2*>(tex + tex_stride*(newVertex + 2 * i + 1)) = t;
466 }
467 }
468 newVertex += 2 * (cN + 1);
469}
470
471
472void Cogs::Core::LoftedCrossSectionsSystem::solidClosedCountCellResources(size_t& newVertices, size_t& outIndices,
473 const int slices, const int samples, const bool doubleSeam)
474{
475 int cN = (samples - (doubleSeam ? 1 : 0));
476 newVertices = 2 * (cN + 1) + 2 * (cN + 1);
477 outIndices = 6 * cN*(slices - 2 - 1) + 3 * cN + 3 * cN;
478}
479
480
481void Cogs::Core::LoftedCrossSectionsSystem::solidClosedSkin(vector<unsigned int>& outSurface,
482 float* pos, const size_t pos_stride,
483 float* tex, const size_t tex_stride,
484 float* nrm, const size_t nrm_stride,
485 const vector<vec3>& spine,
486 const int slices, const int samples, const bool doubleSeam)
487{
488
489 int cN = (samples - (doubleSeam ? 1 : 0));
490
491 unsigned int newVertex = samples * slices;
492 unsigned int outIndex = 0;
493
494 for (int k = 1; k < slices - 2; k++) {
495 for (int i = 0; i < cN; i++) {
496 int ii = (i + 1) % samples;
497
498 outSurface[outIndex++] = (k + 0)*samples + i; // Outer skin triangle 1
499 outSurface[outIndex++] = (k + 0)*samples + ii;
500 outSurface[outIndex++] = (k + 1)*samples + i;
501
502 outSurface[outIndex++] = (k + 1)*samples + ii; // Outer skin triangle 2
503 outSurface[outIndex++] = (k + 1)*samples + i;
504 outSurface[outIndex++] = (k + 0)*samples + ii;
505 }
506 }
507
508 // Cap at 0
509 for (int i = 0; i < cN; i++) {
510 int k = (i + 1) % samples;
511 outSurface[outIndex++] = newVertex + 2 * k + 0;
512 outSurface[outIndex++] = newVertex + 2 * i + 0;
513 outSurface[outIndex++] = newVertex + 2 * i + 1;
514 }
515
516 for (int i = 0; i <= cN; i++) {
517 *reinterpret_cast<vec3*>(pos + pos_stride*(newVertex + 2 * i + 0)) = make_vec3(pos + pos_stride*i);
518 *reinterpret_cast<vec3*>(pos + pos_stride*(newVertex + 2 * i + 1)) = spine[0];
519 }
520 if (nrm_stride) {
521 const vec3 n = normalize(spine[0] - spine[2]);
522 for (int i = 0; i <= cN; i++) {
523 *reinterpret_cast<vec3*>(nrm + nrm_stride*(newVertex + 2 * i + 0)) = n;
524 *reinterpret_cast<vec3*>(nrm + nrm_stride*(newVertex + 2 * i + 1)) = n;
525 }
526 }
527 if (tex_stride) {
528 for (int i = 0; i <= cN; i++) {
529 const vec2 t = make_vec2(tex + tex_stride*i);
530 *reinterpret_cast<vec2*>(tex + tex_stride*(newVertex + 2 * i + 0)) = t;
531 *reinterpret_cast<vec2*>(tex + tex_stride*(newVertex + 2 * i + 1)) = t;
532 }
533 }
534 newVertex += 2 * (cN + 1);
535
536 // cać at 1
537 for (int i = 0; i < cN; i++) {
538 int k = (i + 1) % samples;
539 outSurface[outIndex++] = newVertex + 2 * i + 0;
540 outSurface[outIndex++] = newVertex + 2 * k + 0;
541 outSurface[outIndex++] = newVertex + 2 * i + 1;
542 }
543
544 for (int i = 0; i <= cN; i++) {
545 *reinterpret_cast<vec3*>(pos + pos_stride*(newVertex + 2 * i + 0)) = make_vec3(pos + pos_stride*((slices - 1)*samples + i));
546 *reinterpret_cast<vec3*>(pos + pos_stride*(newVertex + 2 * i + 1)) = spine[slices - 1];
547 }
548 if (nrm_stride) {
549 const vec3 n = normalize(spine[slices - 1] - spine[slices - 3]);
550 for (int i = 0; i <= cN; i++) {
551 *reinterpret_cast<vec3*>(nrm + nrm_stride*(newVertex + 2 * i + 0)) = n;
552 *reinterpret_cast<vec3*>(nrm + nrm_stride*(newVertex + 2 * i + 1)) = n;
553 }
554 }
555 if (tex_stride) {
556 for (int i = 0; i <= cN; i++) {
557 const vec2 t = make_vec2(tex + tex_stride*((slices - 1)*samples + i));
558 *reinterpret_cast<vec2*>(tex + tex_stride*(newVertex + 2 * i + 0)) = t;
559 *reinterpret_cast<vec2*>(tex + tex_stride*(newVertex + 2 * i + 1)) = t;
560 }
561 }
562 newVertex += 2 * (cN + 1);
563}