Separate other rendering parts | Update ChunkWater.cpp, MapTile.cpp, and 9 more files...

This commit is contained in:
Skarn
2022-01-06 20:46:58 +03:00
parent 822ea99238
commit 9e059e1008
11 changed files with 474 additions and 367 deletions

View File

@@ -45,19 +45,15 @@ void ChunkWater::from_mclq(std::vector<mclq>& 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<mclq>& 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();
}
}
}

View File

@@ -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<std::uint8_t> 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<GL_ARRAY_BUFFER>( _mfbo_bottom_vbo
, 9 * sizeof(glm::vec3)
, mMinimumValues
, GL_STATIC_DRAW
);
gl.bufferData<GL_ARRAY_BUFFER>( _mfbo_top_vbo
, 9 * sizeof(glm::vec3)
, mMaximumValues
, GL_STATIC_DRAW
);
{
OpenGL::Scoped::vao_binder const _ (_mfbo_bottom_vao);
OpenGL::Scoped::buffer_binder<GL_ARRAY_BUFFER> 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<GL_ARRAY_BUFFER> const vbo_binder(_mfbo_top_vbo);
mfbo_shader.attrib("position", 3, GL_FLOAT, GL_FALSE, 0, 0);
}
{
OpenGL::Scoped::buffer_binder<GL_ELEMENT_ARRAY_BUFFER> 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<GL_ELEMENT_ARRAY_BUFFER> 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<GL_ELEMENT_ARRAY_BUFFER> 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)

View File

@@ -15,6 +15,7 @@
#include <noggit/Misc.h>
#include <external/tsl/robin_map.h>
#include <noggit/rendering/TileRender.hpp>
#include <noggit/rendering/FlightBoundsRender.hpp>
#include <map>
#include <string>
@@ -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;

View File

@@ -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)
{

View File

@@ -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<float>::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<int> 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<float>::max(), zbase},
glm::vec3{xbase + TILESIZE, std::numeric_limits<float>::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::recalcExtents()
{
_extents = {glm::vec3{xbase, std::numeric_limits<float>::max(), zbase},
glm::vec3{xbase + TILESIZE, std::numeric_limits<float>::lowest(), zbase + TILESIZE}};
void TileWater::updateLayerData(LiquidTextureManager* tex_manager)
for (int i = 0; i < 256; ++i)
{
tsl::robin_map<unsigned, std::tuple<GLuint, glm::vec2, int, unsigned>> const& tex_frames = tex_manager->getTextureFrames();
int x = i / 16;
int z = i % 16;
// create opengl resources if needed
if (_need_buffer_update)
{
_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 = chunks[z][x].get();
if (layer_counter >= chunk->getLayers()->size())
continue;
if (!_has_data)
{
_has_data = chunk->hasData(layer_counter);
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());
}
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<GLuint, glm::vec2, int, unsigned> 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 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

View File

@@ -6,6 +6,7 @@
#include <opengl/context.hpp>
#include <opengl/types.hpp>
#include <noggit/LiquidTextureManager.hpp>
#include <noggit/rendering/LiquidRender.hpp>
#include <memory>
#include <vector>
@@ -22,18 +23,15 @@ namespace BlizzardArchive
class ClientFile;
}
struct LiquidLayerDrawCallData
namespace Noggit::Rendering
{
unsigned n_used_chunks = 0;
std::array<OpenGL::LiquidChunkInstanceDataUniformBlock, 256> chunk_data;
std::array<std::array<glm::vec4, 9 * 9>, 256> vertex_data ;
std::vector<int> 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<glm::vec3, 2>& 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<ChunkWater> chunks[16][16];
std::array<glm::vec3, 2> _extents;
std::vector<LiquidLayerDrawCallData> _render_layers;
bool _need_buffer_update = false;
bool _has_data = true;
bool _extents_changed = true;

View File

@@ -0,0 +1,87 @@
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
#include "FlightBoundsRender.hpp"
#include <noggit/MapTile.h>
#include <array>
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<std::uint8_t, 18> indices = {4, 1, 2, 5, 8, 7, 6, 3, 0, 1, 0, 3, 6, 7, 8, 5, 2, 1};
if (!_uploaded)
{
upload();
gl.bufferData<GL_ARRAY_BUFFER>( _mfbo_bottom_vbo
, 9 * sizeof(glm::vec3)
, _map_tile->mMinimumValues
, GL_STATIC_DRAW
);
gl.bufferData<GL_ARRAY_BUFFER>( _mfbo_top_vbo
, 9 * sizeof(glm::vec3)
, _map_tile->mMaximumValues
, GL_STATIC_DRAW
);
{
OpenGL::Scoped::buffer_binder<GL_ELEMENT_ARRAY_BUFFER> 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<GL_ARRAY_BUFFER> 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<GL_ARRAY_BUFFER> 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<GL_ELEMENT_ARRAY_BUFFER> 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<GL_ELEMENT_ARRAY_BUFFER> 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;
}

View File

@@ -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 <noggit/rendering/BaseRender.hpp>
#include <opengl/scoped.hpp>
#include <opengl/shader.hpp>
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

View File

@@ -0,0 +1,232 @@
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
#include "LiquidRender.hpp"
#include <noggit/MapTile.h>
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<int> 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<unsigned, std::tuple<GLuint, glm::vec2, int, unsigned>> 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<GLuint, glm::vec2, int, unsigned> 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()
{
}

View File

@@ -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 <noggit/rendering/BaseRender.hpp>
#include <opengl/scoped.hpp>
#include <opengl/shader.hpp>
#include <glm/glm.hpp>
#include <noggit/tool_enums.hpp>
namespace math
{
class frustum;
}
class MapTile;
class LiquidTextureManager;
namespace Noggit::Rendering
{
struct LiquidLayerDrawCallData
{
unsigned n_used_chunks = 0;
std::array<OpenGL::LiquidChunkInstanceDataUniformBlock, 256> chunk_data;
std::array<std::array<glm::vec4, 9 * 9>, 256> vertex_data ;
std::vector<int> 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<LiquidLayerDrawCallData> _render_layers;
bool _need_buffer_update = false;
};
}
#endif //NOGGIT_LIQUIDRENDER_HPP

View File

@@ -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);
}
}