diff --git a/res/content/base/generators/demo.files/script.lua b/res/content/base/generators/demo.files/script.lua index 00a91691..cd443163 100644 --- a/res/content/base/generators/demo.files/script.lua +++ b/res/content/base/generators/demo.files/script.lua @@ -1,9 +1,8 @@ -BLOCKS_PER_CHUNK = 65536 - local _, dir = parse_path(__DIR__) ores = file.read_combined_list(dir.."/ores.json") local function place_ores(placements, x, z, w, d, seed, hmap, chunk_height) + local BLOCKS_PER_CHUNK = w * d * chunk_height for _, ore in ipairs(ores) do local count = BLOCKS_PER_CHUNK / ore.rarity diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index 925627e7..640fc656 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -17,6 +17,7 @@ #include "graphics/core/Mesh.hpp" #include "graphics/core/Shader.hpp" #include "graphics/core/Texture.hpp" +#include "graphics/core/ImageData.hpp" #include "graphics/render/WorldRenderer.hpp" #include "graphics/ui/elements/InventoryView.hpp" #include "graphics/ui/elements/Menu.hpp" @@ -29,6 +30,8 @@ #include "items/Inventory.hpp" #include "items/ItemDef.hpp" #include "logic/scripting/scripting.hpp" +#include "logic/LevelController.hpp" +#include "world/generator/WorldGenerator.hpp" #include "maths/voxmaths.hpp" #include "objects/Player.hpp" #include "physics/Hitbox.hpp" @@ -140,12 +143,16 @@ std::shared_ptr Hud::createHotbar() { return view; } -Hud::Hud(Engine* engine, LevelFrontend* frontend, Player* player) - : assets(engine->getAssets()), - gui(engine->getGUI()), - frontend(frontend), - player(player) -{ +static constexpr uint WORLDGEN_IMG_SIZE = 64U; + +Hud::Hud(Engine* engine, LevelFrontend* frontend, Player* player) + : assets(engine->getAssets()), + gui(engine->getGUI()), + frontend(frontend), + player(player), + debugImgWorldGen(std::make_unique( + ImageFormat::rgba8888, WORLDGEN_IMG_SIZE, WORLDGEN_IMG_SIZE + )) { contentAccess = createContentAccess(); contentAccess->setId("hud.content-access"); contentAccessPanel = std::make_shared( @@ -177,6 +184,14 @@ Hud::Hud(Engine* engine, LevelFrontend* frontend, Player* player) dplotter->setGravity(Gravity::bottom_right); dplotter->setInteractive(false); add(HudElement(hud_element_mode::permanent, nullptr, dplotter, true)); + + assets->store(Texture::from(debugImgWorldGen.get()), DEBUG_WORLDGEN_IMAGE); + + add(HudElement(hud_element_mode::permanent, nullptr, + guiutil::create( + "" + ), true)); } Hud::~Hud() { @@ -250,6 +265,40 @@ void Hud::updateHotbarControl() { } } +void Hud::updateWorldGenDebugVisualization() { + auto level = frontend->getLevel(); + auto generator = + frontend->getController()->getChunksController()->getGenerator(); + auto debugInfo = generator->createDebugInfo(); + uint width = debugImgWorldGen->getWidth(); + uint height = debugImgWorldGen->getHeight(); + ubyte* data = debugImgWorldGen->getData(); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + if (x >= debugInfo.areaWidth || y >= debugInfo.areaHeight) { + for (int i = 0; i < 4; i++) { + data[(y * width + x) * 4 + i] = 0; + } + continue; + } + int cx = x + debugInfo.areaOffsetX; + int cz = y + debugInfo.areaOffsetY; + auto value = debugInfo.areaLevels[y * debugInfo.areaWidth + x] * 35; + // Chunk is already generated + if (level->chunks->getChunk(cx, cz)) { + value = 255; + } + for (int i = 0; i < 3; i++) { + data[(y * width + x) * 4 + i] = value; + } + data[(y * width + x) * 4 + 3] = 100; + } + } + + auto texture = assets->get(DEBUG_WORLDGEN_IMAGE); + texture->reload(*debugImgWorldGen); +} + void Hud::update(bool visible) { auto level = frontend->getLevel(); auto menu = gui->getMenu(); @@ -296,6 +345,10 @@ void Hud::update(bool visible) { } } cleanup(); + + if (player->debug) { + updateWorldGenDebugVisualization(); + } } /// @brief Show inventory on the screen and turn on inventory mode blocking movement diff --git a/src/frontend/hud.hpp b/src/frontend/hud.hpp index 26d0d9d3..05e93e32 100644 --- a/src/frontend/hud.hpp +++ b/src/frontend/hud.hpp @@ -18,6 +18,7 @@ class LevelFrontend; class UiDocument; class DrawContext; class Viewport; +class ImageData; namespace gui { class GUI; @@ -107,6 +108,8 @@ class Hud : public util::ObjectsKeeper { /// @brief UI element will be dynamicly positioned near to inventory or in screen center std::shared_ptr secondUI = nullptr; + + std::unique_ptr debugImgWorldGen; std::shared_ptr createContentAccess(); std::shared_ptr createHotbar(); @@ -117,6 +120,7 @@ class Hud : public util::ObjectsKeeper { void cleanup(); void showExchangeSlot(); + void updateWorldGenDebugVisualization(); public: Hud(Engine* engine, LevelFrontend* frontend, Player* player); ~Hud(); @@ -167,4 +171,7 @@ public: Player* getPlayer() const; std::shared_ptr getBlockInventory(); + + /// @brief Runtime updating debug visualization texture + inline static std::string DEBUG_WORLDGEN_IMAGE = "#debug.img.worldgen"; }; diff --git a/src/graphics/core/GLTexture.cpp b/src/graphics/core/GLTexture.cpp index 9a47ef22..9572f415 100644 --- a/src/graphics/core/GLTexture.cpp +++ b/src/graphics/core/GLTexture.cpp @@ -41,7 +41,13 @@ void GLTexture::unbind() { glBindTexture(GL_TEXTURE_2D, 0); } -void GLTexture::reload(const ubyte* data){ +void GLTexture::reload(const ImageData& image) { + width = image.getWidth(); + height = image.getHeight(); + reload(image.getData()); +} + +void GLTexture::reload(const ubyte* data) { glBindTexture(GL_TEXTURE_2D, id); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, static_cast(data)); diff --git a/src/graphics/core/GLTexture.hpp b/src/graphics/core/GLTexture.hpp index 10e002e9..7f9e8f22 100644 --- a/src/graphics/core/GLTexture.hpp +++ b/src/graphics/core/GLTexture.hpp @@ -16,6 +16,8 @@ public: void setNearestFilter(); + virtual void reload(const ImageData& image) override; + virtual std::unique_ptr readData() override; virtual uint getId() const override; diff --git a/src/graphics/core/Texture.hpp b/src/graphics/core/Texture.hpp index 9e16f670..4b3f1651 100644 --- a/src/graphics/core/Texture.hpp +++ b/src/graphics/core/Texture.hpp @@ -20,6 +20,8 @@ public: virtual void bind() = 0; virtual void unbind() = 0; + virtual void reload(const ImageData& image) = 0; + virtual std::unique_ptr readData() = 0; virtual uint getWidth() const { diff --git a/src/logic/ChunksController.hpp b/src/logic/ChunksController.hpp index 85b00e8a..8566ee1b 100644 --- a/src/logic/ChunksController.hpp +++ b/src/logic/ChunksController.hpp @@ -33,4 +33,8 @@ public: int loadDistance, int centerX, int centerY); + + const WorldGenerator* getGenerator() const { + return generator.get(); + } }; diff --git a/src/logic/LevelController.cpp b/src/logic/LevelController.cpp index 1e947b42..f0bee4c5 100644 --- a/src/logic/LevelController.cpp +++ b/src/logic/LevelController.cpp @@ -95,6 +95,10 @@ BlocksController* LevelController::getBlocksController() { return blocks.get(); } +ChunksController* LevelController::getChunksController() { + return chunks.get(); +} + PlayerController* LevelController::getPlayerController() { return player.get(); } diff --git a/src/logic/LevelController.hpp b/src/logic/LevelController.hpp index fe16ed19..a2c5af3e 100644 --- a/src/logic/LevelController.hpp +++ b/src/logic/LevelController.hpp @@ -34,5 +34,6 @@ public: Player* getPlayer(); BlocksController* getBlocksController(); + ChunksController* getChunksController(); PlayerController* getPlayerController(); }; diff --git a/src/world/generator/WorldGenerator.cpp b/src/world/generator/WorldGenerator.cpp index 2043b7a7..365a63fc 100644 --- a/src/world/generator/WorldGenerator.cpp +++ b/src/world/generator/WorldGenerator.cpp @@ -355,3 +355,21 @@ void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ) { } } } + +WorldGenDebugInfo WorldGenerator::createDebugInfo() const { + const auto& area = surroundMap.getArea(); + const auto& levels = area.getBuffer(); + auto values = std::make_unique(area.getWidth()*area.getHeight()); + + for (uint i = 0; i < levels.size(); i++) { + values[i] = levels[i]; + } + + return WorldGenDebugInfo { + area.getOffsetX(), + area.getOffsetY(), + static_cast(area.getWidth()), + static_cast(area.getHeight()), + std::move(values) + }; +} diff --git a/src/world/generator/WorldGenerator.hpp b/src/world/generator/WorldGenerator.hpp index 9b90cb3f..7490ef4d 100644 --- a/src/world/generator/WorldGenerator.hpp +++ b/src/world/generator/WorldGenerator.hpp @@ -34,6 +34,14 @@ struct ChunkPrototype { std::vector structures; }; +struct WorldGenDebugInfo { + int areaOffsetX; + int areaOffsetY; + uint areaWidth; + uint areaHeight; + std::unique_ptr areaLevels; +}; + /// @brief High-level world generation controller class WorldGenerator { /// @param def generator definition @@ -80,5 +88,8 @@ public: /// @param z chunk position Y divided by CHUNK_D void generate(voxel* voxels, int x, int z); + WorldGenDebugInfo createDebugInfo() const; + + /// @brief Default generator name // TODO: move to config inline static std::string DEFAULT = "core:default"; };