From d4b2bb0958348f4df6b061f763a5250d87816168 Mon Sep 17 00:00:00 2001 From: Alexey Nabrodov Date: Sat, 9 Sep 2017 17:58:08 +0300 Subject: [PATCH] background generating and terrain type selection (test) --- CMakeLists.txt | 7 +- include/mapgen/MapGenerator.hpp | 5 ++ src/MapGenerator.cpp | 67 +++++++++++++--- src/main.cpp | 138 ++++++++++++++++++++++---------- src/objectsWindow.cpp | 2 +- 5 files changed, 164 insertions(+), 55 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 465302c..0ade6a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,10 @@ add_executable(${EXECUTABLE_NAME} src/Region.cpp ) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-reorder") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-variable") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-but-set-variable") @@ -76,7 +79,7 @@ if (OPENGL_FOUND) target_link_libraries(${EXECUTABLE_NAME} ${OPENGL_LIBRARIES}) endif() -target_link_libraries(${EXECUTABLE_NAME} voronoi noise imgui sw) +target_link_libraries(${EXECUTABLE_NAME} voronoi noise imgui sw Threads::Threads) target_compile_features(mapgen PRIVATE cxx_delegating_constructors) diff --git a/include/mapgen/MapGenerator.hpp b/include/mapgen/MapGenerator.hpp index 93657ad..86380fc 100644 --- a/include/mapgen/MapGenerator.hpp +++ b/include/mapgen/MapGenerator.hpp @@ -31,12 +31,15 @@ class MapGenerator { std::vector* getPolygons(); void seed(); std::vector* getRegions(); + void setMapTemplate(const char* t); std::vector rivers; std::vector clusters; std::vector megaClusters; bool simpleRivers; + bool ready; + std::string currentOperation; private: void regenHeight(); @@ -49,6 +52,7 @@ class MapGenerator { void makeRiver(Cell* c); void calcHumidity(); void simplifyRivers(); + // module::Module& getSourceModule(); int _seed; VoronoiDiagramGenerator _vdg; int _pointsCount; @@ -68,6 +72,7 @@ class MapGenerator { module::Perlin _perlin; utils::NoiseMap _heightMap; std::vector* _regions; + std::string _terrainType; template Iter select_randomly(Iter start, Iter end); diff --git a/src/MapGenerator.cpp b/src/MapGenerator.cpp index 4f5bfaf..94673bb 100644 --- a/src/MapGenerator.cpp +++ b/src/MapGenerator.cpp @@ -57,11 +57,13 @@ Iter MapGenerator::select_randomly(Iter start, Iter end, int s) { MapGenerator::MapGenerator(int w, int h): _w(w), _h(h) { _vdg = VoronoiDiagramGenerator(); _pointsCount = 10000; - _octaves = 3; + _octaves = 4; _freq = 0.3; _relax = DEFAULT_RELAX; _regions = new std::vector(); simpleRivers = true; + _terrainType = "basic"; + currentOperation = ""; } void MapGenerator::build() { @@ -79,6 +81,7 @@ void MapGenerator::relax() { } void MapGenerator::simplifyRivers() { + currentOperation = "Simplify rivers..."; for (auto r : rivers) { PointList* rvr = r->points; PointList sr; @@ -180,6 +183,7 @@ void MapGenerator::setPointCount(int c) { void MapGenerator::update() { + ready = false; regenHeight(); regenDiagram(); regenRegions(); @@ -190,10 +194,12 @@ void MapGenerator::update() { } calcHumidity(); regenMegaClusters(); + ready = true; } void MapGenerator::forceUpdate() { // regenHeight(); + ready = false; regenDiagram(); regenRegions(); regenClusters(); @@ -201,15 +207,50 @@ void MapGenerator::forceUpdate() { simplifyRivers(); calcHumidity(); regenMegaClusters(); + ready = true; +} + +void MapGenerator::setMapTemplate(const char* templateName) { + _terrainType = std::string(templateName); } void MapGenerator::regenHeight() { + currentOperation = "Making mountains and seas..."; + utils::NoiseMapBuilderPlane heightMapBuilder; + heightMapBuilder.SetDestNoiseMap(_heightMap); + _perlin.SetSeed(_seed); _perlin.SetOctaveCount(_octaves); _perlin.SetFrequency(_freq); - utils::NoiseMapBuilderPlane heightMapBuilder; - heightMapBuilder.SetSourceModule(_perlin); - heightMapBuilder.SetDestNoiseMap(_heightMap); + + module::Perlin terrainType; + module::RidgedMulti mountainTerrain; + module::Select finalTerrain; + + if (_terrainType == "archipelago") { + + terrainType.SetFrequency (0.8); + terrainType.SetPersistence (0.5); + + terrainType.SetSeed(_seed); + mountainTerrain.SetSeed(_seed); + + // module::ScaleBias flatTerrain; + // flatTerrain.SetSourceModule (0, _perlin); + // flatTerrain.SetScale (0.025); + // flatTerrain.SetBias (-0.75); + + finalTerrain.SetSourceModule (0, _perlin); + finalTerrain.SetSourceModule (1, mountainTerrain); + finalTerrain.SetControlModule (terrainType); + finalTerrain.SetBounds (0.0, 100.0); + finalTerrain.SetEdgeFalloff (0.125); + heightMapBuilder.SetSourceModule(terrainType); + + } else { + heightMapBuilder.SetSourceModule(_perlin); + } + heightMapBuilder.SetDestSize(_w, _h); heightMapBuilder.SetBounds(0.0, 10.0, 0.0, 10.0); heightMapBuilder.Build(); @@ -217,13 +258,14 @@ void MapGenerator::regenHeight() { } void MapGenerator::makeRiver(Cell* c) { + currentOperation = "Making rivers..."; std::vector visited; - printf("First cell: %p\n", c); + // printf("First cell: %p\n", c); Region* r = _cells[c]; - printf("First biom: %s\n", r->biom.name.c_str()); + // printf("First biom: %s\n", r->biom.name.c_str()); // r->biom = MARK; float z = r->getHeight(r->site); - printf("First vert: %f\n", z); + // printf("First vert: %f\n", z); River *rvr = new River(); std::string fn = *select_randomly(river_first_names.begin(), river_first_names.end(), std::clock()); @@ -244,7 +286,7 @@ void MapGenerator::makeRiver(Cell* c) { } int count = 0; - while (z > 0.f && count < 100) { + while (z >= -0.01 && count < 100) { std::vector n = c->getNeighbors(); Cell* end; for (Cell* c2 : n) { @@ -288,9 +330,10 @@ void MapGenerator::makeRiver(Cell* c) { } void MapGenerator::regenRivers() { + currentOperation = "Making rivers..."; rivers.clear(); for (auto cluster : clusters){ - if (cluster->biom.name == "Snow" || cluster->biom.name == "Rock") { + if ((cluster->biom.name == "Snow" || cluster->biom.name == "Rock") && cluster->regions.size() > 10) { Cell* c = cellsMap[*select_randomly(cluster->regions.begin(), cluster->regions.end())]; if (c != nullptr) { makeRiver(c); @@ -300,6 +343,7 @@ void MapGenerator::regenRivers() { } void MapGenerator::regenRegions() { + currentOperation = "Splitting nothing..."; _cells.clear(); _regions->clear(); _regions->reserve(_diagram->cells.size()); @@ -356,6 +400,7 @@ bool isDiscard(const Cluster* c) } void MapGenerator::calcHumidity() { + currentOperation = "Making world moist..."; for (auto r : *_regions) { if(r->hasRiver) { r->humidity += 0.1; @@ -376,6 +421,7 @@ void MapGenerator::calcHumidity() { } void MapGenerator::regenMegaClusters() { + currentOperation = "Finding far lands..."; megaClusters.clear(); std::map _megaClusters; for (auto c : clusters) { @@ -461,6 +507,7 @@ void MapGenerator::regenMegaClusters() { } void MapGenerator::regenClusters() { + currentOperation = "Meeting with neighbors..."; clusters.clear(); cellsMap.clear(); std::map _clusters; @@ -568,11 +615,13 @@ int MapGenerator::getRelax() { } void MapGenerator::regenDiagram() { + currentOperation = "Making nothing..."; _bbox = sf::Rect(0,0,_w, _h); _sites = new std::vector>(); genRandomSites(*_sites, _bbox, _w, _h, _pointsCount); _diagram.reset(_vdg.compute(*_sites, _bbox)); for (int n = 0; n < _relax; n++) { + currentOperation = "Relaxing..."; makeRelax(); } delete _sites; diff --git a/src/main.cpp b/src/main.cpp index 4d5dddc..ae4cae9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -27,6 +28,7 @@ bool heights; bool flat; bool hum; bool simplifyRivers; +int t = 0; int main() { @@ -61,6 +63,9 @@ int main() std::vector verticies; sf::Color bgColor; float color[3] = { 0.12, 0.12, 0.12 }; + + std::thread generator([&](){}); + auto updateVisuals = [&](){ log.AddLog("Update geometry\n"); polygons.clear(); @@ -123,6 +128,15 @@ int main() } }; + auto regen = [&](){ + generator.join(); + generator = std::thread([&](){ + mapgen.update(); + seed = mapgen.getSeed(); + relax = mapgen.getRelax(); + updateVisuals(); + });}; + bgColor.r = static_cast(color[0] * 255.f); bgColor.g = static_cast(color[1] * 255.f); bgColor.b = static_cast(color[2] * 255.f); @@ -133,11 +147,21 @@ int main() window.resetGLStates(); // call it if you only draw ImGui. Otherwise not needed. mapgen.setSeed(111629613 /*81238299*/); - mapgen.update(); - seed = mapgen.getSeed(); - updateVisuals(); + regen(); + + sw::ProgressBar progressBar; + progressBar.setShowBackgroundAndFrame(true); + progressBar.setSize(sf::Vector2f(400, 10)); + progressBar.setPosition((sf::Vector2f(window.getSize()) - progressBar.getSize()) / 2.f); + bool isIncreasing{ true }; + + sf::Font sffont; + sffont.loadFromFile("/home/alexeynabrodov/.fonts/FiraCode-Medium.otf"); sf::Clock deltaClock; + sf::Clock clock; + + bool faded = false; while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { @@ -150,11 +174,8 @@ int main() { case sf::Keyboard::R: mapgen.seed(); - seed = mapgen.getSeed(); log.AddLog("Update map\n"); - mapgen.update(); - updateVisuals(); - relax = mapgen.getRelax(); + regen(); break; case sf::Keyboard::Escape: window.close(); @@ -188,8 +209,51 @@ int main() } } - ImGui::SFML::Update(window, deltaClock.restart()); + if (!mapgen.ready) { + // window.clear(bgColor); + if (!faded) { + sf::RectangleShape rectangle; + rectangle.setSize(sf::Vector2f(window.getSize().x, window.getSize().y)); + auto color = sf::Color::Black; + color.a = 150; + rectangle.setFillColor(color); + rectangle.setPosition(0, 0); + window.draw(rectangle); + faded = true; + } + const float frame{ clock.restart().asSeconds() * 0.3f }; + const float target{ isIncreasing ? progressBar.getRatio() + frame : progressBar.getRatio() - frame }; + if (target < 0.f) + isIncreasing = true; + else if (target > 1.f) + isIncreasing = false; + progressBar.setRatio(target); + // Create a text + sf::Text operation(mapgen.currentOperation, sffont); + operation.setCharacterSize(20); + // operation.setStyle(sf::Text::Bold); + operation.setColor(sf::Color::White); + + auto middle = (sf::Vector2f(window.getSize())) / 2.f; + operation.setPosition(sf::Vector2f(middle.x - operation.getGlobalBounds().width/2.f, middle.y+25.f)); + + window.draw(progressBar); + + sf::RectangleShape bg; + bg.setSize(sf::Vector2f(420, 40)); + bg.setFillColor(sf::Color::Black); + bg.setOutlineColor(sf::Color::White); + bg.setOutlineThickness(1); + middle = (sf::Vector2f(window.getSize()) - bg.getSize()) / 2.f; + bg.setPosition(sf::Vector2f(middle.x, middle.y + 37.f)); + window.draw(bg); + window.draw(operation); + window.display(); + continue; + } + faded = false; + ImGui::SFML::Update(window, deltaClock.restart()); ImGui::Begin("Mapgen"); // begin window ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGui::Text("Polygons: %zu", polygons.size()); @@ -228,23 +292,24 @@ int main() ImGui::SameLine(100); if(ImGui::Checkbox("Simplify rivers",&simplifyRivers)) { mapgen.simpleRivers = simplifyRivers; - mapgen.update(); + regen(); } if (ImGui::InputInt("Seed", &seed)) { mapgen.setSeed(seed); log.AddLog("Update map\n"); - mapgen.update(); - updateVisuals(); - relax = mapgen.getRelax(); + regen(); } + + const char* templates[] = {"basic", "archipelago"}; + if (ImGui::Combo("Map template", &t, templates, 2)) { + mapgen.setMapTemplate(templates[t]); + regen(); + } + if (ImGui::Button("Random")) { mapgen.seed(); - seed = mapgen.getSeed(); - log.AddLog("Update map\n"); - mapgen.update(); - updateVisuals(); - relax = mapgen.getRelax(); + regen(); } ImGui::SameLine(100); if (ImGui::Button("Update")) { @@ -257,10 +322,7 @@ int main() octaves = 1; } mapgen.setOctaveCount(octaves); - log.AddLog("Update map\n"); - mapgen.update(); - updateVisuals(); - relax = mapgen.getRelax(); + regen(); } if (ImGui::InputFloat("Height freq", &freq)) { @@ -268,9 +330,7 @@ int main() freq = 0; } mapgen.setFrequency(freq); - log.AddLog("Update map\n"); - mapgen.update(); - updateVisuals(); + regen(); } if (ImGui::InputInt("Points", &nPoints)) { @@ -278,36 +338,27 @@ int main() nPoints = 5; } mapgen.setPointCount(nPoints); - log.AddLog("Update map\n"); - mapgen.update(); - updateVisuals(); - relax = mapgen.getRelax(); + regen(); } - if (ImGui::Button("Relax")) { - log.AddLog("Update map\n"); - mapgen.relax(); - updateVisuals(); - relax = mapgen.getRelax(); - } - ImGui::SameLine(100); + // if (ImGui::Button("Relax")) { + // log.AddLog("Update map\n"); + // mapgen.relax(); + // updateVisuals(); + // relax = mapgen.getRelax(); + // } + // ImGui::SameLine(100); ImGui::Text("Relax iterations: %d", relax); if (ImGui::Button("+1000")) { nPoints+=1000; mapgen.setPointCount(nPoints); - log.AddLog("Update map\n"); - mapgen.update(); - updateVisuals(); - relax = mapgen.getRelax(); + regen(); } ImGui::SameLine(100); if (ImGui::Button("-1000")) { nPoints-=1000; mapgen.setPointCount(nPoints); - log.AddLog("Update map\n"); - mapgen.update(); - updateVisuals(); - relax = mapgen.getRelax(); + regen(); } ImGui::Text("\n[ESC] for exit\n[S] for save screenshot\n[R] for random map"); @@ -446,5 +497,6 @@ int main() window.display(); } + generator.join(); ImGui::SFML::Shutdown(); } diff --git a/src/objectsWindow.cpp b/src/objectsWindow.cpp index ca36e81..bbd1da7 100644 --- a/src/objectsWindow.cpp +++ b/src/objectsWindow.cpp @@ -161,7 +161,7 @@ std::vector objectsWindow(sf::RenderWindow* window, MapGenerato auto n = int(river->points->size()); char rn[30]; - sprintf(rn,"%s: %%d points", river->name.c_str()); + sprintf(rn,"%s [%p]: %%d points", river->name.c_str(), river); ImGuiTreeNodeFlags node_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | (rivers_selection_mask[in] ? ImGuiTreeNodeFlags_Selected : 0); bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)n, node_flags, rn, n); if (ImGui::IsItemClicked()) {