in layer2/ObjectSlice.cpp [266:663]
static void ObjectSliceStateUpdate(ObjectSlice * I, ObjectSliceState * oss,
ObjectMapState * oms)
{
int ok = true;
int min[2] = { 0, 0 }, max[2] = {
0, 0}; /* limits of the rectangle */
int need_normals = false;
int track_camera = SettingGet_b(I->Obj.G, NULL, I->Obj.Setting, cSetting_slice_track_camera);
float grid = SettingGet_f(I->Obj.G, NULL, I->Obj.Setting, cSetting_slice_grid);
int min_expand = 1;
if(SettingGet_b(I->Obj.G, NULL, I->Obj.Setting, cSetting_slice_dynamic_grid)) {
float resol = SettingGet_f(I->Obj.G, NULL, I->Obj.Setting,
cSetting_slice_dynamic_grid_resolution);
float scale = SceneGetScreenVertexScale(I->Obj.G, oss->origin);
oss->last_scale = scale;
grid = resol * scale;
}
CGOFree(oss->shaderCGO);
if (track_camera){
oss->outline_n_points = 0;
}
if(grid < 0.01F)
grid = 0.01F;
/* for the given map, compute a new set of interpolated points with accompanying levels */
/* first, find the limits of the enclosing rectangle, starting at the slice origin,
via a simple brute-force approach... */
if(oss->ExtentFlag) { /* how far out do we need to go to be sure we intersect the map? */
min_expand = (int) (diff3f(oss->ExtentMax, oss->ExtentMin) / grid);
}
if(ok) {
int size = 1, minus_size;
int a;
int keep_going = true;
int n_cycles = 0;
float point[3];
while(keep_going || (n_cycles < min_expand)) {
keep_going = false;
minus_size = -size;
n_cycles++;
for(a = -size; a <= size; a++) {
if((max[1] != size) || (min[0] > a) || (max[0] < a)) {
point[0] = grid * a;
point[1] = grid * size;
point[2] = 0.0F;
transform33f3f(oss->system, point, point);
add3f(oss->origin, point, point);
if(ObjectMapStateContainsPoint(oms, point)) {
keep_going = true;
if(max[1] < size)
max[1] = size;
if(min[0] > a)
min[0] = a;
if(max[0] < a)
max[0] = a;
}
} else
keep_going = true;
if((min[1] != minus_size) || (min[0] > a) || (max[0] < a)) {
point[0] = grid * a;
point[1] = grid * minus_size;
point[2] = 0.0F;
transform33f3f(oss->system, point, point);
add3f(oss->origin, point, point);
if(ObjectMapStateContainsPoint(oms, point)) {
keep_going = true;
if(min[1] > minus_size)
min[1] = minus_size;
if(min[0] > a)
min[0] = a;
if(max[0] < a)
max[0] = a;
}
} else
keep_going = true;
if((max[0] != size) || (min[1] > a) || (max[1] < a)) {
point[0] = grid * size;
point[1] = grid * a;
point[2] = 0.0F;
transform33f3f(oss->system, point, point);
add3f(oss->origin, point, point);
if(ObjectMapStateContainsPoint(oms, point)) {
keep_going = true;
if(max[0] < size)
max[0] = size;
if(min[1] > a)
min[1] = a;
if(max[1] < a)
max[1] = a;
}
} else
keep_going = true;
if((min[0] != minus_size) || (min[1] > a) || (max[1] < a)) {
point[0] = grid * minus_size;
point[1] = grid * a;
point[2] = 0.0F;
transform33f3f(oss->system, point, point);
add3f(oss->origin, point, point);
if(ObjectMapStateContainsPoint(oms, point)) {
keep_going = true;
if(min[0] > minus_size)
min[0] = minus_size;
if(min[1] > a)
min[1] = a;
if(max[1] < a)
max[1] = a;
}
} else
keep_going = true;
}
if(keep_going)
min_expand = 0; /* if we've hit, then don't keep searching blindly */
size++;
}
oss->max[0] = max[0];
oss->max[1] = max[1];
oss->min[0] = min[0];
oss->min[1] = min[1];
}
/* now confirm that storage is available */
if(ok) {
int n_alloc = (1 + oss->max[0] - oss->min[0]) * (1 + oss->max[1] - oss->min[1]);
if(!oss->points) {
oss->points = VLAlloc(float, n_alloc * 3);
} else {
VLACheck(oss->points, float, n_alloc * 3); /* note: this is a macro which reassigns the pointer */
}
if(!oss->values) {
oss->values = VLAlloc(float, n_alloc);
} else {
VLACheck(oss->values, float, n_alloc); /* note: this is a macro which reassigns the pointer */
}
if(!oss->colors) {
oss->colors = VLACalloc(float, n_alloc * 3);
} else {
VLACheck(oss->colors, float, n_alloc * 3); /* note: this is a macro which reassigns the pointer */
}
if(!oss->flags) {
oss->flags = VLAlloc(int, n_alloc);
} else {
VLACheck(oss->flags, int, n_alloc); /* note: this is a macro which reassigns the pointer */
}
if(!(oss->points && oss->values && oss->flags)) {
ok = false;
PRINTFB(I->Obj.G, FB_ObjectSlice, FB_Errors)
"ObjectSlice-Error: allocation failed\n" ENDFB(I->Obj.G);
}
if(!oss->strips) /* this is range-checked during use */
oss->strips = VLAlloc(int, n_alloc);
oss->n_points = n_alloc;
}
/* generate the coordinates */
if(ok) {
int x, y;
float *point = oss->points;
for(y = min[1]; y <= max[1]; y++) {
for(x = min[0]; x <= max[0]; x++) {
point[0] = grid * x;
point[1] = grid * y;
point[2] = 0.0F;
transform33f3f(oss->system, point, point);
add3f(oss->origin, point, point);
point += 3;
}
}
}
/* interpolate and flag the points inside the map */
if(ok) {
ObjectMapStateInterpolate(oms, oss->points, oss->values, oss->flags, oss->n_points);
}
/* apply the height scale (if nonzero) */
if(ok) {
if(SettingGet_b(I->Obj.G, NULL, I->Obj.Setting, cSetting_slice_height_map)) {
float height_scale =
SettingGet_f(I->Obj.G, NULL, I->Obj.Setting, cSetting_slice_height_scale);
float *value = oss->values;
float up[3], scaled[3], factor;
int x, y;
float *point = oss->points;
need_normals = true;
up[0] = oss->system[2];
up[1] = oss->system[5];
up[2] = oss->system[8];
for(y = min[1]; y <= max[1]; y++) {
for(x = min[0]; x <= max[0]; x++) {
factor = ((*value - oss->MapMean) / oss->MapStdev) * height_scale;
scale3f(up, factor, scaled);
add3f(scaled, point, point);
point += 3;
value++;
}
}
/* TODO: For all edge points, move them onto the closest outline line, generated by GenerateOutlineOfSlice */
}
}
/* now generate efficient triangle strips based on the points that are present in the map */
if(ok) {
int x, y;
int cols = 1 + max[0] - min[0];
int flag00, flag01, flag10, flag11;
int offset = 0, offset00, offset01, offset10, offset11;
int strip_active = false;
int n = 0;
for(y = min[1]; y < max[1]; y++) {
offset00 = offset;
for(x = min[0]; x < max[0]; x++) {
offset01 = offset00 + 1;
offset10 = offset00 + cols;
offset11 = offset10 + 1;
flag00 = oss->flags[offset00];
flag01 = oss->flags[offset01];
flag10 = oss->flags[offset10];
flag11 = oss->flags[offset11];
/* first triangle - forward handedness: 10 00 11 */
if(strip_active) {
if(flag10 && flag00 && flag11) {
/* continue current strip */
VLACheck(oss->strips, int, n);
oss->strips[n] = offset10;
n++;
} else {
/* terminate current strip */
VLACheck(oss->strips, int, n);
oss->strips[n] = STOP_STRIP;
strip_active = false;
n++;
}
} else if(flag10 & flag00 && flag11) {
/* start a new strip with correct parity */
VLACheck(oss->strips, int, n + 3);
oss->strips[n] = START_STRIP;
oss->strips[n + 1] = offset10;
oss->strips[n + 2] = offset00;
oss->strips[n + 3] = offset11;
n += 4;
strip_active = true;
}
/* second triangle -- reverse handedness: 00 11 01 */
if(strip_active) {
if(flag00 && flag11 && flag01) {
/* continue current strip */
VLACheck(oss->strips, int, n);
oss->strips[n] = offset01;
n++;
} else {
/* terminate current strip */
VLACheck(oss->strips, int, n);
oss->strips[n] = STOP_STRIP;
strip_active = false;
n++;
}
} else if(flag00 & flag11 && flag01) {
/* singleton triangle -- improper order for strip */
VLACheck(oss->strips, int, n + 5);
oss->strips[n + 0] = START_STRIP;
oss->strips[n + 1] = offset11;
oss->strips[n + 2] = offset00;
oss->strips[n + 3] = offset01;
oss->strips[n + 4] = STOP_STRIP;
n += 5;
}
offset00++;
}
if(strip_active) {
/* terminate current strip */
VLACheck(oss->strips, int, n);
oss->strips[n] = STOP_STRIP;
strip_active = false;
n++;
}
offset += cols;
}
VLACheck(oss->strips, int, n);
n++;
oss->n_strips = n;
}
/* compute triangle normals if we need them */
if(!need_normals) {
VLAFreeP(oss->normals);
} else {
int *cnt = NULL;
if(!oss->normals) {
oss->normals = VLAlloc(float, oss->n_points * 3);
} else {
VLACheck(oss->normals, float, oss->n_points * 3); /* note: this is a macro which reassigns the pointer */
}
cnt = Calloc(int, oss->n_points);
if(cnt && oss->normals) {
int *strip = oss->strips;
float *point = oss->points;
float *normal = oss->normals;
int n = oss->n_strips;
int a;
int offset0 = 0, offset1 = 0, offset2, offset;
int strip_active = false;
int tri_count = 0;
float d1[3], d2[3], cp[3];
UtilZeroMem(oss->normals, sizeof(float) * 3 * oss->n_points);
for(a = 0; a < n; a++) {
offset = *(strip++);
switch (offset) {
case START_STRIP:
strip_active = true;
tri_count = 0;
break;
case STOP_STRIP:
strip_active = false;
break;
default:
if(strip_active) {
tri_count++;
offset2 = offset1;
offset1 = offset0;
offset0 = offset;
if(tri_count >= 3) {
if(tri_count & 0x1) { /* get the handedness right ... */
subtract3f(point + 3 * offset1, point + 3 * offset0, d1);
subtract3f(point + 3 * offset2, point + 3 * offset1, d2);
} else {
subtract3f(point + 3 * offset0, point + 3 * offset1, d1);
subtract3f(point + 3 * offset2, point + 3 * offset0, d2);
}
cross_product3f(d2, d1, cp);
normalize3f(cp);
add3f(cp, normal + 3 * offset0, normal + 3 * offset0);
add3f(cp, normal + 3 * offset1, normal + 3 * offset1);
add3f(cp, normal + 3 * offset2, normal + 3 * offset2);
cnt[offset0]++;
cnt[offset1]++;
cnt[offset2]++;
}
}
}
}
{ /* now normalize the average normals for active vertices */
int x, y;
float *normal = oss->normals;
int *c = cnt;
for(y = min[1]; y <= max[1]; y++) {
for(x = min[0]; x <= max[0]; x++) {
if(*c)
normalize3f(normal);
point += 3;
c++;
}
}
}
}
FreeP(cnt);
}
}