Separate other rendering parts | Update ChunkWater.cpp, MapTile.cpp, and 9 more files...
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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::updateLayerData(LiquidTextureManager* tex_manager)
|
||||
void TileWater::recalcExtents()
|
||||
{
|
||||
tsl::robin_map<unsigned, std::tuple<GLuint, glm::vec2, int, unsigned>> const& tex_frames = tex_manager->getTextureFrames();
|
||||
_extents = {glm::vec3{xbase, std::numeric_limits<float>::max(), zbase},
|
||||
glm::vec3{xbase + TILESIZE, std::numeric_limits<float>::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<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;
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
87
src/noggit/rendering/FlightBoundsRender.cpp
Normal file
87
src/noggit/rendering/FlightBoundsRender.cpp
Normal 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;
|
||||
}
|
||||
40
src/noggit/rendering/FlightBoundsRender.hpp
Normal file
40
src/noggit/rendering/FlightBoundsRender.hpp
Normal 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
|
||||
232
src/noggit/rendering/LiquidRender.cpp
Normal file
232
src/noggit/rendering/LiquidRender.cpp
Normal 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()
|
||||
{
|
||||
|
||||
}
|
||||
69
src/noggit/rendering/LiquidRender.hpp
Normal file
69
src/noggit/rendering/LiquidRender.hpp
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user