-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathVoxelChunk.cpp
693 lines (630 loc) · 27.2 KB
/
VoxelChunk.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
#include "VoxelChunk.h"
#include <vector>
#include "Visualize.h"
using namespace std;
//unsigned int VoxelChunk::indexMap[DataRange * DataRange * DataRange];
const int indexOrder[] = {
-1, -1,
0, -1,
-1, 0,
-1, -1,
0, -1,
-1, -1,
-1, -1,
-1, 0,
};
VoxelChunk::VoxelChunk() :_data(nullptr){
}
VoxelChunk::~VoxelChunk(){
if (_data != nullptr) delete _data;
}
void VoxelChunk::createDataArray(){
_data = new VoxelData[VoxelConstants::DataRange * VoxelConstants::DataRange * VoxelConstants::DataRange];
memset(_data, 0, sizeof(VoxelData) * VoxelConstants::DataRange * VoxelConstants::DataRange * VoxelConstants::DataRange);
}
void VoxelChunk::performSDF(SamplerFunction* sampler){
const ivec3 minBound = sampler->getMinBound();
const ivec3 maxBound = sampler->getMaxBound();
for (int zi = minBound.z; zi <= maxBound.z; zi++){
for (int yi = minBound.y; yi <= maxBound.y; yi++){
for (int xi = minBound.x; xi <= maxBound.x; xi++){
ivec3 pos = ivec3(xi, yi, zi);
vec3 intersections;
VoxelData voxel;
voxel.material = sampler->materialFunc(pos, 1, &intersections, &voxel.normal[0], &voxel.normal[1], &voxel.normal[2]);
voxel.intersections[0] = (unsigned char)(intersections.x * EDGE_SCALE);
voxel.intersections[1] = (unsigned char)(intersections.y * EDGE_SCALE);
voxel.intersections[2] = (unsigned char)(intersections.z * EDGE_SCALE);
writeRaw(xi, yi, zi, voxel);
}
}
}
}
void VoxelChunk::customSDF(int x, int y, int z, int w, SamplerFunction* sampler){
ivec3 minBound = ivec3(x, y, z);
int step = 1 << (w);
for (int zi = 0; zi < VoxelConstants::DataRange; zi++){
for (int yi = 0; yi < VoxelConstants::DataRange; yi++){
for (int xi = 0; xi < VoxelConstants::DataRange; xi++){
ivec3 pos = minBound + ivec3(xi, yi, zi) * step;
vec3 intersections;
VoxelData voxel;
if (xi == 1 && yi == 1 && zi == 1){
int sdf = 0;
}
voxel.material = sampler->materialFunc(pos, step, &intersections, &voxel.normal[0], &voxel.normal[1], &voxel.normal[2]);
if (voxel.material != 0){
int sdf = 0;
}
voxel.intersections[0] = (unsigned char)(intersections.x * EDGE_SCALE);
voxel.intersections[1] = (unsigned char)(intersections.y * EDGE_SCALE);
voxel.intersections[2] = (unsigned char)(intersections.z * EDGE_SCALE);
writeRaw(xi, yi, zi, voxel);
}
}
}
}
void VoxelChunk::writeRaw(int x, int y, int z, const VoxelData& vData){
int idx = calcDataIndex(x, y, z);
if (_data == nullptr)createDataArray();
//_data[idx] = vData;
_data[idx].intersections[0] = vData.intersections[0];
_data[idx].intersections[1] = vData.intersections[1];
_data[idx].intersections[2] = vData.intersections[2];
_data[idx].material = vData.material;
_data[idx].normal[0] = vData.normal[0];
_data[idx].normal[1] = vData.normal[1];
_data[idx].normal[2] = vData.normal[2];
}
/*
we would like to experiment with a method that attempts to solve the seams between different lod chunks.
we need to first separate the generation of vertices and indices(quads) into two phases.
the first phase would include the generation of vertices, minimizers using the qef method.
in addition to this, we also duplicate the vertices that are on the minimal planes of a chunk
to the chunk before it.
so in the second phase in which we need to generate the indices(quads), we can generate quads
between two chunks that are on different lod levels.
*/
void VoxelChunk::generateVertices(){
tempVertices.clear();
tempNormals.clear();
const float QEF_ERROR = 1e-6f;
const int QEF_SWEEPS = 4;
QefSolver solver;
VoxelData* eight[8];
int intersectionCount;
int vertexId = 0;
{
int indexMapLength = VoxelConstants::UsableRange * VoxelConstants::UsableRange * VoxelConstants::UsableRange;
memset(indexMap, -1, sizeof(indexMap));
}
for (int z = 0; z < VoxelConstants::UsableRange; z++){
for (int y = 0; y < VoxelConstants::UsableRange; y++){
for (int x = 0; x < VoxelConstants::UsableRange; x++){
//int idx = calcDataIndex(x, y, z);
int usableIndex = calcUsableIndex(x, y, z);
solver.reset();
vec3 accumNormal;
intersectionCount = 0;
if (x == 1 && y == 1 && z == 0){
int sdf = 0;
}
// step 1: get the pointers to the 8 neighbour cells.
eight[0] = read(x, y, z);
eight[1] = read(x + 1, y, z);
eight[2] = read(x, y + 1, z);
eight[3] = read(x + 1, y + 1, z);
eight[4] = read(x, y, z + 1);
eight[5] = read(x + 1, y, z + 1);
eight[6] = read(x, y + 1, z + 1);
eight[7] = read(x + 1, y + 1, z + 1);
unsigned char baseMat = eight[0]->material;
// step 2 : determine the indices from any crossing on the 3 minimal axis/edges.
char xmin = -1, ymin = -1, zmin = -1;
if (baseMat == 0 && eight[1]->material != 0)xmin = 1;
else if (baseMat != 0 && eight[1]->material == 0)xmin = 0;
if (baseMat == 0 && eight[2]->material != 0)ymin = 1;
else if (baseMat != 0 && eight[2]->material == 0)ymin = 0;
if (baseMat == 0 && eight[4]->material != 0)zmin = 1;
else if (baseMat != 0 && eight[4]->material == 0)zmin = 0;
edgeMap[usableIndex * 3] = xmin;
edgeMap[usableIndex * 3 + 1] = ymin;
edgeMap[usableIndex * 3 + 2] = zmin;
// step 3 : add the intersections and their normals to the solver, up to 12 intersections/edges.
// at the same time, increment the intersection count and normal accumulation.
solverAddX(eight[1]->material, eight[0], solver, intersectionCount, accumNormal, 0, 0, 0);
solverAddY(eight[2]->material, eight[0], solver, intersectionCount, accumNormal, 0, 0, 0);
solverAddZ(eight[4]->material, eight[0], solver, intersectionCount, accumNormal, 0, 0, 0);
solverAddZ(eight[5]->material, eight[1], solver, intersectionCount, accumNormal, 1, 0, 0);
solverAddY(eight[3]->material, eight[1], solver, intersectionCount, accumNormal, 1, 0, 0);
solverAddX(eight[3]->material, eight[2], solver, intersectionCount, accumNormal, 0, 1, 0);
solverAddZ(eight[6]->material, eight[2], solver, intersectionCount, accumNormal, 0, 1, 0);
solverAddX(eight[5]->material, eight[4], solver, intersectionCount, accumNormal, 0, 0, 1);
solverAddY(eight[6]->material, eight[4], solver, intersectionCount, accumNormal, 0, 0, 1);
solverAddZ(eight[7]->material, eight[3], solver, intersectionCount, accumNormal, 1, 1, 0);
solverAddY(eight[7]->material, eight[5], solver, intersectionCount, accumNormal, 1, 0, 1);
solverAddX(eight[7]->material, eight[6], solver, intersectionCount, accumNormal, 0, 1, 1);
// step 4 : calculate the minimizer position
if (intersectionCount > 0)
{
Vec3 res;
solver.solve(res, QEF_ERROR, QEF_SWEEPS, QEF_ERROR);
if (res.x < 0 || res.x > 1.0f ||
res.y < 0 || res.y > 1.0f ||
res.z < 0 || res.z > 1.0f){
VIS_DOT(x, y, z);
VIS_VEC3(x, y + (float)eight[0]->intersections[1] / EDGE_SCALE, z, eight[0]->normal[1].x, eight[0]->normal[1].y, eight[0]->normal[1].z);
VIS_VEC3(x + 1, y + (float)eight[1]->intersections[1] / EDGE_SCALE, z, eight[1]->normal[1].x, eight[1]->normal[1].y, eight[0]->normal[1].z);
VIS_VEC3(x, y + (float)eight[4]->intersections[1] / EDGE_SCALE, z + 1, eight[4]->normal[1].x, eight[4]->normal[1].y, eight[0]->normal[1].z);
VIS_VEC3(x + 1, y + (float)eight[5]->intersections[1] / EDGE_SCALE, z + 1, eight[5]->normal[1].x, eight[5]->normal[1].y, eight[0]->normal[1].z);
}
if (res.x != res.x || res.y != res.y || res.z != res.z){
int sdf = 0;
}
res.x += x;
res.y += y;
res.z += z;
tempVertices.push_back(vec3(res.x, res.y, res.z));
// store the vertex Id to the index map.
/*indexMap[idx] = vertexId;
vertexId++;*/
indexMap[usableIndex] = vertexId;
vertexId++;
// average the normals accumulated from all the intersecting edges.
accumNormal = glm::normalize(accumNormal);
tempNormals.push_back(accumNormal);
if (accumNormal.x != accumNormal.x || accumNormal.y != accumNormal.y || accumNormal.z != accumNormal.z){
int sdf = 0;
}
}
}
}
}
}
// note that generateVertices also generate the edge map for the usable range
// but it does not generate the edge map on the 3 positive surfaces(outside of the usable range), which is needed when
// generating the transition desc in case of loddiff = 1.
void VoxelChunk::generateEdgeMapOnMaxSurface(int surfaceId){
VoxelData* base;
VoxelData* positive;
int c0;
int c1;
int numUsableRange = VoxelConstants::UsableRange;
int* px = nullptr;
int* py = nullptr;
int* pz = nullptr;
ivec3 xincr, yincr;
if (surfaceId == 0){
px = &numUsableRange;
py = &c1;
pz = &c0;
xincr = ivec3(0, 0, 1);
yincr = ivec3(0, 1, 0);
}
else if (surfaceId == 1){
px = &c0;
py = &numUsableRange;
pz = &c1;
xincr = ivec3(1, 0, 0);
yincr = ivec3(0, 0, 1);
}
else if (surfaceId == 2){
px = &c0;
py = &c1;
pz = &numUsableRange;
xincr = ivec3(1, 0, 0);
yincr = ivec3(0, 1, 0);
}
for (c0 = 0; c0 < VoxelConstants::UsableRange; c0++){
for (c1 = 1; c1 < VoxelConstants::UsableRange; c1++){
base = read(*px, *py, *pz);
positive = read((*px) + xincr.x, (*py) + xincr.y, (*pz) + xincr.z);
char xmin = -1;
if (base->material == 0 && positive->material != 0)xmin = 1;
else if (base->material != 0 && positive->material == 0)xmin = 0;
// 0 indicates the first axis/edge.
int idx = calcSurfaceEdgeMapIndex(c0, c1, surfaceId, 0);
surfaceEdgeMap[idx] = xmin;
}
}
for (c0 = 1; c0 < VoxelConstants::UsableRange; c0++){
for (c1 = 0; c1 < VoxelConstants::UsableRange; c1++){
/*base = read(VoxelConstants::UsableRange, c1, c0);
positive = read(VoxelConstants::UsableRange, c1 + 1, c0);*/
base = read(*px, *py, *pz);
positive = read((*px) + yincr.x, (*py) + yincr.y, (*pz) + yincr.z);
char ymin = -1;
if (base->material == 0 && positive->material != 0)ymin = 1;
else if (base->material != 0 && positive->material == 0)ymin = 0;
// 0 indicates the first axis/edge.
int idx = calcSurfaceEdgeMapIndex(c0, c1, surfaceId, 1);
surfaceEdgeMap[idx] = ymin;
}
}
}
void VoxelChunk::generateIndices(){
tempIndices.clear();
for (int z = 0; z < VoxelConstants::UsableRange; z++){
for (int y = 0; y < VoxelConstants::UsableRange; y++){
for (int x = 0; x < VoxelConstants::UsableRange; x++){
//int idx = calcDataIndex(x, y, z);
int usableIndex = calcUsableIndex(x, y, z);
if (x == 1 && y == 1 && z == 0){
int sdf = 0;
}
int xmin = -1, ymin = -1, zmin = -1;
xmin = edgeMap[usableIndex * 3];
ymin = edgeMap[usableIndex * 3 + 1];
zmin = edgeMap[usableIndex * 3 + 2];
/* build a quad for any of the three minimal edge that has mismatching material ends,
as indicated in step 2
xmin, ymin, zmin somewhat indicate the normal at the intersection, as in,
is the axis shooting into the surface, or shooting out of the surface?
-1: the x axis/edge has no intersection;
0: the x axis/edge is pointing into a surface.
1: the x axis/edge is pointing from the inside of a surface.
the same applies to the y and z axis/edges.
pointing inwards/outwards a surface would dictate the order we wind the triangles.
*/
if (xmin != -1){
/*
we also skip generating the indices(quad) when the running cell is at one of
the minimal surfaces.
*/
//if (y != 0 && z != 0 && x != 0){
if (y != 0 && z != 0){
tempIndices.push_back(readVertexIndex(x, y, z));
tempIndices.push_back(readVertexIndex(x, y + indexOrder[xmin * 8], z + indexOrder[xmin * 8 + 1]));
tempIndices.push_back(readVertexIndex(x, y + indexOrder[xmin * 8 + 2], z + indexOrder[xmin * 8 + 3]));
tempIndices.push_back(readVertexIndex(x, y, z));
tempIndices.push_back(readVertexIndex(x, y + indexOrder[xmin * 8 + 4], z + indexOrder[xmin * 8 + 5]));
tempIndices.push_back(readVertexIndex(x, y + indexOrder[xmin * 8 + 6], z + indexOrder[xmin * 8 + 7]));
}
}
if (ymin != -1){
//if (x != 0 && z != 0 && y != 0){
if (x != 0 && z != 0){
tempIndices.push_back(readVertexIndex(x, y, z));
tempIndices.push_back(readVertexIndex(x + indexOrder[ymin * 8 + 1], y, z + indexOrder[ymin * 8]));
tempIndices.push_back(readVertexIndex(x + indexOrder[ymin * 8 + 3], y, z + indexOrder[ymin * 8 + 2]));
tempIndices.push_back(readVertexIndex(x, y, z));
tempIndices.push_back(readVertexIndex(x + indexOrder[ymin * 8 + 5], y, z + indexOrder[ymin * 8 + 4]));
tempIndices.push_back(readVertexIndex(x + indexOrder[ymin * 8 + 7], y, z + indexOrder[ymin * 8 + 6]));
}
}
if (zmin != -1){
//if (x != 0 && y != 0 && z != 0){
if (x != 0 && y != 0){
tempIndices.push_back(readVertexIndex(x, y, z));
tempIndices.push_back(readVertexIndex(x + indexOrder[zmin * 8], y + indexOrder[zmin * 8 + 1], z));
tempIndices.push_back(readVertexIndex(x + indexOrder[zmin * 8 + 2], y + indexOrder[zmin * 8 + 3], z));
tempIndices.push_back(readVertexIndex(x, y, z));
tempIndices.push_back(readVertexIndex(x + indexOrder[zmin * 8 + 4], y + indexOrder[zmin * 8 + 5], z));
tempIndices.push_back(readVertexIndex(x + indexOrder[zmin * 8 + 6], y + indexOrder[zmin * 8 + 7], z));
}
}
}
}
}
edgeDescs[0].gen2D(&tempIndices, false);
edgeDescs[1].gen2D(&tempIndices, false);
edgeDescs[2].gen2D(&tempIndices, true);
/*generateEdge1D(0);
generateEdge1D(1);
generateEdge1D(2);*/
}
// to generate the 1D seam edge desc, we need to specify which of the three seams
// we define 3 being the edge that's parallel to the x axis,
// 4: parallel to the y axis
// 5: parallel to the z axis
void VoxelChunk::createEdgeDesc1D(int lodDiff, int loc0, VoxelChunk* baseChunk, int facing){
int type = facing - 3;
const int mapping[3] = { 0, 1, 2};
const int _1D2DAdjacency[] = {
2, 1,
0, 2,
1, 0,
};
// this determines which of the two end columns to read in the two supporting edge descs.
const int readOrder[] = {
0, 0,
1, 1,
0, 1,
};
VoxelChunkTransitionSurfaceDesc* edgeDesc;
edgeDesc = &(baseChunk->edgeDescs[facing]);
if (edgeDesc->initialized == false){
// gather the two 2D transition desc, or the supporting edge desc.
VoxelChunkTransitionSurfaceDesc* left = &(baseChunk->edgeDescs[_1D2DAdjacency[type * 2]]);
VoxelChunkTransitionSurfaceDesc* right = &(baseChunk->edgeDescs[_1D2DAdjacency[type * 2 + 1]]);
edgeDesc->init1D(lodDiff, left, right);
// now form the left and right column of the index map structure.
{
int length = edgeDesc->getDim();
for (int c0 = 0; c0 < length; c0++){
int leftIndex;
if(readOrder[type * 2] == 0)leftIndex = left->readIndex2D_X(c0, length);
if (readOrder[type * 2] == 1)leftIndex = left->readIndex2D_Y(c0, length);
edgeDesc->writeIndex1D(c0, 1, leftIndex);
// right
int rightIndex;
if (readOrder[type * 2 + 1] == 0)rightIndex = right->readIndex2D_X(c0, length);
if (readOrder[type * 2 + 1] == 1)rightIndex = right->readIndex2D_Y(c0, length);
edgeDesc->writeIndex1D(c0, 2, rightIndex);
// write from the baseChunk index map.
// here we actually dont need to sample from the baseChunk because the two supporting edge desc(2D)
// already contains the data we need to fill the 1D edge desc.
int baseIndex = 0;
if (type == 0)baseIndex = baseChunk->readIndex_X(c0, length);
else if (type == 1)baseIndex = baseChunk->readIndex_Y(c0, length);
else if (type == 2)baseIndex = baseChunk->readIndex_Z(c0, length);
edgeDesc->writeIndex1D(c0, 0, baseIndex);
}
}
}
vec3 vertTranslate;
if (facing == 3){
vertTranslate.x = (float)(loc0 * VoxelConstants::UsableRange) * 0.5f;
vertTranslate.y = VoxelConstants::UsableRange;
vertTranslate.z = VoxelConstants::UsableRange;
}
else if (facing == 4){
vertTranslate.x = VoxelConstants::UsableRange;
vertTranslate.y = (float)(loc0 * VoxelConstants::UsableRange) * 0.5f;
vertTranslate.z = VoxelConstants::UsableRange;
}
else if (facing == 5){
vertTranslate.x = VoxelConstants::UsableRange;
vertTranslate.y = VoxelConstants::UsableRange;
vertTranslate.z = (float)(loc0 * VoxelConstants::UsableRange) * 0.5f;
}
if (lodDiff == -1){
_1DPhase_MinusOne(vertTranslate, baseChunk, loc0, edgeDesc, type);
}
else if (lodDiff == 0){
_1DPhase_Zero(vertTranslate, baseChunk, edgeDesc, type);
}
else if (lodDiff == 1){
_1DPhase_PlusOne(vertTranslate, baseChunk, loc0, edgeDesc, type);
}
}
// the calling chunk only constitutes half of the baseChunk's 1D edge desc.
void VoxelChunk::_1DPhase_MinusOne(const vec3& vertTranslate, VoxelChunk* baseChunk, int loc0, VoxelChunkTransitionSurfaceDesc* edgeDesc, int type){
int vertIncre = baseChunk->tempVertices.size();
const int mapping[3] = { 0, 1, 2 };
for (int c0 = 0; c0 < VoxelConstants::UsableRange; c0++){
int usableIndex = 0;
if (type == 0)usableIndex = calcUsableIndex(c0, 0, 0);
else if (type == 1)usableIndex = calcUsableIndex(0, c0, 0);
else if (type == 2)usableIndex = calcUsableIndex(0, 0, c0);
int vidx = indexMap[usableIndex];
if (vidx == -1)continue;
// first we get the vertex from this chunk's vertex list.
vec3 vert = tempVertices[vidx];
// transform this vertex with respect to loddiff.
vert *= edgeDesc->vertScale;
vert += vertTranslate;
// copy the vertex to baseChunk's vertex array,(and the normal too)
baseChunk->tempVertices.push_back(vert);
vec3 normal = tempNormals[vidx];
baseChunk->tempNormals.push_back(normal);
// then store the index in the edge desc structure.
edgeDesc->writeIndex1D(c0 + loc0 * VoxelConstants::UsableRange, 3, vertIncre);
vertIncre++;
// now we copy the edge flag.
//edgeDesc->writeSeamEdge1D(c0 + loc0 * VoxelConstants::UsableRange, edgeMap[usableIndex * 3 + mapping[type]]);
}
}
// the calling chunk is of the same lod as the baseChunk's 1D edge desc.
// but we also need to take care of the case where the dim of the 1D edge desc is greater than the calling chunk
void VoxelChunk::_1DPhase_Zero(const vec3& vertTranslate, VoxelChunk* baseChunk, VoxelChunkTransitionSurfaceDesc* edgeDesc, int type){
int vertIncre = baseChunk->tempVertices.size();
const int mapping[3] = { 0, 1, 2 };
for (int c0 = 0; c0 < VoxelConstants::UsableRange; c0++){
int usableIndex = 0;
if (type == 0)usableIndex = calcUsableIndex(c0, 0, 0);
else if (type == 1)usableIndex = calcUsableIndex(0, c0, 0);
else if (type == 2)usableIndex = calcUsableIndex(0, 0, c0);
int vidx = indexMap[usableIndex];
if (vidx == -1)continue;
// first we get the vertex from this chunk's vertex list.
vec3 vert = tempVertices[vidx];
// transform this vertex with respect to loddiff.
vert *= edgeDesc->vertScale;
vert += vertTranslate;
// copy the vertex to baseChunk's vertex array,(and the normal too)
baseChunk->tempVertices.push_back(vert);
vec3 normal = tempNormals[vidx];
baseChunk->tempNormals.push_back(normal);
// then store the index in the edge desc structure.
edgeDesc->writeIndex1D_Dupe(c0, 3, vertIncre);
vertIncre++;
}
}
// the edge desc is only half dim of the calling chunk's.
void VoxelChunk::_1DPhase_PlusOne(const vec3& vertTranslate, VoxelChunk* baseChunk, int loc0, VoxelChunkTransitionSurfaceDesc* edgeDesc, int type){
int vertIncre = baseChunk->tempVertices.size();
const int mapping[3] = { 0, 1, 2 };
int halfUsableRange = VoxelConstants::UsableRange / 2;
for (int c0 = 0; c0 < halfUsableRange; c0++){
int usableIndex = 0;
if (type == 0)usableIndex = calcUsableIndex(c0 + loc0 * halfUsableRange, 0, 0);
else if (type == 1)usableIndex = calcUsableIndex(0, c0 + loc0 * halfUsableRange, 0);
else if (type == 2)usableIndex = calcUsableIndex(0, 0, c0 + loc0 * halfUsableRange);
int vidx = indexMap[usableIndex];
if (vidx == -1)continue;
// first we get the vertex from this chunk's vertex list.
vec3 vert = tempVertices[vidx];
// transform this vertex with respect to loddiff.
vert *= edgeDesc->vertScale;
vert += vertTranslate;
// copy the vertex to baseChunk's vertex array,(and the normal too)
baseChunk->tempVertices.push_back(vert);
vec3 normal = tempNormals[vidx];
baseChunk->tempNormals.push_back(normal);
// then store the index in the edge desc structure.
edgeDesc->writeIndex1D_Dupe2(c0, halfUsableRange, 3, vertIncre);
vertIncre++;
// now we copy the edge flag.
//edgeDesc->writeSeamEdge1D(c0 + loc0 * VoxelConstants::UsableRange, edgeMap[usableIndex * 3 + mapping[type]]);
}
}
int VoxelChunk::readIndex_X(int c, int maxDim){
int ret;
int tempC = (maxDim > VoxelConstants::UsableRange) ? (c >> 1) : c;
ret = readVertexIndex(tempC, VoxelConstants::UsableRange - 1, VoxelConstants::UsableRange - 1);
return ret;
}
int VoxelChunk::readIndex_Y(int c, int maxDim){
int ret;
int tempC = (maxDim > VoxelConstants::UsableRange) ? (c >> 1) : c;
ret = readVertexIndex(VoxelConstants::UsableRange - 1, tempC, VoxelConstants::UsableRange - 1);
return ret;
}
int VoxelChunk::readIndex_Z(int c, int maxDim){
int ret;
int tempC = (maxDim > VoxelConstants::UsableRange) ? (c >> 1) : c;
ret = readVertexIndex(VoxelConstants::UsableRange - 1, VoxelConstants::UsableRange - 1, tempC);
return ret;
}
void VoxelChunk::createEdgeDesc2D(int lodDiff, int loc0, int loc1, VoxelChunk* baseChunk, int facing)
{
VoxelChunkTransitionSurfaceDesc* edgeDesc;
edgeDesc = &(baseChunk->edgeDescs[facing]);
if (edgeDesc->initialized == false){
edgeDesc->init(lodDiff);
int scaler = edgeDesc->getDim() / VoxelConstants::UsableRange;
// copy the original index from the adjacent chunk to the edge desc structure.
for (int c1 = 0; c1 < VoxelConstants::UsableRange; c1++){
for (int c0 = 0; c0 < VoxelConstants::UsableRange; c0++){
int adjUsableIndex = 0;
if (facing == 0)adjUsableIndex = calcUsableIndex(VoxelConstants::UsableRange - 1, c1, c0);
else if (facing == 1)adjUsableIndex = calcUsableIndex(c0, VoxelConstants::UsableRange - 1, c1);
else if (facing == 2)adjUsableIndex = calcUsableIndex(c0, c1, VoxelConstants::UsableRange - 1);
int indexValue = baseChunk->indexMap[adjUsableIndex];
if (scaler == 1){
edgeDesc->writeIndex2D(c0, c1, 0, indexValue);
}
else{
edgeDesc->writeIndex2D(c0 * 2, c1 * 2, 0, indexValue);
edgeDesc->writeIndex2D(c0 * 2 + 1, c1 * 2, 0, indexValue);
edgeDesc->writeIndex2D(c0 * 2, c1 * 2 + 1, 0, indexValue);
edgeDesc->writeIndex2D(c0 * 2 + 1, c1 * 2 + 1, 0, indexValue);
}
}
}
}
vec3 vertTranslate;
if (facing == 0){
vertTranslate.x = VoxelConstants::UsableRange;
vertTranslate.y = (float)(loc1 * VoxelConstants::UsableRange) * 0.5f;
vertTranslate.z = (float)(loc0 * VoxelConstants::UsableRange) * 0.5f;
}
else if (facing == 1){
vertTranslate.x = (float)(loc0 * VoxelConstants::UsableRange) * 0.5f;
vertTranslate.y = VoxelConstants::UsableRange;
vertTranslate.z = (float)(loc1 * VoxelConstants::UsableRange) * 0.5f;
}
else if (facing == 2){
vertTranslate.x = (float)(loc0 * VoxelConstants::UsableRange) * 0.5f;
vertTranslate.y = (float)(loc1 * VoxelConstants::UsableRange) * 0.5f;
vertTranslate.z = VoxelConstants::UsableRange;
}
if (lodDiff == -1){
copyIndicesAndEdgeFlags(vertTranslate, baseChunk, loc0, loc1, edgeDesc, facing);
}
else if (lodDiff == 0){
copyIndicesAndEdgeFlags(vertTranslate, baseChunk, 0, 0, edgeDesc, facing);
}
else if (lodDiff == 1){
if (facing == 0){
vertTranslate.x = VoxelConstants::UsableRange;
vertTranslate.y = loc1 * -VoxelConstants::UsableRange;
vertTranslate.z = loc0 * -VoxelConstants::UsableRange;
}
else if (facing == 1){
vertTranslate.x = loc0 * -VoxelConstants::UsableRange;
vertTranslate.y = VoxelConstants::UsableRange;
vertTranslate.z = loc1 * -VoxelConstants::UsableRange;
}
else if (facing == 2){
vertTranslate.x = loc0 * -VoxelConstants::UsableRange;
vertTranslate.y = loc1 * -VoxelConstants::UsableRange;
vertTranslate.z = VoxelConstants::UsableRange;
}
duplicateIndicesAndEdgeFlags(vertTranslate, baseChunk, loc0, loc1, edgeDesc, facing);
}
}
void VoxelChunk::copyIndicesAndEdgeFlags(const vec3& vertTranslate, VoxelChunk* baseChunk, int loc0, int loc1, VoxelChunkTransitionSurfaceDesc* edgeDesc, int facing){
const int mapping[6] = { 2, 1, 0, 2, 0, 1 };
int vertIncre = baseChunk->tempVertices.size();
for (int c1 = 0; c1 < VoxelConstants::UsableRange; c1++){
for (int c0 = 0; c0 < VoxelConstants::UsableRange; c0++){
int usableIndex = 0;
if (facing == 0)usableIndex = calcUsableIndex(0, c1, c0);
else if (facing == 1)usableIndex = calcUsableIndex(c0, 0, c1);
else if (facing == 2)usableIndex = calcUsableIndex(c0, c1, 0);
int vidx = indexMap[usableIndex];
if (vidx == -1)continue;
// first we get the vertex from this chunk's vertex list.
vec3 vert = tempVertices[vidx];
// transform this vertex with respect to lodDiff
vert *= edgeDesc->vertScale;
vert += vertTranslate;
// step 1: copy the vertex to baseChunk's vertex array,(and the normal too)
baseChunk->tempVertices.push_back(vert);
vec3 normal = tempNormals[vidx];
baseChunk->tempNormals.push_back(normal);
// step 2: then store the index in the edge desc structure.
edgeDesc->writeIndex2D(c0 + loc0 * VoxelConstants::UsableRange, c1 + loc1 * VoxelConstants::UsableRange, 1, vertIncre);
vertIncre++;
// now we copy the edge flags.
edgeDesc->writeSeamEdgeXY(c0 + loc0 * VoxelConstants::UsableRange, c1 + loc1 * VoxelConstants::UsableRange,
edgeMap[usableIndex * 3 + mapping[facing * 2]],
edgeMap[usableIndex * 3 + mapping[facing * 2 + 1]]);
}
}
}
void VoxelChunk::duplicateIndicesAndEdgeFlags(const vec3& vertTranslate, VoxelChunk* baseChunk ,int loc0, int loc1, VoxelChunkTransitionSurfaceDesc* edgeDesc, int facing){
const int mapping[6] = { 2, 1, 0, 2, 0, 1 };
int vertIncre = baseChunk->tempVertices.size();
int halfUsableRange = VoxelConstants::UsableRange / 2;
for (int c1 = 0; c1 < halfUsableRange; c1++){
for (int c0 = 0; c0 < halfUsableRange; c0++){
int usableIndex = 0;
if (facing == 0)usableIndex = calcUsableIndex(0, c1 + loc1 * halfUsableRange, c0 + loc0 * halfUsableRange);
else if (facing == 1)usableIndex = calcUsableIndex(c0 + loc0 * halfUsableRange, 0, c1 + loc1 * halfUsableRange);
else if (facing == 2)usableIndex = calcUsableIndex(c0 + loc0 * halfUsableRange, c1 + loc1 * halfUsableRange, 0);
int vidx = indexMap[usableIndex];
if (vidx == -1)continue;
// first we get the vertex from this chunk's vertex list.
vec3 vert = tempVertices[vidx];
// transform this vertex with respect to the two lod values.
vert *= edgeDesc->vertScale;
vert += vertTranslate;
// step 1: copy the vertex to baseChunk's vertex array,(and the normal too)
baseChunk->tempVertices.push_back(vert);
vec3 normal = tempNormals[vidx];
baseChunk->tempNormals.push_back(normal);
// step 2: then store the index in the edge desc structure.
// notice that we need to duplicate it four times.
edgeDesc->writeIndex2D(c0 * 2, c1 * 2, 1, vertIncre);
edgeDesc->writeIndex2D(c0 * 2 + 1, c1 * 2, 1, vertIncre);
edgeDesc->writeIndex2D(c0 * 2, c1 * 2 + 1, 1, vertIncre);
edgeDesc->writeIndex2D(c0 * 2 + 1, c1 * 2 + 1, 1, vertIncre);
vertIncre++;
}
}
baseChunk->generateEdgeMapOnMaxSurface(0);
baseChunk->generateEdgeMapOnMaxSurface(1);
baseChunk->generateEdgeMapOnMaxSurface(2);
for (int c1 = 0; c1 < VoxelConstants::UsableRange; c1++){
for (int c0 = 0; c0 < VoxelConstants::UsableRange; c0++){
int usableIndex = 0;
usableIndex = baseChunk->calcSurfaceEdgeMapIndex(c0, c1, facing, 0);
char edgeX = baseChunk->surfaceEdgeMap[usableIndex];
char edgeY = baseChunk->surfaceEdgeMap[usableIndex + 1];
edgeDesc->writeSeamEdgeXY(c0, c1, edgeX, edgeY);
}
}
}