move tile rendering to separate class | Update MapTile.cpp, MapTile.h, and 7 more files...
This commit is contained in:
@@ -43,6 +43,7 @@ MapTile::MapTile( int pX
|
||||
, tile_mode mode
|
||||
)
|
||||
: AsyncObject(pFilename)
|
||||
, _renderer(this)
|
||||
, index(TileIndex(pX, pZ))
|
||||
, xbase(pX * TILESIZE)
|
||||
, zbase(pZ * TILESIZE)
|
||||
@@ -360,14 +361,7 @@ void MapTile::finishLoading()
|
||||
mChunks[x][z] = std::make_unique<MapChunk> (this, &theFile, mBigAlpha, _mode, _context);
|
||||
|
||||
auto& chunk = mChunks[x][z];
|
||||
auto& chunk_render_instance = _chunk_instance_data[nextChunk];
|
||||
|
||||
chunk_render_instance.ChunkHoles_DrawImpass_TexLayerCount_CantPaint[0] = chunk->holes;
|
||||
chunk_render_instance.ChunkHoles_DrawImpass_TexLayerCount_CantPaint[1] = chunk->header_flags.flags.impass;
|
||||
chunk_render_instance.ChunkHoles_DrawImpass_TexLayerCount_CantPaint[2] = chunk->texture_set->num();
|
||||
chunk_render_instance.ChunkHoles_DrawImpass_TexLayerCount_CantPaint[3] = 0;
|
||||
chunk_render_instance.AreaIDColor_Pad2_DrawSelection[0] = chunk->areaID;
|
||||
chunk_render_instance.AreaIDColor_Pad2_DrawSelection[3] = 0;
|
||||
_renderer.initChunkData(chunk.get());
|
||||
}
|
||||
|
||||
theFile.close();
|
||||
@@ -421,312 +415,6 @@ void MapTile::convert_alphamap(bool to_big_alpha)
|
||||
}
|
||||
}
|
||||
|
||||
void MapTile::draw (OpenGL::Scoped::use_program& mcnk_shader
|
||||
, const glm::vec3& camera
|
||||
, bool show_unpaintable_chunks
|
||||
, bool draw_paintability_overlay
|
||||
, bool is_selected
|
||||
)
|
||||
{
|
||||
ZoneScopedN(NOGGIT_CURRENT_FUNCTION);
|
||||
|
||||
static constexpr unsigned NUM_SAMPLERS = 11;
|
||||
|
||||
if (!finished)
|
||||
[[unlikely]]
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_uploaded)
|
||||
[[unlikely]]
|
||||
{
|
||||
uploadTextures();
|
||||
_buffers.upload();
|
||||
|
||||
gl.bindBuffer(GL_UNIFORM_BUFFER, _chunk_instance_data_ubo);
|
||||
gl.bindBufferRange(GL_UNIFORM_BUFFER, OpenGL::ubo_targets::CHUNK_INSTANCE_DATA,
|
||||
_chunk_instance_data_ubo, 0, sizeof(OpenGL::ChunkInstanceDataUniformBlock) * 256);
|
||||
gl.bufferData(GL_UNIFORM_BUFFER, sizeof(OpenGL::ChunkInstanceDataUniformBlock) * 256, NULL, GL_DYNAMIC_DRAW);
|
||||
|
||||
MapTileDrawCall& draw_call = _draw_calls.emplace_back();
|
||||
draw_call.start_chunk = 0;
|
||||
draw_call.n_chunks = 256;
|
||||
std::fill(draw_call.samplers.begin(), draw_call.samplers.end(), -1);
|
||||
|
||||
gl.genQueries(1, &_tile_occlusion_query);
|
||||
|
||||
_uploaded = true;
|
||||
}
|
||||
|
||||
bool alphamap_bound = false;
|
||||
bool heightmap_bound = false;
|
||||
bool shadowmap_bound = false;
|
||||
bool mccv_bound = false;
|
||||
|
||||
_texture_not_loaded = false;
|
||||
|
||||
// figure out if we need to update based on paintability
|
||||
bool need_paintability_update = false;
|
||||
if (_requires_paintability_recalc && draw_paintability_overlay && show_unpaintable_chunks)
|
||||
[[unlikely]]
|
||||
{
|
||||
auto cur_tex = Noggit::Ui::selected_texture::get();
|
||||
for (int j = 0; j < 16; ++j)
|
||||
{
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
auto& chunk = mChunks[j][i];
|
||||
bool cant_paint = cur_tex && !chunk->canPaintTexture(*cur_tex);
|
||||
|
||||
if (chunk->currently_paintable != !cant_paint)
|
||||
{
|
||||
chunk->currently_paintable = !cant_paint;
|
||||
_chunk_instance_data[i * 16 + j].ChunkHoles_DrawImpass_TexLayerCount_CantPaint[3] = cant_paint;
|
||||
need_paintability_update = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_requires_paintability_recalc = false;
|
||||
}
|
||||
|
||||
// run chunk updates. running this when splitdraw call detected unused sampler configuration as well.
|
||||
if (_chunk_update_flags || is_selected != _selected || need_paintability_update || _requires_sampler_reset || _texture_not_loaded)
|
||||
{
|
||||
|
||||
gl.bindBuffer(GL_UNIFORM_BUFFER, _chunk_instance_data_ubo);
|
||||
|
||||
if (_requires_sampler_reset)
|
||||
[[unlikely]]
|
||||
{
|
||||
_draw_calls.clear();
|
||||
MapTileDrawCall& draw_call = _draw_calls.emplace_back();
|
||||
std::fill(draw_call.samplers.begin(), draw_call.samplers.end(), -1);
|
||||
draw_call.start_chunk = 0;
|
||||
draw_call.n_chunks = 256;
|
||||
}
|
||||
|
||||
_selected = is_selected;
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
int chunk_x = i / 16;
|
||||
int chunk_y = i % 16;
|
||||
|
||||
auto& chunk = mChunks[chunk_y][chunk_x];
|
||||
|
||||
_chunk_instance_data[i].ChunkXYZBase_Pad1 = {chunk->xbase, chunk->ybase, chunk->zbase, 1.0};
|
||||
|
||||
unsigned flags = chunk->getUpdateFlags();
|
||||
|
||||
if (flags & ChunkUpdateFlags::ALPHAMAP || _requires_sampler_reset || _texture_not_loaded)
|
||||
{
|
||||
gl.activeTexture(GL_TEXTURE0 + 3);
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, _alphamap_tex);
|
||||
alphamap_bound = true;
|
||||
chunk->texture_set->uploadAlphamapData();
|
||||
|
||||
if (!_split_drawcall && !fillSamplers(chunk.get(), i, _draw_calls.size() - 1))
|
||||
{
|
||||
_split_drawcall = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!flags)
|
||||
continue;
|
||||
|
||||
if (flags & ChunkUpdateFlags::VERTEX || flags & ChunkUpdateFlags::NORMALS)
|
||||
{
|
||||
heightmap_bound = true;
|
||||
if (flags & ChunkUpdateFlags::VERTEX)
|
||||
{
|
||||
chunk->updateVerticesData();
|
||||
}
|
||||
|
||||
gl.activeTexture(GL_TEXTURE0 + 0);
|
||||
gl.bindTexture(GL_TEXTURE_2D, _height_tex);
|
||||
gl.texSubImage2D(GL_TEXTURE_2D, 0, 0, i, mapbufsize, 1, GL_RGBA, GL_FLOAT, _chunk_heightmap_buffer.data() + i * mapbufsize * 4);
|
||||
}
|
||||
|
||||
if (flags & ChunkUpdateFlags::MCCV)
|
||||
{
|
||||
mccv_bound = true;
|
||||
gl.activeTexture(GL_TEXTURE0 + 1);
|
||||
gl.bindTexture(GL_TEXTURE_2D, _mccv_tex);
|
||||
chunk->update_vertex_colors();
|
||||
}
|
||||
|
||||
if (flags & ChunkUpdateFlags::SHADOW)
|
||||
{
|
||||
shadowmap_bound = true;
|
||||
gl.activeTexture(GL_TEXTURE0 + 2);
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, _shadowmap_tex);
|
||||
chunk->update_shadows();
|
||||
}
|
||||
|
||||
if (flags & ChunkUpdateFlags::HOLES)
|
||||
{
|
||||
_chunk_instance_data[i].ChunkHoles_DrawImpass_TexLayerCount_CantPaint[0] = chunk->holes;
|
||||
}
|
||||
|
||||
if (flags & ChunkUpdateFlags::FLAGS)
|
||||
{
|
||||
_chunk_instance_data[i].ChunkHoles_DrawImpass_TexLayerCount_CantPaint[1] = chunk->header_flags.flags.impass;
|
||||
|
||||
for (int k = 0; k < chunk->texture_set->num(); ++k)
|
||||
{
|
||||
unsigned layer_flags = chunk->texture_set->flag(k);
|
||||
auto flag_view = reinterpret_cast<MCLYFlags*>(&layer_flags);
|
||||
|
||||
_chunk_instance_data[i].ChunkTexDoAnim[k] = flag_view->animation_enabled;
|
||||
_chunk_instance_data[i].ChunkTexAnimSpeed[k] = flag_view->animation_speed;
|
||||
_chunk_instance_data[i].ChunkTexAnimDir[k] = flag_view->animation_rotation;
|
||||
}
|
||||
|
||||
_chunk_instance_data[i].ChunkTexDoAnim[1] = chunk->header_flags.flags.impass;
|
||||
}
|
||||
|
||||
if (flags & ChunkUpdateFlags::AREA_ID)
|
||||
{
|
||||
_chunk_instance_data[i].AreaIDColor_Pad2_DrawSelection[0] = chunk->areaID;
|
||||
}
|
||||
|
||||
_chunk_instance_data[i].AreaIDColor_Pad2_DrawSelection[3] = _selected;
|
||||
|
||||
chunk->endChunkUpdates();
|
||||
|
||||
if (_texture_not_loaded)
|
||||
chunk->registerChunkUpdate(ChunkUpdateFlags::ALPHAMAP);
|
||||
|
||||
}
|
||||
|
||||
_requires_sampler_reset = false;
|
||||
|
||||
|
||||
if (_split_drawcall)
|
||||
{
|
||||
_draw_calls.clear();
|
||||
MapTileDrawCall& draw_call = _draw_calls.emplace_back();
|
||||
std::fill(draw_call.samplers.begin(), draw_call.samplers.end(), -1);
|
||||
draw_call.start_chunk = 0;
|
||||
draw_call.n_chunks = 0;
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
auto& chunk = mChunks[i % 16][i / 16];
|
||||
|
||||
if (!fillSamplers(chunk.get(), i, _draw_calls.size() - 1))
|
||||
{
|
||||
MapTileDrawCall& previous_draw_call = _draw_calls[_draw_calls.size() - 1];
|
||||
unsigned new_start = previous_draw_call.start_chunk + previous_draw_call.n_chunks;
|
||||
|
||||
MapTileDrawCall& new_draw_call = _draw_calls.emplace_back();
|
||||
std::fill(new_draw_call.samplers.begin(), new_draw_call.samplers.end(), -1);
|
||||
new_draw_call.start_chunk = new_start;
|
||||
new_draw_call.n_chunks = 1;
|
||||
|
||||
fillSamplers(chunk.get(), i, _draw_calls.size() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
MapTileDrawCall& last_draw_call = _draw_calls.back();
|
||||
last_draw_call.n_chunks++;
|
||||
assert(last_draw_call.n_chunks <= 256);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (_draw_calls.size() <= 1)
|
||||
{
|
||||
_split_drawcall = false;
|
||||
_requires_sampler_reset = true;
|
||||
}
|
||||
}
|
||||
|
||||
endChunkUpdates();
|
||||
|
||||
if (_texture_not_loaded)
|
||||
registerChunkUpdate(ChunkUpdateFlags::ALPHAMAP);
|
||||
|
||||
gl.bufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(OpenGL::ChunkInstanceDataUniformBlock) * 256, &_chunk_instance_data);
|
||||
}
|
||||
|
||||
recalcExtents();
|
||||
|
||||
// do not draw anything when textures did not finish loading
|
||||
if (_texture_not_loaded)
|
||||
[[unlikely]]
|
||||
{
|
||||
gl.bindBufferRange(GL_UNIFORM_BUFFER, OpenGL::ubo_targets::CHUNK_INSTANCE_DATA,
|
||||
_chunk_instance_data_ubo, 0, sizeof(OpenGL::ChunkInstanceDataUniformBlock) * 256);
|
||||
return;
|
||||
}
|
||||
|
||||
gl.bindBufferRange(GL_UNIFORM_BUFFER, OpenGL::ubo_targets::CHUNK_INSTANCE_DATA,
|
||||
_chunk_instance_data_ubo, 0, sizeof(OpenGL::ChunkInstanceDataUniformBlock) * 256);
|
||||
|
||||
|
||||
for (auto& draw_call : _draw_calls)
|
||||
{
|
||||
|
||||
if (!alphamap_bound)
|
||||
{
|
||||
gl.activeTexture(GL_TEXTURE0 + 3);
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, _alphamap_tex);
|
||||
}
|
||||
|
||||
if (!shadowmap_bound)
|
||||
{
|
||||
gl.activeTexture(GL_TEXTURE0 + 2);
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, _shadowmap_tex);
|
||||
}
|
||||
|
||||
if (!mccv_bound)
|
||||
{
|
||||
gl.activeTexture(GL_TEXTURE0 + 1);
|
||||
gl.bindTexture(GL_TEXTURE_2D, _mccv_tex);
|
||||
}
|
||||
|
||||
if (!heightmap_bound)
|
||||
{
|
||||
gl.activeTexture(GL_TEXTURE0 + 0);
|
||||
gl.bindTexture(GL_TEXTURE_2D, _height_tex);
|
||||
}
|
||||
|
||||
float tile_center_x = xbase + TILESIZE / 2.0f;
|
||||
float tile_center_z = zbase + TILESIZE / 2.0f;
|
||||
|
||||
bool is_lod = misc::dist(tile_center_x, tile_center_z, camera.x, camera.z) > TILESIZE * 3;
|
||||
mcnk_shader.uniform("lod_level", int(is_lod));
|
||||
|
||||
assert(draw_call.n_chunks <= 256);
|
||||
mcnk_shader.uniform("base_instance", static_cast<int>(draw_call.start_chunk));
|
||||
|
||||
for (int i = 0; i < NUM_SAMPLERS; ++i)
|
||||
{
|
||||
gl.activeTexture(GL_TEXTURE0 + 5 + i);
|
||||
|
||||
if (draw_call.samplers[i] < 0)
|
||||
{
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, draw_call.samplers[i]);
|
||||
}
|
||||
|
||||
if (is_lod)
|
||||
{
|
||||
gl.drawElementsInstanced(GL_TRIANGLES, 192, GL_UNSIGNED_SHORT, reinterpret_cast<void*>(768 * sizeof(std::uint16_t)), draw_call.n_chunks);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl.drawElementsInstanced(GL_TRIANGLES, 768, GL_UNSIGNED_SHORT, nullptr, draw_call.n_chunks);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool MapTile::intersect (math::ray const& ray, selection_result* results) const
|
||||
{
|
||||
@@ -1809,81 +1497,8 @@ void MapTile::setVertexColorImage(QImage const& image, int mode)
|
||||
}
|
||||
}
|
||||
|
||||
void MapTile::unload()
|
||||
{
|
||||
if (_uploaded)
|
||||
{
|
||||
_chunk_texture_arrays.unload();
|
||||
_buffers.unload();
|
||||
_uploaded = false;
|
||||
gl.deleteQueries(1, &_tile_occlusion_query);
|
||||
}
|
||||
|
||||
if (_mfbo_buffer_are_setup)
|
||||
{
|
||||
_mfbo_vaos.unload();
|
||||
_mfbo_vbos.unload();
|
||||
|
||||
_mfbo_buffer_are_setup = false;
|
||||
}
|
||||
|
||||
_chunk_update_flags = ChunkUpdateFlags::VERTEX | ChunkUpdateFlags::ALPHAMAP
|
||||
| ChunkUpdateFlags::SHADOW | ChunkUpdateFlags::MCCV
|
||||
| ChunkUpdateFlags::NORMALS| ChunkUpdateFlags::HOLES
|
||||
| ChunkUpdateFlags::AREA_ID| ChunkUpdateFlags::FLAGS;
|
||||
}
|
||||
|
||||
void MapTile::uploadTextures()
|
||||
{
|
||||
_chunk_texture_arrays.upload();
|
||||
gl.activeTexture(GL_TEXTURE0 + 0);
|
||||
gl.bindTexture(GL_TEXTURE_2D, _height_tex);
|
||||
gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, mapbufsize, 256, 0, GL_RGBA, GL_FLOAT,nullptr);
|
||||
|
||||
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
//gl.texParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
//gl.texParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
//gl.texParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
//const GLint swizzleMask[] = {GL_RED, GL_RED, GL_RED, GL_ONE};
|
||||
//gl.texParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
|
||||
|
||||
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
gl.bindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
gl.activeTexture(GL_TEXTURE0 + 2);
|
||||
gl.bindTexture(GL_TEXTURE_2D, _mccv_tex);
|
||||
gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, mapbufsize, 256, 0, GL_RGB, GL_FLOAT, nullptr);
|
||||
|
||||
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
//gl.texParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
//gl.texParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
//gl.texParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
gl.bindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
gl.activeTexture(GL_TEXTURE0 + 4);
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, _alphamap_tex);
|
||||
gl.texImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, 64, 64, 256, 0, GL_RGB, GL_FLOAT,nullptr);
|
||||
|
||||
gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, 0);
|
||||
|
||||
|
||||
gl.activeTexture(GL_TEXTURE0 + 3);
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, _shadowmap_tex);
|
||||
gl.texImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RED, 64, 64, 256, 0, GL_RED, GL_UNSIGNED_BYTE,nullptr);
|
||||
|
||||
gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, 0);
|
||||
}
|
||||
|
||||
void MapTile::recalcExtents()
|
||||
{
|
||||
@@ -1966,133 +1581,11 @@ void MapTile::recalcObjectInstanceExtents()
|
||||
|
||||
}
|
||||
|
||||
|
||||
void MapTile::doTileOcclusionQuery(OpenGL::Scoped::use_program& occlusion_shader)
|
||||
{
|
||||
if (_tile_occlusion_query_in_use || !_uploaded)
|
||||
return;
|
||||
|
||||
_tile_occlusion_query_in_use = true;
|
||||
gl.beginQuery(GL_ANY_SAMPLES_PASSED, _tile_occlusion_query);
|
||||
occlusion_shader.uniform("aabb", _combined_extents.data(), _combined_extents.size());
|
||||
gl.drawElements(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, nullptr);
|
||||
gl.endQuery(GL_ANY_SAMPLES_PASSED);
|
||||
}
|
||||
|
||||
bool MapTile::getTileOcclusionQueryResult(glm::vec3 const& camera)
|
||||
{
|
||||
// returns true if tile is not occluded by other tiles
|
||||
|
||||
if (!_tile_occlusion_query_in_use)
|
||||
[[unlikely]]
|
||||
{
|
||||
return !tile_occluded;
|
||||
}
|
||||
|
||||
if (!_uploaded)
|
||||
return !tile_occluded;
|
||||
|
||||
if (misc::pointInside(camera, _combined_extents))
|
||||
{
|
||||
_tile_occlusion_query_in_use = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
GLint result;
|
||||
gl.getQueryObjectiv(_tile_occlusion_query, GL_QUERY_RESULT_AVAILABLE, &result);
|
||||
|
||||
if (result != GL_TRUE)
|
||||
{
|
||||
return tile_occlusion_cull_override || !tile_occluded;
|
||||
}
|
||||
|
||||
if (!tile_occlusion_cull_override)
|
||||
{
|
||||
gl.getQueryObjectiv(_tile_occlusion_query, GL_QUERY_RESULT, &result);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
|
||||
_tile_occlusion_query_in_use = false;
|
||||
tile_occlusion_cull_override = false;
|
||||
|
||||
return static_cast<bool>(result);
|
||||
}
|
||||
|
||||
|
||||
void MapTile::calcCamDist(glm::vec3 const& camera)
|
||||
{
|
||||
_cam_dist = glm::distance(camera, _center);
|
||||
}
|
||||
|
||||
bool MapTile::fillSamplers(MapChunk* chunk, unsigned chunk_index, unsigned int draw_call_index)
|
||||
{
|
||||
MapTileDrawCall& draw_call = _draw_calls[draw_call_index];
|
||||
|
||||
_chunk_instance_data[chunk_index].ChunkHoles_DrawImpass_TexLayerCount_CantPaint[2] = chunk->texture_set->num();
|
||||
|
||||
static constexpr unsigned NUM_SAMPLERS = 11;
|
||||
|
||||
_chunk_instance_data[chunk_index].ChunkTextureSamplers[0] = 0;
|
||||
_chunk_instance_data[chunk_index].ChunkTextureSamplers[1] = 0;
|
||||
_chunk_instance_data[chunk_index].ChunkTextureSamplers[2] = 0;
|
||||
_chunk_instance_data[chunk_index].ChunkTextureSamplers[3] = 0;
|
||||
|
||||
_chunk_instance_data[chunk_index].ChunkTextureArrayIDs[0] = -1;
|
||||
_chunk_instance_data[chunk_index].ChunkTextureArrayIDs[1] = -1;
|
||||
_chunk_instance_data[chunk_index].ChunkTextureArrayIDs[2] = -1;
|
||||
_chunk_instance_data[chunk_index].ChunkTextureArrayIDs[3] = -1;
|
||||
|
||||
|
||||
auto& chunk_textures = (*chunk->texture_set->getTextures());
|
||||
for (int k = 0; k < chunk->texture_set->num(); ++k)
|
||||
{
|
||||
chunk_textures[k]->upload();
|
||||
|
||||
if (!chunk_textures[k]->is_uploaded())
|
||||
{
|
||||
_texture_not_loaded = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
GLuint tex_array = (*chunk->texture_set->getTextures())[k]->texture_array();
|
||||
int tex_index = (*chunk->texture_set->getTextures())[k]->array_index();
|
||||
|
||||
int sampler_id = -1;
|
||||
for (int n = 0; n < draw_call.samplers.size(); ++n)
|
||||
{
|
||||
if (draw_call.samplers[n] == tex_array)
|
||||
{
|
||||
sampler_id = n;
|
||||
break;
|
||||
}
|
||||
else if (draw_call.samplers[n] < 0)
|
||||
{
|
||||
draw_call.samplers[n] = tex_array;
|
||||
sampler_id = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If there are not enough sampler slots (11) we have to split the drawcall :(.
|
||||
// Extremely infrequent for terrain. Never for Blizzard terrain as their tilesets
|
||||
// use uniform BLP format per map.
|
||||
if (sampler_id < 0)
|
||||
[[unlikely]]
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_chunk_instance_data[chunk_index].ChunkTextureSamplers[k] = sampler_id;
|
||||
_chunk_instance_data[chunk_index].ChunkTextureArrayIDs[k] = (*chunk->texture_set->getTextures())[k]->is_specular() ? tex_index : -tex_index;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MapTile::recalcCombinedExtents()
|
||||
{
|
||||
if (!_combined_extents_dirty)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <noggit/ContextObject.hpp>
|
||||
#include <noggit/Misc.h>
|
||||
#include <external/tsl/robin_map.h>
|
||||
#include <noggit/rendering/TileRender.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
@@ -26,17 +27,20 @@ namespace math
|
||||
struct vector_3d;
|
||||
}
|
||||
|
||||
namespace Noggit::Rendering
|
||||
{
|
||||
class TileRender;
|
||||
}
|
||||
|
||||
class World;
|
||||
|
||||
struct MapTileDrawCall
|
||||
{
|
||||
std::array<int, 11> samplers;
|
||||
unsigned start_chunk;
|
||||
unsigned n_chunks;
|
||||
};
|
||||
|
||||
class MapTile : public AsyncObject
|
||||
{
|
||||
friend class Noggit::Rendering::TileRender;
|
||||
friend class MapChunk;
|
||||
friend class TextureSet;
|
||||
|
||||
public:
|
||||
MapTile( int x0
|
||||
, int z0
|
||||
@@ -51,8 +55,8 @@ public:
|
||||
);
|
||||
~MapTile();
|
||||
|
||||
void finishLoading();
|
||||
void waitForChildrenLoaded();
|
||||
void finishLoading() override;
|
||||
void waitForChildrenLoaded() override;
|
||||
|
||||
//! \todo on destruction, unload ModelInstances and WMOInstances on this tile:
|
||||
// a) either keep up the information what tiles the instances are on at all times
|
||||
@@ -76,28 +80,25 @@ public:
|
||||
void convert_alphamap(bool to_big_alpha);
|
||||
|
||||
//! \brief Get chunk for sub offset x,z.
|
||||
|
||||
[[nodiscard]]
|
||||
MapChunk* getChunk(unsigned int x, unsigned int z);
|
||||
//! \todo map_index style iterators
|
||||
|
||||
[[nodiscard]]
|
||||
std::vector<MapChunk*> chunks_in_range (glm::vec3 const& pos, float radius) const;
|
||||
|
||||
[[nodiscard]]
|
||||
std::vector<MapChunk*> chunks_in_rect (glm::vec3 const& pos, float radius) const;
|
||||
|
||||
const TileIndex index;
|
||||
float xbase, zbase;
|
||||
|
||||
std::atomic<bool> changed;
|
||||
unsigned objects_frustum_cull_test = 0;
|
||||
bool tile_occluded = false;
|
||||
bool tile_frustum_culled = true;
|
||||
bool tile_occlusion_cull_override = true;
|
||||
|
||||
void draw (OpenGL::Scoped::use_program& mcnk_shader
|
||||
, const glm::vec3& camera
|
||||
, bool show_unpaintable_chunks
|
||||
, bool draw_paintability_overlay
|
||||
, bool is_selected
|
||||
);
|
||||
|
||||
bool intersect (math::ray const&, selection_result*) const;
|
||||
|
||||
void drawWater ( math::frustum const& frustum
|
||||
, const glm::vec3& camera
|
||||
, bool camera_moved
|
||||
@@ -161,40 +162,27 @@ public:
|
||||
std::array<glm::vec3, 2>& getExtents() { return _extents; };
|
||||
std::array<glm::vec3, 2>& getCombinedExtents() { return _combined_extents; };
|
||||
|
||||
void unload();
|
||||
|
||||
GLuint getAlphamapTextureHandle() { return _alphamap_tex; };
|
||||
World* getWorld() { return _world; };
|
||||
|
||||
void notifyTileRendererOnSelectedTextureChange() { _requires_paintability_recalc = true; };
|
||||
|
||||
[[nodiscard]]
|
||||
tsl::robin_map<AsyncObject*, std::vector<SceneObject*>> const& getObjectInstances() const { return object_instances; };
|
||||
|
||||
void doTileOcclusionQuery(OpenGL::Scoped::use_program& occlusion_shader);
|
||||
bool getTileOcclusionQueryResult(glm::vec3 const& camera);
|
||||
void discardTileOcclusionQuery() { _tile_occlusion_query_in_use = false; }
|
||||
|
||||
float camDist() { return _cam_dist; }
|
||||
void calcCamDist(glm::vec3 const& camera);
|
||||
void markExtentsDirty() { _extents_dirty = true; }
|
||||
void tagCombinedExtents(bool state) { _combined_extents_dirty = state; };
|
||||
|
||||
private:
|
||||
Noggit::Rendering::TileRender* renderer() { return &_renderer; };
|
||||
|
||||
void uploadTextures();
|
||||
bool fillSamplers(MapChunk* chunk, unsigned chunk_index, unsigned draw_call_index);
|
||||
private:
|
||||
|
||||
tile_mode _mode;
|
||||
bool _tile_is_being_reloaded;
|
||||
bool _uploaded = false;
|
||||
bool _selected = false;
|
||||
bool _split_drawcall = false;
|
||||
bool _requires_sampler_reset = false;
|
||||
bool _requires_paintability_recalc = true;
|
||||
bool _requires_object_extents_recalc = true;
|
||||
bool _texture_not_loaded = false;
|
||||
|
||||
bool _extents_dirty = true;
|
||||
bool _combined_extents_dirty = true;
|
||||
bool _requires_object_extents_recalc = true;
|
||||
|
||||
|
||||
std::array<glm::vec3, 2> _extents;
|
||||
std::array<glm::vec3, 2> _object_instance_extents;
|
||||
@@ -206,34 +194,8 @@ private:
|
||||
glm::vec3 mMinimumValues[3 * 3];
|
||||
glm::vec3 mMaximumValues[3 * 3];
|
||||
|
||||
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];
|
||||
|
||||
OpenGL::Scoped::deferred_upload_textures<4> _chunk_texture_arrays;
|
||||
GLuint const& _height_tex = _chunk_texture_arrays[0];
|
||||
GLuint const& _mccv_tex = _chunk_texture_arrays[1];
|
||||
GLuint const& _shadowmap_tex = _chunk_texture_arrays[2];
|
||||
GLuint const& _alphamap_tex = _chunk_texture_arrays[3];
|
||||
|
||||
GLuint _tile_occlusion_query;
|
||||
bool _tile_occlusion_query_in_use = false;
|
||||
|
||||
OpenGL::Scoped::deferred_upload_buffers<1> _buffers;
|
||||
|
||||
GLuint const& _chunk_instance_data_ubo = _buffers[0];
|
||||
OpenGL::ChunkInstanceDataUniformBlock _chunk_instance_data[256];
|
||||
std::array<float, 145 * 256 * 4> _chunk_heightmap_buffer;
|
||||
|
||||
unsigned _chunk_update_flags;
|
||||
|
||||
std::vector<MapTileDrawCall> _draw_calls;
|
||||
|
||||
// MHDR:
|
||||
int mFlags;
|
||||
bool mBigAlpha;
|
||||
@@ -247,12 +209,22 @@ private:
|
||||
tsl::robin_map<AsyncObject*, std::vector<SceneObject*>> object_instances; // only includes M2 and WMO. perhaps a medium common ancestor then?
|
||||
|
||||
std::unique_ptr<MapChunk> mChunks[16][16];
|
||||
std::array<float, 145 * 256 * 4> _chunk_heightmap_buffer;
|
||||
|
||||
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::NoggitRenderContext _context;
|
||||
|
||||
friend class MapChunk;
|
||||
friend class TextureSet;
|
||||
};
|
||||
|
||||
@@ -5123,7 +5123,7 @@ void MapView::unloadOpenglData(bool from_manager)
|
||||
|
||||
for (MapTile* tile : _world->mapIndex.loaded_tiles())
|
||||
{
|
||||
tile->unload();
|
||||
tile->renderer()->unload();
|
||||
tile->Water.unload();
|
||||
|
||||
for (int i = 0; i < 16; ++i)
|
||||
|
||||
@@ -86,11 +86,11 @@ void WMOInstance::draw ( OpenGL::Scoped::use_program& wmo_shader
|
||||
{
|
||||
for (auto& tile : getTiles())
|
||||
{
|
||||
if (tile->objects_frustum_cull_test && !tile->tile_occluded)
|
||||
if (tile->renderer()->objectsFrustumCullTest() && !tile->renderer()->isOccluded())
|
||||
{
|
||||
region_visible = tile->objects_frustum_cull_test;
|
||||
region_visible = tile->renderer()->objectsFrustumCullTest();
|
||||
|
||||
if (tile->objects_frustum_cull_test > 1)
|
||||
if (tile->renderer()->objectsFrustumCullTest() > 1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2956,7 +2956,7 @@ void World::notifyTileRendererOnSelectedTextureChange()
|
||||
|
||||
for (MapTile* tile : mapIndex.loaded_tiles())
|
||||
{
|
||||
tile->notifyTileRendererOnSelectedTextureChange();
|
||||
tile->renderer()->notifyTileRendererOnSelectedTextureChange();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -352,8 +352,8 @@ public:
|
||||
bool need_model_updates = false;
|
||||
|
||||
void loadAllTiles();
|
||||
unsigned getNumLoadedTiles() { return _n_loaded_tiles; };
|
||||
unsigned getNumRenderedTiles() { return _n_rendered_tiles; };
|
||||
unsigned getNumLoadedTiles() const { return _n_loaded_tiles; };
|
||||
unsigned getNumRenderedTiles() const { return _n_rendered_tiles; };
|
||||
|
||||
protected:
|
||||
void update_models_by_filename();
|
||||
|
||||
540
src/noggit/rendering/TileRender.cpp
Normal file
540
src/noggit/rendering/TileRender.cpp
Normal file
@@ -0,0 +1,540 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#include <noggit/rendering/TileRender.hpp>
|
||||
#include <noggit/MapTile.h>
|
||||
#include <noggit/MapChunk.h>
|
||||
#include <noggit/ui/TexturingGUI.h>
|
||||
#include <external/tracy/Tracy.hpp>
|
||||
|
||||
using namespace Noggit::Rendering;
|
||||
|
||||
|
||||
TileRender::TileRender(MapTile* map_tile)
|
||||
: _map_tile(map_tile)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void TileRender::upload()
|
||||
{
|
||||
uploadTextures();
|
||||
_buffers.upload();
|
||||
|
||||
gl.bindBuffer(GL_UNIFORM_BUFFER, _chunk_instance_data_ubo);
|
||||
gl.bindBufferRange(GL_UNIFORM_BUFFER, OpenGL::ubo_targets::CHUNK_INSTANCE_DATA,
|
||||
_chunk_instance_data_ubo, 0, sizeof(OpenGL::ChunkInstanceDataUniformBlock) * 256);
|
||||
gl.bufferData(GL_UNIFORM_BUFFER, sizeof(OpenGL::ChunkInstanceDataUniformBlock) * 256, NULL, GL_DYNAMIC_DRAW);
|
||||
|
||||
MapTileDrawCall& draw_call = _draw_calls.emplace_back();
|
||||
draw_call.start_chunk = 0;
|
||||
draw_call.n_chunks = 256;
|
||||
std::fill(draw_call.samplers.begin(), draw_call.samplers.end(), -1);
|
||||
|
||||
gl.genQueries(1, &_tile_occlusion_query);
|
||||
|
||||
_uploaded = true;
|
||||
|
||||
}
|
||||
|
||||
void TileRender::unload()
|
||||
{
|
||||
if (_uploaded)
|
||||
{
|
||||
_chunk_texture_arrays.unload();
|
||||
_buffers.unload();
|
||||
_uploaded = false;
|
||||
gl.deleteQueries(1, &_tile_occlusion_query);
|
||||
}
|
||||
|
||||
|
||||
_map_tile->_chunk_update_flags = ChunkUpdateFlags::VERTEX | ChunkUpdateFlags::ALPHAMAP
|
||||
| ChunkUpdateFlags::SHADOW | ChunkUpdateFlags::MCCV
|
||||
| ChunkUpdateFlags::NORMALS| ChunkUpdateFlags::HOLES
|
||||
| ChunkUpdateFlags::AREA_ID| ChunkUpdateFlags::FLAGS;
|
||||
}
|
||||
|
||||
|
||||
void TileRender::draw (OpenGL::Scoped::use_program& mcnk_shader
|
||||
, const glm::vec3& camera
|
||||
, bool show_unpaintable_chunks
|
||||
, bool draw_paintability_overlay
|
||||
, bool is_selected
|
||||
)
|
||||
{
|
||||
ZoneScopedN(NOGGIT_CURRENT_FUNCTION);
|
||||
|
||||
static constexpr unsigned NUM_SAMPLERS = 11;
|
||||
|
||||
if (!_map_tile->finished)
|
||||
[[unlikely]]
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_uploaded)
|
||||
[[unlikely]]
|
||||
{
|
||||
upload();
|
||||
}
|
||||
|
||||
bool alphamap_bound = false;
|
||||
bool heightmap_bound = false;
|
||||
bool shadowmap_bound = false;
|
||||
bool mccv_bound = false;
|
||||
|
||||
_texture_not_loaded = false;
|
||||
|
||||
// figure out if we need to update based on paintability
|
||||
bool need_paintability_update = false;
|
||||
if (_requires_paintability_recalc && draw_paintability_overlay && show_unpaintable_chunks)
|
||||
[[unlikely]]
|
||||
{
|
||||
auto cur_tex = Noggit::Ui::selected_texture::get();
|
||||
for (int j = 0; j < 16; ++j)
|
||||
{
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
auto& chunk = _map_tile->mChunks[j][i];
|
||||
bool cant_paint = cur_tex && !chunk->canPaintTexture(*cur_tex);
|
||||
|
||||
if (chunk->currently_paintable != !cant_paint)
|
||||
{
|
||||
chunk->currently_paintable = !cant_paint;
|
||||
_chunk_instance_data[i * 16 + j].ChunkHoles_DrawImpass_TexLayerCount_CantPaint[3] = cant_paint;
|
||||
need_paintability_update = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_requires_paintability_recalc = false;
|
||||
}
|
||||
|
||||
// run chunk updates. running this when splitdraw call detected unused sampler configuration as well.
|
||||
if (_map_tile->_chunk_update_flags || is_selected != _selected || need_paintability_update || _requires_sampler_reset || _texture_not_loaded)
|
||||
{
|
||||
|
||||
gl.bindBuffer(GL_UNIFORM_BUFFER, _chunk_instance_data_ubo);
|
||||
|
||||
if (_requires_sampler_reset)
|
||||
[[unlikely]]
|
||||
{
|
||||
_draw_calls.clear();
|
||||
MapTileDrawCall& draw_call = _draw_calls.emplace_back();
|
||||
std::fill(draw_call.samplers.begin(), draw_call.samplers.end(), -1);
|
||||
draw_call.start_chunk = 0;
|
||||
draw_call.n_chunks = 256;
|
||||
}
|
||||
|
||||
_selected = is_selected;
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
int chunk_x = i / 16;
|
||||
int chunk_y = i % 16;
|
||||
|
||||
auto& chunk = _map_tile->mChunks[chunk_y][chunk_x];
|
||||
|
||||
_chunk_instance_data[i].ChunkXYZBase_Pad1 = {chunk->xbase, chunk->ybase, chunk->zbase, 1.0};
|
||||
|
||||
unsigned flags = chunk->getUpdateFlags();
|
||||
|
||||
if (flags & ChunkUpdateFlags::ALPHAMAP || _requires_sampler_reset || _texture_not_loaded)
|
||||
{
|
||||
gl.activeTexture(GL_TEXTURE0 + 3);
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, _alphamap_tex);
|
||||
alphamap_bound = true;
|
||||
chunk->texture_set->uploadAlphamapData();
|
||||
|
||||
if (!_split_drawcall && !fillSamplers(chunk.get(), i, _draw_calls.size() - 1))
|
||||
{
|
||||
_split_drawcall = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!flags)
|
||||
continue;
|
||||
|
||||
if (flags & ChunkUpdateFlags::VERTEX || flags & ChunkUpdateFlags::NORMALS)
|
||||
{
|
||||
heightmap_bound = true;
|
||||
if (flags & ChunkUpdateFlags::VERTEX)
|
||||
{
|
||||
chunk->updateVerticesData();
|
||||
}
|
||||
|
||||
gl.activeTexture(GL_TEXTURE0 + 0);
|
||||
gl.bindTexture(GL_TEXTURE_2D, _height_tex);
|
||||
gl.texSubImage2D(GL_TEXTURE_2D, 0, 0, i, mapbufsize, 1, GL_RGBA,
|
||||
GL_FLOAT, _map_tile->_chunk_heightmap_buffer.data() + i * mapbufsize * 4);
|
||||
}
|
||||
|
||||
if (flags & ChunkUpdateFlags::MCCV)
|
||||
{
|
||||
mccv_bound = true;
|
||||
gl.activeTexture(GL_TEXTURE0 + 1);
|
||||
gl.bindTexture(GL_TEXTURE_2D, _mccv_tex);
|
||||
chunk->update_vertex_colors();
|
||||
}
|
||||
|
||||
if (flags & ChunkUpdateFlags::SHADOW)
|
||||
{
|
||||
shadowmap_bound = true;
|
||||
gl.activeTexture(GL_TEXTURE0 + 2);
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, _shadowmap_tex);
|
||||
chunk->update_shadows();
|
||||
}
|
||||
|
||||
if (flags & ChunkUpdateFlags::HOLES)
|
||||
{
|
||||
_chunk_instance_data[i].ChunkHoles_DrawImpass_TexLayerCount_CantPaint[0] = chunk->holes;
|
||||
}
|
||||
|
||||
if (flags & ChunkUpdateFlags::FLAGS)
|
||||
{
|
||||
_chunk_instance_data[i].ChunkHoles_DrawImpass_TexLayerCount_CantPaint[1] = chunk->header_flags.flags.impass;
|
||||
|
||||
for (int k = 0; k < chunk->texture_set->num(); ++k)
|
||||
{
|
||||
unsigned layer_flags = chunk->texture_set->flag(k);
|
||||
auto flag_view = reinterpret_cast<MCLYFlags*>(&layer_flags);
|
||||
|
||||
_chunk_instance_data[i].ChunkTexDoAnim[k] = flag_view->animation_enabled;
|
||||
_chunk_instance_data[i].ChunkTexAnimSpeed[k] = flag_view->animation_speed;
|
||||
_chunk_instance_data[i].ChunkTexAnimDir[k] = flag_view->animation_rotation;
|
||||
}
|
||||
|
||||
_chunk_instance_data[i].ChunkTexDoAnim[1] = chunk->header_flags.flags.impass;
|
||||
}
|
||||
|
||||
if (flags & ChunkUpdateFlags::AREA_ID)
|
||||
{
|
||||
_chunk_instance_data[i].AreaIDColor_Pad2_DrawSelection[0] = chunk->areaID;
|
||||
}
|
||||
|
||||
_chunk_instance_data[i].AreaIDColor_Pad2_DrawSelection[3] = _selected;
|
||||
|
||||
chunk->endChunkUpdates();
|
||||
|
||||
if (_texture_not_loaded)
|
||||
chunk->registerChunkUpdate(ChunkUpdateFlags::ALPHAMAP);
|
||||
|
||||
}
|
||||
|
||||
_requires_sampler_reset = false;
|
||||
|
||||
|
||||
if (_split_drawcall)
|
||||
{
|
||||
_draw_calls.clear();
|
||||
MapTileDrawCall& draw_call = _draw_calls.emplace_back();
|
||||
std::fill(draw_call.samplers.begin(), draw_call.samplers.end(), -1);
|
||||
draw_call.start_chunk = 0;
|
||||
draw_call.n_chunks = 0;
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
auto& chunk = _map_tile->mChunks[i % 16][i / 16];
|
||||
|
||||
if (!fillSamplers(chunk.get(), i, _draw_calls.size() - 1))
|
||||
{
|
||||
MapTileDrawCall& previous_draw_call = _draw_calls[_draw_calls.size() - 1];
|
||||
unsigned new_start = previous_draw_call.start_chunk + previous_draw_call.n_chunks;
|
||||
|
||||
MapTileDrawCall& new_draw_call = _draw_calls.emplace_back();
|
||||
std::fill(new_draw_call.samplers.begin(), new_draw_call.samplers.end(), -1);
|
||||
new_draw_call.start_chunk = new_start;
|
||||
new_draw_call.n_chunks = 1;
|
||||
|
||||
fillSamplers(chunk.get(), i, _draw_calls.size() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
MapTileDrawCall& last_draw_call = _draw_calls.back();
|
||||
last_draw_call.n_chunks++;
|
||||
assert(last_draw_call.n_chunks <= 256);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (_draw_calls.size() <= 1)
|
||||
{
|
||||
_split_drawcall = false;
|
||||
_requires_sampler_reset = true;
|
||||
}
|
||||
}
|
||||
|
||||
_map_tile->endChunkUpdates();
|
||||
|
||||
if (_texture_not_loaded)
|
||||
_map_tile->registerChunkUpdate(ChunkUpdateFlags::ALPHAMAP);
|
||||
|
||||
gl.bufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(OpenGL::ChunkInstanceDataUniformBlock) * 256,
|
||||
&_chunk_instance_data);
|
||||
}
|
||||
|
||||
_map_tile->recalcExtents();
|
||||
|
||||
// do not draw anything when textures did not finish loading
|
||||
if (_texture_not_loaded)
|
||||
[[unlikely]]
|
||||
{
|
||||
gl.bindBufferRange(GL_UNIFORM_BUFFER, OpenGL::ubo_targets::CHUNK_INSTANCE_DATA,
|
||||
_chunk_instance_data_ubo, 0, sizeof(OpenGL::ChunkInstanceDataUniformBlock) * 256);
|
||||
return;
|
||||
}
|
||||
|
||||
gl.bindBufferRange(GL_UNIFORM_BUFFER, OpenGL::ubo_targets::CHUNK_INSTANCE_DATA,
|
||||
_chunk_instance_data_ubo, 0, sizeof(OpenGL::ChunkInstanceDataUniformBlock) * 256);
|
||||
|
||||
|
||||
for (auto& draw_call : _draw_calls)
|
||||
{
|
||||
|
||||
if (!alphamap_bound)
|
||||
{
|
||||
gl.activeTexture(GL_TEXTURE0 + 3);
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, _alphamap_tex);
|
||||
}
|
||||
|
||||
if (!shadowmap_bound)
|
||||
{
|
||||
gl.activeTexture(GL_TEXTURE0 + 2);
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, _shadowmap_tex);
|
||||
}
|
||||
|
||||
if (!mccv_bound)
|
||||
{
|
||||
gl.activeTexture(GL_TEXTURE0 + 1);
|
||||
gl.bindTexture(GL_TEXTURE_2D, _mccv_tex);
|
||||
}
|
||||
|
||||
if (!heightmap_bound)
|
||||
{
|
||||
gl.activeTexture(GL_TEXTURE0 + 0);
|
||||
gl.bindTexture(GL_TEXTURE_2D, _height_tex);
|
||||
}
|
||||
|
||||
float tile_center_x = _map_tile->xbase + TILESIZE / 2.0f;
|
||||
float tile_center_z = _map_tile->zbase + TILESIZE / 2.0f;
|
||||
|
||||
bool is_lod = misc::dist(tile_center_x, tile_center_z, camera.x, camera.z) > TILESIZE * 3;
|
||||
mcnk_shader.uniform("lod_level", int(is_lod));
|
||||
|
||||
assert(draw_call.n_chunks <= 256);
|
||||
mcnk_shader.uniform("base_instance", static_cast<int>(draw_call.start_chunk));
|
||||
|
||||
for (int i = 0; i < NUM_SAMPLERS; ++i)
|
||||
{
|
||||
gl.activeTexture(GL_TEXTURE0 + 5 + i);
|
||||
|
||||
if (draw_call.samplers[i] < 0)
|
||||
{
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, draw_call.samplers[i]);
|
||||
}
|
||||
|
||||
if (is_lod)
|
||||
{
|
||||
gl.drawElementsInstanced(GL_TRIANGLES, 192, GL_UNSIGNED_SHORT,
|
||||
reinterpret_cast<void*>(768 * sizeof(std::uint16_t)), draw_call.n_chunks);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl.drawElementsInstanced(GL_TRIANGLES, 768, GL_UNSIGNED_SHORT, nullptr,
|
||||
draw_call.n_chunks);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void TileRender::uploadTextures()
|
||||
{
|
||||
_chunk_texture_arrays.upload();
|
||||
gl.activeTexture(GL_TEXTURE0 + 0);
|
||||
gl.bindTexture(GL_TEXTURE_2D, _height_tex);
|
||||
gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, mapbufsize,
|
||||
256, 0, GL_RGBA, GL_FLOAT,nullptr);
|
||||
|
||||
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
//gl.texParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
//gl.texParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
//gl.texParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
//const GLint swizzleMask[] = {GL_RED, GL_RED, GL_RED, GL_ONE};
|
||||
//gl.texParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
|
||||
|
||||
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
gl.bindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
gl.activeTexture(GL_TEXTURE0 + 2);
|
||||
gl.bindTexture(GL_TEXTURE_2D, _mccv_tex);
|
||||
gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, mapbufsize,
|
||||
256, 0, GL_RGB, GL_FLOAT, nullptr);
|
||||
|
||||
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
//gl.texParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
//gl.texParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
//gl.texParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
gl.bindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
gl.activeTexture(GL_TEXTURE0 + 4);
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, _alphamap_tex);
|
||||
gl.texImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, 64, 64,
|
||||
256, 0, GL_RGB, GL_FLOAT,nullptr);
|
||||
|
||||
gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, 0);
|
||||
|
||||
|
||||
gl.activeTexture(GL_TEXTURE0 + 3);
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, _shadowmap_tex);
|
||||
gl.texImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RED, 64, 64, 256,
|
||||
0, GL_RED, GL_UNSIGNED_BYTE,nullptr);
|
||||
|
||||
gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, 0);
|
||||
}
|
||||
|
||||
void TileRender::doTileOcclusionQuery(OpenGL::Scoped::use_program& occlusion_shader)
|
||||
{
|
||||
if (_tile_occlusion_query_in_use || !_uploaded)
|
||||
return;
|
||||
|
||||
_tile_occlusion_query_in_use = true;
|
||||
gl.beginQuery(GL_ANY_SAMPLES_PASSED, _tile_occlusion_query);
|
||||
occlusion_shader.uniform("aabb", _map_tile->_combined_extents.data(), _map_tile->_combined_extents.size());
|
||||
gl.drawElements(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, nullptr);
|
||||
gl.endQuery(GL_ANY_SAMPLES_PASSED);
|
||||
}
|
||||
|
||||
bool TileRender::getTileOcclusionQueryResult(glm::vec3 const& camera)
|
||||
{
|
||||
// returns true if tile is not occluded by other tiles
|
||||
|
||||
if (!_tile_occlusion_query_in_use)
|
||||
[[unlikely]]
|
||||
{
|
||||
return !_tile_occluded;
|
||||
}
|
||||
|
||||
if (!_uploaded)
|
||||
return !_tile_occluded;
|
||||
|
||||
if (misc::pointInside(camera, _map_tile->_combined_extents))
|
||||
{
|
||||
_tile_occlusion_query_in_use = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
GLint result;
|
||||
gl.getQueryObjectiv(_tile_occlusion_query, GL_QUERY_RESULT_AVAILABLE, &result);
|
||||
|
||||
if (result != GL_TRUE)
|
||||
{
|
||||
return _tile_occlusion_cull_override || !_tile_occluded;
|
||||
}
|
||||
|
||||
if (!_tile_occlusion_cull_override)
|
||||
{
|
||||
gl.getQueryObjectiv(_tile_occlusion_query, GL_QUERY_RESULT, &result);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
|
||||
_tile_occlusion_query_in_use = false;
|
||||
_tile_occlusion_cull_override = false;
|
||||
|
||||
return static_cast<bool>(result);
|
||||
}
|
||||
|
||||
|
||||
bool TileRender::fillSamplers(MapChunk* chunk, unsigned chunk_index, unsigned int draw_call_index)
|
||||
{
|
||||
MapTileDrawCall& draw_call = _draw_calls[draw_call_index];
|
||||
|
||||
_chunk_instance_data[chunk_index].ChunkHoles_DrawImpass_TexLayerCount_CantPaint[2] = chunk->texture_set->num();
|
||||
|
||||
static constexpr unsigned NUM_SAMPLERS = 11;
|
||||
|
||||
_chunk_instance_data[chunk_index].ChunkTextureSamplers[0] = 0;
|
||||
_chunk_instance_data[chunk_index].ChunkTextureSamplers[1] = 0;
|
||||
_chunk_instance_data[chunk_index].ChunkTextureSamplers[2] = 0;
|
||||
_chunk_instance_data[chunk_index].ChunkTextureSamplers[3] = 0;
|
||||
|
||||
_chunk_instance_data[chunk_index].ChunkTextureArrayIDs[0] = -1;
|
||||
_chunk_instance_data[chunk_index].ChunkTextureArrayIDs[1] = -1;
|
||||
_chunk_instance_data[chunk_index].ChunkTextureArrayIDs[2] = -1;
|
||||
_chunk_instance_data[chunk_index].ChunkTextureArrayIDs[3] = -1;
|
||||
|
||||
|
||||
auto& chunk_textures = (*chunk->texture_set->getTextures());
|
||||
for (int k = 0; k < chunk->texture_set->num(); ++k)
|
||||
{
|
||||
chunk_textures[k]->upload();
|
||||
|
||||
if (!chunk_textures[k]->is_uploaded())
|
||||
{
|
||||
_texture_not_loaded = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
GLuint tex_array = (*chunk->texture_set->getTextures())[k]->texture_array();
|
||||
int tex_index = (*chunk->texture_set->getTextures())[k]->array_index();
|
||||
|
||||
int sampler_id = -1;
|
||||
for (int n = 0; n < draw_call.samplers.size(); ++n)
|
||||
{
|
||||
if (draw_call.samplers[n] == tex_array)
|
||||
{
|
||||
sampler_id = n;
|
||||
break;
|
||||
}
|
||||
else if (draw_call.samplers[n] < 0)
|
||||
{
|
||||
draw_call.samplers[n] = tex_array;
|
||||
sampler_id = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If there are not enough sampler slots (11) we have to split the drawcall :(.
|
||||
// Extremely infrequent for terrain. Never for Blizzard terrain as their tilesets
|
||||
// use uniform BLP format per map.
|
||||
if (sampler_id < 0)
|
||||
[[unlikely]]
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_chunk_instance_data[chunk_index].ChunkTextureSamplers[k] = sampler_id;
|
||||
_chunk_instance_data[chunk_index].ChunkTextureArrayIDs[k] = (*chunk->texture_set->getTextures())[k]->is_specular() ? tex_index : -tex_index;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TileRender::initChunkData(MapChunk* chunk)
|
||||
{
|
||||
auto& chunk_render_instance = _chunk_instance_data[chunk->px * 16 + chunk->py];
|
||||
|
||||
chunk_render_instance.ChunkHoles_DrawImpass_TexLayerCount_CantPaint[0] = chunk->holes;
|
||||
chunk_render_instance.ChunkHoles_DrawImpass_TexLayerCount_CantPaint[1] = chunk->header_flags.flags.impass;
|
||||
chunk_render_instance.ChunkHoles_DrawImpass_TexLayerCount_CantPaint[2] = chunk->texture_set->num();
|
||||
chunk_render_instance.ChunkHoles_DrawImpass_TexLayerCount_CantPaint[3] = 0;
|
||||
chunk_render_instance.AreaIDColor_Pad2_DrawSelection[0] = chunk->areaID;
|
||||
chunk_render_instance.AreaIDColor_Pad2_DrawSelection[3] = 0;
|
||||
}
|
||||
101
src/noggit/rendering/TileRender.hpp
Normal file
101
src/noggit/rendering/TileRender.hpp
Normal file
@@ -0,0 +1,101 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#ifndef NOGGIT_TILERENDER_HPP
|
||||
#define NOGGIT_TILERENDER_HPP
|
||||
|
||||
#include <noggit/rendering/BaseRender.hpp>
|
||||
#include <opengl/scoped.hpp>
|
||||
#include <opengl/shader.hpp>
|
||||
#include <array>
|
||||
|
||||
class MapTile;
|
||||
class MapChunk;
|
||||
|
||||
namespace Noggit::Rendering
|
||||
{
|
||||
struct MapTileDrawCall
|
||||
{
|
||||
std::array<int, 11> samplers;
|
||||
unsigned start_chunk;
|
||||
unsigned n_chunks;
|
||||
};
|
||||
|
||||
class TileRender : public BaseRender
|
||||
{
|
||||
public:
|
||||
explicit TileRender(MapTile* map_tile);
|
||||
|
||||
void upload() override;
|
||||
void unload() override;
|
||||
|
||||
void draw (OpenGL::Scoped::use_program& mcnk_shader
|
||||
, const glm::vec3& camera
|
||||
, bool show_unpaintable_chunks
|
||||
, bool draw_paintability_overlay
|
||||
, bool is_selected
|
||||
);
|
||||
|
||||
void doTileOcclusionQuery(OpenGL::Scoped::use_program& occlusion_shader);
|
||||
bool getTileOcclusionQueryResult(glm::vec3 const& camera);
|
||||
void discardTileOcclusionQuery() { _tile_occlusion_query_in_use = false; }
|
||||
void notifyTileRendererOnSelectedTextureChange() { _requires_paintability_recalc = true; };
|
||||
|
||||
void initChunkData(MapChunk* chunk);
|
||||
|
||||
[[nodiscard]]
|
||||
unsigned objectsFrustumCullTest() const { return _objects_frustum_cull_test; };
|
||||
void setObjectsFrustumCullTest(unsigned state) { _objects_frustum_cull_test = state; };
|
||||
|
||||
[[nodiscard]]
|
||||
bool isOccluded() const { return _tile_occluded; } ;
|
||||
void setOccluded(bool state) { _tile_occluded = state; };
|
||||
|
||||
[[nodiscard]]
|
||||
bool isFrustumCulled() const{ return _tile_frustum_culled; };
|
||||
void setFrustumCulled(bool state) {_tile_frustum_culled = state; };
|
||||
|
||||
[[nodiscard]]
|
||||
bool isOverridingOcclusionCulling() const { return _tile_occlusion_cull_override; };
|
||||
void setOverrideOcclusionCulling(bool state) { _tile_frustum_culled = state; };
|
||||
|
||||
private:
|
||||
|
||||
void uploadTextures();
|
||||
bool fillSamplers(MapChunk* chunk, unsigned chunk_index, unsigned draw_call_index);
|
||||
|
||||
MapTile* _map_tile;
|
||||
|
||||
bool _uploaded = false;
|
||||
bool _selected = false;
|
||||
bool _split_drawcall = false;
|
||||
bool _requires_sampler_reset = false;
|
||||
bool _requires_paintability_recalc = true;
|
||||
bool _texture_not_loaded = false;
|
||||
|
||||
// culling
|
||||
unsigned _objects_frustum_cull_test = 0;
|
||||
bool _tile_occluded = false;
|
||||
bool _tile_frustum_culled = true;
|
||||
bool _tile_occlusion_cull_override = true;
|
||||
|
||||
// drawing
|
||||
std::vector<MapTileDrawCall> _draw_calls;
|
||||
|
||||
OpenGL::Scoped::deferred_upload_textures<4> _chunk_texture_arrays;
|
||||
GLuint const& _height_tex = _chunk_texture_arrays[0];
|
||||
GLuint const& _mccv_tex = _chunk_texture_arrays[1];
|
||||
GLuint const& _shadowmap_tex = _chunk_texture_arrays[2];
|
||||
GLuint const& _alphamap_tex = _chunk_texture_arrays[3];
|
||||
|
||||
GLuint _tile_occlusion_query;
|
||||
bool _tile_occlusion_query_in_use = false;
|
||||
|
||||
OpenGL::Scoped::deferred_upload_buffers<1> _buffers;
|
||||
|
||||
GLuint const& _chunk_instance_data_ubo = _buffers[0];
|
||||
OpenGL::ChunkInstanceDataUniformBlock _chunk_instance_data[256];
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif //NOGGIT_TILERENDER_HPP
|
||||
@@ -103,9 +103,9 @@ void WorldRender::draw (glm::mat4x4 const& model_view
|
||||
{
|
||||
auto& tile_extents = tile->getCombinedExtents();
|
||||
tile->calcCamDist(camera_pos);
|
||||
tile->tile_frustum_culled = false;
|
||||
tile->objects_frustum_cull_test = 2;
|
||||
tile->tile_occluded = false;
|
||||
tile->renderer()->setFrustumCulled(false);
|
||||
tile->renderer()->setObjectsFrustumCullTest(2);
|
||||
tile->renderer()->setOccluded(false);
|
||||
_world->_loaded_tiles_buffer[tile_counter] = std::make_pair(std::make_pair(tile->index.x, tile->index.z), tile);
|
||||
|
||||
tile_counter++;
|
||||
@@ -119,27 +119,27 @@ void WorldRender::draw (glm::mat4x4 const& model_view
|
||||
tile->calcCamDist(camera_pos);
|
||||
_world->_loaded_tiles_buffer[tile_counter] = std::make_pair(std::make_pair(tile->index.x, tile->index.z), tile);
|
||||
|
||||
tile->objects_frustum_cull_test = 1;
|
||||
tile->renderer()->setObjectsFrustumCullTest(1);
|
||||
if (frustum.contains(tile_extents[0]) && frustum.contains(tile_extents[1]))
|
||||
{
|
||||
tile->objects_frustum_cull_test++;
|
||||
tile->renderer()->setObjectsFrustumCullTest( tile->renderer()->objectsFrustumCullTest() + 1);
|
||||
}
|
||||
|
||||
if (tile->tile_frustum_culled)
|
||||
if (tile->renderer()->isFrustumCulled())
|
||||
{
|
||||
tile->tile_occlusion_cull_override = true;
|
||||
tile->discardTileOcclusionQuery();
|
||||
tile->tile_occluded = false;
|
||||
tile->renderer()->setOverrideOcclusionCulling(true);
|
||||
tile->renderer()->discardTileOcclusionQuery();
|
||||
tile->renderer()->setOccluded(false);
|
||||
}
|
||||
|
||||
tile->tile_frustum_culled = false;
|
||||
tile->renderer()->setFrustumCulled(false);
|
||||
|
||||
tile_counter++;
|
||||
}
|
||||
else
|
||||
{
|
||||
tile->tile_frustum_culled = true;
|
||||
tile->objects_frustum_cull_test = 0;
|
||||
tile->renderer()->setFrustumCulled(true);
|
||||
tile->renderer()->setObjectsFrustumCullTest(0);
|
||||
}
|
||||
|
||||
_world->_n_loaded_tiles++;
|
||||
@@ -277,12 +277,13 @@ void WorldRender::draw (glm::mat4x4 const& model_view
|
||||
}
|
||||
|
||||
if (minimap_render)
|
||||
tile->tile_occluded = false;
|
||||
tile->renderer()->setOccluded(false);
|
||||
|
||||
if (tile->tile_occluded && !tile->getChunkUpdateFlags() && !tile->tile_occlusion_cull_override)
|
||||
if (tile->renderer()->isOccluded() && !tile->getChunkUpdateFlags() && !tile->renderer()->isOverridingOcclusionCulling())
|
||||
continue;
|
||||
|
||||
tile->draw (mcnk_shader
|
||||
tile->renderer()->draw(
|
||||
mcnk_shader
|
||||
, camera_pos
|
||||
, show_unpaintable_chunks
|
||||
, draw_paintability_overlay
|
||||
@@ -354,9 +355,9 @@ void WorldRender::draw (glm::mat4x4 const& model_view
|
||||
}
|
||||
|
||||
if (minimap_render)
|
||||
tile->tile_occluded = false;
|
||||
tile->renderer()->setOccluded(false);
|
||||
|
||||
if (tile->tile_occluded && !tile->getChunkUpdateFlags() && !tile->tile_occlusion_cull_override)
|
||||
if (tile->renderer()->isOccluded() && !tile->getChunkUpdateFlags() && !tile->renderer()->isOverridingOcclusionCulling())
|
||||
continue;
|
||||
|
||||
// early dist check
|
||||
@@ -373,7 +374,7 @@ void WorldRender::draw (glm::mat4x4 const& model_view
|
||||
// memory allocation heuristic. all objects will pass if tile is entirely in frustum.
|
||||
// otherwise we only allocate for a half
|
||||
|
||||
if (tile->objects_frustum_cull_test > 1)
|
||||
if (tile->renderer()->objectsFrustumCullTest() > 1)
|
||||
{
|
||||
instances.reserve(instances.size() + pair.second.size());
|
||||
}
|
||||
@@ -395,7 +396,7 @@ void WorldRender::draw (glm::mat4x4 const& model_view
|
||||
|
||||
auto m2_instance = static_cast<ModelInstance*>(instance);
|
||||
|
||||
if ((tile->objects_frustum_cull_test > 1 || m2_instance->isInFrustum(frustum)) && m2_instance->isInRenderDist(_cull_distance, camera_pos, display))
|
||||
if ((tile->renderer()->objectsFrustumCullTest() > 1 || m2_instance->isInFrustum(frustum)) && m2_instance->isInRenderDist(_cull_distance, camera_pos, display))
|
||||
{
|
||||
instances.push_back(m2_instance->transformMatrix());
|
||||
}
|
||||
@@ -408,7 +409,7 @@ void WorldRender::draw (glm::mat4x4 const& model_view
|
||||
// memory allocation heuristic. all objects will pass if tile is entirely in frustum.
|
||||
// otherwise we only allocate for a half
|
||||
|
||||
if (tile->objects_frustum_cull_test > 1)
|
||||
if (tile->renderer()->objectsFrustumCullTest() > 1)
|
||||
{
|
||||
wmos_to_draw.reserve(wmos_to_draw.size() + pair.second.size());
|
||||
}
|
||||
@@ -429,7 +430,7 @@ void WorldRender::draw (glm::mat4x4 const& model_view
|
||||
|
||||
auto wmo_instance = static_cast<WMOInstance*>(instance);
|
||||
|
||||
if (tile->objects_frustum_cull_test > 1 || frustum.intersects(wmo_instance->extents[1], wmo_instance->extents[0]))
|
||||
if (tile->renderer()->objectsFrustumCullTest() > 1 || frustum.intersects(wmo_instance->extents[1], wmo_instance->extents[0]))
|
||||
{
|
||||
wmos_to_draw.push_back(wmo_instance);
|
||||
}
|
||||
@@ -498,8 +499,8 @@ void WorldRender::draw (glm::mat4x4 const& model_view
|
||||
break;
|
||||
}
|
||||
|
||||
tile->tile_occluded = !tile->getTileOcclusionQueryResult(camera_pos);
|
||||
tile->doTileOcclusionQuery(occluder_shader);
|
||||
tile->renderer()->setOccluded(!tile->renderer()->getTileOcclusionQueryResult(camera_pos));
|
||||
tile->renderer()->doTileOcclusionQuery(occluder_shader);
|
||||
}
|
||||
|
||||
gl.enable(GL_CULL_FACE);
|
||||
@@ -752,7 +753,7 @@ void WorldRender::draw (glm::mat4x4 const& model_view
|
||||
if (!tile)
|
||||
break;
|
||||
|
||||
if (tile->tile_occluded && !tile->Water.needsUpdate() && !tile->tile_occlusion_cull_override)
|
||||
if (tile->renderer()->isOccluded() && !tile->Water.needsUpdate() && !tile->renderer()->isOverridingOcclusionCulling())
|
||||
continue;
|
||||
|
||||
tile->drawWater ( frustum
|
||||
|
||||
Reference in New Issue
Block a user