From 9e059e1008760de0ae72cb3cd475541de071b46b Mon Sep 17 00:00:00 2001 From: Skarn Date: Thu, 6 Jan 2022 20:46:58 +0300 Subject: [PATCH] Separate other rendering parts | Update ChunkWater.cpp, MapTile.cpp, and 9 more files... --- src/noggit/ChunkWater.cpp | 19 +- src/noggit/MapTile.cpp | 89 +------- src/noggit/MapTile.h | 24 +- src/noggit/MapView.cpp | 2 +- src/noggit/TileWater.cpp | 238 +------------------- src/noggit/TileWater.hpp | 36 ++- src/noggit/rendering/FlightBoundsRender.cpp | 87 +++++++ src/noggit/rendering/FlightBoundsRender.hpp | 40 ++++ src/noggit/rendering/LiquidRender.cpp | 232 +++++++++++++++++++ src/noggit/rendering/LiquidRender.hpp | 69 ++++++ src/noggit/rendering/WorldRender.cpp | 5 +- 11 files changed, 474 insertions(+), 367 deletions(-) create mode 100644 src/noggit/rendering/FlightBoundsRender.cpp create mode 100644 src/noggit/rendering/FlightBoundsRender.hpp create mode 100644 src/noggit/rendering/LiquidRender.cpp create mode 100644 src/noggit/rendering/LiquidRender.hpp diff --git a/src/noggit/ChunkWater.cpp b/src/noggit/ChunkWater.cpp index 4cd3d1d3..c8ff63f5 100644 --- a/src/noggit/ChunkWater.cpp +++ b/src/noggit/ChunkWater.cpp @@ -45,19 +45,15 @@ void ChunkWater::from_mclq(std::vector& layers) switch (mclq_liquid_type) { case 1: - _water_tile->registerNewChunk(_layers.size()); _layers.emplace_back(this, pos, liquid, 2); break; case 3: - _water_tile->registerNewChunk(_layers.size()); _layers.emplace_back(this, pos, liquid, 4); break; case 4: - _water_tile->registerNewChunk(_layers.size()); _layers.emplace_back(this, pos, liquid, 1); break; case 6: - _water_tile->registerNewChunk(_layers.size()); _layers.emplace_back(this, pos, liquid, (_use_mclq_green_lava ? 15 : 3)); break; @@ -65,6 +61,7 @@ void ChunkWater::from_mclq(std::vector& layers) LogError << "Invalid/unhandled MCLQ liquid type" << std::endl; break; } + _water_tile->tagUpdate(); } update_layers(); } @@ -106,7 +103,7 @@ void ChunkWater::fromFile(BlizzardArchive::ClientFile &f, size_t basePos) } glm::vec3 pos(xbase, 0.0f, zbase); - _water_tile->registerNewChunk(_layers.size()); + _water_tile->tagUpdate(); _layers.emplace_back(this, f, basePos, pos, info, infoMask); } @@ -177,7 +174,7 @@ void ChunkWater::setType(int type, size_t layer) { _layers[layer].changeLiquidID(type); } - _water_tile->updateLayer(layer); + _water_tile->tagUpdate(); } bool ChunkWater::is_visible ( const float& cull_distance @@ -212,7 +209,7 @@ void ChunkWater::update_layers() extents[0].y = std::min(extents[0].y, vmin.y); extents[1].y = std::max(extents[1].y, vmax.y); - _water_tile->updateLayer(count); + _water_tile->tagUpdate(); count++; } @@ -258,7 +255,7 @@ void ChunkWater::paintLiquid( glm::vec3 const& pos { liquid_layer layer(this, glm::vec3(xbase, 0.0f, zbase), pos.y, liquid_id); copy_height_to_layer(layer, pos, radius); - _water_tile->registerNewChunk(_layers.size()); + _water_tile->tagUpdate(); _layers.push_back(layer); } } @@ -292,14 +289,14 @@ void ChunkWater::paintLiquid( glm::vec3 const& pos layer.clear(); // remove the liquid to not override the other layer layer.paintLiquid(pos, radius, true, angle, orientation, lock, origin, override_height, chunk, opacity_factor); layer.changeLiquidID(liquid_id); - _water_tile->registerNewChunk(_layers.size()); + _water_tile->tagUpdate(); _layers.push_back(layer); } else { liquid_layer layer(this, glm::vec3(xbase, 0.0f, zbase), pos.y, liquid_id); layer.paintLiquid(pos, radius, true, angle, orientation, lock, origin, override_height, chunk, opacity_factor); - _water_tile->registerNewChunk(_layers.size()); + _water_tile->tagUpdate(); _layers.push_back(layer); } @@ -313,7 +310,7 @@ void ChunkWater::cleanup() if (_layers[i].empty()) { _layers.erase(_layers.begin() + i); - _water_tile->unregisterChunk(i); + _water_tile->tagUpdate(); } } } diff --git a/src/noggit/MapTile.cpp b/src/noggit/MapTile.cpp index c38d643d..b2e3e047 100644 --- a/src/noggit/MapTile.cpp +++ b/src/noggit/MapTile.cpp @@ -44,6 +44,7 @@ MapTile::MapTile( int pX ) : AsyncObject(pFilename) , _renderer(this) + , _fl_bounds_render(this) , index(TileIndex(pX, pZ)) , xbase(pX * TILESIZE) , zbase(pZ * TILESIZE) @@ -438,94 +439,6 @@ bool MapTile::intersect (math::ray const& ray, selection_result* results) const return false; } - -void MapTile::drawMFBO (OpenGL::Scoped::use_program& mfbo_shader) -{ - static std::vector const indices = {4, 1, 2, 5, 8, 7, 6, 3, 0, 1, 0, 3, 6, 7, 8, 5, 2, 1}; - - if (!_mfbo_buffer_are_setup) - { - _mfbo_vbos.upload(); - _mfbo_vaos.upload(); - - - - gl.bufferData( _mfbo_bottom_vbo - , 9 * sizeof(glm::vec3) - , mMinimumValues - , GL_STATIC_DRAW - ); - gl.bufferData( _mfbo_top_vbo - , 9 * sizeof(glm::vec3) - , mMaximumValues - , GL_STATIC_DRAW - ); - - { - OpenGL::Scoped::vao_binder const _ (_mfbo_bottom_vao); - OpenGL::Scoped::buffer_binder const vbo_binder (_mfbo_bottom_vbo); - mfbo_shader.attrib("position", 3, GL_FLOAT, GL_FALSE, 0, 0); - } - - { - OpenGL::Scoped::vao_binder const _(_mfbo_top_vao); - OpenGL::Scoped::buffer_binder const vbo_binder(_mfbo_top_vbo); - mfbo_shader.attrib("position", 3, GL_FLOAT, GL_FALSE, 0, 0); - } - - { - OpenGL::Scoped::buffer_binder ibo_binder(_mfbo_indices); - gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(uint16_t), indices.data(), GL_STATIC_DRAW); - } - - _mfbo_buffer_are_setup = true; - } - - { - OpenGL::Scoped::vao_binder const _(_mfbo_bottom_vao); - OpenGL::Scoped::buffer_binder ibo_binder(_mfbo_indices); - - mfbo_shader.uniform("color", glm::vec4(1.0f, 1.0f, 0.0f, 0.2f)); - gl.drawElements(GL_TRIANGLE_FAN, indices.size(), GL_UNSIGNED_BYTE, nullptr); - } - - { - OpenGL::Scoped::vao_binder const _(_mfbo_top_vao); - OpenGL::Scoped::buffer_binder ibo_binder(_mfbo_indices); - - mfbo_shader.uniform("color", glm::vec4(0.0f, 1.0f, 1.0f, 0.2f)); - gl.drawElements(GL_TRIANGLE_FAN, indices.size(), GL_UNSIGNED_BYTE, nullptr); - } - -} - -void MapTile::drawWater ( math::frustum const& frustum - , const glm::vec3& camera - , bool camera_moved - , OpenGL::Scoped::use_program& water_shader - , int animtime - , int layer - , display_mode display - , LiquidTextureManager* tex_manager - ) -{ - if (!Water.hasData()) - { - return; //no need to draw water on tile without water =) - } - - // process water bounds - Water.draw ( frustum - , camera - , camera_moved - , water_shader - , animtime - , layer - , display - , tex_manager - ); -} - MapChunk* MapTile::getChunk(unsigned int x, unsigned int z) { if (x < 16 && z < 16) diff --git a/src/noggit/MapTile.h b/src/noggit/MapTile.h index 9a134d58..02715535 100644 --- a/src/noggit/MapTile.h +++ b/src/noggit/MapTile.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -30,6 +31,7 @@ namespace math namespace Noggit::Rendering { class TileRender; + class FlightBoundsRender; } class World; @@ -38,6 +40,7 @@ class World; class MapTile : public AsyncObject { friend class Noggit::Rendering::TileRender; + friend class Noggit::Rendering::FlightBoundsRender; friend class MapChunk; friend class TextureSet; @@ -99,17 +102,6 @@ public: bool intersect (math::ray const&, selection_result*) const; - void drawWater ( math::frustum const& frustum - , const glm::vec3& camera - , bool camera_moved - , OpenGL::Scoped::use_program& water_shader - , int animtime - , int layer - , display_mode display - , LiquidTextureManager* tex_manager - ); - - void drawMFBO (OpenGL::Scoped::use_program&); bool GetVertex(float x, float z, glm::vec3 *V); void getVertexInternal(float x, float z, glm::vec3* v); @@ -173,6 +165,7 @@ public: void tagCombinedExtents(bool state) { _combined_extents_dirty = state; }; Noggit::Rendering::TileRender* renderer() { return &_renderer; }; + Noggit::Rendering::FlightBoundsRender* flightBoundsRenderer() { return &_fl_bounds_render; }; private: @@ -214,16 +207,9 @@ private: bool _load_models; World* _world; - bool _mfbo_buffer_are_setup = false; - OpenGL::Scoped::deferred_upload_vertex_arrays<2> _mfbo_vaos; - GLuint const& _mfbo_bottom_vao = _mfbo_vaos[0]; - GLuint const& _mfbo_top_vao = _mfbo_vaos[1]; - OpenGL::Scoped::deferred_upload_buffers<3> _mfbo_vbos; - GLuint const& _mfbo_bottom_vbo = _mfbo_vbos[0]; - GLuint const& _mfbo_top_vbo = _mfbo_vbos[1]; - GLuint const& _mfbo_indices = _mfbo_vbos[2]; Noggit::Rendering::TileRender _renderer; + Noggit::Rendering::FlightBoundsRender _fl_bounds_render; Noggit::NoggitRenderContext _context; diff --git a/src/noggit/MapView.cpp b/src/noggit/MapView.cpp index dae09d4a..1c0f1ff6 100644 --- a/src/noggit/MapView.cpp +++ b/src/noggit/MapView.cpp @@ -5124,7 +5124,7 @@ void MapView::unloadOpenglData(bool from_manager) for (MapTile* tile : _world->mapIndex.loaded_tiles()) { tile->renderer()->unload(); - tile->Water.unload(); + tile->Water.renderer()->unload(); for (int i = 0; i < 16; ++i) { diff --git a/src/noggit/TileWater.cpp b/src/noggit/TileWater.cpp index 8e646844..9eb2ebfd 100644 --- a/src/noggit/TileWater.cpp +++ b/src/noggit/TileWater.cpp @@ -15,6 +15,7 @@ TileWater::TileWater(MapTile *pTile, float pXbase, float pZbase, bool use_mclq_green_lava) : tile(pTile) + , _renderer(pTile) , xbase(pXbase) , zbase(pZbase) , _extents{glm::vec3{pXbase, std::numeric_limits::max(), pZbase}, @@ -41,79 +42,6 @@ void TileWater::readFromFile(BlizzardArchive::ClientFile &theFile, size_t basePo } } -void TileWater::draw ( math::frustum const& frustum - , const glm::vec3& camera - , bool camera_moved - , OpenGL::Scoped::use_program& water_shader - , int animtime - , int layer - , display_mode display - , LiquidTextureManager* tex_manager - ) -{ - - constexpr int N_SAMPLERS = 14; - static std::vector samplers_upload_buf {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; - - updateLayerData(tex_manager); - - if (_extents_changed) - { - _extents = {glm::vec3{xbase, std::numeric_limits::max(), zbase}, - glm::vec3{xbase + TILESIZE, std::numeric_limits::lowest(), zbase + TILESIZE}}; - - for (int i = 0; i < 256; ++i) - { - int x = i / 16; - int z = i % 16; - - auto& chunk = chunks[x][z]; - _extents[0].y = std::min(_extents[0].y, chunk->getMinHeight()); - _extents[1].y = std::max(_extents[1].y, chunk->getMaxHeight()); - } - - tile->tagCombinedExtents(true); - tagExtents(false); - } - - std::size_t n_render_blocks = _render_layers.size(); - - for (auto& render_layer : _render_layers) - { - gl.bindBufferRange(GL_UNIFORM_BUFFER, OpenGL::ubo_targets::CHUNK_LIQUID_INSTANCE_INDEX, render_layer.chunk_data_buf, 0, sizeof(OpenGL::LiquidChunkInstanceDataUniformBlock) * 256); - - gl.activeTexture(GL_TEXTURE0); - gl.bindTexture(GL_TEXTURE_2D_ARRAY, render_layer.vertex_data_tex); - - if (render_layer.texture_samplers.size() > N_SAMPLERS) - [[unlikely]] // multi draw-call mode - { - // TODO: - } - else - { - std::fill(samplers_upload_buf.begin(), samplers_upload_buf.end(), -1); - - for (std::size_t j = 0; j < render_layer.texture_samplers.size(); ++j) - { - samplers_upload_buf[j] = render_layer.texture_samplers[j]; - } - - for (std::size_t j = 0; j < N_SAMPLERS; ++j) - { - if (samplers_upload_buf[j] < 0) - break; - - gl.activeTexture(GL_TEXTURE0 + 2 + j); - gl.bindTexture(GL_TEXTURE_2D_ARRAY, samplers_upload_buf[j]); - } - - gl.drawArraysInstanced(GL_TRIANGLES, 0, 8 * 8 * 6, render_layer.n_used_chunks); - } - - } - -} ChunkWater* TileWater::getChunk(int x, int z) { @@ -208,165 +136,23 @@ int TileWater::getType(size_t layer) return 0; } - -void TileWater::updateLayerData(LiquidTextureManager* tex_manager) +void TileWater::recalcExtents() { - tsl::robin_map> const& tex_frames = tex_manager->getTextureFrames(); + _extents = {glm::vec3{xbase, std::numeric_limits::max(), zbase}, + glm::vec3{xbase + TILESIZE, std::numeric_limits::lowest(), zbase + TILESIZE}}; - // create opengl resources if needed - if (_need_buffer_update) + for (int i = 0; i < 256; ++i) { - _has_data = false; + int x = i / 16; + int z = i % 16; - std::size_t layer_counter = 0; - for(;;) - { - std::size_t n_chunks = 0; - for (std::size_t z = 0; z < 16; ++z) - { - for (std::size_t x = 0; x < 16; ++x) - { - ChunkWater* chunk = chunks[z][x].get(); - - if (layer_counter >= chunk->getLayers()->size()) - continue; - - if (!_has_data) - { - _has_data = chunk->hasData(layer_counter); - } - - liquid_layer& layer = (*chunk->getLayers())[layer_counter]; - - // create layer - if (layer_counter >= _render_layers.size()) - { - auto& render_layer = _render_layers.emplace_back(); - - gl.genTextures(1, &render_layer.vertex_data_tex); - gl.bindTexture(GL_TEXTURE_2D_ARRAY, render_layer.vertex_data_tex); - gl.texImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA32F, 9, 9, 256, 0, GL_RGBA, GL_FLOAT, nullptr); - gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0); - - gl.genBuffers(1, &render_layer.chunk_data_buf); - gl.bindBuffer(GL_UNIFORM_BUFFER, render_layer.chunk_data_buf); - gl.bufferData(GL_UNIFORM_BUFFER, sizeof(OpenGL::LiquidChunkInstanceDataUniformBlock) * 256, NULL, GL_DYNAMIC_DRAW);} - - auto& layer_params = _render_layers[layer_counter]; - - // fill per-chunk data - std::tuple const& tex_profile = tex_frames.at(layer.liquidID()); - OpenGL::LiquidChunkInstanceDataUniformBlock& params_data = layer_params.chunk_data[n_chunks]; - - params_data.xbase = layer.getChunk()->xbase; - params_data.zbase = layer.getChunk()->zbase; - - GLuint tex_array = std::get<0>(tex_profile); - auto it = std::find(layer_params.texture_samplers.begin(), layer_params.texture_samplers.end(), tex_array); - - unsigned sampler_index = 0; - - if (it != layer_params.texture_samplers.end()) - { - sampler_index = std::distance(layer_params.texture_samplers.begin(), it); - } - else - { - sampler_index = layer_params.texture_samplers.size(); - layer_params.texture_samplers.emplace_back(std::get<0>(tex_profile)); - } - - params_data.texture_array = sampler_index; - params_data.type = std::get<2>(tex_profile); - params_data.n_texture_frames = std::get<3>(tex_profile); - - glm::vec2 anim = std::get<1>(tex_profile); - params_data.anim_u = anim.x; - params_data.anim_v = anim.y; - - std::uint64_t subchunks = layer.getSubchunks(); - - params_data.subchunks_1 = subchunks & 0xFF'FF'FF'FF; - params_data.subchunks_2 = subchunks >> 32; - - // fill vertex data - auto& vertices = layer.getVertices(); - auto& tex_coords = layer.getTexCoords(); - auto& depth = layer.getDepth(); - - for (int z_v = 0; z_v < 9; ++z_v) - { - for (int x_v = 0; x_v < 9; ++x_v) - { - const unsigned v_index = z_v * 9 + x_v; - glm::vec2& tex_coord = tex_coords[v_index]; - layer_params.vertex_data[n_chunks][v_index] = glm::vec4(vertices[v_index].y, depth[v_index], tex_coord.x, tex_coord.y); - } - } - - n_chunks++; - } - } - - - if (!n_chunks) // break and clean-up - { - if (long diff = _render_layers.size() - layer_counter; diff > 0) - { - for (int i = 0; i < diff; ++i) - { - auto& layer_params = _render_layers.back(); - - gl.deleteBuffers(1, &layer_params.chunk_data_buf); - gl.deleteTextures(1, &layer_params.vertex_data_tex); - - _render_layers.pop_back(); - } - } - - break; - } - else - { - auto& layer_params = _render_layers[layer_counter]; - layer_params.n_used_chunks = n_chunks; - - gl.bindTexture(GL_TEXTURE_2D_ARRAY, layer_params.vertex_data_tex); - gl.bindBuffer(GL_UNIFORM_BUFFER, layer_params.chunk_data_buf); - - gl.bufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(OpenGL::LiquidChunkInstanceDataUniformBlock) * 256, layer_params.chunk_data.data()); - gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 9, 9, 256, GL_RGBA, GL_FLOAT, layer_params.vertex_data.data()); - } - - layer_counter++; - } - - _need_buffer_update = false; + auto& chunk = chunks[x][z]; + _extents[0].y = std::min(_extents[0].y, chunk->getMinHeight()); + _extents[1].y = std::max(_extents[1].y, chunk->getMaxHeight()); } -} - -void TileWater::unload() -{ - _need_buffer_update = true; - _render_layers.clear(); -} - - -void TileWater::registerNewChunk(std::size_t layer) -{ - _need_buffer_update = true; -} - -void TileWater::unregisterChunk(std::size_t layer) -{ - _need_buffer_update = true; -} - -void TileWater::updateLayer(std::size_t layer) -{ - _need_buffer_update = true; + tile->tagCombinedExtents(true); + tagExtents(false); } bool TileWater::isVisible(const math::frustum& frustum) const diff --git a/src/noggit/TileWater.hpp b/src/noggit/TileWater.hpp index 174fb517..bd8d2b24 100644 --- a/src/noggit/TileWater.hpp +++ b/src/noggit/TileWater.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -22,18 +23,15 @@ namespace BlizzardArchive class ClientFile; } -struct LiquidLayerDrawCallData +namespace Noggit::Rendering { - unsigned n_used_chunks = 0; - std::array chunk_data; - std::array, 256> vertex_data ; - std::vector texture_samplers; - GLuint chunk_data_buf = 0; - GLuint vertex_data_tex = 0; -}; + class LiquidRender; +} + class TileWater { + friend class Noggit::Rendering::LiquidRender; public: TileWater(MapTile *pTile, float pXbase, float pZbase, bool use_mclq_green_lava); @@ -62,31 +60,29 @@ public: void setType(int type, size_t layer); int getType(size_t layer); - void registerNewChunk(std::size_t layer); - void unregisterChunk(std::size_t layer); - void updateLayer(std::size_t layer); - - void updateLayerData(LiquidTextureManager* tex_manager); - std::array& getExtents() { return _extents; }; - void unload(); - + [[nodiscard]] bool isVisible(const math::frustum& frustum) const; void tagExtents(bool state) { _extents_changed = state; }; - bool needsUpdate() { return _need_buffer_update || _extents_changed; }; + void tagUpdate() { _renderer.tagUpdate(); }; + + Noggit::Rendering::LiquidRender* renderer() { return &_renderer; }; + + [[nodiscard]] + bool needsUpdate() { return _renderer.needsUpdate() || _extents_changed; }; + + void recalcExtents(); private: MapTile *tile; + Noggit::Rendering::LiquidRender _renderer; std::unique_ptr chunks[16][16]; std::array _extents; - std::vector _render_layers; - - bool _need_buffer_update = false; bool _has_data = true; bool _extents_changed = true; diff --git a/src/noggit/rendering/FlightBoundsRender.cpp b/src/noggit/rendering/FlightBoundsRender.cpp new file mode 100644 index 00000000..b7a1496c --- /dev/null +++ b/src/noggit/rendering/FlightBoundsRender.cpp @@ -0,0 +1,87 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include "FlightBoundsRender.hpp" +#include + +#include + +using namespace Noggit::Rendering; + +FlightBoundsRender::FlightBoundsRender(MapTile* map_tile) +: _map_tile(map_tile) +{ + +} + +void FlightBoundsRender::draw(OpenGL::Scoped::use_program& mfbo_shader) +{ + static constexpr std::array indices = {4, 1, 2, 5, 8, 7, 6, 3, 0, 1, 0, 3, 6, 7, 8, 5, 2, 1}; + + if (!_uploaded) + { + upload(); + + gl.bufferData( _mfbo_bottom_vbo + , 9 * sizeof(glm::vec3) + , _map_tile->mMinimumValues + , GL_STATIC_DRAW + ); + gl.bufferData( _mfbo_top_vbo + , 9 * sizeof(glm::vec3) + , _map_tile->mMaximumValues + , GL_STATIC_DRAW + ); + + + { + OpenGL::Scoped::buffer_binder ibo_binder(_mfbo_indices); + gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(uint16_t), indices.data(), GL_STATIC_DRAW); + } + + { + OpenGL::Scoped::vao_binder const _ (_mfbo_bottom_vao); + OpenGL::Scoped::buffer_binder const vbo_binder (_mfbo_bottom_vbo); + mfbo_shader.attrib("position", 3, GL_FLOAT, GL_FALSE, 0, 0); + } + + { + OpenGL::Scoped::vao_binder const _(_mfbo_top_vao); + OpenGL::Scoped::buffer_binder const vbo_binder(_mfbo_top_vbo); + mfbo_shader.attrib("position", 3, GL_FLOAT, GL_FALSE, 0, 0); + } + + } + + { + OpenGL::Scoped::vao_binder const _(_mfbo_bottom_vao); + OpenGL::Scoped::buffer_binder ibo_binder(_mfbo_indices); + + mfbo_shader.uniform("color", glm::vec4(1.0f, 1.0f, 0.0f, 0.2f)); + gl.drawElements(GL_TRIANGLE_FAN, indices.size(), GL_UNSIGNED_BYTE, nullptr); + } + + { + OpenGL::Scoped::vao_binder const _(_mfbo_top_vao); + OpenGL::Scoped::buffer_binder ibo_binder(_mfbo_indices); + + mfbo_shader.uniform("color", glm::vec4(0.0f, 1.0f, 1.0f, 0.2f)); + gl.drawElements(GL_TRIANGLE_FAN, indices.size(), GL_UNSIGNED_BYTE, nullptr); + } + +} + +void FlightBoundsRender::upload() +{ + _mfbo_vbos.upload(); + _mfbo_vaos.upload(); + + _uploaded = true; +} + +void FlightBoundsRender::unload() +{ + _mfbo_vbos.unload(); + _mfbo_vaos.unload(); + + _uploaded = false; +} \ No newline at end of file diff --git a/src/noggit/rendering/FlightBoundsRender.hpp b/src/noggit/rendering/FlightBoundsRender.hpp new file mode 100644 index 00000000..8074ca47 --- /dev/null +++ b/src/noggit/rendering/FlightBoundsRender.hpp @@ -0,0 +1,40 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#ifndef NOGGIT_FLIGHTBOUNDSRENDER_HPP +#define NOGGIT_FLIGHTBOUNDSRENDER_HPP + +#include +#include +#include + +class MapTile; + +namespace Noggit::Rendering +{ + class FlightBoundsRender : public BaseRender + { + public: + FlightBoundsRender(MapTile* map_tile); + + void upload() override; + void unload() override; + + void draw(OpenGL::Scoped::use_program&); + + private: + MapTile* _map_tile; + + bool _uploaded = false; + + OpenGL::Scoped::deferred_upload_vertex_arrays<2> _mfbo_vaos; + GLuint const& _mfbo_bottom_vao = _mfbo_vaos[0]; + GLuint const& _mfbo_top_vao = _mfbo_vaos[1]; + OpenGL::Scoped::deferred_upload_buffers<3> _mfbo_vbos; + GLuint const& _mfbo_bottom_vbo = _mfbo_vbos[0]; + GLuint const& _mfbo_top_vbo = _mfbo_vbos[1]; + GLuint const& _mfbo_indices = _mfbo_vbos[2]; + + }; +} + +#endif //NOGGIT_FLIGHTBOUNDSRENDER_HPP diff --git a/src/noggit/rendering/LiquidRender.cpp b/src/noggit/rendering/LiquidRender.cpp new file mode 100644 index 00000000..66b3fe1d --- /dev/null +++ b/src/noggit/rendering/LiquidRender.cpp @@ -0,0 +1,232 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include "LiquidRender.hpp" +#include + +using namespace Noggit::Rendering; + +LiquidRender::LiquidRender(MapTile* map_tile) +: _map_tile(map_tile) +{ +} + +void LiquidRender::draw(math::frustum const& frustum + , const glm::vec3& camera + , bool camera_moved + , OpenGL::Scoped::use_program& water_shader + , int animtime + , int layer + , display_mode display + , LiquidTextureManager* tex_manager +) +{ + if (!_map_tile->Water.hasData()) + { + return; + } + + constexpr int N_SAMPLERS = 14; + static std::vector samplers_upload_buf {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; + + updateLayerData(tex_manager); + + if (_map_tile->Water._extents_changed) + { + _map_tile->Water.recalcExtents(); + } + + std::size_t n_render_blocks = _render_layers.size(); + + for (auto& render_layer : _render_layers) + { + gl.bindBufferRange(GL_UNIFORM_BUFFER, OpenGL::ubo_targets::CHUNK_LIQUID_INSTANCE_INDEX, render_layer.chunk_data_buf, 0, sizeof(OpenGL::LiquidChunkInstanceDataUniformBlock) * 256); + + gl.activeTexture(GL_TEXTURE0); + gl.bindTexture(GL_TEXTURE_2D_ARRAY, render_layer.vertex_data_tex); + + if (render_layer.texture_samplers.size() > N_SAMPLERS) + [[unlikely]] // multi draw-call mode + { + // TODO: + } + else + { + std::fill(samplers_upload_buf.begin(), samplers_upload_buf.end(), -1); + + for (std::size_t j = 0; j < render_layer.texture_samplers.size(); ++j) + { + samplers_upload_buf[j] = render_layer.texture_samplers[j]; + } + + for (std::size_t j = 0; j < N_SAMPLERS; ++j) + { + if (samplers_upload_buf[j] < 0) + break; + + gl.activeTexture(GL_TEXTURE0 + 2 + j); + gl.bindTexture(GL_TEXTURE_2D_ARRAY, samplers_upload_buf[j]); + } + + gl.drawArraysInstanced(GL_TRIANGLES, 0, 8 * 8 * 6, render_layer.n_used_chunks); + } + + } + + +} +void LiquidRender::updateLayerData(LiquidTextureManager* tex_manager) +{ + tsl::robin_map> const& tex_frames = tex_manager->getTextureFrames(); + + // create opengl resources if needed + if (_need_buffer_update) + { + _map_tile->Water._has_data = false; + + std::size_t layer_counter = 0; + for(;;) + { + std::size_t n_chunks = 0; + for (std::size_t z = 0; z < 16; ++z) + { + for (std::size_t x = 0; x < 16; ++x) + { + ChunkWater* chunk = _map_tile->Water.chunks[z][x].get(); + + if (layer_counter >= chunk->getLayers()->size()) + continue; + + if (!_map_tile->Water._has_data) + { + _map_tile->Water._has_data = chunk->hasData(layer_counter); + } + + liquid_layer& layer = (*chunk->getLayers())[layer_counter]; + + // create layer + if (layer_counter >= _render_layers.size()) + { + auto& render_layer = _render_layers.emplace_back(); + + gl.genTextures(1, &render_layer.vertex_data_tex); + gl.bindTexture(GL_TEXTURE_2D_ARRAY, render_layer.vertex_data_tex); + gl.texImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA32F, 9, 9, 256, 0, GL_RGBA, GL_FLOAT, nullptr); + gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0); + + gl.genBuffers(1, &render_layer.chunk_data_buf); + gl.bindBuffer(GL_UNIFORM_BUFFER, render_layer.chunk_data_buf); + gl.bufferData(GL_UNIFORM_BUFFER, sizeof(OpenGL::LiquidChunkInstanceDataUniformBlock) * 256, NULL, GL_DYNAMIC_DRAW);} + + auto& layer_params = _render_layers[layer_counter]; + + // fill per-chunk data + std::tuple const& tex_profile = tex_frames.at(layer.liquidID()); + OpenGL::LiquidChunkInstanceDataUniformBlock& params_data = layer_params.chunk_data[n_chunks]; + + params_data.xbase = layer.getChunk()->xbase; + params_data.zbase = layer.getChunk()->zbase; + + GLuint tex_array = std::get<0>(tex_profile); + auto it = std::find(layer_params.texture_samplers.begin(), layer_params.texture_samplers.end(), tex_array); + + unsigned sampler_index = 0; + + if (it != layer_params.texture_samplers.end()) + { + sampler_index = std::distance(layer_params.texture_samplers.begin(), it); + } + else + { + sampler_index = layer_params.texture_samplers.size(); + layer_params.texture_samplers.emplace_back(std::get<0>(tex_profile)); + } + + params_data.texture_array = sampler_index; + params_data.type = std::get<2>(tex_profile); + params_data.n_texture_frames = std::get<3>(tex_profile); + + glm::vec2 anim = std::get<1>(tex_profile); + params_data.anim_u = anim.x; + params_data.anim_v = anim.y; + + std::uint64_t subchunks = layer.getSubchunks(); + + params_data.subchunks_1 = subchunks & 0xFF'FF'FF'FF; + params_data.subchunks_2 = subchunks >> 32; + + // fill vertex data + auto& vertices = layer.getVertices(); + auto& tex_coords = layer.getTexCoords(); + auto& depth = layer.getDepth(); + + for (int z_v = 0; z_v < 9; ++z_v) + { + for (int x_v = 0; x_v < 9; ++x_v) + { + const unsigned v_index = z_v * 9 + x_v; + glm::vec2& tex_coord = tex_coords[v_index]; + layer_params.vertex_data[n_chunks][v_index] = glm::vec4(vertices[v_index].y, depth[v_index], tex_coord.x, tex_coord.y); + } + } + + n_chunks++; + } + } + + + if (!n_chunks) // break and clean-up + { + if (long diff = _render_layers.size() - layer_counter; diff > 0) + { + for (int i = 0; i < diff; ++i) + { + auto& layer_params = _render_layers.back(); + + gl.deleteBuffers(1, &layer_params.chunk_data_buf); + gl.deleteTextures(1, &layer_params.vertex_data_tex); + + _render_layers.pop_back(); + } + } + + break; + } + else + { + auto& layer_params = _render_layers[layer_counter]; + layer_params.n_used_chunks = n_chunks; + + gl.bindTexture(GL_TEXTURE_2D_ARRAY, layer_params.vertex_data_tex); + gl.bindBuffer(GL_UNIFORM_BUFFER, layer_params.chunk_data_buf); + + gl.bufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(OpenGL::LiquidChunkInstanceDataUniformBlock) * 256, layer_params.chunk_data.data()); + gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 9, 9, 256, GL_RGBA, GL_FLOAT, layer_params.vertex_data.data()); + } + + layer_counter++; + } + + _need_buffer_update = false; + } +} + + +void LiquidRender::unload() +{ + _need_buffer_update = true; + + for (auto& render_layer : _render_layers) + { + gl.deleteBuffers(1, &render_layer.chunk_data_buf); + gl.deleteTextures(1, &render_layer.vertex_data_tex); + } + + _render_layers.clear(); + +} + +void LiquidRender::upload() +{ + +} diff --git a/src/noggit/rendering/LiquidRender.hpp b/src/noggit/rendering/LiquidRender.hpp new file mode 100644 index 00000000..28eacaf1 --- /dev/null +++ b/src/noggit/rendering/LiquidRender.hpp @@ -0,0 +1,69 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#ifndef NOGGIT_LIQUIDRENDER_HPP +#define NOGGIT_LIQUIDRENDER_HPP + +#include +#include +#include +#include +#include + +namespace math +{ + class frustum; +} + +class MapTile; +class LiquidTextureManager; + + +namespace Noggit::Rendering +{ + + struct LiquidLayerDrawCallData + { + unsigned n_used_chunks = 0; + std::array chunk_data; + std::array, 256> vertex_data ; + std::vector texture_samplers; + GLuint chunk_data_buf = 0; + GLuint vertex_data_tex = 0; + }; + + + class LiquidRender : public BaseRender + { + public: + explicit LiquidRender(MapTile* map_tile); + + void upload() override; + void unload() override; + + void draw( + math::frustum const& frustum + , const glm::vec3& camera + , bool camera_moved + , OpenGL::Scoped::use_program& water_shader + , int animtime + , int layer + , display_mode display + , LiquidTextureManager* tex_manager + ); + + bool needsUpdate() const { return _need_buffer_update; }; + void tagUpdate() { _need_buffer_update = true; } + + private: + void updateLayerData(LiquidTextureManager* tex_manager); + + MapTile* _map_tile; + + std::vector _render_layers; + + bool _need_buffer_update = false; + + }; +} + +#endif //NOGGIT_LIQUIDRENDER_HPP diff --git a/src/noggit/rendering/WorldRender.cpp b/src/noggit/rendering/WorldRender.cpp index 5dfc71a2..2d4bdc6f 100644 --- a/src/noggit/rendering/WorldRender.cpp +++ b/src/noggit/rendering/WorldRender.cpp @@ -756,7 +756,8 @@ void WorldRender::draw (glm::mat4x4 const& model_view if (tile->renderer()->isOccluded() && !tile->Water.needsUpdate() && !tile->renderer()->isOverridingOcclusionCulling()) continue; - tile->drawWater ( frustum + tile->Water.renderer()->draw( + frustum , camera_pos , camera_moved , water_shader @@ -831,7 +832,7 @@ void WorldRender::draw (glm::mat4x4 const& model_view for (MapTile* tile : _world->mapIndex.loaded_tiles()) { - tile->drawMFBO(mfbo_shader); + tile->flightBoundsRenderer()->draw(mfbo_shader); } }