game: new better selection render code

This commit is contained in:
Crypto City 2020-07-07 17:39:10 +00:00
parent a0151f3322
commit ba37b600e1
6 changed files with 159 additions and 215 deletions

View File

@ -440,63 +440,33 @@ void CityMeshSection::setHighlight(const Selection &selection, const std::shared
rebuild_flags.insert(map->get_flag(under_construction_flag_id));
under_construction_flag_id = id;
}
Selection local_selection = selection;
local_selection.set_intersection(vx0, vy0, vx1, vy1);
if (local_selection != current_selection)
{
if (!current_selection.is_empty())
{
std::set<std::shared_ptr<Flag>> res;
map->get_flags(current_selection.x0, current_selection.y0, current_selection.x1, current_selection.y1, res);
for (const std::shared_ptr<Flag> &flag: res)
rebuild_flags.insert(flag);
}
current_selection = local_selection;
if (!current_selection.is_empty())
{
std::set<std::shared_ptr<Flag>> res;
map->get_flags(current_selection.x0, current_selection.y0, current_selection.x1, current_selection.y1, res);
for (const std::shared_ptr<Flag> &flag: res)
rebuild_flags.insert(flag);
}
if (selected_flag)
rebuild_flags.insert(selected_flag);
}
if (!rebuild_flags.empty())
{
RebuildFlags(rebuild_flags, false);
RebuildFlags(rebuild_flags, local_selection, false);
}
if (!forceHighlightRefresh && !flagUnderConstruction)
if (selection == current_selection)
return;
ResourceCache* cache = node->GetSubsystem<ResourceCache>();
std::set<std::shared_ptr<Flag>> flags;
map->get_flags(vx0, vy0, vx1, vy1, flags);
for (const std::shared_ptr<Flag> &flag: flags)
{
const bool ignore = game->ignore_flag(flag->id);
const uint32_t fy0 = std::max(flag->y0, vy0);
const uint32_t fy1 = std::min(flag->y1, vy1);
for (uint32_t y = fy0; y <= fy1; ++y)
{
const uint32_t fx0 = std::max(flag->x0, vx0);
const uint32_t fx1 = std::min(flag->x1, vx1);
for (uint32_t x = fx0; x <= fx1; ++x)
{
const bool was_selected = current_selection.is_selected(x, y);
const bool selected = selection.is_selected(x, y);
if (was_selected == selected && !forceHighlightRefresh)
continue;
const uint16_t th = ignore ? 0u : flag->get_tile_height(x, y);
for (uint32_t h = 0; h < th; ++h)
{
auto &tile = nodes[y - vy0][x - vx0].blocks[h];
if (!tile.node)
continue;
StaticModel *model = tile.node->GetComponent<BlockModel>();
if (!model)
continue;
{
SharedPtr<Material> material;
const uint8_t type = flag->get_tile_type(x, y, h);
MaterialVersion mv = selected ? MVSelected : MVNormal;
if (!selected && tile.is_new)
{
mv = MVNew;
flagsWithNew.insert(flag->id);
}
material = resources.materials[mv][get_material_for_block(flag, type, h)];
model->SetMaterial(material);
}
}
}
}
}
current_selection = selection;
forceHighlightRefresh = false;
}
@ -525,7 +495,7 @@ void CityMeshSection::buildMap()
std::set<std::shared_ptr<Flag>> flags;
game->map.get_flags(vx0, vy0, vx1, vy1, flags);
RebuildFlags(flags, false);
RebuildFlags(flags, {}, false);
blocksNode->SetParent(selectableNode);
@ -657,14 +627,6 @@ static StaticModel *create_area(Node *node, Material *material, uint32_t fx0, ui
return model;
}
static bool is_selection_in_flag(const Selection &sel, const std::shared_ptr<Flag> &flag)
{
if (!flag || sel.is_empty())
return false;
uint32_t d = cc::get_distance(flag->x0, flag->y0, flag->x1, flag->y1, sel.x0, sel.y0, sel.x1, sel.y1);
return d == 0;
}
void CityMeshSection::GetFlags(std::set<uint32_t> &flags) const
{
for (const auto &e: blockNodes)
@ -692,7 +654,7 @@ void CityMeshSection::ClearFlags(const std::set<uint32_t> &flags)
}
template<typename C>
void CityMeshSection::RebuildFlags(const C &flags, bool highlight_new)
void CityMeshSection::RebuildFlags(const C &flags, const Selection &selection, bool highlight_new)
{
if (!game)
return;
@ -782,31 +744,15 @@ void CityMeshSection::RebuildFlags(const C &flags, bool highlight_new)
const uint32_t fx1 = std::min(flag->x1, vx1);
const bool origin_in_section = fx0 == flag->x0 && fy0 == flag->y0;
auto check_new_blocks = [fx0, fy0, fx1, fy1, &flag, this](bool highlight_new)
{
for (uint32_t y = fy0; y <= fy1; ++y)
{
for (uint32_t x = fx0; x <= fx1; ++x)
{
const uint16_t th = flag->get_tile_height(x, y);
const uint16_t prevth = nodes[y - vy0][x - vx0].blocks.size();
const bool is_new = th > prevth;
if (highlight_new && is_new)
return true;
for (const auto &e: nodes[y - vy0][x - vx0].blocks)
if (e.is_new)
return true;
}
}
return false;
};
bool has_new = check_new_blocks(highlight_new);
const uint32_t tile_width = flag->x1 - flag->x0 + 1;
const uint32_t w = fx1 - fx0 + 1;
const uint32_t h = fy1 - fy0 + 1;
const ::Tile* tiles = flag->get_raw_tiles();
const uint32_t dx0 = fx0 - flag->x0;
const uint32_t dx1 = flag->x1 - fx1;
const uint32_t dy0 = fy0 - flag->y0;
RenderMode flagRenderMode = renderMode;
if (has_new)
flagRenderMode = RenderCubeModels;
else if (flag->owner == game->playerState.id && ((!!under_construction_flag_id && under_construction_flag_id == flag->id) || !under_construction_flag_id) && is_selection_in_flag(current_selection, flag))
flagRenderMode = RenderCubeModels;
const RenderMode flagRenderMode = renderMode;
SharedPtr<Node> parent;
auto it = blockNodes.find(flag->id);
@ -847,14 +793,17 @@ void CityMeshSection::RebuildFlags(const C &flags, bool highlight_new)
}
std::vector<std::vector<uint8_t>> front_spans, back_spans, left_spans, right_spans, bottom_spans, top_spans;
std::vector<std::vector<uint8_t>> sel_front_spans, sel_back_spans, sel_left_spans, sel_right_spans, sel_bottom_spans, sel_top_spans;
std::vector<std::vector<uint8_t>> new_front_spans, new_back_spans, new_left_spans, new_right_spans, new_bottom_spans, new_top_spans;
uint32_t max_height = 0;
if (flagRenderMode == RenderSpanningColumns || flagRenderMode == RenderSpanningRectangles)
{
for (uint32_t y = fy0; y <= fy1; ++y)
uint32_t tile_idx = dx0 + dy0 * tile_width;
for (uint32_t y = fy0; y <= fy1; ++y, tile_idx += dx0 + dx1)
{
for (uint32_t x = fx0; x <= fx1; ++x)
for (uint32_t x = fx0; x <= fx1; ++x, ++tile_idx)
{
const uint16_t th = flag->get_tile_height(x, y);
const uint16_t th = tiles[tile_idx].get_height();
if (th > max_height)
max_height = th;
}
@ -867,69 +816,91 @@ void CityMeshSection::RebuildFlags(const C &flags, bool highlight_new)
right_spans.resize(width);
bottom_spans.resize(max_height);
top_spans.resize(max_height);
sel_front_spans.resize(height);
sel_back_spans.resize(height);
sel_left_spans.resize(width);
sel_right_spans.resize(width);
sel_bottom_spans.resize(max_height);
sel_top_spans.resize(max_height);
new_front_spans.resize(height);
new_back_spans.resize(height);
new_left_spans.resize(width);
new_right_spans.resize(width);
new_bottom_spans.resize(max_height);
new_top_spans.resize(max_height);
}
const bool ignore = game->ignore_flag(flag->id);
for (uint32_t y = fy0; y <= fy1; ++y)
uint32_t tile_idx = dx0 + dy0 * tile_width;
for (uint32_t y = fy0; y <= fy1; ++y, tile_idx += dx0 + dx1)
{
for (uint32_t x = fx0; x <= fx1; ++x)
for (uint32_t x = fx0; x <= fx1; ++x, ++tile_idx)
{
const uint16_t th = ignore ? 0u : flag->get_tile_height(x, y);
const uint16_t prevth = nodes[y - vy0][x - vx0].blocks.size();
auto &node = nodes[y - vy0][x - vx0];
const uint16_t th = ignore ? 0u : tiles[tile_idx].get_height();
const uint16_t prevth = node.blocks.size();
if (highlight_new && th > prevth)
has_new = true;
maxh = std::max(maxh, th);
if (th < prevth)
{
for (uint32_t h = th; h < prevth; ++h)
if (nodes[y - vy0][x - vx0].blocks[h].node)
nodes[y - vy0][x - vx0].blocks[h].node->Remove();
if (node.blocks[h].node)
node.blocks[h].node->Remove();
}
nodes[y - vy0][x - vx0].blocks.resize(th);
node.blocks.resize(th);
const bool is_selected = selection.is_selected(x, y);
for (uint32_t h = 0; h < th; ++h)
{
++n_total;
const uint8_t type = flag->get_tile_type(x, y, h);
const uint8_t type = tiles[tile_idx].get_type(h);
const uint16_t material_type = get_material_for_block(flag, type, h);
bool hidden = type == 0;
bool bottom_hidden = false, top_hidden = false, left_hidden = false, right_hidden = false, front_hidden = false, back_hidden = false;
if (!hidden)
{
bottom_hidden = h == 0 || flag->get_tile_type(x, y, h-1) != 0;
top_hidden = h+1 < th && flag->get_tile_type(x, y, h+1) != 0;
left_hidden = x > flag->x0 && flag->get_tile_height(x-1, y) > h && flag->get_tile_type(x-1, y, h) != 0;
right_hidden = x < flag->x1 && flag->get_tile_height(x+1, y) > h && flag->get_tile_type(x+1, y, h) != 0;
front_hidden = y > flag->y0 && flag->get_tile_height(x, y-1) > h && flag->get_tile_type(x, y-1, h) != 0;
back_hidden = y < flag->y1 && flag->get_tile_height(x, y+1) > h && flag->get_tile_type(x, y+1, h) != 0;
bottom_hidden = h == 0 || tiles[tile_idx].get_type(h-1) != 0;
top_hidden = h+1 < th && tiles[tile_idx].get_type(h+1) != 0;
left_hidden = x > flag->x0 && tiles[tile_idx-1].get_height() > h && tiles[tile_idx-1].get_type(h) != 0;
right_hidden = x < flag->x1 && tiles[tile_idx+1].get_height() > h && tiles[tile_idx+1].get_type(h) != 0;
front_hidden = y > flag->y0 && tiles[tile_idx - tile_width].get_height() > h && tiles[tile_idx - tile_width].get_type(h) != 0;
back_hidden = y < flag->y1 && tiles[tile_idx + tile_width].get_height() > h && tiles[tile_idx + tile_width].get_type(h) != 0;
hidden = bottom_hidden && top_hidden && left_hidden && right_hidden && front_hidden && back_hidden;
}
if (node.blocks[h].is_new)
has_new = true;
if (hidden)
{
++n_hidden;
if (nodes[y - vy0][x - vx0].blocks[h].node)
nodes[y - vy0][x - vx0].blocks[h].node->Remove();
nodes[y - vy0][x - vx0].blocks[h] = {NULL, type, false};
if (node.blocks[h].node)
node.blocks[h].node->Remove();
node.blocks[h] = {NULL, type, false};
continue;
}
if (flagRenderMode == RenderCubeModels)
{
if (nodes[y - vy0][x - vx0].blocks[h].material == type && nodes[y - vy0][x - vx0].blocks[h].node)
if (node.blocks[h].material == type && node.blocks[h].node)
continue;
}
else
{
if (nodes[y - vy0][x - vx0].blocks[h].node)
if (node.blocks[h].node)
{
nodes[y - vy0][x - vx0].blocks[h].node->Remove();
nodes[y - vy0][x - vx0].blocks[h].node = NULL;
node.blocks[h].node->Remove();
node.blocks[h].node = NULL;
}
}
const bool is_new = highlight_new && h >= prevth;
if (is_new)
has_new = true;
const MaterialVersion mv = is_new ? MVNew : MVNormal;
SharedPtr<BlockModel> blockObject;
if (!nodes[y - vy0][x - vx0].blocks[h].node)
if (!node.blocks[h].node)
{
switch (flagRenderMode)
{
@ -1013,28 +984,28 @@ void CityMeshSection::RebuildFlags(const C &flags, bool highlight_new)
blockObject = blockNode->CreateComponent<BlockModel>();
blockObject->SetModel(resources.block8Model, true);
blockObject->SetMaterial(resources.materials[mv][material_type]);
nodes[y - vy0][x - vx0].blocks[h].node = std::move(blockNode);
node.blocks[h].node = std::move(blockNode);
break;
}
case RenderSpanningColumns:
case RenderSpanningRectangles:
{
if (!front_hidden) add_span(front_spans, x - fx0, y - fy0, h, fx1-fx0+1, max_height, material_type);
if (!left_hidden) add_span(left_spans, y - fy0, x - fx0, h, fy1-fy0+1, max_height, material_type);
if (!back_hidden) add_span(back_spans, x - fx0, y - fy0, h, fx1-fx0+1, max_height, material_type);
if (!right_hidden) add_span(right_spans, y - fy0, x - fx0, h, fy1-fy0+1, max_height, material_type);
if (!bottom_hidden) add_span(bottom_spans, y - fy0, h, x - fx0, fy1-fy0+1, fx1-fx0+1, material_type);
if (!top_hidden) add_span(top_spans, y - fy0, h, x - fx0, fy1-fy0+1, fx1-fx0+1, material_type);
if (!front_hidden) add_span(is_new ? new_front_spans : is_selected ? sel_front_spans : front_spans, x - fx0, y - fy0, h, fx1-fx0+1, max_height, material_type);
if (!left_hidden) add_span(is_new ? new_left_spans : is_selected ? sel_left_spans : left_spans, y - fy0, x - fx0, h, fy1-fy0+1, max_height, material_type);
if (!back_hidden) add_span(is_new ? new_back_spans : is_selected ? sel_back_spans : back_spans, x - fx0, y - fy0, h, fx1-fx0+1, max_height, material_type);
if (!right_hidden) add_span(is_new ? new_right_spans : is_selected ? sel_right_spans : right_spans, y - fy0, x - fx0, h, fy1-fy0+1, max_height, material_type);
if (!bottom_hidden) add_span(is_new ? new_bottom_spans : is_selected ? sel_bottom_spans : bottom_spans, y - fy0, h, x - fx0, fy1-fy0+1, fx1-fx0+1, material_type);
if (!top_hidden) add_span(is_new ? new_top_spans : is_selected ? sel_top_spans : top_spans, y - fy0, h, x - fx0, fy1-fy0+1, fx1-fx0+1, material_type);
break;
}
}
}
else
blockObject = nodes[y - vy0][x - vx0].blocks[h].node->GetComponent<BlockModel>();
blockObject = node.blocks[h].node->GetComponent<BlockModel>();
if (blockObject)
blockObject->SetMaterial(resources.materials[mv][material_type]);
nodes[y - vy0][x - vx0].blocks[h].material = material_type;
nodes[y - vy0][x - vx0].blocks[h].is_new = is_new;
node.blocks[h].material = material_type;
node.blocks[h].is_new = is_new;
if (blockObject)
blockObject->SetCastShadows(true);
@ -1046,19 +1017,24 @@ void CityMeshSection::RebuildFlags(const C &flags, bool highlight_new)
if (flagRenderMode == RenderSpanningRectangles || flagRenderMode == RenderSpanningColumns)
{
std::vector<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t, uint8_t>> rectangles;
const struct
struct span_t
{
const char *name;
const std::vector<std::vector<uint8_t>> &spans;
const std::vector<std::vector<uint8_t>> &sel_spans;
const std::vector<std::vector<uint8_t>> &new_spans;
std::function<bool(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, bool,
const std::vector<uint8_t>&, std::vector<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t, uint8_t>>&)> rectanglizer;
std::function<void(std::vector<float>&, std::vector<uint32_t>&,
uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, float)> add_face;
} spans[] =
};
const span_t spans[] =
{
{
"Front",
front_spans,
sel_front_spans,
new_front_spans,
[](uint32_t fx0, uint32_t fy0, uint32_t fx1, uint32_t fy1, uint32_t max_height, bool vertical_only,
const std::vector<uint8_t> &span, std::vector<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t, uint8_t>> &rectangles) {
const uint32_t span_width = fx1 - fx0 + 1;
@ -1077,6 +1053,8 @@ void CityMeshSection::RebuildFlags(const C &flags, bool highlight_new)
{
"Left",
left_spans,
sel_left_spans,
new_left_spans,
[](uint32_t fx0, uint32_t fy0, uint32_t fx1, uint32_t fy1, uint32_t max_height, bool vertical_only,
const std::vector<uint8_t> &span, std::vector<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t, uint8_t>> &rectangles) {
const uint32_t span_width = fy1 - fy0 + 1;
@ -1095,6 +1073,8 @@ void CityMeshSection::RebuildFlags(const C &flags, bool highlight_new)
{
"Back",
back_spans,
sel_back_spans,
new_back_spans,
[](uint32_t fx0, uint32_t fy0, uint32_t fx1, uint32_t fy1, uint32_t max_height, bool vertical_only,
const std::vector<uint8_t> &span, std::vector<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t, uint8_t>> &rectangles) {
const uint32_t span_width = fx1 - fx0 + 1;
@ -1113,6 +1093,8 @@ void CityMeshSection::RebuildFlags(const C &flags, bool highlight_new)
{
"Right",
right_spans,
sel_right_spans,
new_right_spans,
[](uint32_t fx0, uint32_t fy0, uint32_t fx1, uint32_t fy1, uint32_t max_height, bool vertical_only,
const std::vector<uint8_t> &span, std::vector<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t, uint8_t>> &rectangles) {
const uint32_t span_width = fy1 - fy0 + 1;
@ -1131,6 +1113,8 @@ void CityMeshSection::RebuildFlags(const C &flags, bool highlight_new)
{
"Bottom",
bottom_spans,
sel_bottom_spans,
new_bottom_spans,
[](uint32_t fx0, uint32_t fy0, uint32_t fx1, uint32_t fy1, uint32_t max_height, bool vertical_only,
const std::vector<uint8_t> &span, std::vector<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t, uint8_t>> &rectangles) {
const uint32_t span_width = fy1 - fy0 + 1;
@ -1149,6 +1133,8 @@ void CityMeshSection::RebuildFlags(const C &flags, bool highlight_new)
{
"Top",
top_spans,
sel_top_spans,
new_top_spans,
[](uint32_t fx0, uint32_t fy0, uint32_t fx1, uint32_t fy1, uint32_t max_height, bool vertical_only,
const std::vector<uint8_t> &span, std::vector<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t, uint8_t>> &rectangles) {
const uint32_t span_width = fy1 - fy0 + 1;
@ -1166,24 +1152,15 @@ void CityMeshSection::RebuildFlags(const C &flags, bool highlight_new)
},
};
for (const auto &e: spans)
auto process_span = [&](const span_t &e, size_t i, const std::vector<uint8_t> &span, MaterialVersion material_version)
{
for (size_t i = 0; i < e.spans.size(); ++i)
{
const auto &span = e.spans[i];
if (span.empty())
continue;
uint32_t n_tiles = 0;
for (const auto &hit: span)
if (hit)
++n_tiles;
if (!e.rectanglizer(fx0, fy0, fx1, fy1, max_height, flagRenderMode == RenderSpanningColumns, span, rectangles))
printf("Rectanglizer failure !!!\n");
for (const auto &r: rectangles)
{
const uint8_t material_type = std::get<4>(r);
std::vector<float> &vdata = vertex_data[material_type][MVNormal];
std::vector<uint32_t> &idata = index_data[material_type][MVNormal];
std::vector<float> &vdata = vertex_data[material_type][material_version];
std::vector<uint32_t> &idata = index_data[material_type][material_version];
const uint32_t rx0 = std::get<0>(r);
const uint32_t ry0 = std::get<1>(r);
const uint32_t rx_span = std::get<2>(r);
@ -1192,7 +1169,19 @@ void CityMeshSection::RebuildFlags(const C &flags, bool highlight_new)
if (vdata.size() > 65535)
indices_fit_in_16_bits = false;
}
}
};
for (const auto &e: spans)
{
for (size_t i = 0; i < e.spans.size(); ++i)
if (!e.spans[i].empty())
process_span(e, i, e.spans[i], MVNormal);
for (size_t i = 0; i < e.sel_spans.size(); ++i)
if (!e.sel_spans[i].empty())
process_span(e, i, e.sel_spans[i], MVSelected);
for (size_t i = 0; i < e.new_spans.size(); ++i)
if (!e.new_spans[i].empty())
process_span(e, i, e.new_spans[i], MVNew);
}
}
@ -1246,7 +1235,7 @@ void CityMeshSection::RebuildFlags(const C &flags, bool highlight_new)
MINFO("Mesh with " << ncubes << " cubes: generated in " << (t1-t0)/1e6 << " seconds for render mode " << renderMode << " (" << n_hidden << "/" << n_total << " hidden blocks");
}
void CityMeshSection::Update(float timeStep, bool mark_new_block)
void CityMeshSection::Update(float timeStep, const Selection &selection, bool mark_new_block)
{
if (mark_new_block)
{
@ -1303,7 +1292,7 @@ void CityMeshSection::Update(float timeStep, bool mark_new_block)
}
}
if (!rebuild_flags.empty())
RebuildFlags(rebuild_flags, false);
RebuildFlags(rebuild_flags, selection, false);
flagsWithNew.clear();
}
}
@ -1537,7 +1526,7 @@ void CityMeshSection::updateHeightMap()
*/
}
void CityMeshUrho3D::Update(float timeStep, bool mark_new_block)
void CityMeshUrho3D::Update(float timeStep, const Selection &selection, bool mark_new_block)
{
time += timeStep;
float pulseIntensity = (sinf(time * 10) + 1) / 2;
@ -1563,7 +1552,7 @@ void CityMeshUrho3D::Update(float timeStep, bool mark_new_block)
for (int y = 0; y < NUM_CITY_SECTIONS; ++y)
for (int x = 0; x < NUM_CITY_SECTIONS; ++x)
if (sections[x][y])
sections[x][y]->Update(timeStep, mark_new_block);
sections[x][y]->Update(timeStep, selection, mark_new_block);
}
void CityMeshUrho3D::SetView(const Vector3 &pos)
@ -1690,7 +1679,7 @@ void CityMeshUrho3D::ClearFlags(const std::set<uint32_t> &flags)
}
template<typename C>
void CityMeshUrho3D::RebuildFlags(const C &flags, bool highlight_new)
void CityMeshUrho3D::RebuildFlags(const C &flags, const Selection &selection, bool highlight_new)
{
if (!game || flags.empty())
return;
@ -1700,7 +1689,7 @@ void CityMeshUrho3D::RebuildFlags(const C &flags, bool highlight_new)
for (int y = 0; y < NUM_CITY_SECTIONS; ++y)
for (int x = 0; x < NUM_CITY_SECTIONS; ++x)
if (sections[x][y])
sections[x][y]->RebuildFlags(flags, highlight_new);
sections[x][y]->RebuildFlags(flags, selection, highlight_new);
const uint64_t t1 = get_us();
MINFO(flags.size() << " flags rebuilt in " << (t1-t0)/1e6<< " seconds");
@ -1735,7 +1724,7 @@ void CityMeshUrho3D::GetBlockTextures(std::map<uint8_t, std::map<uint16_t, std::
}
}
template void CityMeshSection::RebuildFlags(const std::deque<std::shared_ptr<Flag>> &flags, bool highlight_new);
template void CityMeshUrho3D::RebuildFlags(const std::deque<std::shared_ptr<Flag>> &flags, bool highlight_new);
template void CityMeshSection::RebuildFlags(const std::set<std::shared_ptr<Flag>> &flags, bool highlight_new);
template void CityMeshUrho3D::RebuildFlags(const std::set<std::shared_ptr<Flag>> &flags, bool highlight_new);
template void CityMeshSection::RebuildFlags(const std::deque<std::shared_ptr<Flag>> &flags, const Selection &selection, bool highlight_new);
template void CityMeshUrho3D::RebuildFlags(const std::deque<std::shared_ptr<Flag>> &flags, const Selection &selection, bool highlight_new);
template void CityMeshSection::RebuildFlags(const std::set<std::shared_ptr<Flag>> &flags, const Selection &selection, bool highlight_new);
template void CityMeshUrho3D::RebuildFlags(const std::set<std::shared_ptr<Flag>> &flags, const Selection &selection, bool highlight_new);

View File

@ -85,12 +85,12 @@ public:
void setDisplayMode(DisplayMode mode);
void setRenderMode(RenderMode mode);
void setGroundMode(GroundMode mode);
void Update(float timeStep, bool mark_new_block);
void Update(float timeStep, const Selection &selection, bool mark_new_block);
void setView(uint32_t vx0, uint32_t vy0, uint32_t vx1, uint32_t vy1);
void setCameraPos(const Urho3D::Vector3 &pos);
void GetFlags(std::set<uint32_t> &flags) const;
void ClearFlags(const std::set<uint32_t> &flags);
template<typename C> void RebuildFlags(const C &flags, bool highlight_new);
template<typename C> void RebuildFlags(const C &flags, const Selection &selection, bool highlight_new);
bool hasFlagsWithNew() const { return !flagsWithNew.empty(); }
private:
@ -149,11 +149,11 @@ public:
void setHighlight(const Selection &selection, const std::shared_ptr<Flag> &hoverFlag, const std::shared_ptr<Flag> &selectedFlag, const boost::optional<std::tuple<uint32_t, std::vector<uint16_t>, std::vector<std::vector<uint8_t>>>> &flagUnderConstruction, uint32_t mouse_x, uint32_t mouse_y, uint32_t mouse_h, uint32_t top_x, uint32_t top_y, uint32_t top_h);
void setDisplayMode(DisplayMode mode);
void setRenderMode(RenderMode mode);
void Update(float timeStep, bool mark_new_block = false);
void Update(float timeStep, const Selection &selection, bool mark_new_block = false);
void SetView(const Urho3D::Vector3 &pos);
void GetFlags(std::set<uint32_t> &flags) const;
void ClearFlags(const std::set<uint32_t> &flags);
template<typename C> void RebuildFlags(const C &flags, bool highlight_new);
template<typename C> void RebuildFlags(const C &flags, const Selection &selection, bool highlight_new);
DisplayMode getDisplayMode() const { return displayMode; }
RenderMode getRenderMode() const { return renderMode; }
bool hasFlagsWithNew() const;

View File

@ -981,7 +981,6 @@ void CryptoCityUrho3D::HandleMouseButtonDown(StringHash eventType, VariantMap& e
}
selection.set_rectangle(sx0, sy0, sx1, sy1);
hasSelection_ = true;
cityMesh->setHighlight(GetEffectiveSelection(), GetHoverFlag(), GetSelectedFlag(), flagUnderConstruction, mouse_x, mouse_y, mouse_h, top_x, top_y, top_h);
if (camera_)
camera_->set_target(point);
@ -990,7 +989,6 @@ void CryptoCityUrho3D::HandleMouseButtonDown(StringHash eventType, VariantMap& e
{
selection.clear();
hasSelection_ = false;
cityMesh->setHighlight(GetEffectiveSelection(), GetHoverFlag(), GetSelectedFlag(), flagUnderConstruction, mouse_x, mouse_y, mouse_h, top_x, top_y, top_h);
}
}
}
@ -1046,7 +1044,6 @@ void CryptoCityUrho3D::UpdateTargetting()
selection.set_rectangle(sx0, sy0, sx1, sy1);
if (editMode == EM_SELECT_ELLIPSE)
selection.make_circular();
cityMesh->setHighlight(GetEffectiveSelection(), hover_flag, GetSelectedFlag(), flagUnderConstruction, mouse_x, mouse_y, mouse_h, top_x, top_y, top_h);
}
if (!hover_flag)
{
@ -1387,7 +1384,7 @@ void CryptoCityUrho3D::RebuildMap()
current_flags.erase(f->id);
if (!current_flags.empty())
cityMesh->ClearFlags(current_flags);
cityMesh->RebuildFlags(res, false);
cityMesh->RebuildFlags(res, GetEffectiveSelection(), false);
gameState.clear_dirty_flags();
mark_new_block = true;
}
@ -1655,13 +1652,11 @@ void CryptoCityUrho3D::HandleUpdate(StringHash eventType, VariantMap& eventData)
// Take the frame time step, which is stored as a float
float timeStep = eventData[P_TIMESTEP].GetFloat();
// Move the camera, scale movement with time step
MoveCamera(timeStep);
cityMesh->SetView(cameraNode_->GetWorldPosition());
cityMesh->Update(timeStep, mark_new_block);
cityMesh->setHighlight(GetEffectiveSelection(), GetHoverFlag(), GetSelectedFlag(), flagUnderConstruction, mouse_x, mouse_y, mouse_h, top_x, top_y, top_h);
UpdateSky();
auto* input = GetSubsystem<Input>();
cityMesh->Update(timeStep, GetEffectiveSelection(), mark_new_block);
{
auto dirty_flags = gameState.get_dirty_flags();
@ -1700,14 +1695,11 @@ void CryptoCityUrho3D::HandleUpdate(StringHash eventType, VariantMap& eventData)
if (!clear_flags.empty())
cityMesh->ClearFlags(clear_flags);
cityMesh->RebuildFlags(dirty_flags, true);
cityMesh->RebuildFlags(dirty_flags, GetEffectiveSelection(), true);
gameState.clear_dirty_flags();
cityMesh->setHighlight(GetEffectiveSelection(), GetHoverFlag(), GetSelectedFlag(), flagUnderConstruction, mouse_x, mouse_y, mouse_h, top_x, top_y, top_h);
}
// Move the camera, scale movement with time step
MoveCamera(timeStep);
Node *zoneNode = scene_->GetChild("Zone");
if (zoneNode)
{
@ -1716,6 +1708,8 @@ void CryptoCityUrho3D::HandleUpdate(StringHash eventType, VariantMap& eventData)
zoneNode->SetPosition(pos);
}
UpdateSky();
clouds.Update(timeStep, cameraNode_->GetPosition());
horizon.Update(timeStep, cameraNode_->GetPosition());
@ -2766,8 +2760,7 @@ void CryptoCityUrho3D::AddBlock(bool use_selection)
undo.Push({map.get_flag_tiles(flag->id)});
std::deque<std::shared_ptr<Flag>> flags;
flags.push_back(flag);
cityMesh->RebuildFlags(flags, false);
cityMesh->setHighlight(GetEffectiveSelection(), GetHoverFlag(), GetSelectedFlag(), flagUnderConstruction, mouse_x, mouse_y, mouse_h, top_x, top_y, top_h);
cityMesh->RebuildFlags(flags, GetEffectiveSelection(), false);
}
flag->budget = flag_budget;
}
@ -2942,8 +2935,7 @@ void CryptoCityUrho3D::RemoveBlock(bool use_selection, bool top_level)
undo.Push({map.get_flag_tiles(flag->id)});
std::deque<std::shared_ptr<Flag>> flags;
flags.push_back(flag);
cityMesh->RebuildFlags(flags, false);
cityMesh->setHighlight(GetEffectiveSelection(), GetHoverFlag(), GetSelectedFlag(), flagUnderConstruction, mouse_x, mouse_y, mouse_h, top_x, top_y, top_h);
cityMesh->RebuildFlags(flags, GetEffectiveSelection(), false);
}
}
@ -3124,10 +3116,7 @@ void CryptoCityUrho3D::Undo()
}
auto state = undo.Undo();
map.set_flag_tiles(std::get<0>(*flagUnderConstruction), state.tiles);
std::deque<std::shared_ptr<Flag>> flags;
flags.push_back(flag);
cityMesh->RebuildFlags(flags, false);
cityMesh->setHighlight(GetEffectiveSelection(), GetHoverFlag(), GetSelectedFlag(), flagUnderConstruction, mouse_x, mouse_y, mouse_h, top_x, top_y, top_h);
gameState.add_dirty_flag(flag);
}
void CryptoCityUrho3D::HandleRedo(StringHash eventType, VariantMap& eventData)
@ -3153,10 +3142,7 @@ void CryptoCityUrho3D::Redo()
}
auto state = undo.Redo();
map.set_flag_tiles(std::get<0>(*flagUnderConstruction), state.tiles);
std::deque<std::shared_ptr<Flag>> flags;
flags.push_back(flag);
cityMesh->RebuildFlags(flags, true);
cityMesh->setHighlight(GetEffectiveSelection(), GetHoverFlag(), GetSelectedFlag(), flagUnderConstruction, mouse_x, mouse_y, mouse_h, top_x, top_y, top_h);
gameState.add_dirty_flag(flag);
}
void CryptoCityUrho3D::HandleLoadModel(StringHash eventType, VariantMap& eventData)
@ -3298,10 +3284,7 @@ void CryptoCityUrho3D::HandleLoadModel(StringHash eventType, VariantMap& eventDa
new MessageBox(context_, msg.c_str(), ok ? String(partial ? "Partial model loaded" : "Model loaded") : String("Error placing model"));
undo.Push({map.get_flag_tiles(flag->id)});
std::deque<std::shared_ptr<Flag>> flags;
flags.push_back(flag);
cityMesh->RebuildFlags(flags, false);
cityMesh->setHighlight(GetEffectiveSelection(), GetHoverFlag(), GetSelectedFlag(), flagUnderConstruction, mouse_x, mouse_y, mouse_h, top_x, top_y, top_h);
gameState.add_dirty_flag(flag);
}
void CryptoCityUrho3D::HandleSaveModel(StringHash eventType, VariantMap& eventData)
@ -3813,10 +3796,7 @@ void CryptoCityUrho3D::RestoreFlagUnderConstruction()
flag->palette = std::get<1>(*flagUnderConstruction);
map.set_flag_tiles(std::get<0>(*flagUnderConstruction), original_tiles);
SetNoFlagUnderConstruction();
std::deque<std::shared_ptr<Flag>> flags;
flags.push_back(flag);
cityMesh->RebuildFlags(flags, false);
cityMesh->setHighlight(GetEffectiveSelection(), GetHoverFlag(), GetSelectedFlag(), flagUnderConstruction, mouse_x, mouse_y, mouse_h, top_x, top_y, top_h);
gameState.add_dirty_flag(flag);
}
void CryptoCityUrho3D::HandleExit(StringHash eventType, VariantMap& eventData)
@ -4059,10 +4039,7 @@ void CryptoCityUrho3D::HandleNewSnapshot(StringHash eventType, VariantMap& event
if (flag)
{
flag->set_tiles(tiles); // reset to under construction state
std::deque<std::shared_ptr<Flag>> flags;
flags.push_back(flag);
cityMesh->RebuildFlags(flags, true);
cityMesh->setHighlight(GetEffectiveSelection(), GetHoverFlag(), GetSelectedFlag(), flagUnderConstruction, mouse_x, mouse_y, mouse_h, top_x, top_y, top_h);
gameState.add_dirty_flag(flag);
}
}
else
@ -4592,14 +4569,12 @@ void CryptoCityUrho3D::HandleExtendSelection(StringHash eventType, VariantMap& e
const int32_t dy1 = eventData[SelectExtend::P_DY1].GetInt();
selection.extend(dx0, dy0, dx1, dy1);
cityMesh->setHighlight(GetEffectiveSelection(), GetHoverFlag(), GetSelectedFlag(), flagUnderConstruction, mouse_x, mouse_y, mouse_h, top_x, top_y, top_h);
}
void CryptoCityUrho3D::HandleGrowSelection(StringHash eventType, VariantMap& eventData)
{
UnsetFocus();
selection.grow();
cityMesh->setHighlight(GetEffectiveSelection(), GetHoverFlag(), GetSelectedFlag(), flagUnderConstruction, mouse_x, mouse_y, mouse_h, top_x, top_y, top_h);
}
void CryptoCityUrho3D::HandleSelectWholeFlag(StringHash eventType, VariantMap& eventData)
@ -4626,22 +4601,18 @@ void CryptoCityUrho3D::HandleSelectWholeFlag(StringHash eventType, VariantMap& e
new MessageBox(context_, "First select part of the desired flag");
return;
}
cityMesh->setHighlight(GetEffectiveSelection(), GetHoverFlag(), GetSelectedFlag(), flagUnderConstruction, mouse_x, mouse_y, mouse_h, top_x, top_y, top_h);
}
void CryptoCityUrho3D::HandleShrinkSelection(StringHash eventType, VariantMap& eventData)
{
UnsetFocus();
selection.shrink();
cityMesh->setHighlight(GetEffectiveSelection(), GetHoverFlag(), GetSelectedFlag(), flagUnderConstruction, mouse_x, mouse_y, mouse_h, top_x, top_y, top_h);
}
void CryptoCityUrho3D::HandleSelectEdge(StringHash eventType, VariantMap& eventData)
{
UnsetFocus();
selection.make_edge();
cityMesh->setHighlight(GetEffectiveSelection(), GetHoverFlag(), GetSelectedFlag(), flagUnderConstruction, mouse_x, mouse_y, mouse_h, top_x, top_y, top_h);
}
void CryptoCityUrho3D::HandleGoToFlag(StringHash eventType, VariantMap& eventData)
@ -4670,7 +4641,6 @@ void CryptoCityUrho3D::HandleGoToFlag(StringHash eventType, VariantMap& eventDat
UITBWindow::CloseModal();
selection = Selection(flag->x0, flag->y0, flag->x1, flag->y1);
cityMesh->setHighlight(GetEffectiveSelection(), GetHoverFlag(), GetSelectedFlag(), flagUnderConstruction, mouse_x, mouse_y, mouse_h, top_x, top_y, top_h);
}
void CryptoCityUrho3D::HandleGetGameUpdateEvents(StringHash eventType, VariantMap& eventData)
@ -5098,10 +5068,7 @@ void CryptoCityUrho3D::HandleSetIgnoreSettings(StringHash eventType, VariantMap&
wallet->get_ignored_flag_ids(ids);
for (uint32_t id: ids)
if (auto f = map.get_flag(id))
res.insert(f);
if (!res.empty())
cityMesh->RebuildFlags(res, false);
gameState.add_dirty_flag(f);
}
}

View File

@ -102,20 +102,6 @@ void Tile::pop()
}
--height;
}
uint8_t Tile::get_type(uint16_t h) const
{
if (h >= height)
throw std::runtime_error("Height overflow");
if (height <= 8)
{
return local_blocks[h];
}
else
{
return remote_blocks[h];
}
}
void Tile::set_type(uint16_t h, uint8_t type)
{

View File

@ -40,7 +40,7 @@ public:
uint16_t get_height() const { return height; }
void push(uint8_t type);
void pop();
uint8_t get_type(uint16_t h) const;
uint8_t get_type(uint16_t h) const { return height <= 8 ? local_blocks[h] : remote_blocks[h]; }
void set_type(uint16_t h, uint8_t type);
private:
@ -90,6 +90,7 @@ public:
void resize(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint8_t stability);
const Tile &tile(uint32_t x, uint32_t y) const { return tiles[(y - y0) * (x1 - x0 + 1) + x - x0]; }
Tile &tile(uint32_t x, uint32_t y) { return tiles[(y - y0) * (x1 - x0 + 1) + x - x0]; }
const Tile* get_raw_tiles() const { return tiles; }
uint8_t get_tile_type(uint32_t x, uint32_t y, uint16_t h) const;
uint16_t get_tile_height(uint32_t x, uint32_t y) const;
uint16_t get_max_height() const;

View File

@ -16,6 +16,7 @@ public:
Selection(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, const std::vector<uint8_t> &selected);
bool operator==(const Selection &s) const;
bool operator!=(const Selection &s) const { return !operator==(s); }
bool is_selected(uint32_t x, uint32_t y) const;
bool is_empty() const;