push water changes (does not work yet)
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
|
||||
uniform sampler2D tex;
|
||||
#version 410 core
|
||||
|
||||
layout (std140) uniform lighting
|
||||
{
|
||||
@@ -16,16 +14,85 @@ layout (std140) uniform lighting
|
||||
};
|
||||
|
||||
|
||||
uniform int type;
|
||||
uniform float animtime;
|
||||
uniform vec2 param;
|
||||
uniform sampler2DArray texture_samplers[14] ;
|
||||
|
||||
in float depth_;
|
||||
in vec2 tex_coord_;
|
||||
in float dist_from_camera_;
|
||||
flat in uint tex_array;
|
||||
flat in uint type;
|
||||
flat in vec2 anim_uv;
|
||||
|
||||
out vec4 out_color;
|
||||
|
||||
int get_texture_frame()
|
||||
{
|
||||
return int(animtime / 60) % 30;
|
||||
}
|
||||
|
||||
vec4 get_tex_color(vec2 tex_coord, uint tex_sampler, int array_index)
|
||||
{
|
||||
if (tex_sampler == 0)
|
||||
{
|
||||
return texture(texture_samplers[0], vec3(tex_coord, array_index)).rgba;
|
||||
}
|
||||
else if (tex_sampler == 1)
|
||||
{
|
||||
return texture(texture_samplers[1], vec3(tex_coord, array_index)).rgba;
|
||||
}
|
||||
else if (tex_sampler == 2)
|
||||
{
|
||||
return texture(texture_samplers[2], vec3(tex_coord, array_index)).rgba;
|
||||
}
|
||||
else if (tex_sampler == 3)
|
||||
{
|
||||
return texture(texture_samplers[3], vec3(tex_coord, array_index)).rgba;
|
||||
}
|
||||
else if (tex_sampler == 4)
|
||||
{
|
||||
return texture(texture_samplers[4], vec3(tex_coord, array_index)).rgba;
|
||||
}
|
||||
else if (tex_sampler == 5)
|
||||
{
|
||||
return texture(texture_samplers[5], vec3(tex_coord, array_index)).rgba;
|
||||
}
|
||||
else if (tex_sampler == 6)
|
||||
{
|
||||
return texture(texture_samplers[6], vec3(tex_coord, array_index)).rgba;
|
||||
}
|
||||
else if (tex_sampler == 7)
|
||||
{
|
||||
return texture(texture_samplers[7], vec3(tex_coord, array_index)).rgba;
|
||||
}
|
||||
else if (tex_sampler == 8)
|
||||
{
|
||||
return texture(texture_samplers[8], vec3(tex_coord, array_index)).rgba;
|
||||
}
|
||||
else if (tex_sampler == 9)
|
||||
{
|
||||
return texture(texture_samplers[9], vec3(tex_coord, array_index)).rgba;
|
||||
}
|
||||
else if (tex_sampler == 10)
|
||||
{
|
||||
return texture(texture_samplers[10], vec3(tex_coord, array_index)).rgba;
|
||||
}
|
||||
else if (tex_sampler == 11)
|
||||
{
|
||||
return texture(texture_samplers[11], vec3(tex_coord, array_index)).rgba;
|
||||
}
|
||||
else if (tex_sampler == 12)
|
||||
{
|
||||
return texture(texture_samplers[12], vec3(tex_coord, array_index)).rgba;
|
||||
}
|
||||
else if (tex_sampler == 13)
|
||||
{
|
||||
return texture(texture_samplers[13], vec3(tex_coord, array_index)).rgba;
|
||||
}
|
||||
|
||||
return vec4(0);
|
||||
}
|
||||
|
||||
vec2 rot2(vec2 p, float degree)
|
||||
{
|
||||
float a = radians(degree);
|
||||
@@ -37,12 +104,12 @@ void main()
|
||||
// lava || slime
|
||||
if(type == 2 || type == 3)
|
||||
{
|
||||
out_color = texture(tex, tex_coord_ + vec2(param.x*animtime, param.y*animtime));
|
||||
out_color = get_tex_color(tex_coord_ + vec2(anim_uv.x*animtime, anim_uv.y*animtime), tex_array, get_texture_frame());
|
||||
}
|
||||
else
|
||||
{
|
||||
vec2 uv = rot2(tex_coord_ * param.x, param.y);
|
||||
vec4 texel = texture(tex, uv);
|
||||
vec2 uv = rot2(tex_coord_ * anim_uv.x, anim_uv.y);
|
||||
vec4 texel = get_tex_color(uv, tex_array, get_texture_frame());
|
||||
vec4 lerp = (type == 1)
|
||||
? mix (OceanColorLight, OceanColorDark, depth_)
|
||||
: mix (RiverColorLight, RiverColorDark, depth_)
|
||||
@@ -70,4 +137,6 @@ void main()
|
||||
|
||||
out_color.rgb = mix(out_color.rgb, FogColor_FogOn.rgb, fogFactor);
|
||||
}
|
||||
|
||||
out_color = vec4(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
@@ -1,18 +1,39 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
#version 330 core
|
||||
#version 410 core
|
||||
|
||||
in vec4 position;
|
||||
in vec2 tex_coord;
|
||||
in float depth;
|
||||
const float TILESIZE = 533.33333f;
|
||||
const float CHUNKSIZE = ((TILESIZE) / 16.0f);
|
||||
const float UNITSIZE = (CHUNKSIZE / 8.0f);
|
||||
|
||||
in vec2 position;
|
||||
|
||||
uniform vec3 camera;
|
||||
|
||||
struct LiquidChunkInstanceDataUniformBlock
|
||||
{
|
||||
uint texture_array;
|
||||
uint type;
|
||||
float xbase;
|
||||
float zbase;
|
||||
float anim_u;
|
||||
float anim_v;
|
||||
uint subchunks_1;
|
||||
uint subchunks_2;
|
||||
};
|
||||
|
||||
layout (std140) uniform matrices
|
||||
{
|
||||
mat4 model_view;
|
||||
mat4 projection;
|
||||
};
|
||||
|
||||
layout (std140) uniform liquid_layers_params
|
||||
{
|
||||
LiquidChunkInstanceDataUniformBlock[256] layer_params;
|
||||
};
|
||||
|
||||
uniform sampler2DArray vertex_data;
|
||||
|
||||
uniform mat4 transform;
|
||||
|
||||
uniform int use_transform = int(0);
|
||||
@@ -20,19 +41,60 @@ uniform int use_transform = int(0);
|
||||
out float depth_;
|
||||
out vec2 tex_coord_;
|
||||
out float dist_from_camera_;
|
||||
flat out uint tex_array;
|
||||
flat out uint type;
|
||||
flat out vec2 anim_uv;
|
||||
|
||||
bool hasSubchunk(uint x, uint z, uint subchunks_first, uint subchunks_second)
|
||||
{
|
||||
return bool((subchunks_second >> (z * 8 + x - 32 * uint(z < 4))) & 1u);
|
||||
}
|
||||
|
||||
float makeNaN(float nonneg)
|
||||
{
|
||||
return sqrt(-nonneg-1.0);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
depth_ = depth;
|
||||
tex_coord_ = tex_coord;
|
||||
dist_from_camera_ = distance(camera, position.xyz);
|
||||
uint vertex_x = uint(position.x / UNITSIZE);
|
||||
uint vertex_y = uint(position.y / UNITSIZE);
|
||||
|
||||
if(use_transform == 1)
|
||||
vec4 v_data = texelFetch(vertex_data, ivec3(vertex_x, vertex_y, gl_InstanceID), 0);
|
||||
|
||||
LiquidChunkInstanceDataUniformBlock params = layer_params[gl_InstanceID];
|
||||
|
||||
uint sschunk = gl_VertexID / 3 / 2;
|
||||
uint schunk_x = sschunk % 8;
|
||||
uint schunk_z = sschunk / 8;
|
||||
|
||||
vec4 final_pos;
|
||||
|
||||
if (hasSubchunk(schunk_x, schunk_z, params.subchunks_1, params.subchunks_2))
|
||||
{
|
||||
gl_Position = projection * model_view * transform * position;
|
||||
final_pos = vec4(position.x + params.xbase, v_data.r, position.y + params.zbase, 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_Position = projection * model_view * position;
|
||||
float NaN = makeNaN(1);
|
||||
final_pos = vec4(NaN, NaN, NaN, NaN);
|
||||
}
|
||||
|
||||
final_pos = vec4(position.x + params.xbase, 0, position.y + params.zbase, 1.0);
|
||||
|
||||
depth_ = v_data.g;
|
||||
tex_coord_ = v_data.ba;
|
||||
dist_from_camera_ = distance(camera, final_pos.xyz);
|
||||
tex_array = params.texture_array;
|
||||
type = params.type;
|
||||
anim_uv = vec2(params.anim_u, params.anim_v);
|
||||
|
||||
if(use_transform == 1)
|
||||
{
|
||||
gl_Position = projection * model_view * transform * final_pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_Position = projection * model_view * final_pos;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,10 +44,23 @@ void ChunkWater::from_mclq(std::vector<mclq>& layers)
|
||||
|
||||
switch (mclq_liquid_type)
|
||||
{
|
||||
case 1:_layers.emplace_back(this, pos, liquid, 2); break;
|
||||
case 3:_layers.emplace_back(this, pos, liquid, 4); break;
|
||||
case 4:_layers.emplace_back(this, pos, liquid, 1); break;
|
||||
case 6:_layers.emplace_back(this, pos, liquid, (_use_mclq_green_lava ? 15 : 3)); break;
|
||||
case 1:
|
||||
_layers.emplace_back(this, pos, liquid, 2);
|
||||
_water_tile->markBuffersDirty();
|
||||
break;
|
||||
case 3:
|
||||
_layers.emplace_back(this, pos, liquid, 4);
|
||||
_water_tile->markBuffersDirty();
|
||||
break;
|
||||
case 4:
|
||||
_layers.emplace_back(this, pos, liquid, 1);
|
||||
_water_tile->markBuffersDirty();
|
||||
break;
|
||||
case 6:
|
||||
_layers.emplace_back(this, pos, liquid, (_use_mclq_green_lava ? 15 : 3));
|
||||
_water_tile->markBuffersDirty();
|
||||
|
||||
break;
|
||||
default:
|
||||
LogError << "Invalid/unhandled MCLQ liquid type" << std::endl;
|
||||
break;
|
||||
@@ -94,6 +107,7 @@ void ChunkWater::fromFile(MPQFile &f, size_t basePos)
|
||||
|
||||
math::vector_3d pos(xbase, 0.0f, zbase);
|
||||
_layers.emplace_back(this, f, basePos, pos, info, infoMask);
|
||||
_water_tile->markBuffersDirty();
|
||||
}
|
||||
|
||||
update_layers();
|
||||
@@ -259,6 +273,8 @@ void ChunkWater::paintLiquid( math::vector_3d const& pos
|
||||
liquid_layer layer(this, math::vector_3d(xbase, 0.0f, zbase), pos.y, liquid_id);
|
||||
copy_height_to_layer(layer, pos, radius);
|
||||
_layers.push_back(layer);
|
||||
_water_tile->markBuffersDirty();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,12 +308,14 @@ void ChunkWater::paintLiquid( math::vector_3d const& pos
|
||||
layer.paintLiquid(pos, radius, true, angle, orientation, lock, origin, override_height, chunk, opacity_factor);
|
||||
layer.changeLiquidID(liquid_id);
|
||||
_layers.push_back(layer);
|
||||
_water_tile->markBuffersDirty();
|
||||
}
|
||||
else
|
||||
{
|
||||
liquid_layer layer(this, math::vector_3d(xbase, 0.0f, zbase), pos.y, liquid_id);
|
||||
layer.paintLiquid(pos, radius, true, angle, orientation, lock, origin, override_height, chunk, opacity_factor);
|
||||
_layers.push_back(layer);
|
||||
_water_tile->markBuffersDirty();
|
||||
}
|
||||
|
||||
update_layers();
|
||||
@@ -309,6 +327,7 @@ void ChunkWater::cleanup()
|
||||
{
|
||||
if (_layers[i].empty())
|
||||
{
|
||||
_water_tile->unregisterChunkLayer(&*(_layers.begin() + i));
|
||||
_layers.erase(_layers.begin() + i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ void LiquidTextureManager::upload()
|
||||
|
||||
// init 2D texture array
|
||||
// loading a texture is required to get its dimensions and format
|
||||
blp_texture tex(boost::str(boost::format(filename) % i), _context);
|
||||
blp_texture tex(boost::str(boost::format(filename) % 1), _context);
|
||||
tex.finishLoading();
|
||||
|
||||
int width_ = tex.width();
|
||||
@@ -95,7 +95,7 @@ void LiquidTextureManager::upload()
|
||||
|
||||
for (int j = 0; j < N_FRAMES; ++j)
|
||||
{
|
||||
blp_texture tex_frame(boost::str(boost::format(filename) % j), _context);
|
||||
blp_texture tex_frame(boost::str(boost::format(filename) % (j + 1)), _context);
|
||||
tex_frame.finishLoading();
|
||||
|
||||
// error checking
|
||||
|
||||
@@ -426,15 +426,15 @@ void MapTile::draw ( math::frustum const& frustum
|
||||
|
||||
// figure out if we need to update based on paintability
|
||||
bool need_paintability_update = false;
|
||||
if (draw_paintability_overlay && show_unpaintable_chunks)
|
||||
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];
|
||||
auto cur_tex = noggit::ui::selected_texture::get();
|
||||
bool cant_paint = cur_tex && !chunk->canPaintTexture(*cur_tex);
|
||||
|
||||
if (chunk->currently_paintable != !cant_paint)
|
||||
@@ -445,6 +445,8 @@ void MapTile::draw ( math::frustum const& frustum
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_requires_paintability_recalc = false;
|
||||
}
|
||||
|
||||
// run chunk updates. running this when splitdraw call detected unused sampler configuration as well.
|
||||
@@ -851,11 +853,11 @@ void MapTile::drawWater ( math::frustum const& frustum
|
||||
, const float& cull_distance
|
||||
, const math::vector_3d& camera
|
||||
, bool camera_moved
|
||||
, liquid_render& render
|
||||
, opengl::scoped::use_program& water_shader
|
||||
, int animtime
|
||||
, int layer
|
||||
, display_mode display
|
||||
, LiquidTextureManager* tex_manager
|
||||
)
|
||||
{
|
||||
if (!Water.hasData(0))
|
||||
@@ -867,11 +869,11 @@ void MapTile::drawWater ( math::frustum const& frustum
|
||||
, cull_distance
|
||||
, camera
|
||||
, camera_moved
|
||||
, render
|
||||
, water_shader
|
||||
, animtime
|
||||
, layer
|
||||
, display
|
||||
, tex_manager
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -95,11 +95,11 @@ public:
|
||||
, const float& cull_distance
|
||||
, const math::vector_3d& camera
|
||||
, bool camera_moved
|
||||
, liquid_render& render
|
||||
, opengl::scoped::use_program& water_shader
|
||||
, int animtime
|
||||
, int layer
|
||||
, display_mode display
|
||||
, LiquidTextureManager* tex_manager
|
||||
);
|
||||
|
||||
void drawMFBO (opengl::scoped::use_program&);
|
||||
@@ -155,6 +155,8 @@ public:
|
||||
GLuint getAlphamapTextureHandle() { return _alphamap_tex; };
|
||||
World* getWorld() { return _world; };
|
||||
|
||||
void notifyTileRendererOnSelectedTextureChange() { _requires_paintability_recalc = true; }
|
||||
|
||||
private:
|
||||
|
||||
void uploadTextures();
|
||||
@@ -165,6 +167,7 @@ private:
|
||||
bool _selected = false;
|
||||
bool _split_drawcall = false;
|
||||
bool _requires_sampler_reset = true;
|
||||
bool _requires_paintability_recalc = true;
|
||||
|
||||
std::array<math::vector_3d, 2> _extents;
|
||||
|
||||
|
||||
@@ -655,7 +655,12 @@ void MapView::setupTexturePainterUi()
|
||||
, &_show_texture_palette_small_window, &noggit::bool_toggle_property::set
|
||||
);
|
||||
|
||||
|
||||
connect(texturingTool->_current_texture, &noggit::ui::current_texture::texture_updated
|
||||
, [=]()
|
||||
{
|
||||
_world->notifyTileRendererOnSelectedTextureChange();
|
||||
}
|
||||
);
|
||||
|
||||
/* Texture Picker */
|
||||
|
||||
|
||||
@@ -248,7 +248,7 @@ void PreviewRenderer::draw()
|
||||
wmo_instance.draw(
|
||||
wmo_program, model_view().transposed(), projection().transposed(), frustum, culldistance,
|
||||
math::vector_3d(0.0f, 0.0f, 0.0f), _draw_boxes.get(), _draw_models.get() // doodads
|
||||
, false, _liquid_render.get(), std::vector<selection_type>(), 0, false, display_mode::in_3D
|
||||
, false, std::vector<selection_type>(), 0, false, display_mode::in_3D
|
||||
);
|
||||
|
||||
gl.enable(GL_BLEND);
|
||||
|
||||
@@ -322,8 +322,14 @@ void blp_texture::loadFromUncompressedData(BLPHeader const* lHeader, char const*
|
||||
{
|
||||
unsigned int k = pal[*c++];
|
||||
k = ((k & 0x00FF0000) >> 16) | ((k & 0x0000FF00)) | ((k & 0x000000FF) << 16);
|
||||
|
||||
int alpha = 0xFF;
|
||||
if (hasalpha)
|
||||
|
||||
if (_is_tileset && !_is_specular)
|
||||
{
|
||||
alpha = 0x00;
|
||||
}
|
||||
else if (hasalpha)
|
||||
{
|
||||
if (alphabits == 8)
|
||||
{
|
||||
@@ -414,6 +420,8 @@ void blp_texture::finishLoading()
|
||||
|
||||
if (filename.starts_with("tileset/"))
|
||||
{
|
||||
_is_tileset = true;
|
||||
|
||||
spec_filename = filename.substr(0, filename.find_last_of(".")) + "_s.blp";
|
||||
has_specular = MPQFile::exists(spec_filename);
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ private:
|
||||
noggit::NoggitRenderContext _context;
|
||||
|
||||
bool _is_specular = false;
|
||||
bool _is_tileset = false;
|
||||
|
||||
private:
|
||||
std::map<int, std::vector<uint32_t>> _data;
|
||||
|
||||
@@ -6,18 +6,22 @@
|
||||
#include <noggit/Misc.h>
|
||||
#include <noggit/TileWater.hpp>
|
||||
#include <noggit/liquid_layer.hpp>
|
||||
#include <stdexcept>
|
||||
#include <noggit/World.h>
|
||||
#include <noggit/LiquidTextureManager.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <iterator>
|
||||
|
||||
TileWater::TileWater(MapTile *pTile, float pXbase, float pZbase, bool use_mclq_green_lava)
|
||||
: tile(pTile)
|
||||
, xbase(pXbase)
|
||||
, zbase(pZbase)
|
||||
, _update_flags(ll_HEIGHT || ll_DEPTH || ll_UV || ll_FLAGS || ll_TYPE)
|
||||
{
|
||||
// by default we allocate space only for one liquid layer
|
||||
_chunk_instances.reserve(256);
|
||||
_chunk_layer_refs.reserve(256);
|
||||
_chunk_instance_indices.reserve(256);
|
||||
_chunk_layer_ptrs.reserve(256);
|
||||
_chunk_data.reserve(256);
|
||||
|
||||
for (int z = 0; z < 16; ++z)
|
||||
{
|
||||
@@ -44,29 +48,66 @@ void TileWater::draw ( math::frustum const& frustum
|
||||
, const float& cull_distance
|
||||
, const math::vector_3d& camera
|
||||
, bool camera_moved
|
||||
, liquid_render& render
|
||||
, opengl::scoped::use_program& water_shader
|
||||
, int animtime
|
||||
, int layer
|
||||
, display_mode display
|
||||
, LiquidTextureManager* tex_manager
|
||||
)
|
||||
{
|
||||
for (int z = 0; z < 16; ++z)
|
||||
|
||||
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};
|
||||
|
||||
if (!_loaded)
|
||||
[[unlikely]]
|
||||
{
|
||||
for (int x = 0; x < 16; ++x)
|
||||
{
|
||||
chunks[z][x]->draw ( frustum
|
||||
, cull_distance
|
||||
, camera
|
||||
, camera_moved
|
||||
, render
|
||||
, water_shader
|
||||
, animtime
|
||||
, layer
|
||||
, display
|
||||
);
|
||||
}
|
||||
upload();
|
||||
}
|
||||
|
||||
updateLayerData(tex_manager);
|
||||
|
||||
std::size_t n_render_blocks = _liquid_vertex_data_textures.size();
|
||||
|
||||
for (std::size_t i = 0; i < n_render_blocks; ++i)
|
||||
{
|
||||
std::size_t chunk_index = i % 256;
|
||||
|
||||
gl.bindBuffer(GL_UNIFORM_BUFFER, _liquid_parameters_buffers[i]);
|
||||
gl.bindBufferRange(GL_UNIFORM_BUFFER, opengl::ubo_targets::CHUNK_LIQUID_INSTANCE_INDEX, _liquid_vertex_data_textures[i], 0, sizeof(opengl::LiquidChunkInstanceDataUniformBlock));
|
||||
|
||||
gl.activeTexture(GL_TEXTURE0);
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, _liquid_vertex_data_textures[i]);
|
||||
|
||||
if (_chunk_layer_texture_samplers[i].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 < _chunk_layer_texture_samplers[i].size(); ++j)
|
||||
{
|
||||
samplers_upload_buf[j] = _chunk_layer_texture_samplers[i][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, std::min(static_cast<unsigned>(_n_chunk_instances - (i * 256)),
|
||||
256u));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ChunkWater* TileWater::getChunk(int x, int z)
|
||||
@@ -162,64 +203,219 @@ int TileWater::getType(size_t layer)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TileWater::registerChunkLayerUpdate(unsigned flags)
|
||||
{
|
||||
_update_flags |= flags;
|
||||
}
|
||||
|
||||
void TileWater::updateLayerData(LiquidTextureManager* tex_manager)
|
||||
{
|
||||
tsl::robin_map<unsigned, std::tuple<GLuint, math::vector_2d, int>> const& tex_frames = tex_manager->getTextureFrames();
|
||||
|
||||
// create opengl resources if needed
|
||||
if (_need_buffer_update)
|
||||
{
|
||||
// alloc or realloc index texture
|
||||
/*
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
gl.bindTexture(GL_TEXTURE_2D, _liquid_chunk_index_texture);
|
||||
gl.texImage2D(GL_TEXTURE_2D, 0, GL_R32UI, 9, 9, 0, GL_R, GL_UNSIGNED_INT, nullptr);
|
||||
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||
*/
|
||||
|
||||
_chunk_layer_ptrs.clear();
|
||||
_chunk_data.clear();
|
||||
_chunk_layer_ptrs.reserve(256);
|
||||
_chunk_data.reserve(256);
|
||||
_n_chunk_instances = 0;
|
||||
|
||||
for (std::size_t z = 0; z < 16; ++z)
|
||||
{
|
||||
for (std::size_t x = 0; x < 16; ++x)
|
||||
{
|
||||
for (auto& layer : *chunks[z][x]->getLayers())
|
||||
{
|
||||
_chunk_layer_ptrs.emplace_back(&layer);
|
||||
_chunk_data.emplace_back();
|
||||
_n_chunk_instances++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// grow
|
||||
while (_liquid_vertex_data_textures.size() * 256 < _n_chunk_instances)
|
||||
{
|
||||
GLuint& data_tex = _liquid_vertex_data_textures.emplace_back();
|
||||
gl.genTextures(1, &data_tex);
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, 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);
|
||||
|
||||
GLuint& buf = _liquid_parameters_buffers.emplace_back();
|
||||
gl.genBuffers(1, &buf);
|
||||
gl.bindBuffer(GL_UNIFORM_BUFFER, buf);
|
||||
gl.bufferData(GL_UNIFORM_BUFFER, sizeof(opengl::LiquidChunkInstanceDataUniformBlock) * 256, NULL, GL_DYNAMIC_DRAW);
|
||||
gl.bindBufferRange(GL_UNIFORM_BUFFER, opengl::ubo_targets::CHUNK_LIQUID_INSTANCE_INDEX, buf, 0, sizeof(opengl::LiquidChunkInstanceDataUniformBlock));
|
||||
|
||||
_chunk_layer_texture_samplers.emplace_back();
|
||||
}
|
||||
|
||||
// shrink
|
||||
while (_liquid_vertex_data_textures.size() * 256 > _n_chunk_instances && _liquid_vertex_data_textures.size() * 256 - _n_chunk_instances % 256 >= 256)
|
||||
{
|
||||
GLuint data_tex = _liquid_vertex_data_textures.back();
|
||||
gl.deleteTextures(1, &data_tex);
|
||||
_liquid_vertex_data_textures.pop_back();
|
||||
|
||||
GLuint params_buf = _liquid_parameters_buffers.back();
|
||||
gl.deleteBuffers(1, ¶ms_buf);
|
||||
_liquid_parameters_buffers.pop_back();
|
||||
|
||||
_chunk_layer_texture_samplers.pop_back();
|
||||
}
|
||||
|
||||
// vertex data
|
||||
unsigned cur_buf_index = 0;
|
||||
for (std::size_t i = 0; i < _chunk_layer_ptrs.size(); ++i)
|
||||
{
|
||||
unsigned tex_index = i % 256;
|
||||
|
||||
if (!tex_index)
|
||||
{
|
||||
gl.bindTexture(GL_TEXTURE_2D_ARRAY, _liquid_vertex_data_textures[cur_buf_index]);
|
||||
gl.bindBuffer(GL_UNIFORM_BUFFER, _liquid_parameters_buffers[cur_buf_index]);
|
||||
cur_buf_index++;
|
||||
}
|
||||
|
||||
prepareBufferData(i);
|
||||
gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, tex_index, 9, 9, 1, GL_RGBA, GL_FLOAT, &_chunk_data[i]);
|
||||
|
||||
// per layer chunk params
|
||||
liquid_layer* layer = _chunk_layer_ptrs[i];
|
||||
std::tuple<GLuint, math::vector_2d, int> const& tex_profile = tex_frames.at(layer->liquidID());
|
||||
opengl::LiquidChunkInstanceDataUniformBlock params_data{};
|
||||
params_data.xbase = layer->getChunk()->xbase;
|
||||
params_data.zbase = layer->getChunk()->zbase;
|
||||
|
||||
GLuint tex_array = std::get<0>(tex_profile);
|
||||
std::vector<int>& samplers_array = _chunk_layer_texture_samplers[cur_buf_index - 1];
|
||||
auto it = std::find(samplers_array.begin(), samplers_array.end(), tex_array);
|
||||
|
||||
unsigned sampler_index = 0;
|
||||
|
||||
if (it != samplers_array.end())
|
||||
{
|
||||
sampler_index = std::distance(samplers_array.begin(), it);
|
||||
}
|
||||
else
|
||||
{
|
||||
sampler_index = samplers_array.size();
|
||||
samplers_array.emplace_back(std::get<0>(tex_profile));
|
||||
}
|
||||
|
||||
params_data.texture_array = sampler_index;
|
||||
params_data.type = std::get<2>(tex_profile);
|
||||
|
||||
math::vector_2d 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'FFull << 32;
|
||||
params_data.subchunks_2 = subchunks & 0xFF'FF'FF'FF;
|
||||
|
||||
gl.bufferSubData(GL_UNIFORM_BUFFER, tex_index * sizeof(opengl::LiquidChunkInstanceDataUniformBlock), sizeof(opengl::LiquidChunkInstanceDataUniformBlock), ¶ms_data);
|
||||
|
||||
}
|
||||
_need_buffer_update = false;
|
||||
}
|
||||
}
|
||||
|
||||
void TileWater::upload()
|
||||
{
|
||||
_buffers.upload();
|
||||
gl.genTextures(1, &_liquid_chunk_index_texture);
|
||||
_loaded = true;
|
||||
}
|
||||
|
||||
void TileWater::unload()
|
||||
{
|
||||
_buffers.unload();
|
||||
|
||||
gl.deleteTextures(_liquid_vertex_data_textures.size(), _liquid_vertex_data_textures.data());
|
||||
gl.deleteBuffers(_liquid_parameters_buffers.size(), _liquid_parameters_buffers.data());
|
||||
_liquid_vertex_data_textures.clear();
|
||||
_liquid_parameters_buffers.clear();
|
||||
_liquid_vertex_data_textures.clear();
|
||||
|
||||
gl.deleteTextures(1, &_liquid_chunk_index_texture);
|
||||
|
||||
//gl.deleteTextures(0, &_liquid_vertex_data);
|
||||
_update_flags = ll_HEIGHT || ll_DEPTH || ll_UV || ll_FLAGS || ll_TYPE;
|
||||
|
||||
_loaded = false;
|
||||
_need_buffer_update = true;
|
||||
}
|
||||
|
||||
void TileWater::registerChunkLayer(liquid_layer* layer)
|
||||
{
|
||||
if (_chunk_layer_refs.capacity() == _chunk_layer_refs.size())
|
||||
{
|
||||
_chunk_layer_refs.reserve(_chunk_layer_refs.capacity() + 256);
|
||||
}
|
||||
|
||||
if (_chunk_instances.capacity() == _chunk_instances.size())
|
||||
{
|
||||
_chunk_instances.reserve(_chunk_instances.capacity() + 256);
|
||||
}
|
||||
|
||||
_chunk_layer_refs.emplace_back(layer);
|
||||
|
||||
opengl::LiquidChunkInstanceDataUniformBlock chunk_instance{};
|
||||
MapChunk* chunk = layer->getChunk()->getChunk();
|
||||
//chunk_instance.BaseHeight_ChunkXY_Pad1[1] = chunk->mt->xbase + (chunk->px * CHUNKSIZE);
|
||||
//chunk_instance.BaseHeight_ChunkXY_Pad1[2] = chunk->mt->zbase + (chunk->py * CHUNKSIZE);
|
||||
|
||||
_chunk_instances.push_back(chunk_instance);
|
||||
_chunk_layer_ptrs.emplace_back(layer);
|
||||
_chunk_instance_indices.emplace_back(_n_layer_chunks);
|
||||
_chunk_data.emplace_back();
|
||||
_chunk_layer_texture_samplers.clear();
|
||||
|
||||
_n_layer_chunks++;
|
||||
_need_buffer_update = true;
|
||||
}
|
||||
|
||||
void TileWater::unregisterChunkLayer(liquid_layer* layer)
|
||||
{
|
||||
auto it = std::find(_chunk_layer_refs.begin(), _chunk_layer_refs.end(), layer);
|
||||
auto it = std::find(_chunk_layer_ptrs.begin(), _chunk_layer_ptrs.end(), layer);
|
||||
|
||||
if (it != _chunk_layer_refs.end())
|
||||
if (it != _chunk_layer_ptrs.end())
|
||||
{
|
||||
int index = it - _chunk_layer_ptrs.begin();
|
||||
|
||||
_chunk_instance_indices.erase(_chunk_instance_indices.begin() + index);
|
||||
_chunk_data.erase(_chunk_data.begin() + index);
|
||||
_chunk_layer_ptrs.erase(it);
|
||||
_n_layer_chunks--;
|
||||
|
||||
// shrink the container
|
||||
if (_chunk_layer_ptrs.capacity() > _chunk_layer_ptrs.size() && _chunk_layer_ptrs.capacity() - _chunk_layer_ptrs.size() >= 256)
|
||||
{
|
||||
_chunk_instance_indices.resize(_chunk_layer_ptrs.size());
|
||||
_chunk_layer_ptrs.resize(_chunk_layer_ptrs.size());
|
||||
_chunk_data.resize(_chunk_data.size());
|
||||
}
|
||||
|
||||
_need_buffer_update = true;
|
||||
_chunk_layer_texture_samplers.clear();
|
||||
|
||||
int index = it - _chunk_layer_refs.begin();
|
||||
_chunk_layer_refs.erase(it);
|
||||
_chunk_instances.erase(_chunk_instances.begin() + index);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::logic_error("Tried unregistering already freed liquid chunk");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TileWater::updateChunkLayer(liquid_layer* layer)
|
||||
void TileWater::prepareBufferData(std::size_t layer_index)
|
||||
{
|
||||
auto it = std::find(_chunk_layer_refs.begin(), _chunk_layer_refs.end(), layer);
|
||||
liquid_layer* layer = _chunk_layer_ptrs[layer_index];
|
||||
std::array<math::vector_4d, 9 * 9>& chunk_layer_data = _chunk_data.at(layer_index);
|
||||
|
||||
if (it != _chunk_layer_refs.end())
|
||||
auto& vertices = layer->getVertices();
|
||||
auto& tex_coords = layer->getTexCoords();
|
||||
auto& depth = layer->getDepth();
|
||||
|
||||
for (int z = 0; z < 9; ++z)
|
||||
{
|
||||
int index = it - _chunk_layer_refs.begin();
|
||||
|
||||
opengl::LiquidChunkInstanceDataUniformBlock& instance = _chunk_instances[index];
|
||||
auto const& texture_frames = tile->getWorld()->getLiquidTextureManager()->getTextureFrames();
|
||||
std::tuple<GLuint, math::vector_2d, int> const& lq_layer_texture_params = texture_frames.at(layer->liquidID());
|
||||
|
||||
instance.TextureArray_Pad3[0] = std::get<0>(lq_layer_texture_params);
|
||||
|
||||
for (int x = 0; x < 9; ++x)
|
||||
{
|
||||
const unsigned v_index = z * 9 + x;
|
||||
math::vector_2d& tex_coord = tex_coords[v_index];
|
||||
chunk_layer_data[v_index] = math::vector_4d(vertices[v_index].y, depth[v_index], tex_coord.x, tex_coord.y);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::logic_error("Tried updating non-existing liquid chunk");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,22 +3,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <math/vector_3d.hpp>
|
||||
#include <math/vector_4d.hpp>
|
||||
#include <noggit/ChunkWater.hpp>
|
||||
#include <noggit/MPQ.h>
|
||||
#include <noggit/MapHeaders.h>
|
||||
#include <noggit/tool_enums.hpp>
|
||||
#include <opengl/context.hpp>
|
||||
#include <opengl/types.hpp>
|
||||
#include <noggit/LiquidTextureManager.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <set>
|
||||
|
||||
class MapTile;
|
||||
class liquid_layer;
|
||||
class sExtendableArray;
|
||||
enum LiquidLayerUpdateFlags;
|
||||
|
||||
class TileWater
|
||||
{
|
||||
struct LiquidTexBinding
|
||||
{
|
||||
unsigned tex_array;
|
||||
unsigned type;
|
||||
unsigned pad0;
|
||||
unsigned pad1;
|
||||
};
|
||||
|
||||
public:
|
||||
TileWater(MapTile *pTile, float pXbase, float pZbase, bool use_mclq_green_lava);
|
||||
|
||||
@@ -31,11 +44,11 @@ public:
|
||||
, const float& cull_distance
|
||||
, const math::vector_3d& camera
|
||||
, bool camera_moved
|
||||
, liquid_render& render
|
||||
, opengl::scoped::use_program& water_shader
|
||||
, int animtime
|
||||
, int layer
|
||||
, display_mode display
|
||||
, LiquidTextureManager* tex_manager
|
||||
);
|
||||
bool hasData(size_t layer);
|
||||
void CropMiniChunk(int x, int z, MapChunk* chunkTerrain);
|
||||
@@ -47,14 +60,39 @@ public:
|
||||
|
||||
void registerChunkLayer(liquid_layer* layer);
|
||||
void unregisterChunkLayer(liquid_layer* layer);
|
||||
void updateChunkLayer(liquid_layer* layer);
|
||||
void registerChunkLayerUpdate(unsigned flags);
|
||||
void doneChunkLayerUpdate() { _update_flags = 0; };
|
||||
void markBuffersDirty() { _need_buffer_update = true; };
|
||||
void updateLayerData(LiquidTextureManager* tex_manager);
|
||||
|
||||
void prepareBufferData(std::size_t layer_index);
|
||||
|
||||
void unload();
|
||||
|
||||
void upload();
|
||||
|
||||
private:
|
||||
|
||||
MapTile *tile;
|
||||
std::unique_ptr<ChunkWater> chunks[16][16];
|
||||
std::vector<opengl::LiquidChunkInstanceDataUniformBlock> _chunk_instances;
|
||||
std::vector<liquid_layer*> _chunk_layer_refs;
|
||||
std::vector<unsigned> _chunk_instance_indices;
|
||||
std::vector<std::array<math::vector_4d, 9 * 9>> _chunk_data;
|
||||
std::vector<liquid_layer*> _chunk_layer_ptrs;
|
||||
std::vector<std::vector<int>> _chunk_layer_texture_samplers;
|
||||
std::size_t _n_chunk_instances = 256;
|
||||
|
||||
opengl::scoped::deferred_upload_buffers<1> _buffers;
|
||||
|
||||
std::vector<GLuint> _liquid_vertex_data_textures;
|
||||
std::vector<GLuint> _liquid_parameters_buffers;
|
||||
GLuint _liquid_chunk_index_texture = 0;
|
||||
|
||||
unsigned _n_layer_chunks = 0;
|
||||
|
||||
bool _need_buffer_update = false;
|
||||
bool _loaded = false;
|
||||
|
||||
unsigned _update_flags;
|
||||
|
||||
float xbase;
|
||||
float zbase;
|
||||
|
||||
@@ -332,7 +332,6 @@ void WMO::draw ( opengl::scoped::use_program& wmo_shader
|
||||
, const math::vector_3d& camera
|
||||
, bool // draw_doodads
|
||||
, bool draw_fog
|
||||
, liquid_render& render
|
||||
, int animtime
|
||||
, bool world_has_skies
|
||||
, display_mode display
|
||||
@@ -360,11 +359,14 @@ void WMO::draw ( opengl::scoped::use_program& wmo_shader
|
||||
, world_has_skies
|
||||
);
|
||||
|
||||
/*
|
||||
group.drawLiquid ( transform_matrix_transposed
|
||||
, render
|
||||
, draw_fog
|
||||
, animtime
|
||||
);
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
if (boundingbox)
|
||||
|
||||
@@ -266,7 +266,6 @@ public:
|
||||
, const math::vector_3d& camera
|
||||
, bool draw_doodads
|
||||
, bool draw_fog
|
||||
, liquid_render& render
|
||||
, int animtime
|
||||
, bool world_has_skies
|
||||
, display_mode display
|
||||
|
||||
@@ -54,7 +54,6 @@ void WMOInstance::draw ( opengl::scoped::use_program& wmo_shader
|
||||
, bool force_box
|
||||
, bool draw_doodads
|
||||
, bool draw_fog
|
||||
, liquid_render& render
|
||||
, std::vector<selection_type> selection
|
||||
, int animtime
|
||||
, bool world_has_skies
|
||||
@@ -95,7 +94,6 @@ void WMOInstance::draw ( opengl::scoped::use_program& wmo_shader
|
||||
, camera
|
||||
, draw_doodads
|
||||
, draw_fog
|
||||
, render
|
||||
, animtime
|
||||
, world_has_skies
|
||||
, display
|
||||
|
||||
@@ -95,7 +95,6 @@ public:
|
||||
, bool force_box
|
||||
, bool draw_doodads
|
||||
, bool draw_fog
|
||||
, liquid_render& render
|
||||
, std::vector<selection_type> selection
|
||||
, int animtime
|
||||
, bool world_has_skies
|
||||
|
||||
@@ -860,10 +860,7 @@ void World::initShaders()
|
||||
}
|
||||
);
|
||||
}
|
||||
if (!_liquid_render)
|
||||
{
|
||||
_liquid_render.emplace(_context);
|
||||
}
|
||||
|
||||
if (!_wmo_program)
|
||||
{
|
||||
_wmo_program.reset
|
||||
@@ -874,6 +871,16 @@ void World::initShaders()
|
||||
);
|
||||
}
|
||||
|
||||
if (!_liquid_program)
|
||||
{
|
||||
_liquid_program.reset(
|
||||
new opengl::program
|
||||
{ { GL_VERTEX_SHADER, opengl::shader::src_from_qrc("liquid_vs") }
|
||||
, { GL_FRAGMENT_SHADER, opengl::shader::src_from_qrc("liquid_fs") }
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
_liquid_texture_manager.upload();
|
||||
|
||||
{
|
||||
@@ -959,9 +966,19 @@ void World::initShaders()
|
||||
*/
|
||||
|
||||
{
|
||||
opengl::scoped::use_program liquid_render {_liquid_render.get().shader_program()};
|
||||
opengl::scoped::use_program liquid_render {*_liquid_program.get()};
|
||||
|
||||
setupLiquidChunkBuffers();
|
||||
setupLiquidChunkVAO(liquid_render);
|
||||
|
||||
static std::vector<int> samplers {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
|
||||
|
||||
liquid_render.bind_uniform_block("matrices", 0);
|
||||
liquid_render.bind_uniform_block("lighting", 1);
|
||||
liquid_render.bind_uniform_block("liquid_layers_params", 4);
|
||||
liquid_render.uniform("vertex_data", 0);
|
||||
liquid_render.uniform("texture_samplers", samplers);
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
@@ -1214,7 +1231,6 @@ void World::draw ( math::matrix_4x4 const& model_view
|
||||
, is_hidden
|
||||
, draw_wmo_doodads
|
||||
, draw_fog
|
||||
, _liquid_render.get()
|
||||
, current_selection()
|
||||
, animtime
|
||||
, skies->hasSkies()
|
||||
@@ -1354,7 +1370,7 @@ void World::draw ( math::matrix_4x4 const& model_view
|
||||
|
||||
// set anim time only once per frame
|
||||
{
|
||||
opengl::scoped::use_program water_shader {_liquid_render->shader_program()};
|
||||
opengl::scoped::use_program water_shader {*_liquid_program.get()};
|
||||
water_shader.uniform("animtime", static_cast<float>(animtime) / 2880.f);
|
||||
|
||||
water_shader.uniform("camera", camera_pos);
|
||||
@@ -1409,12 +1425,13 @@ void World::draw ( math::matrix_4x4 const& model_view
|
||||
if (draw_water)
|
||||
{
|
||||
ZoneScopedN("World::draw() : Draw water");
|
||||
_liquid_render->force_texture_update();
|
||||
|
||||
// draw the water on both sides
|
||||
opengl::scoped::bool_setter<GL_CULL_FACE, GL_FALSE> const cull;
|
||||
|
||||
opengl::scoped::use_program water_shader{ _liquid_render->shader_program() };
|
||||
opengl::scoped::use_program water_shader{ *_liquid_program.get()};
|
||||
|
||||
gl.bindVertexArray(_liquid_chunk_vao);
|
||||
|
||||
water_shader.uniform ("use_transform", 0);
|
||||
|
||||
@@ -1424,16 +1441,15 @@ void World::draw ( math::matrix_4x4 const& model_view
|
||||
, culldistance
|
||||
, camera_pos
|
||||
, camera_moved
|
||||
, _liquid_render.get()
|
||||
, water_shader
|
||||
, animtime
|
||||
, water_layer
|
||||
, display
|
||||
, &_liquid_texture_manager
|
||||
);
|
||||
}
|
||||
|
||||
gl.bindVertexArray(0);
|
||||
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
gl.disable(GL_BLEND);
|
||||
@@ -3672,6 +3688,7 @@ void World::unload_shaders()
|
||||
_m2_ribbons_program.reset();
|
||||
_m2_box_program.reset();
|
||||
_wmo_program.reset();
|
||||
_liquid_program.reset();
|
||||
|
||||
_mcnk_program_mini.reset();
|
||||
_m2_program_mini.reset();
|
||||
@@ -3683,8 +3700,6 @@ void World::unload_shaders()
|
||||
_square_render.unload();
|
||||
_horizon_render.reset();
|
||||
|
||||
_liquid_render = boost::none;
|
||||
_liquid_render_mini = boost::none;
|
||||
_liquid_texture_manager.unload();
|
||||
|
||||
skies->unload();
|
||||
@@ -4411,3 +4426,11 @@ void World::setupLiquidChunkBuffers()
|
||||
|
||||
}
|
||||
|
||||
void World::notifyTileRendererOnSelectedTextureChange()
|
||||
{
|
||||
for (MapTile* tile : mapIndex.loaded_tiles())
|
||||
{
|
||||
tile->notifyTileRendererOnSelectedTextureChange();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -295,7 +295,7 @@ public:
|
||||
void ensureAllTilesetsADT(math::vector_3d const& pos);
|
||||
void ensureAllTilesetsAllADTs();
|
||||
|
||||
|
||||
void notifyTileRendererOnSelectedTextureChange();
|
||||
|
||||
void addM2 ( std::string const& filename
|
||||
, math::vector_3d newPos
|
||||
@@ -453,6 +453,7 @@ private:
|
||||
std::unique_ptr<opengl::program> _m2_ribbons_program;
|
||||
std::unique_ptr<opengl::program> _m2_box_program;
|
||||
std::unique_ptr<opengl::program> _wmo_program;
|
||||
std::unique_ptr<opengl::program> _liquid_program;
|
||||
|
||||
// Minimap programs. Ugly, but those can't be shared between contexts, so we compile twice
|
||||
std::unique_ptr<opengl::program> _mcnk_program_mini;
|
||||
@@ -464,9 +465,6 @@ private:
|
||||
opengl::primitives::sphere _sphere_render;
|
||||
opengl::primitives::square _square_render;
|
||||
|
||||
boost::optional<liquid_render> _liquid_render = boost::none;
|
||||
boost::optional<liquid_render> _liquid_render_mini = boost::none;
|
||||
|
||||
noggit::NoggitRenderContext _context;
|
||||
|
||||
opengl::scoped::deferred_upload_buffers<7> _buffers;
|
||||
|
||||
@@ -33,9 +33,11 @@ liquid_layer::liquid_layer(ChunkWater* chunk, math::vector_3d const& base, float
|
||||
{
|
||||
for (int x = 0; x < 9; ++x)
|
||||
{
|
||||
_tex_coords.emplace_back(default_uv(x, z));
|
||||
_depth.emplace_back(1.0f);
|
||||
_vertices.emplace_back( pos.x + UNITSIZE * x
|
||||
unsigned v_index = z * 9 + x;
|
||||
_tex_coords[v_index] = default_uv(x, z);
|
||||
_depth[v_index] = 1.0f;
|
||||
_vertices[v_index] = math::vector_3d(
|
||||
pos.x + UNITSIZE * x
|
||||
, height
|
||||
, pos.z + UNITSIZE * z
|
||||
);
|
||||
@@ -43,7 +45,7 @@ liquid_layer::liquid_layer(ChunkWater* chunk, math::vector_3d const& base, float
|
||||
}
|
||||
|
||||
changeLiquidID(_liquid_id);
|
||||
chunk->getWaterTile()->registerChunkLayer(this);
|
||||
|
||||
}
|
||||
|
||||
liquid_layer::liquid_layer(ChunkWater* chunk, math::vector_3d const& base, mclq& liquid, int liquid_id)
|
||||
@@ -68,20 +70,22 @@ liquid_layer::liquid_layer(ChunkWater* chunk, math::vector_3d const& base, mclq&
|
||||
{
|
||||
for (int x = 0; x < 9; ++x)
|
||||
{
|
||||
mclq_vertex const& v = liquid.vertices[z * 9 + x];
|
||||
const unsigned v_index = z * 9 + x;
|
||||
mclq_vertex const& v = liquid.vertices[v_index];
|
||||
|
||||
if (_liquid_vertex_format == 1)
|
||||
{
|
||||
_depth.emplace_back(1.0f);
|
||||
_tex_coords.emplace_back(static_cast<float>(v.magma.x) / 255.f, static_cast<float>(v.magma.y) / 255.f);
|
||||
_depth[v_index] = 1.0f;
|
||||
_tex_coords[v_index] = math::vector_2d(static_cast<float>(v.magma.x) / 255.f, static_cast<float>(v.magma.y) / 255.f);
|
||||
}
|
||||
else
|
||||
{
|
||||
_depth.emplace_back(static_cast<float>(v.water.depth) / 255.f);
|
||||
_tex_coords.emplace_back(default_uv(x, z));
|
||||
_depth[v_index] = static_cast<float>(v.water.depth) / 255.f;
|
||||
_tex_coords[v_index] = default_uv(x, z);
|
||||
}
|
||||
|
||||
_vertices.emplace_back( pos.x + UNITSIZE * x
|
||||
_vertices[v_index] = math::vector_3d(
|
||||
pos.x + UNITSIZE * x
|
||||
// sometimes there's garbage data on unused tiles that mess things up
|
||||
, std::max(std::min(v.height, _maximum), _minimum)
|
||||
, pos.z + UNITSIZE * z
|
||||
@@ -89,7 +93,6 @@ liquid_layer::liquid_layer(ChunkWater* chunk, math::vector_3d const& base, mclq&
|
||||
}
|
||||
}
|
||||
|
||||
chunk->getWaterTile()->registerChunkLayer(this);
|
||||
}
|
||||
|
||||
liquid_layer::liquid_layer(ChunkWater* chunk, MPQFile &f, std::size_t base_pos, math::vector_3d const& base, MH2O_Information const& info, std::uint64_t infomask)
|
||||
@@ -116,9 +119,11 @@ liquid_layer::liquid_layer(ChunkWater* chunk, MPQFile &f, std::size_t base_pos,
|
||||
{
|
||||
for (int x = 0; x < 9; ++x)
|
||||
{
|
||||
_tex_coords.emplace_back(default_uv(x, z));
|
||||
_depth.emplace_back(1.0f);
|
||||
_vertices.emplace_back(pos.x + UNITSIZE * x
|
||||
const unsigned v_index = z * 9 + x;
|
||||
_tex_coords[v_index] = default_uv(x, z);
|
||||
_depth[v_index] = 1.0f;
|
||||
_vertices[v_index] = math::vector_3d(
|
||||
pos.x + UNITSIZE * x
|
||||
, _minimum
|
||||
, pos.z + UNITSIZE * z
|
||||
);
|
||||
@@ -171,7 +176,7 @@ liquid_layer::liquid_layer(ChunkWater* chunk, MPQFile &f, std::size_t base_pos,
|
||||
}
|
||||
}
|
||||
|
||||
chunk->getWaterTile()->registerChunkLayer(this);
|
||||
|
||||
}
|
||||
|
||||
liquid_layer::liquid_layer(liquid_layer&& other)
|
||||
@@ -189,7 +194,6 @@ liquid_layer::liquid_layer(liquid_layer&& other)
|
||||
, _chunk(other._chunk)
|
||||
{
|
||||
changeLiquidID(_liquid_id);
|
||||
_chunk->getWaterTile()->registerChunkLayer(this);
|
||||
}
|
||||
|
||||
liquid_layer::liquid_layer(liquid_layer const& other)
|
||||
@@ -207,7 +211,6 @@ liquid_layer::liquid_layer(liquid_layer const& other)
|
||||
, _chunk(other._chunk)
|
||||
{
|
||||
changeLiquidID(_liquid_id);
|
||||
_chunk->getWaterTile()->registerChunkLayer(this);
|
||||
}
|
||||
|
||||
liquid_layer& liquid_layer::operator= (liquid_layer&& other)
|
||||
@@ -390,6 +393,8 @@ void liquid_layer::changeLiquidID(int id)
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
|
||||
registerUpdate(ll_TYPE);
|
||||
}
|
||||
|
||||
void liquid_layer::update_indices()
|
||||
@@ -564,6 +569,8 @@ void liquid_layer::crop(MapChunk* chunk)
|
||||
}
|
||||
}
|
||||
|
||||
registerUpdate(ll_HEIGHT);
|
||||
|
||||
update_min_max();
|
||||
}
|
||||
|
||||
@@ -576,6 +583,8 @@ void liquid_layer::update_opacity(MapChunk* chunk, float factor)
|
||||
update_vertex_opacity(x, z, chunk, factor);
|
||||
}
|
||||
}
|
||||
|
||||
registerUpdate(ll_DEPTH);
|
||||
}
|
||||
|
||||
bool liquid_layer::hasSubchunk(int x, int z, int size) const
|
||||
@@ -596,6 +605,7 @@ bool liquid_layer::hasSubchunk(int x, int z, int size) const
|
||||
void liquid_layer::setSubchunk(int x, int z, bool water)
|
||||
{
|
||||
misc::set_bit(_subchunks, x, z, water);
|
||||
registerUpdate(ll_HEIGHT);
|
||||
}
|
||||
|
||||
void liquid_layer::paintLiquid( math::vector_3d const& cursor_pos
|
||||
@@ -649,6 +659,8 @@ void liquid_layer::paintLiquid( math::vector_3d const& cursor_pos
|
||||
id++;
|
||||
}
|
||||
|
||||
registerUpdate(ll_HEIGHT || ll_DEPTH);
|
||||
|
||||
update_min_max();
|
||||
}
|
||||
|
||||
@@ -695,12 +707,14 @@ void liquid_layer::copy_subchunk_height(int x, int z, liquid_layer const& from)
|
||||
}
|
||||
|
||||
setSubchunk(x, z, true);
|
||||
registerUpdate(ll_HEIGHT);
|
||||
}
|
||||
|
||||
void liquid_layer::update_vertex_opacity(int x, int z, MapChunk* chunk, float factor)
|
||||
{
|
||||
float diff = _vertices[z * 9 + x].y - chunk->mVertices[z * 17 + x].y;
|
||||
_depth[z * 9 + x] = diff < 0.0f ? 0.0f : (std::min(1.0f, std::max(0.0f, (diff + 1.0f) * factor)));
|
||||
registerUpdate(ll_DEPTH);
|
||||
}
|
||||
|
||||
int liquid_layer::get_lod_level(math::vector_3d const& camera_pos) const
|
||||
@@ -720,7 +734,13 @@ void liquid_layer::set_lod_level(int lod_level)
|
||||
_current_lod_indices_count = _indices_by_lod[lod_level].size();
|
||||
}
|
||||
|
||||
void liquid_layer::registerUpdate(unsigned flags)
|
||||
{
|
||||
_update_flags |= flags;
|
||||
_chunk->getWaterTile()->registerChunkLayerUpdate(flags);
|
||||
}
|
||||
|
||||
liquid_layer::~liquid_layer()
|
||||
{
|
||||
_chunk->getWaterTile()->unregisterChunkLayer(this);
|
||||
_update_flags = _update_flags;
|
||||
}
|
||||
|
||||
@@ -6,15 +6,25 @@
|
||||
#include <noggit/MapHeaders.h>
|
||||
#include <noggit/liquid_render.hpp>
|
||||
#include <opengl/scoped.hpp>
|
||||
#include <array>
|
||||
|
||||
class MapChunk;
|
||||
class sExtendableArray;
|
||||
class ChunkWater;
|
||||
|
||||
enum LiquidLayerUpdateFlags
|
||||
{
|
||||
ll_HEIGHT = 0x1,
|
||||
ll_DEPTH = 0x2,
|
||||
ll_UV = 0x4,
|
||||
ll_TYPE = 0x8,
|
||||
ll_FLAGS = 0x10
|
||||
};
|
||||
|
||||
// handle liquids like oceans, lakes, rivers, slime, magma
|
||||
class liquid_layer
|
||||
{
|
||||
|
||||
public:
|
||||
liquid_layer() = delete;
|
||||
liquid_layer(ChunkWater* chunk, math::vector_3d const& base, float height, int liquid_id);
|
||||
@@ -42,6 +52,9 @@ public:
|
||||
void crop(MapChunk* chunk);
|
||||
void update_opacity(MapChunk* chunk, float factor);
|
||||
|
||||
std::array<math::vector_3d, 9 * 9>& getVertices() { return _vertices; };
|
||||
std::array<float, 9 * 9>& getDepth() { return _depth; };
|
||||
std::array<math::vector_2d, 9 * 9>& getTexCoords() { return _tex_coords; };
|
||||
|
||||
float min() const { return _minimum; }
|
||||
float max() const { return _maximum; }
|
||||
@@ -50,6 +63,8 @@ public:
|
||||
bool hasSubchunk(int x, int z, int size = 1) const;
|
||||
void setSubchunk(int x, int z, bool water);
|
||||
|
||||
std::uint64_t getSubchunks() { return _subchunks; };
|
||||
|
||||
bool empty() const { return !_subchunks; }
|
||||
bool full() const { return _subchunks == std::uint64_t(-1); }
|
||||
void clear() { _subchunks = std::uint64_t(0); }
|
||||
@@ -69,7 +84,9 @@ public:
|
||||
void copy_subchunk_height(int x, int z, liquid_layer const& from);
|
||||
|
||||
void unload();
|
||||
|
||||
void registerUpdate(unsigned flags);
|
||||
void doneUpdate() { _update_flags = 0; };
|
||||
unsigned getUpdateFlags() { return _update_flags; };
|
||||
ChunkWater* getChunk() { return _chunk; };
|
||||
|
||||
private:
|
||||
@@ -95,10 +112,12 @@ private:
|
||||
int _liquid_vertex_format;
|
||||
float _minimum;
|
||||
float _maximum;
|
||||
|
||||
std::uint64_t _subchunks;
|
||||
std::vector<math::vector_3d> _vertices;
|
||||
std::vector<float> _depth;
|
||||
std::vector<math::vector_2d> _tex_coords;
|
||||
std::array<math::vector_3d, 9 * 9> _vertices;
|
||||
std::array<float, 9 * 9> _depth;
|
||||
std::array<math::vector_2d, 9 * 9> _tex_coords;
|
||||
|
||||
std::map<int, std::vector<std::uint16_t>> _indices_by_lod;
|
||||
|
||||
bool _need_buffer_update = true;
|
||||
@@ -112,4 +131,5 @@ private:
|
||||
private:
|
||||
math::vector_3d pos;
|
||||
ChunkWater* _chunk;
|
||||
unsigned _update_flags = ll_HEIGHT || ll_DEPTH || ll_UV || ll_FLAGS || ll_TYPE;;
|
||||
};
|
||||
|
||||
@@ -44,6 +44,8 @@ namespace noggit
|
||||
_filename = texture;
|
||||
_need_update = true;
|
||||
update_texture_if_needed();
|
||||
|
||||
emit texture_updated();
|
||||
}
|
||||
|
||||
void current_texture::update_texture_if_needed()
|
||||
|
||||
@@ -42,6 +42,10 @@ namespace noggit
|
||||
|
||||
signals:
|
||||
void texture_dropped(std::string const& filename);
|
||||
|
||||
void texture_updated();
|
||||
|
||||
|
||||
public:
|
||||
current_texture(bool accept_drop, QWidget* parent = nullptr);
|
||||
|
||||
|
||||
@@ -169,7 +169,14 @@ namespace noggit
|
||||
if (file.open(QFile::ReadOnly))
|
||||
{
|
||||
QString style_sheet = QLatin1String(file.readAll());
|
||||
qApp->setStyleSheet(style_sheet);;
|
||||
QString style_sheet_fixed = style_sheet.replace("@rpath", QCoreApplication::applicationDirPath());
|
||||
|
||||
if (style_sheet_fixed.endsWith("/"))
|
||||
style_sheet_fixed.chop(1);
|
||||
else if (style_sheet_fixed.endsWith("\\"))
|
||||
style_sheet_fixed.chop(2);
|
||||
|
||||
qApp->setStyleSheet(style_sheet_fixed);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace noggit
|
||||
_brush_level_slider->setRange (0, 255);
|
||||
_brush_level_slider->setSliderPosition (_brush_level);
|
||||
|
||||
_brush_level_slider->setAccessibleName("texturing_brush_level_slider");
|
||||
_brush_level_slider->setObjectName("texturing_brush_level_slider");
|
||||
|
||||
slider_layout_right->addWidget(_brush_level_slider, 0, Qt::AlignHCenter);
|
||||
|
||||
|
||||
@@ -207,6 +207,8 @@ namespace opengl
|
||||
|
||||
BOOST_FORCEINLINE void drawElements (GLenum mode, GLuint index_buffer, GLsizei count, GLenum type, GLvoid const* indices);
|
||||
|
||||
BOOST_FORCEINLINE void drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
|
||||
|
||||
QOpenGLContext* getCurrentContext();
|
||||
|
||||
BOOST_FORCEINLINE void bufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
|
||||
|
||||
@@ -1058,4 +1058,13 @@ void opengl::context::drawElements (GLenum mode, GLuint index_buffer, GLsizei co
|
||||
gl.bindBuffer (GL_ELEMENT_ARRAY_BUFFER, old);
|
||||
}
|
||||
|
||||
void opengl::context::drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount)
|
||||
{
|
||||
#ifndef NOGGIT_DO_NOT_CHECK_FOR_OPENGL_ERRORS
|
||||
verify_context_and_check_for_gl_errors const _ (_current_context, BOOST_CURRENT_FUNCTION);
|
||||
#endif
|
||||
|
||||
return _4_1_core_func->glDrawArraysInstanced (mode, first, count, instancecount);
|
||||
}
|
||||
|
||||
#endif //NOGGIT_CONTEXT_INL
|
||||
|
||||
@@ -256,6 +256,14 @@ namespace opengl
|
||||
|
||||
gl.uniform1iv (loc, value.size(), value.data());
|
||||
}
|
||||
void use_program::uniform (std::string const& name, int const* data, std::size_t size)
|
||||
{
|
||||
GLuint loc = uniform_location (name);
|
||||
if (loc < 0)
|
||||
return;
|
||||
|
||||
gl.uniform1iv (loc, size, data);
|
||||
}
|
||||
void use_program::uniform (GLint pos, std::vector<int> const& value)
|
||||
{
|
||||
gl.uniform1iv (pos, value.size(), value.data());
|
||||
|
||||
@@ -91,6 +91,7 @@ namespace opengl
|
||||
|
||||
void bind_uniform_block(std::string const& name, unsigned);
|
||||
void uniform (std::string const& name, std::vector<int> const&);
|
||||
void uniform (std::string const& name, int const* data, std::size_t size);
|
||||
void uniform (GLint pos, std::vector<int> const&);
|
||||
void uniform (std::string const& name, GLint);
|
||||
void uniform (GLint pos, GLint);
|
||||
|
||||
@@ -15,7 +15,8 @@ namespace opengl
|
||||
MVP,
|
||||
LIGHTING,
|
||||
TERRAIN_OVERLAYS,
|
||||
CHUNK_INSTANCE_DATA
|
||||
CHUNK_INSTANCE_DATA,
|
||||
CHUNK_LIQUID_INSTANCE_INDEX
|
||||
};
|
||||
|
||||
struct MVPUniformBlock
|
||||
@@ -47,9 +48,9 @@ namespace opengl
|
||||
int wireframe_type;
|
||||
float wireframe_radius;
|
||||
float wireframe_width;
|
||||
int draw_impass_overlay;
|
||||
int draw_paintability_overlay;
|
||||
int draw_selection_overlay;
|
||||
int draw_impass_overlay = false;
|
||||
int draw_paintability_overlay = false;
|
||||
int draw_selection_overlay = false;
|
||||
math::vector_4d wireframe_color;
|
||||
|
||||
};
|
||||
@@ -66,10 +67,17 @@ namespace opengl
|
||||
int ChunkTexAnimDir[4];
|
||||
};
|
||||
|
||||
struct LiquidChunkInstanceDataUniformBlock
|
||||
{
|
||||
unsigned TextureArray_Pad3[4];
|
||||
float ChunkXY_Animation[4];
|
||||
};
|
||||
struct LiquidChunkInstanceDataUniformBlock
|
||||
{
|
||||
unsigned texture_array;
|
||||
unsigned type;
|
||||
float xbase;
|
||||
float zbase;
|
||||
float anim_u;
|
||||
float anim_v;
|
||||
unsigned subchunks_1;
|
||||
unsigned subchunks_2;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user