in featurizers/fogofwar.cpp [136:316]
void FogOfWar::generateSightValues() {
for (size_t i = 0; i != sight_values.size(); ++i) {
auto& v = sight_values[i];
v.max_width = 3 + (int)i * 2;
v.max_height = 3 + (int)i * 2;
v.min_width = 3;
v.min_height = 3;
v.min_mask_size = 0;
v.ext_masked_count = 0;
}
struct base_mask_t {
sight_values_t::maskdat_node_t* maskdat_node;
bool masked;
};
std::vector<base_mask_t> base_mask;
for (auto& v : sight_values) {
base_mask.clear();
base_mask.resize(v.max_width * v.max_height);
auto mask = [&](size_t index) { base_mask[index].masked = true; };
v.min_mask_size = v.min_width * v.min_height;
int offx = v.max_width / 2 - v.min_width / 2;
int offy = v.max_height / 2 - v.min_height / 2;
for (int y = 0; y < v.min_height; ++y) {
for (int x = 0; x < v.min_width; ++x) {
mask((offy + y) * v.max_width + offx + x);
}
}
auto generate_base_mask = [&]() {
int offset = v.max_height / 2 - v.max_width / 2;
int half_width = v.max_width / 2;
int max_x2 = half_width;
int max_x1 = half_width * 2;
int cur_x1 = 0;
int cur_x2 = half_width;
int i = 0;
int max_i = half_width;
int cursize1 = 0;
int cursize2 = half_width * half_width;
int min_cursize2 = half_width * (half_width - 1);
int min_cursize2_chg = half_width * 2;
while (true) {
if (cur_x1 <= max_x1) {
for (int i = 0; i <= max_x1 - cur_x1; ++i) {
mask((offset + cur_x2) * v.max_width + cur_x1 + i);
mask((offset + max_x2) * v.max_width + cur_x1 + i);
}
}
if (cur_x2 <= max_x2) {
for (int i = 0; i <= max_x2 - cur_x2; ++i) {
mask((offset + cur_x1) * v.max_width + cur_x2 + i);
mask((offset + max_x1) * v.max_width + cur_x2 + i);
}
}
cursize2 += 1 - cursize1 - 2;
cursize1 += 2;
--cur_x2;
++max_x2;
if (cursize2 <= min_cursize2) {
--max_i;
++cur_x1;
--max_x1;
min_cursize2 -= min_cursize2_chg - 2;
min_cursize2_chg -= 2;
}
++i;
if (i > max_i)
break;
}
};
generate_base_mask();
int masked_count = 0;
for (auto& v : base_mask) {
if (v.masked)
++masked_count;
}
v.ext_masked_count = masked_count - v.min_mask_size;
v.maskdat.clear();
v.maskdat.resize(masked_count);
size_t center_index = v.max_height / 2 * v.max_width + v.max_width / 2;
base_mask[center_index].maskdat_node = &v.maskdat.front();
auto at = [&](int relative_index) -> base_mask_t& {
size_t index = center_index + relative_index;
return base_mask[index];
};
size_t next_entry_index = 1;
int cur_x = -1;
int cur_y = -1;
int added_count = 1;
for (int i = 2; added_count < masked_count; i += 2) {
for (int dir = 0; dir < 4; ++dir) {
static const std::array<int, 4> direction_x = {1, 0, -1, 0};
static const std::array<int, 4> direction_y = {0, 1, 0, -1};
int this_x;
int this_y;
auto do_n = [&](int n) {
for (int i = 0; i < n; ++i) {
if (at(this_y * v.max_width + this_x).masked) {
if (this_x || this_y) {
auto* this_entry = &v.maskdat.at(next_entry_index++);
auto index = [&](FogOfWar::sight_values_t::maskdat_node_t* n) {
if (!n)
return (size_t)-1;
return (size_t)(n - v.maskdat.data());
};
int prev_x = this_x;
int prev_y = this_y;
if (prev_x > 0)
--prev_x;
else if (prev_x < 0)
++prev_x;
if (prev_y > 0)
--prev_y;
else if (prev_y < 0)
++prev_y;
if (std::abs(prev_x) == std::abs(prev_y) ||
(this_x == 0 && direction_x[dir]) ||
(this_y == 0 && direction_y[dir])) {
this_entry->prev =
index(at(prev_y * v.max_width + prev_x).maskdat_node);
this_entry->prev2 = (size_t)-1;
} else {
this_entry->prev =
index(at(prev_y * v.max_width + prev_x).maskdat_node);
int prev2_x = prev_x;
int prev2_y = prev_y;
if (std::abs(prev2_x) <= std::abs(prev2_y)) {
if (this_x >= 0)
++prev2_x;
else
--prev2_x;
} else {
if (this_y >= 0)
++prev2_y;
else
--prev2_y;
}
this_entry->prev2 =
index(at(prev2_y * v.max_width + prev2_x).maskdat_node);
}
this_entry->relative_tile_index =
this_y * (int)TilesInfo::tilesWidth + this_x;
this_entry->x = this_x;
this_entry->y = this_y;
at(this_y * v.max_width + this_x).maskdat_node = this_entry;
++added_count;
}
}
this_x += direction_x[dir];
this_y += direction_y[dir];
}
};
const std::array<int, 4> max_i = {
v.max_height, v.max_width, v.max_height, v.max_width};
if (i > max_i[dir]) {
this_x = cur_x + i * direction_x[dir];
this_y = cur_y + i * direction_y[dir];
do_n(1);
} else {
this_x = cur_x + direction_x[dir];
this_y = cur_y + direction_y[dir];
do_n(std::min(max_i[(dir + 1) % 4] - 1, i));
}
cur_x = this_x - direction_x[dir];
cur_y = this_y - direction_y[dir];
}
if (i < v.max_width - 1)
--cur_x;
if (i < v.max_height - 1)
--cur_y;
}
}
}