update liquid attributes and fatigue auto updates
This commit is contained in:
@@ -12,6 +12,7 @@ ChunkWater::ChunkWater(MapChunk* chunk, TileWater* water_tile, float x, float z,
|
|||||||
, zbase(z)
|
, zbase(z)
|
||||||
, vmin(x, 0.f, z)
|
, vmin(x, 0.f, z)
|
||||||
, vmax(x + CHUNKSIZE, 0.f, z + CHUNKSIZE)
|
, vmax(x + CHUNKSIZE, 0.f, z + CHUNKSIZE)
|
||||||
|
, vcenter((vmin + vmax) * 0.5f)
|
||||||
, _use_mclq_green_lava(use_mclq_green_lava)
|
, _use_mclq_green_lava(use_mclq_green_lava)
|
||||||
, _chunk(chunk)
|
, _chunk(chunk)
|
||||||
, _water_tile(water_tile)
|
, _water_tile(water_tile)
|
||||||
@@ -22,7 +23,6 @@ void ChunkWater::from_mclq(std::vector<mclq>& layers)
|
|||||||
{
|
{
|
||||||
glm::vec3 pos(xbase, 0.0f, zbase);
|
glm::vec3 pos(xbase, 0.0f, zbase);
|
||||||
|
|
||||||
if (!Render.has_value()) Render.emplace();
|
|
||||||
for (mclq& liquid : layers)
|
for (mclq& liquid : layers)
|
||||||
{
|
{
|
||||||
std::uint8_t mclq_liquid_type = 0;
|
std::uint8_t mclq_liquid_type = 0;
|
||||||
@@ -33,8 +33,8 @@ void ChunkWater::from_mclq(std::vector<mclq>& layers)
|
|||||||
{
|
{
|
||||||
mclq_tile const& tile = liquid.tiles[z * 8 + x];
|
mclq_tile const& tile = liquid.tiles[z * 8 + x];
|
||||||
|
|
||||||
misc::bit_or(Render.value().fishable, x, z, tile.fishable);
|
misc::bit_or(attributes.fishable, x, z, tile.fishable);
|
||||||
misc::bit_or(Render.value().fatigue, x, z, tile.fatigue);
|
misc::bit_or(attributes.fatigue, x, z, tile.fatigue);
|
||||||
|
|
||||||
if (!tile.dont_render)
|
if (!tile.dont_render)
|
||||||
{
|
{
|
||||||
@@ -45,17 +45,17 @@ void ChunkWater::from_mclq(std::vector<mclq>& layers)
|
|||||||
|
|
||||||
switch (mclq_liquid_type)
|
switch (mclq_liquid_type)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1: // mclq ocean
|
||||||
_layers.emplace_back(this, pos, liquid, 2);
|
_layers.emplace_back(this, pos, liquid, LIQUID_OCEAN);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3: // mclq slime
|
||||||
_layers.emplace_back(this, pos, liquid, 4);
|
_layers.emplace_back(this, pos, liquid, LIQUID_SLIME);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4: // mclq river
|
||||||
_layers.emplace_back(this, pos, liquid, 1);
|
_layers.emplace_back(this, pos, liquid, LIQUID_WATER);
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6: // mclq magma
|
||||||
_layers.emplace_back(this, pos, liquid, (_use_mclq_green_lava ? 15 : 3));
|
_layers.emplace_back(this, pos, liquid, (_use_mclq_green_lava ? LIQUID_Green_Lava : LIQUID_MAGMA));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -78,17 +78,22 @@ void ChunkWater::fromFile(BlizzardArchive::ClientFile &f, size_t basePos)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//render
|
//render
|
||||||
if (header.ofsRenderMask)
|
if (header.ofsAttributes)
|
||||||
{
|
{
|
||||||
Render.emplace();
|
f.seek(basePos + header.ofsAttributes);
|
||||||
f.seek(basePos + header.ofsRenderMask);
|
f.read(&attributes, sizeof(MH2O_Attributes));
|
||||||
f.read(&Render.value(), sizeof(MH2O_Render));
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// when chunks don't have attributes it means everything is set.
|
||||||
|
attributes.fishable = 0xFFFFFFFFFFFFFFFF;
|
||||||
|
attributes.fatigue = 0xFFFFFFFFFFFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::size_t k = 0; k < header.nLayers; ++k)
|
for (std::size_t k = 0; k < header.nLayers; ++k)
|
||||||
{
|
{
|
||||||
MH2O_Information info;
|
MH2O_Information info;
|
||||||
uint64_t infoMask = 0xFFFFFFFFFFFFFFFF; // default = all water
|
uint64_t infoMask = 0xFFFFFFFFFFFFFFFF; // default = all water. InfoMask + HeightMap combined
|
||||||
|
|
||||||
//info
|
//info
|
||||||
f.seek(basePos + header.ofsInformation + sizeof(MH2O_Information)* k);
|
f.seek(basePos + header.ofsInformation + sizeof(MH2O_Information)* k);
|
||||||
@@ -106,6 +111,8 @@ void ChunkWater::fromFile(BlizzardArchive::ClientFile &f, size_t basePos)
|
|||||||
|
|
||||||
glm::vec3 pos(xbase, 0.0f, zbase);
|
glm::vec3 pos(xbase, 0.0f, zbase);
|
||||||
_water_tile->tagUpdate();
|
_water_tile->tagUpdate();
|
||||||
|
// liquid_layer(ChunkWater* chunk, BlizzardArchive::ClientFile& f, std::size_t base_pos, glm::vec3 const& base
|
||||||
|
// ,MH2O_Information const& info, std::uint64_t infomask);
|
||||||
_layers.emplace_back(this, f, basePos, pos, info, infoMask);
|
_layers.emplace_back(this, f, basePos, pos, info, infoMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,20 +126,23 @@ void ChunkWater::save(sExtendableArray& adt, int base_pos, int& header_pos, int&
|
|||||||
|
|
||||||
// remove empty layers
|
// remove empty layers
|
||||||
cleanup();
|
cleanup();
|
||||||
|
update_attributes();
|
||||||
|
|
||||||
if (hasData(0))
|
if (hasData(0))
|
||||||
{
|
{
|
||||||
header.nLayers = static_cast<std::uint32_t>(_layers.size());
|
header.nLayers = static_cast<std::uint32_t>(_layers.size());
|
||||||
|
|
||||||
if (Render.has_value())
|
// fagique only for single layer ocean chunk
|
||||||
|
bool fatigue = _layers[0].has_fatigue();
|
||||||
|
if (!fatigue)
|
||||||
{
|
{
|
||||||
header.ofsRenderMask = current_pos - base_pos;
|
header.ofsAttributes = current_pos - base_pos;
|
||||||
adt.Insert(current_pos, sizeof(MH2O_Render), reinterpret_cast<char*>(&Render.value()));
|
adt.Insert(current_pos, sizeof(MH2O_Attributes), reinterpret_cast<char*>(&attributes));
|
||||||
current_pos += sizeof(MH2O_Render);
|
current_pos += sizeof(MH2O_Attributes);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
header.ofsRenderMask = 0;
|
header.ofsAttributes = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
header.ofsInformation = current_pos - base_pos;
|
header.ofsInformation = current_pos - base_pos;
|
||||||
@@ -211,6 +221,16 @@ void ChunkWater::update_layers()
|
|||||||
vmin.y = std::numeric_limits<float>::max();
|
vmin.y = std::numeric_limits<float>::max();
|
||||||
vmax.y = std::numeric_limits<float>::lowest();
|
vmax.y = std::numeric_limits<float>::lowest();
|
||||||
|
|
||||||
|
std::uint64_t debug_fishable_old = attributes.fishable;
|
||||||
|
std::uint64_t debug_fatigue_old = attributes.fatigue;
|
||||||
|
|
||||||
|
if (_auto_update_attributes)
|
||||||
|
{
|
||||||
|
// reset attributes
|
||||||
|
attributes.fishable = 0;
|
||||||
|
attributes.fatigue = 0;
|
||||||
|
}
|
||||||
|
|
||||||
for (liquid_layer& layer : _layers)
|
for (liquid_layer& layer : _layers)
|
||||||
{
|
{
|
||||||
vmin.y = std::min (vmin.y, layer.min());
|
vmin.y = std::min (vmin.y, layer.min());
|
||||||
@@ -220,9 +240,45 @@ void ChunkWater::update_layers()
|
|||||||
extents[1].y = std::max(extents[1].y, vmax.y);
|
extents[1].y = std::max(extents[1].y, vmax.y);
|
||||||
|
|
||||||
_water_tile->tagUpdate();
|
_water_tile->tagUpdate();
|
||||||
|
|
||||||
|
if (_auto_update_attributes)
|
||||||
|
layer.update_attributes(attributes);
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// some tests to compare with blizzard
|
||||||
|
const bool run_tests = false;
|
||||||
|
if (run_tests)
|
||||||
|
{
|
||||||
|
if (attributes.fishable != debug_fishable_old && _layers.size())
|
||||||
|
{
|
||||||
|
uint64_t x = attributes.fishable ^ debug_fishable_old;
|
||||||
|
int difference_count = 0;
|
||||||
|
|
||||||
|
|
||||||
|
while (x > 0) {
|
||||||
|
difference_count += x & 1;
|
||||||
|
x >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto type = _layers.front().liquidID();
|
||||||
|
std::vector<float> depths;
|
||||||
|
|
||||||
|
int zero_depth_num = 0;
|
||||||
|
int below_20_num = 0; // below 0.2
|
||||||
|
for (auto& vert : _layers.front().getVertices())
|
||||||
|
{
|
||||||
|
depths.push_back(vert.depth);
|
||||||
|
if (vert.depth == 0.0f)
|
||||||
|
zero_depth_num++;
|
||||||
|
if (vert.depth < 0.2f && vert.depth != 0.0f)
|
||||||
|
below_20_num++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
_water_tile->tagExtents(true);
|
_water_tile->tagExtents(true);
|
||||||
|
|
||||||
vcenter = (vmin + vmax) * 0.5f;
|
vcenter = (vmin + vmax) * 0.5f;
|
||||||
@@ -350,6 +406,17 @@ void ChunkWater::copy_height_to_layer(liquid_layer& target, glm::vec3 const& pos
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChunkWater::update_attributes()
|
||||||
|
{
|
||||||
|
attributes.fishable = 0;
|
||||||
|
attributes.fatigue = 0;
|
||||||
|
|
||||||
|
for (liquid_layer& layer : _layers)
|
||||||
|
{
|
||||||
|
layer.update_attributes(attributes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ChunkWater::tagUpdate()
|
void ChunkWater::tagUpdate()
|
||||||
{
|
{
|
||||||
_water_tile->tagUpdate();
|
_water_tile->tagUpdate();
|
||||||
|
|||||||
@@ -70,10 +70,13 @@ public:
|
|||||||
|
|
||||||
MapChunk* getChunk() { return _chunk; };
|
MapChunk* getChunk() { return _chunk; };
|
||||||
TileWater* getWaterTile() { return _water_tile; };
|
TileWater* getWaterTile() { return _water_tile; };
|
||||||
std::optional<MH2O_Render> Render;
|
|
||||||
|
MH2O_Attributes& const getAttributes() { return attributes; };
|
||||||
|
|
||||||
float xbase, zbase;
|
float xbase, zbase;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
MH2O_Attributes attributes;
|
||||||
|
|
||||||
glm::vec3 vmin, vmax, vcenter;
|
glm::vec3 vmin, vmax, vcenter;
|
||||||
bool _use_mclq_green_lava;
|
bool _use_mclq_green_lava;
|
||||||
@@ -83,8 +86,9 @@ private:
|
|||||||
|
|
||||||
void copy_height_to_layer(liquid_layer& target, glm::vec3 const& pos, float radius);
|
void copy_height_to_layer(liquid_layer& target, glm::vec3 const& pos, float radius);
|
||||||
|
|
||||||
|
bool _auto_update_attributes = true;
|
||||||
|
// updates attributes for all layers
|
||||||
|
void update_attributes();
|
||||||
|
|
||||||
std::vector<liquid_layer> _layers;
|
std::vector<liquid_layer> _layers;
|
||||||
MapChunk* _chunk;
|
MapChunk* _chunk;
|
||||||
|
|||||||
@@ -187,15 +187,49 @@ struct ENTRY_MCSE
|
|||||||
struct MH2O_Header{
|
struct MH2O_Header{
|
||||||
uint32_t ofsInformation;
|
uint32_t ofsInformation;
|
||||||
uint32_t nLayers;
|
uint32_t nLayers;
|
||||||
uint32_t ofsRenderMask;
|
uint32_t ofsAttributes;
|
||||||
|
|
||||||
MH2O_Header()
|
MH2O_Header()
|
||||||
: ofsInformation(0)
|
: ofsInformation(0)
|
||||||
, nLayers(0)
|
, nLayers(0)
|
||||||
, ofsRenderMask(0)
|
, ofsAttributes(0)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// enum for type column of liquidtype.dbc
|
||||||
|
enum liquid_basic_types
|
||||||
|
{
|
||||||
|
liquid_basic_types_water = 0,
|
||||||
|
liquid_basic_types_ocean = 1,
|
||||||
|
liquid_basic_types_magma = 2,
|
||||||
|
liquid_basic_types_slime = 3,
|
||||||
|
|
||||||
|
liquid_basic_types_MASK = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
// just liquidtype.dbc
|
||||||
|
enum liquid_types
|
||||||
|
{
|
||||||
|
LIQUID_WATER = 1,
|
||||||
|
LIQUID_OCEAN = 2,
|
||||||
|
LIQUID_MAGMA = 3,
|
||||||
|
LIQUID_SLIME = 4,
|
||||||
|
// slow
|
||||||
|
// fast
|
||||||
|
LIQUID_WMO_Water = 13,
|
||||||
|
LIQUID_WMO_Ocean = 14,
|
||||||
|
LIQUID_Green_Lava = 15,
|
||||||
|
LIQUID_WMO_Water_Interior = 17,
|
||||||
|
LIQUID_WMO_Magma = 19,
|
||||||
|
LIQUID_WMO_Slime = 20,
|
||||||
|
|
||||||
|
LIQUID_END_BASIC_LIQUIDS = LIQUID_WMO_Slime,
|
||||||
|
|
||||||
|
LIQUID_FIRST_NONBASIC_LIQUID_TYPE = 21,
|
||||||
|
|
||||||
|
LIQUID_NAXX_SLIME = LIQUID_FIRST_NONBASIC_LIQUID_TYPE,
|
||||||
|
};
|
||||||
|
|
||||||
struct MH2O_Information{
|
struct MH2O_Information{
|
||||||
uint16_t liquid_id;
|
uint16_t liquid_id;
|
||||||
uint16_t liquid_vertex_format;
|
uint16_t liquid_vertex_format;
|
||||||
@@ -231,11 +265,10 @@ struct mh2o_uv
|
|||||||
std::uint16_t y;
|
std::uint16_t y;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MH2O_Render
|
struct MH2O_Attributes
|
||||||
{
|
{
|
||||||
// seems to be usable as visibility information (as per https://wowdev.wiki/ADT/v18#MH2O_chunk_.28WotLK.2B.29)
|
|
||||||
std::uint64_t fishable = 0xFFFFFFFFFFFFFFFF;
|
std::uint64_t fishable = 0xFFFFFFFFFFFFFFFF;
|
||||||
std::uint64_t fatigue = 0;
|
std::uint64_t fatigue = 0; // should be set to max ?
|
||||||
};
|
};
|
||||||
|
|
||||||
struct water_vert
|
struct water_vert
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ void selected_chunk_type::updateDetails(Noggit::Ui::detail_infos* detail_widget)
|
|||||||
{
|
{
|
||||||
ChunkWater* waterchunk = chunk->liquid_chunk();
|
ChunkWater* waterchunk = chunk->liquid_chunk();
|
||||||
|
|
||||||
MH2O_Render liquid_render = waterchunk->Render.value_or(MH2O_Render{ 0xffffffffffffffff,0xffffffffffffffff });
|
MH2O_Attributes attributes = waterchunk->getAttributes();
|
||||||
|
|
||||||
if (waterchunk->hasData(0))
|
if (waterchunk->hasData(0))
|
||||||
{
|
{
|
||||||
@@ -179,11 +179,13 @@ void selected_chunk_type::updateDetails(Noggit::Ui::detail_infos* detail_widget)
|
|||||||
liquid_layer liquid = waterchunk->getLayers()->at(0); // only getting data from layer 0, maybe loop them ?
|
liquid_layer liquid = waterchunk->getLayers()->at(0); // only getting data from layer 0, maybe loop them ?
|
||||||
int liquid_flags = liquid.getSubchunks();
|
int liquid_flags = liquid.getSubchunks();
|
||||||
|
|
||||||
select_info << "<br><b>liquid type</b>: " << liquid.liquidID() << " (\"" << gLiquidTypeDB.getLiquidName(liquid.liquidID()) << "\")"
|
select_info << "<br><b>Liquid type</b>: " << liquid.liquidID() << " (\"" << gLiquidTypeDB.getLiquidName(liquid.liquidID()) << "\")"
|
||||||
<< "<br><b>liquid flags</b>: "
|
<< "<br><b>liquid flags(center)</b>: "
|
||||||
// getting flags from the center tile
|
// getting flags from the center tile
|
||||||
<< ((liquid_render.fishable >> (4 * 8 + 4)) & 1 ? "fishable " : "")
|
<< ((attributes.fishable >> (4 * 8 + 4)) & 1 ? "fishable " : "")
|
||||||
<< ((liquid_render.fatigue >> (4 * 8 + 4)) & 1 ? "fatigue" : "");
|
<< ((attributes.fatigue >> (4 * 8 + 4)) & 1 ? "fatigue " : "")
|
||||||
|
|
||||||
|
<< (liquid.has_fatigue() ? "<br><b>entire chunk has fatigue!</b>" : "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ namespace Noggit
|
|||||||
private:
|
private:
|
||||||
TabletManager() : QObject() {}
|
TabletManager() : QObject() {}
|
||||||
|
|
||||||
|
// gets activated by MapView::tabletEvent(QTabletEvent* event)
|
||||||
bool _is_active = false;
|
bool _is_active = false;
|
||||||
|
// 0.0 to 1.0 scale
|
||||||
double _pressure = 0.0;
|
double _pressure = 0.0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace
|
|||||||
|
|
||||||
liquid_layer::liquid_layer(ChunkWater* chunk, glm::vec3 const& base, float height, int liquid_id)
|
liquid_layer::liquid_layer(ChunkWater* chunk, glm::vec3 const& base, float height, int liquid_id)
|
||||||
: _liquid_id(liquid_id)
|
: _liquid_id(liquid_id)
|
||||||
, _liquid_vertex_format(0)
|
, _liquid_vertex_format(HEIGHT_DEPTH)
|
||||||
, _minimum(height)
|
, _minimum(height)
|
||||||
, _maximum(height)
|
, _maximum(height)
|
||||||
, _subchunks(0)
|
, _subchunks(0)
|
||||||
@@ -28,22 +28,9 @@ liquid_layer::liquid_layer(ChunkWater* chunk, glm::vec3 const& base, float heigh
|
|||||||
, _chunk(chunk)
|
, _chunk(chunk)
|
||||||
{
|
{
|
||||||
if (!gLiquidTypeDB.CheckIfIdExists(_liquid_id))
|
if (!gLiquidTypeDB.CheckIfIdExists(_liquid_id))
|
||||||
_liquid_id = 1;
|
_liquid_id = LIQUID_WATER;
|
||||||
|
|
||||||
for (int z = 0; z < 9; ++z)
|
create_vertices(height);
|
||||||
{
|
|
||||||
for (int x = 0; x < 9; ++x)
|
|
||||||
{
|
|
||||||
unsigned v_index = z * 9 + x;
|
|
||||||
_tex_coords[v_index] = default_uv(x, z);
|
|
||||||
_depth[v_index] = 1.0f;
|
|
||||||
_vertices[v_index] = glm::vec3(
|
|
||||||
pos.x + UNITSIZE * x
|
|
||||||
, height
|
|
||||||
, pos.z + UNITSIZE * z
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
changeLiquidID(_liquid_id);
|
changeLiquidID(_liquid_id);
|
||||||
|
|
||||||
@@ -58,7 +45,7 @@ liquid_layer::liquid_layer(ChunkWater* chunk, glm::vec3 const& base, mclq& liqui
|
|||||||
, _chunk(chunk)
|
, _chunk(chunk)
|
||||||
{
|
{
|
||||||
if (!gLiquidTypeDB.CheckIfIdExists(_liquid_id))
|
if (!gLiquidTypeDB.CheckIfIdExists(_liquid_id))
|
||||||
_liquid_id = 1;
|
_liquid_id = LIQUID_WATER;
|
||||||
|
|
||||||
changeLiquidID(_liquid_id);
|
changeLiquidID(_liquid_id);
|
||||||
|
|
||||||
@@ -77,23 +64,25 @@ liquid_layer::liquid_layer(ChunkWater* chunk, glm::vec3 const& base, mclq& liqui
|
|||||||
const unsigned v_index = z * 9 + x;
|
const unsigned v_index = z * 9 + x;
|
||||||
mclq_vertex const& v = liquid.vertices[v_index];
|
mclq_vertex const& v = liquid.vertices[v_index];
|
||||||
|
|
||||||
if (_liquid_vertex_format == 1)
|
liquid_vertex lv;
|
||||||
|
|
||||||
|
// _liquid_vertex_format is set by changeLiquidID()
|
||||||
|
if (_liquid_vertex_format == HEIGHT_UV)
|
||||||
{
|
{
|
||||||
_depth[v_index] = 1.0f;
|
lv.depth = 1.f;
|
||||||
_tex_coords[v_index] = glm::vec2(static_cast<float>(v.magma.x) / 255.f, static_cast<float>(v.magma.y) / 255.f);
|
lv.uv = { static_cast<float>(v.magma.x) / 255.f, static_cast<float>(v.magma.y) / 255.f };
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_depth[v_index] = static_cast<float>(v.water.depth) / 255.f;
|
lv.depth = static_cast<float>(v.water.depth) / 255.f;
|
||||||
_tex_coords[v_index] = default_uv(x, z);
|
lv.uv = default_uv(x, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
_vertices[v_index] = glm::vec3(
|
// sometimes there's garbage data on unused tiles that mess things up
|
||||||
pos.x + UNITSIZE * x
|
lv.position = { pos.x + UNITSIZE * x, std::clamp(v.height, _minimum, _maximum), pos.z + UNITSIZE * z };
|
||||||
// sometimes there's garbage data on unused tiles that mess things up
|
|
||||||
, std::clamp(v.height, _minimum, _maximum)
|
|
||||||
, pos.z + UNITSIZE * z
|
_vertices[v_index] = lv;
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +104,7 @@ liquid_layer::liquid_layer(ChunkWater* chunk
|
|||||||
{
|
{
|
||||||
// check if liquid id is valid or some downported maps will crash
|
// check if liquid id is valid or some downported maps will crash
|
||||||
if (!gLiquidTypeDB.CheckIfIdExists(_liquid_id))
|
if (!gLiquidTypeDB.CheckIfIdExists(_liquid_id))
|
||||||
_liquid_id = 1;
|
_liquid_id = LIQUID_WATER;
|
||||||
|
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
for (int z = 0; z < info.height; ++z)
|
for (int z = 0; z < info.height; ++z)
|
||||||
@@ -128,40 +117,28 @@ liquid_layer::liquid_layer(ChunkWater* chunk
|
|||||||
}
|
}
|
||||||
|
|
||||||
// default values
|
// default values
|
||||||
for (int z = 0; z < 9; ++z)
|
create_vertices(_minimum);
|
||||||
{
|
|
||||||
for (int x = 0; x < 9; ++x)
|
|
||||||
{
|
|
||||||
const unsigned v_index = z * 9 + x;
|
|
||||||
_tex_coords[v_index] = default_uv(x, z);
|
|
||||||
_depth[v_index] = 1.0f;
|
|
||||||
_vertices[v_index] = glm::vec3(
|
|
||||||
pos.x + UNITSIZE * x
|
|
||||||
, _minimum
|
|
||||||
, pos.z + UNITSIZE * z
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.ofsHeightMap)
|
if (info.ofsHeightMap)
|
||||||
{
|
{
|
||||||
f.seek(base_pos + info.ofsHeightMap);
|
f.seek(base_pos + info.ofsHeightMap);
|
||||||
|
|
||||||
if (_liquid_vertex_format == 0 || _liquid_vertex_format == 1)
|
if (_liquid_vertex_format == HEIGHT_DEPTH || _liquid_vertex_format == HEIGHT_UV)
|
||||||
{
|
{
|
||||||
|
|
||||||
for (int z = info.yOffset; z <= info.yOffset + info.height; ++z)
|
for (int z = info.yOffset; z <= info.yOffset + info.height; ++z)
|
||||||
{
|
{
|
||||||
for (int x = info.xOffset; x <= info.xOffset + info.width; ++x)
|
for (int x = info.xOffset; x <= info.xOffset + info.width; ++x)
|
||||||
{
|
{
|
||||||
int index = z * 9 + x;
|
float h;
|
||||||
f.read(&_vertices[index].y, sizeof(float));
|
f.read(&h, sizeof(float));
|
||||||
_vertices[index].y = std::clamp(_vertices[index].y, _minimum, _maximum);
|
|
||||||
|
_vertices[z * 9 + x].position.y = std::clamp(h, _minimum, _maximum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_liquid_vertex_format == 1)
|
if (_liquid_vertex_format == HEIGHT_UV)
|
||||||
{
|
{
|
||||||
for (int z = info.yOffset; z <= info.yOffset + info.height; ++z)
|
for (int z = info.yOffset; z <= info.yOffset + info.height; ++z)
|
||||||
{
|
{
|
||||||
@@ -169,7 +146,7 @@ liquid_layer::liquid_layer(ChunkWater* chunk
|
|||||||
{
|
{
|
||||||
mh2o_uv uv;
|
mh2o_uv uv;
|
||||||
f.read(&uv, sizeof(mh2o_uv));
|
f.read(&uv, sizeof(mh2o_uv));
|
||||||
_tex_coords[z * 9 + x] =
|
_vertices[z * 9 + x].uv =
|
||||||
{ static_cast<float>(uv.x) / 255.f
|
{ static_cast<float>(uv.x) / 255.f
|
||||||
, static_cast<float>(uv.y) / 255.f
|
, static_cast<float>(uv.y) / 255.f
|
||||||
};
|
};
|
||||||
@@ -177,7 +154,7 @@ liquid_layer::liquid_layer(ChunkWater* chunk
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_liquid_vertex_format == 0 || _liquid_vertex_format == 2)
|
if (_liquid_vertex_format == HEIGHT_DEPTH || _liquid_vertex_format == DEPTH)
|
||||||
{
|
{
|
||||||
for (int z = info.yOffset; z <= info.yOffset + info.height; ++z)
|
for (int z = info.yOffset; z <= info.yOffset + info.height; ++z)
|
||||||
{
|
{
|
||||||
@@ -185,13 +162,16 @@ liquid_layer::liquid_layer(ChunkWater* chunk
|
|||||||
{
|
{
|
||||||
std::uint8_t depth;
|
std::uint8_t depth;
|
||||||
f.read(&depth, sizeof(std::uint8_t));
|
f.read(&depth, sizeof(std::uint8_t));
|
||||||
_depth[z * 9 + x] = static_cast<float>(depth) / 255.f;
|
_vertices[z * 9 + x].depth = static_cast<float>(depth) / 255.f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changeLiquidID(_liquid_id); // to update the liquid type
|
||||||
|
|
||||||
|
if (check_fatigue())
|
||||||
|
_fatigue_enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
liquid_layer::liquid_layer(liquid_layer&& other)
|
liquid_layer::liquid_layer(liquid_layer&& other)
|
||||||
@@ -199,14 +179,15 @@ liquid_layer::liquid_layer(liquid_layer&& other)
|
|||||||
, _liquid_vertex_format(other._liquid_vertex_format)
|
, _liquid_vertex_format(other._liquid_vertex_format)
|
||||||
, _minimum(other._minimum)
|
, _minimum(other._minimum)
|
||||||
, _maximum(other._maximum)
|
, _maximum(other._maximum)
|
||||||
|
// , _center(other._center)
|
||||||
, _subchunks(other._subchunks)
|
, _subchunks(other._subchunks)
|
||||||
, _vertices(other._vertices)
|
, _vertices(other._vertices)
|
||||||
, _depth(other._depth)
|
// , _indices_by_lod(other._indices_by_lod)
|
||||||
, _tex_coords(other._tex_coords)
|
, _fatigue_enabled(other._fatigue_enabled)
|
||||||
, _indices_by_lod(other._indices_by_lod)
|
|
||||||
, pos(other.pos)
|
, pos(other.pos)
|
||||||
, _chunk(other._chunk)
|
, _chunk(other._chunk)
|
||||||
{
|
{
|
||||||
|
// update liquid type and vertex format
|
||||||
changeLiquidID(_liquid_id);
|
changeLiquidID(_liquid_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,12 +198,12 @@ liquid_layer::liquid_layer(liquid_layer const& other)
|
|||||||
, _maximum(other._maximum)
|
, _maximum(other._maximum)
|
||||||
, _subchunks(other._subchunks)
|
, _subchunks(other._subchunks)
|
||||||
, _vertices(other._vertices)
|
, _vertices(other._vertices)
|
||||||
, _depth(other._depth)
|
// , _indices_by_lod(other._indices_by_lod)
|
||||||
, _tex_coords(other._tex_coords)
|
, _fatigue_enabled(other._fatigue_enabled)
|
||||||
, _indices_by_lod(other._indices_by_lod)
|
|
||||||
, pos(other.pos)
|
, pos(other.pos)
|
||||||
, _chunk(other._chunk)
|
, _chunk(other._chunk)
|
||||||
{
|
{
|
||||||
|
// update liquid type and vertex format
|
||||||
changeLiquidID(_liquid_id);
|
changeLiquidID(_liquid_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,12 +215,12 @@ liquid_layer& liquid_layer::operator= (liquid_layer&& other)
|
|||||||
std::swap(_maximum, other._maximum);
|
std::swap(_maximum, other._maximum);
|
||||||
std::swap(_subchunks, other._subchunks);
|
std::swap(_subchunks, other._subchunks);
|
||||||
std::swap(_vertices, other._vertices);
|
std::swap(_vertices, other._vertices);
|
||||||
std::swap(_depth, other._depth);
|
std::swap(_fatigue_enabled, other._fatigue_enabled);
|
||||||
std::swap(_tex_coords, other._tex_coords);
|
|
||||||
std::swap(pos, other.pos);
|
std::swap(pos, other.pos);
|
||||||
std::swap(_indices_by_lod, other._indices_by_lod);
|
// std::swap(_indices_by_lod, other._indices_by_lod);
|
||||||
std::swap(_chunk, other._chunk);
|
std::swap(_chunk, other._chunk);
|
||||||
|
|
||||||
|
// update liquid type and vertex format
|
||||||
changeLiquidID(_liquid_id);
|
changeLiquidID(_liquid_id);
|
||||||
other.changeLiquidID(other._liquid_id);
|
other.changeLiquidID(other._liquid_id);
|
||||||
|
|
||||||
@@ -248,21 +229,38 @@ liquid_layer& liquid_layer::operator= (liquid_layer&& other)
|
|||||||
|
|
||||||
liquid_layer& liquid_layer::operator=(liquid_layer const& other)
|
liquid_layer& liquid_layer::operator=(liquid_layer const& other)
|
||||||
{
|
{
|
||||||
changeLiquidID(other._liquid_id);
|
|
||||||
_liquid_vertex_format = other._liquid_vertex_format;
|
_liquid_vertex_format = other._liquid_vertex_format;
|
||||||
_minimum = other._minimum;
|
_minimum = other._minimum;
|
||||||
_maximum = other._maximum;
|
_maximum = other._maximum;
|
||||||
_subchunks = other._subchunks;
|
_subchunks = other._subchunks;
|
||||||
_vertices = other._vertices;
|
_vertices = other._vertices;
|
||||||
_depth = other._depth;
|
|
||||||
_tex_coords = other._tex_coords;
|
|
||||||
pos = other.pos;
|
pos = other.pos;
|
||||||
_indices_by_lod = other._indices_by_lod;
|
// _indices_by_lod = other._indices_by_lod;
|
||||||
|
_fatigue_enabled = other._fatigue_enabled;
|
||||||
_chunk = other._chunk;
|
_chunk = other._chunk;
|
||||||
|
|
||||||
|
// update liquid type and vertex format
|
||||||
|
changeLiquidID(other._liquid_id);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void liquid_layer::create_vertices(float height)
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
for (int z = 0; z < 9; ++z)
|
||||||
|
{
|
||||||
|
const float posZ = pos.z + UNITSIZE * z;
|
||||||
|
for (int x = 0; x < 9; ++x, ++index)
|
||||||
|
{
|
||||||
|
_vertices[index] = liquid_vertex( glm::vec3(pos.x + UNITSIZE * x, height, posZ)
|
||||||
|
, default_uv(x, z)
|
||||||
|
, 1.f
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void liquid_layer::save(sExtendableArray& adt, int base_pos, int& info_pos, int& current_pos) const
|
void liquid_layer::save(sExtendableArray& adt, int base_pos, int& info_pos, int& current_pos) const
|
||||||
{
|
{
|
||||||
int min_x = 9, min_z = 9, max_x = 0, max_z = 0;
|
int min_x = 9, min_z = 9, max_x = 0, max_z = 0;
|
||||||
@@ -325,11 +323,10 @@ void liquid_layer::save(sExtendableArray& adt, int base_pos, int& info_pos, int&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int vertices_count = (info.width + 1) * (info.height + 1);
|
||||||
info.ofsHeightMap = current_pos - base_pos;
|
info.ofsHeightMap = current_pos - base_pos;
|
||||||
|
|
||||||
int vertices_count = (info.width + 1) * (info.height + 1);
|
if (_liquid_vertex_format == HEIGHT_DEPTH || _liquid_vertex_format == HEIGHT_UV)
|
||||||
|
|
||||||
if (_liquid_vertex_format == 0 || _liquid_vertex_format == 1)
|
|
||||||
{
|
{
|
||||||
adt.Extend(vertices_count * sizeof(float));
|
adt.Extend(vertices_count * sizeof(float));
|
||||||
|
|
||||||
@@ -337,13 +334,18 @@ void liquid_layer::save(sExtendableArray& adt, int base_pos, int& info_pos, int&
|
|||||||
{
|
{
|
||||||
for (int x = info.xOffset; x <= info.xOffset + info.width; ++x)
|
for (int x = info.xOffset; x <= info.xOffset + info.width; ++x)
|
||||||
{
|
{
|
||||||
memcpy(adt.GetPointer<char>(current_pos), &_vertices[z * 9 + x].y, sizeof(float));
|
memcpy(adt.GetPointer<char>(current_pos), &_vertices[z * 9 + x].position.y, sizeof(float));
|
||||||
current_pos += sizeof(float);
|
current_pos += sizeof(float);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// no heightmap/depth data for fatigue chunks
|
||||||
|
else if (_fatigue_enabled)
|
||||||
|
{
|
||||||
|
info.ofsHeightMap = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (_liquid_vertex_format == 1)
|
if (_liquid_vertex_format == HEIGHT_UV)
|
||||||
{
|
{
|
||||||
adt.Extend(vertices_count * sizeof(mh2o_uv));
|
adt.Extend(vertices_count * sizeof(mh2o_uv));
|
||||||
|
|
||||||
@@ -352,8 +354,8 @@ void liquid_layer::save(sExtendableArray& adt, int base_pos, int& info_pos, int&
|
|||||||
for (int x = info.xOffset; x <= info.xOffset + info.width; ++x)
|
for (int x = info.xOffset; x <= info.xOffset + info.width; ++x)
|
||||||
{
|
{
|
||||||
mh2o_uv uv;
|
mh2o_uv uv;
|
||||||
uv.x = static_cast<std::uint16_t>(std::min(_tex_coords[z * 9 + x].x * 255.f, 65535.f));
|
uv.x = static_cast<std::uint16_t>(std::min(_vertices[z * 9 + x].uv.x * 255.f, 65535.f));
|
||||||
uv.y = static_cast<std::uint16_t>(std::min(_tex_coords[z * 9 + x].y * 255.f, 65535.f));
|
uv.y = static_cast<std::uint16_t>(std::min(_vertices[z * 9 + x].uv.y * 255.f, 65535.f));
|
||||||
|
|
||||||
memcpy(adt.GetPointer<char>(current_pos), &uv, sizeof(mh2o_uv));
|
memcpy(adt.GetPointer<char>(current_pos), &uv, sizeof(mh2o_uv));
|
||||||
current_pos += sizeof(mh2o_uv);
|
current_pos += sizeof(mh2o_uv);
|
||||||
@@ -361,7 +363,7 @@ void liquid_layer::save(sExtendableArray& adt, int base_pos, int& info_pos, int&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_liquid_vertex_format == 0 || _liquid_vertex_format == 2)
|
if (_liquid_vertex_format == HEIGHT_DEPTH || (_liquid_vertex_format == DEPTH && !_fatigue_enabled))
|
||||||
{
|
{
|
||||||
adt.Extend(vertices_count * sizeof(std::uint8_t));
|
adt.Extend(vertices_count * sizeof(std::uint8_t));
|
||||||
|
|
||||||
@@ -369,7 +371,7 @@ void liquid_layer::save(sExtendableArray& adt, int base_pos, int& info_pos, int&
|
|||||||
{
|
{
|
||||||
for (int x = info.xOffset; x <= info.xOffset + info.width; ++x)
|
for (int x = info.xOffset; x <= info.xOffset + info.width; ++x)
|
||||||
{
|
{
|
||||||
std::uint8_t depth = static_cast<std::uint8_t>(std::min(_depth[z * 9 + x] * 255.0f, 255.f));
|
std::uint8_t depth = static_cast<std::uint8_t>(std::min(_vertices[z * 9 + x].depth * 255.0f, 255.f));
|
||||||
memcpy(adt.GetPointer<char>(current_pos), &depth, sizeof(std::uint8_t));
|
memcpy(adt.GetPointer<char>(current_pos), &depth, sizeof(std::uint8_t));
|
||||||
current_pos += sizeof(std::uint8_t);
|
current_pos += sizeof(std::uint8_t);
|
||||||
}
|
}
|
||||||
@@ -388,19 +390,26 @@ void liquid_layer::changeLiquidID(int id)
|
|||||||
{
|
{
|
||||||
DBCFile::Record lLiquidTypeRow = gLiquidTypeDB.getByID(_liquid_id);
|
DBCFile::Record lLiquidTypeRow = gLiquidTypeDB.getByID(_liquid_id);
|
||||||
|
|
||||||
switch (lLiquidTypeRow.getInt(LiquidTypeDB::Type))
|
_liquid_type = lLiquidTypeRow.getInt(LiquidTypeDB::Type);
|
||||||
|
|
||||||
|
switch (_liquid_type)
|
||||||
{
|
{
|
||||||
case 2: // magma
|
case liquid_basic_types_magma:
|
||||||
case 3: // slime
|
case liquid_basic_types_slime:
|
||||||
_liquid_vertex_format = 1;
|
_liquid_vertex_format = HEIGHT_UV;
|
||||||
|
break;
|
||||||
|
case liquid_basic_types_ocean: // ocean
|
||||||
|
_liquid_vertex_format = DEPTH;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
_liquid_vertex_format = 0;
|
_liquid_vertex_format = HEIGHT_DEPTH;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (LiquidTypeDB::NotFound)
|
||||||
{
|
{
|
||||||
|
assert(false);
|
||||||
|
LogError << "Liquid type id " << _liquid_type << " not found in LiquidType dbc" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,10 +429,10 @@ void liquid_layer::crop(MapChunk* chunk)
|
|||||||
{
|
{
|
||||||
int water_index = 9 * z + x, terrain_index = 17 * z + x;
|
int water_index = 9 * z + x, terrain_index = 17 * z + x;
|
||||||
|
|
||||||
if (_vertices[water_index].y < chunk->mVertices[terrain_index].y
|
if ( _vertices[water_index + 0].position.y < chunk->mVertices[terrain_index + 0].y
|
||||||
&& _vertices[water_index + 1].y < chunk->mVertices[terrain_index + 1].y
|
&& _vertices[water_index + 1].position.y < chunk->mVertices[terrain_index + 1].y
|
||||||
&& _vertices[water_index + 9].y < chunk->mVertices[terrain_index + 17].y
|
&& _vertices[water_index + 9].position.y < chunk->mVertices[terrain_index + 17].y
|
||||||
&& _vertices[water_index + 10].y < chunk->mVertices[terrain_index + 18].y
|
&& _vertices[water_index + 10].position.y < chunk->mVertices[terrain_index + 18].y
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
setSubchunk(x, z, false);
|
setSubchunk(x, z, false);
|
||||||
@@ -490,18 +499,18 @@ void liquid_layer::paintLiquid( glm::vec3 const& cursor_pos
|
|||||||
{
|
{
|
||||||
for (int x = 0; x < 8; ++x)
|
for (int x = 0; x < 8; ++x)
|
||||||
{
|
{
|
||||||
if (misc::getShortestDist(cursor_pos, _vertices[id], UNITSIZE) <= radius)
|
if (misc::getShortestDist(cursor_pos, _vertices[id].position, UNITSIZE) <= radius)
|
||||||
{
|
{
|
||||||
if (add)
|
if (add)
|
||||||
{
|
{
|
||||||
for (int index : {id, id + 1, id + 9, id + 10})
|
for (int index : {id, id + 1, id + 9, id + 10})
|
||||||
{
|
{
|
||||||
bool no_subchunk = !hasSubchunk(x, z);
|
bool no_subchunk = !hasSubchunk(x, z);
|
||||||
bool in_range = misc::dist(cursor_pos, _vertices[index]) <= radius;
|
bool in_range = misc::dist(cursor_pos, _vertices[index].position) <= radius;
|
||||||
|
|
||||||
if (no_subchunk || (in_range && override_height))
|
if (no_subchunk || (in_range && override_height))
|
||||||
{
|
{
|
||||||
_vertices[index].y = misc::angledHeight(ref, _vertices[index], angle, orientation);
|
_vertices[index].position.y = misc::angledHeight(ref, _vertices[index].position, angle, orientation);
|
||||||
}
|
}
|
||||||
if (no_subchunk || in_range)
|
if (no_subchunk || in_range)
|
||||||
{
|
{
|
||||||
@@ -527,12 +536,12 @@ void liquid_layer::update_min_max()
|
|||||||
_maximum = std::numeric_limits<float>::lowest();
|
_maximum = std::numeric_limits<float>::lowest();
|
||||||
int x = 0, z = 0;
|
int x = 0, z = 0;
|
||||||
|
|
||||||
for (glm::vec3& v : _vertices)
|
for (liquid_vertex& v : _vertices)
|
||||||
{
|
{
|
||||||
if (hasSubchunk(std::min(x, 7), std::min(z, 7)))
|
if (hasSubchunk(std::min(x, 7), std::min(z, 7)))
|
||||||
{
|
{
|
||||||
_maximum = std::max(_maximum, v.y);
|
_maximum = std::max(_maximum, v.position.y);
|
||||||
_minimum = std::min(_minimum, v.y);
|
_minimum = std::min(_minimum, v.position.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (++x == 9)
|
if (++x == 9)
|
||||||
@@ -543,15 +552,19 @@ void liquid_layer::update_min_max()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// lvf = 2 means the liquid height is 0, switch to lvf 0 when that's not the case
|
// lvf = 2 means the liquid height is 0, switch to lvf 0 when that's not the case
|
||||||
if (_liquid_vertex_format == 2 && (!misc::float_equals(0.f, _minimum) || !misc::float_equals(0.f, _maximum)))
|
if (_liquid_vertex_format == DEPTH && (!misc::float_equals(0.f, _minimum) || !misc::float_equals(0.f, _maximum)))
|
||||||
{
|
{
|
||||||
_liquid_vertex_format = 0;
|
_liquid_vertex_format = HEIGHT_DEPTH;
|
||||||
}
|
}
|
||||||
// use lvf 2 when possible to save space
|
// use lvf 2 when possible to save space
|
||||||
else if (_liquid_vertex_format == 0 && misc::float_equals(0.f, _minimum) && misc::float_equals(0.f, _maximum))
|
else if (_liquid_vertex_format == HEIGHT_DEPTH && misc::float_equals(0.f, _minimum) && misc::float_equals(0.f, _maximum))
|
||||||
{
|
{
|
||||||
_liquid_vertex_format = 2;
|
_liquid_vertex_format = DEPTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_fatigue_enabled = check_fatigue();
|
||||||
|
// recalc all atributes instead?
|
||||||
|
// _chunk->update_layers();
|
||||||
}
|
}
|
||||||
|
|
||||||
void liquid_layer::copy_subchunk_height(int x, int z, liquid_layer const& from)
|
void liquid_layer::copy_subchunk_height(int x, int z, liquid_layer const& from)
|
||||||
@@ -560,7 +573,7 @@ void liquid_layer::copy_subchunk_height(int x, int z, liquid_layer const& from)
|
|||||||
|
|
||||||
for (int index : {id, id + 1, id + 9, id + 10})
|
for (int index : {id, id + 1, id + 9, id + 10})
|
||||||
{
|
{
|
||||||
_vertices[index].y = from._vertices[index].y;
|
_vertices[index].position.y = from._vertices[index].position.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
setSubchunk(x, z, true);
|
setSubchunk(x, z, true);
|
||||||
@@ -568,18 +581,93 @@ void liquid_layer::copy_subchunk_height(int x, int z, liquid_layer const& from)
|
|||||||
|
|
||||||
void liquid_layer::update_vertex_opacity(int x, int z, MapChunk* chunk, float factor)
|
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;
|
const int index = z * 9 + x;
|
||||||
_depth[z * 9 + x] = diff < 0.0f ? 0.0f : (std::min(1.0f, std::max(0.0f, (diff + 1.0f) * factor)));
|
float diff = _vertices[index].position.y - chunk->mVertices[z * 17 + x].y;
|
||||||
|
_vertices[z * 9 + x].depth = diff < 0.0f ? 0.0f : (std::min(1.0f, std::max(0.0f, (diff + 1.0f) * factor)));
|
||||||
}
|
}
|
||||||
|
|
||||||
int liquid_layer::get_lod_level(glm::vec3 const& camera_pos) const
|
int liquid_layer::get_lod_level(glm::vec3 const& camera_pos) const
|
||||||
{
|
{
|
||||||
auto const& center_vertex (_vertices[5 * 9 + 4]);
|
glm::vec3 const& center_vertex (_vertices[5 * 9 + 4].position);
|
||||||
auto const dist ((center_vertex - camera_pos).length());
|
// this doesn't look like it's using the right length function...
|
||||||
|
// auto const dist ((center_vertex - camera_pos).length());
|
||||||
|
float const dist = misc::dist(center_vertex, camera_pos);
|
||||||
|
|
||||||
return dist < 1000.f ? 0
|
return dist < 1000.f ? 0
|
||||||
: dist < 2000.f ? 1
|
: dist < 2000.f ? 1
|
||||||
: dist < 4000.f ? 2
|
: dist < 4000.f ? 2
|
||||||
: 3;
|
: 3;
|
||||||
}
|
}
|
||||||
|
// if ocean and all subchunks are at max depth
|
||||||
|
bool liquid_layer::check_fatigue() const
|
||||||
|
{
|
||||||
|
// only oceans have fatigue
|
||||||
|
if (_liquid_type != liquid_basic_types_ocean)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int z = 0; z < 8; ++z)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < 8; ++x)
|
||||||
|
{
|
||||||
|
if (!(hasSubchunk(x, z) && subchunk_at_max_depth(x, z)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void liquid_layer::update_attributes(MH2O_Attributes& attributes)
|
||||||
|
{
|
||||||
|
if (check_fatigue())
|
||||||
|
{
|
||||||
|
attributes.fishable = 0xFFFFFFFFFFFFFFFF;
|
||||||
|
attributes.fatigue = 0xFFFFFFFFFFFFFFFF;
|
||||||
|
|
||||||
|
_fatigue_enabled = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_fatigue_enabled = false;
|
||||||
|
for (int z = 0; z < 8; ++z)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < 8; ++x)
|
||||||
|
{
|
||||||
|
if (hasSubchunk(x, z))
|
||||||
|
{
|
||||||
|
// todo : find out when fishable isn't set. maybe lava/slime or very shallow water ?
|
||||||
|
// Most likely when subchunk is entirely above terrain.
|
||||||
|
misc::set_bit(attributes.fishable, x, z, true);
|
||||||
|
|
||||||
|
// only oceans have fatigue
|
||||||
|
// warning: not used by TrinityCore
|
||||||
|
if (_liquid_type == liquid_basic_types_ocean && subchunk_at_max_depth(x, z))
|
||||||
|
{
|
||||||
|
misc::set_bit(attributes.fatigue, x, z, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool liquid_layer::subchunk_at_max_depth(int x, int z) const
|
||||||
|
{
|
||||||
|
for (int id_z = z; id_z <= z + 1; ++id_z)
|
||||||
|
{
|
||||||
|
for (int id_x = x; id_x <= x + 1; ++id_x)
|
||||||
|
{
|
||||||
|
if (_vertices[id_x + 9 * id_z].depth < 1.f)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,14 @@ enum LiquidLayerUpdateFlags
|
|||||||
ll_FLAGS = 0x10
|
ll_FLAGS = 0x10
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum LiquidVertexFormats
|
||||||
|
{
|
||||||
|
HEIGHT_DEPTH = 0,
|
||||||
|
HEIGHT_UV = 1,
|
||||||
|
DEPTH = 2,
|
||||||
|
HEIGHT_DEPTH_UV = 3
|
||||||
|
};
|
||||||
|
|
||||||
namespace BlizzardArchive
|
namespace BlizzardArchive
|
||||||
{
|
{
|
||||||
class ClientFile;
|
class ClientFile;
|
||||||
@@ -29,6 +37,15 @@ namespace BlizzardArchive
|
|||||||
// handle liquids like oceans, lakes, rivers, slime, magma
|
// handle liquids like oceans, lakes, rivers, slime, magma
|
||||||
class liquid_layer
|
class liquid_layer
|
||||||
{
|
{
|
||||||
|
struct liquid_vertex
|
||||||
|
{
|
||||||
|
glm::vec3 position;
|
||||||
|
glm::vec2 uv;
|
||||||
|
float depth;
|
||||||
|
|
||||||
|
liquid_vertex() = default;
|
||||||
|
liquid_vertex(glm::vec3 const& pos, glm::vec2 const& uv, float depth) : position(pos), uv(uv), depth(depth) {}
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
liquid_layer() = delete;
|
liquid_layer() = delete;
|
||||||
@@ -44,19 +61,23 @@ public:
|
|||||||
|
|
||||||
void save(sExtendableArray& adt, int base_pos, int& info_pos, int& current_pos) const;
|
void save(sExtendableArray& adt, int base_pos, int& info_pos, int& current_pos) const;
|
||||||
|
|
||||||
|
void update_attributes(MH2O_Attributes& attributes);
|
||||||
void changeLiquidID(int id);
|
void changeLiquidID(int id);
|
||||||
|
|
||||||
void crop(MapChunk* chunk);
|
void crop(MapChunk* chunk);
|
||||||
void update_opacity(MapChunk* chunk, float factor);
|
void update_opacity(MapChunk* chunk, float factor);
|
||||||
|
|
||||||
std::array<glm::vec3, 9 * 9>& getVertices() { return _vertices; };
|
std::array<liquid_vertex, 9 * 9>& getVertices() { return _vertices; };
|
||||||
std::array<float, 9 * 9>& getDepth() { return _depth; };
|
// std::array<float, 9 * 9>& getDepth() { return _depth; };
|
||||||
std::array<glm::vec2, 9 * 9>& getTexCoords() { return _tex_coords; };
|
// std::array<glm::vec2, 9 * 9>& getTexCoords() { return _tex_coords; };
|
||||||
|
|
||||||
float min() const { return _minimum; }
|
float min() const { return _minimum; }
|
||||||
float max() const { return _maximum; }
|
float max() const { return _maximum; }
|
||||||
int liquidID() const { return _liquid_id; }
|
int liquidID() const { return _liquid_id; }
|
||||||
|
|
||||||
|
// used for fatigue calculation
|
||||||
|
bool subchunk_at_max_depth(int x, int z) const;
|
||||||
|
|
||||||
bool hasSubchunk(int x, int z, int size = 1) const;
|
bool hasSubchunk(int x, int z, int size = 1) const;
|
||||||
void setSubchunk(int x, int z, bool water);
|
void setSubchunk(int x, int z, bool water);
|
||||||
|
|
||||||
@@ -82,23 +103,34 @@ public:
|
|||||||
|
|
||||||
ChunkWater* getChunk() { return _chunk; };
|
ChunkWater* getChunk() { return _chunk; };
|
||||||
|
|
||||||
|
bool has_fatigue() const { return _fatigue_enabled; }
|
||||||
private:
|
private:
|
||||||
|
void create_vertices(float height);
|
||||||
|
|
||||||
void update_min_max();
|
void update_min_max();
|
||||||
void update_vertex_opacity(int x, int z, MapChunk* chunk, float factor);
|
void update_vertex_opacity(int x, int z, MapChunk* chunk, float factor);
|
||||||
int get_lod_level(glm::vec3 const& camera_pos) const;
|
int get_lod_level(glm::vec3 const& camera_pos) const;
|
||||||
void set_lod_level(int lod_level);
|
// void set_lod_level(int lod_level);
|
||||||
|
|
||||||
|
bool check_fatigue() const;
|
||||||
|
// gets enabled when all subchunks are at max depth and type is ocean : check_fatigue()
|
||||||
|
bool _fatigue_enabled = false;
|
||||||
|
|
||||||
int _liquid_id;
|
int _liquid_id;
|
||||||
|
int _liquid_type;
|
||||||
int _liquid_vertex_format;
|
int _liquid_vertex_format;
|
||||||
float _minimum;
|
float _minimum;
|
||||||
float _maximum;
|
float _maximum;
|
||||||
|
|
||||||
std::uint64_t _subchunks;
|
std::uint64_t _subchunks;
|
||||||
std::array<glm::vec3, 9 * 9> _vertices;
|
// std::array<glm::vec3, 9 * 9> _vertices;
|
||||||
std::array<float, 9 * 9> _depth;
|
// std::array<float, 9 * 9> _depth;
|
||||||
std::array<glm::vec2, 9 * 9> _tex_coords;
|
// std::array<glm::vec2, 9 * 9> _tex_coords;
|
||||||
|
|
||||||
std::map<int, std::vector<std::uint16_t>> _indices_by_lod;
|
// std::vector<liquid_vertex> _vertices;
|
||||||
|
std::array<liquid_vertex, 9 * 9> _vertices;
|
||||||
|
|
||||||
|
// std::map<int, std::vector<liquid_indice>> _indices_by_lod;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -161,16 +161,16 @@ void LiquidRender::updateLayerData(LiquidTextureManager* tex_manager)
|
|||||||
|
|
||||||
// fill vertex data
|
// fill vertex data
|
||||||
auto& vertices = layer.getVertices();
|
auto& vertices = layer.getVertices();
|
||||||
auto& tex_coords = layer.getTexCoords();
|
// auto& tex_coords = layer.getTexCoords();
|
||||||
auto& depth = layer.getDepth();
|
// auto& depth = layer.getDepth();
|
||||||
|
|
||||||
for (int z_v = 0; z_v < 9; ++z_v)
|
for (int z_v = 0; z_v < 9; ++z_v)
|
||||||
{
|
{
|
||||||
for (int x_v = 0; x_v < 9; ++x_v)
|
for (int x_v = 0; x_v < 9; ++x_v)
|
||||||
{
|
{
|
||||||
const unsigned v_index = z_v * 9 + x_v;
|
const unsigned v_index = z_v * 9 + x_v;
|
||||||
glm::vec2& tex_coord = tex_coords[v_index];
|
glm::vec2& tex_coord = vertices[v_index].uv;
|
||||||
layer_params.vertex_data[n_chunks][v_index] = glm::vec4(vertices[v_index].y, depth[v_index], tex_coord.x, tex_coord.y);
|
layer_params.vertex_data[n_chunks][v_index] = glm::vec4(vertices[v_index].position.y, vertices[v_index].depth, tex_coord.x, tex_coord.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -151,37 +151,14 @@ namespace Noggit
|
|||||||
return vert(state(), _chunk, index);
|
return vert(state(), _chunk, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool chunk::has_render_flags()
|
MH2O_Attributes& chunk::getAttributes()
|
||||||
{
|
{
|
||||||
return _chunk->liquid_chunk()->Render.has_value();
|
return _chunk->liquid_chunk()->getAttributes();
|
||||||
}
|
|
||||||
|
|
||||||
MH2O_Render chunk::getRenderOrDefault()
|
|
||||||
{
|
|
||||||
std::optional<MH2O_Render> render = _chunk->liquid_chunk()->Render;
|
|
||||||
if (render.has_value())
|
|
||||||
{
|
|
||||||
return render.value();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return { 0xFFFFFFFFFFFFFFFF,1 };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MH2O_Render& chunk::getOrCreateRender()
|
|
||||||
{
|
|
||||||
std::optional<MH2O_Render>& render = _chunk->liquid_chunk()->Render;
|
|
||||||
if (!render.has_value())
|
|
||||||
{
|
|
||||||
render.emplace();
|
|
||||||
}
|
|
||||||
return render.value();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void chunk::set_deep_flag(std::uint32_t low, std::uint32_t high)
|
void chunk::set_deep_flag(std::uint32_t low, std::uint32_t high)
|
||||||
{
|
{
|
||||||
getOrCreateRender().fatigue = std::uint64_t(low) | (std::uint64_t(high) << 32);
|
_chunk->liquid_chunk()->getAttributes().fatigue = std::uint64_t(low) | (std::uint64_t(high) << 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
void chunk::set_deep_flag_1(std::uint32_t low)
|
void chunk::set_deep_flag_1(std::uint32_t low)
|
||||||
@@ -191,17 +168,17 @@ namespace Noggit
|
|||||||
|
|
||||||
std::uint32_t chunk::get_deep_flag()
|
std::uint32_t chunk::get_deep_flag()
|
||||||
{
|
{
|
||||||
return static_cast<std::uint32_t>(getRenderOrDefault().fatigue);
|
return static_cast<std::uint32_t>(getAttributes().fatigue);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint32_t chunk::get_deep_flag_high()
|
std::uint32_t chunk::get_deep_flag_high()
|
||||||
{
|
{
|
||||||
return static_cast<std::uint32_t>(getRenderOrDefault().fatigue >> 32);
|
return static_cast<std::uint32_t>(getAttributes().fatigue >> 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
void chunk::set_fishable_flag(std::uint32_t low, std::uint32_t high)
|
void chunk::set_fishable_flag(std::uint32_t low, std::uint32_t high)
|
||||||
{
|
{
|
||||||
getOrCreateRender().fishable = std::uint64_t(low) | (std::uint64_t(high) << 32);
|
_chunk->liquid_chunk()->getAttributes().fishable = std::uint64_t(low) | (std::uint64_t(high) << 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
void chunk::set_fishable_flag_1(std::uint32_t low)
|
void chunk::set_fishable_flag_1(std::uint32_t low)
|
||||||
@@ -211,11 +188,11 @@ namespace Noggit
|
|||||||
|
|
||||||
std::uint32_t chunk::get_fishable_flag()
|
std::uint32_t chunk::get_fishable_flag()
|
||||||
{
|
{
|
||||||
return static_cast<std::uint32_t>(getRenderOrDefault().fishable);
|
return static_cast<std::uint32_t>(getAttributes().fishable);
|
||||||
}
|
}
|
||||||
std::uint32_t chunk::get_fishable_flag_high()
|
std::uint32_t chunk::get_fishable_flag_high()
|
||||||
{
|
{
|
||||||
return static_cast<std::uint32_t>(getRenderOrDefault().fishable >> 32);
|
return static_cast<std::uint32_t>(getAttributes().fishable >> 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<selection> chunk::to_selection()
|
std::shared_ptr<selection> chunk::to_selection()
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ namespace Noggit
|
|||||||
void set_fishable_flag_1(std::uint32_t low);
|
void set_fishable_flag_1(std::uint32_t low);
|
||||||
std::uint32_t get_fishable_flag();
|
std::uint32_t get_fishable_flag();
|
||||||
std::uint32_t get_fishable_flag_high();
|
std::uint32_t get_fishable_flag_high();
|
||||||
bool has_render_flags();
|
|
||||||
|
|
||||||
void set_impassable(bool add);
|
void set_impassable(bool add);
|
||||||
int get_area_id();
|
int get_area_id();
|
||||||
@@ -52,8 +51,7 @@ namespace Noggit
|
|||||||
vert get_vert(int index);
|
vert get_vert(int index);
|
||||||
std::shared_ptr<selection> to_selection();
|
std::shared_ptr<selection> to_selection();
|
||||||
private:
|
private:
|
||||||
MH2O_Render getRenderOrDefault();
|
MH2O_Attributes& getAttributes();
|
||||||
MH2O_Render& getOrCreateRender();
|
|
||||||
MapChunk* _chunk;
|
MapChunk* _chunk;
|
||||||
friend class selection;
|
friend class selection;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <noggit/World.h>
|
#include <noggit/World.h>
|
||||||
#include <noggit/ui/pushbutton.hpp>
|
#include <noggit/ui/pushbutton.hpp>
|
||||||
#include <noggit/ui/Water.h>
|
#include <noggit/ui/Water.h>
|
||||||
|
#include <noggit/MapHeaders.h>
|
||||||
#include <util/qt/overload.hpp>
|
#include <util/qt/overload.hpp>
|
||||||
|
|
||||||
#include <QtWidgets/QButtonGroup>
|
#include <QtWidgets/QButtonGroup>
|
||||||
@@ -63,7 +64,8 @@ namespace Noggit
|
|||||||
int liquid_id = i->getInt(LiquidTypeDB::ID);
|
int liquid_id = i->getInt(LiquidTypeDB::ID);
|
||||||
|
|
||||||
// filter WMO liquids
|
// filter WMO liquids
|
||||||
if (liquid_id == 13 || liquid_id == 14 || liquid_id == 17 || liquid_id == 19 || liquid_id == 20)
|
if (liquid_id == LIQUID_WMO_Water || liquid_id == LIQUID_WMO_Ocean || liquid_id == LIQUID_WMO_Water_Interior
|
||||||
|
|| liquid_id == LIQUID_WMO_Magma || liquid_id == LIQUID_WMO_Slime)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
@@ -81,13 +83,14 @@ namespace Noggit
|
|||||||
if (_opacity_mode == custom_opacity)
|
if (_opacity_mode == custom_opacity)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// other liquid types shouldn't use opacity(depth)
|
||||||
int liquid_type = LiquidTypeDB::getLiquidType(_liquid_id);
|
int liquid_type = LiquidTypeDB::getLiquidType(_liquid_id);
|
||||||
if (liquid_type == 1) // ocean
|
if (liquid_type == liquid_basic_types_ocean) // ocean
|
||||||
{
|
{
|
||||||
ocean_button->setChecked(true);
|
ocean_button->setChecked(true);
|
||||||
_opacity_mode = ocean_opacity;
|
_opacity_mode = ocean_opacity;
|
||||||
}
|
}
|
||||||
else
|
else // water. opacity doesn't matter for lava/slim
|
||||||
{
|
{
|
||||||
river_button->setChecked(true);
|
river_button->setChecked(true);
|
||||||
_opacity_mode = river_opacity;
|
_opacity_mode = river_opacity;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <noggit/World.h>
|
#include <noggit/World.h>
|
||||||
#include <noggit/wmo_liquid.hpp>
|
#include <noggit/wmo_liquid.hpp>
|
||||||
#include <noggit/application/NoggitApplication.hpp>
|
#include <noggit/application/NoggitApplication.hpp>
|
||||||
|
#include <noggit/MapHeaders.h>
|
||||||
#include <opengl/context.hpp>
|
#include <opengl/context.hpp>
|
||||||
#include <opengl/context.inl>
|
#include <opengl/context.inl>
|
||||||
#include <opengl/shader.hpp>
|
#include <opengl/shader.hpp>
|
||||||
@@ -14,30 +15,6 @@
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
enum liquid_basic_types
|
|
||||||
{
|
|
||||||
liquid_basic_types_water = 0,
|
|
||||||
liquid_basic_types_ocean = 1,
|
|
||||||
liquid_basic_types_magma = 2,
|
|
||||||
liquid_basic_types_slime = 3,
|
|
||||||
|
|
||||||
liquid_basic_types_MASK = 3,
|
|
||||||
};
|
|
||||||
enum liquid_types
|
|
||||||
{
|
|
||||||
LIQUID_WMO_Water = 13,
|
|
||||||
LIQUID_WMO_Ocean = 14,
|
|
||||||
LIQUID_Green_Lava = 15,
|
|
||||||
LIQUID_WMO_Magma = 19,
|
|
||||||
LIQUID_WMO_Slime = 20,
|
|
||||||
|
|
||||||
LIQUID_END_BASIC_LIQUIDS = 20,
|
|
||||||
LIQUID_FIRST_NONBASIC_LIQUID_TYPE = 21,
|
|
||||||
|
|
||||||
LIQUID_NAXX_SLIME = 21,
|
|
||||||
};
|
|
||||||
|
|
||||||
liquid_types to_wmo_liquid(int x, bool ocean)
|
liquid_types to_wmo_liquid(int x, bool ocean)
|
||||||
{
|
{
|
||||||
liquid_basic_types const basic(static_cast<liquid_basic_types>(x & liquid_basic_types_MASK));
|
liquid_basic_types const basic(static_cast<liquid_basic_types>(x & liquid_basic_types_MASK));
|
||||||
@@ -117,8 +94,8 @@ wmo_liquid::wmo_liquid(wmo_liquid const& other)
|
|||||||
|
|
||||||
int wmo_liquid::initGeometry(BlizzardArchive::ClientFile* f)
|
int wmo_liquid::initGeometry(BlizzardArchive::ClientFile* f)
|
||||||
{
|
{
|
||||||
LiquidVertex const* map = reinterpret_cast<LiquidVertex const*>(f->getPointer());
|
WmoLiquidVertex const* map = reinterpret_cast<WmoLiquidVertex const*>(f->getPointer());
|
||||||
SMOLTile const* tiles = reinterpret_cast<SMOLTile const*>(f->getPointer() + (xtiles + 1)*(ytiles + 1) * sizeof(LiquidVertex));
|
SMOLTile const* tiles = reinterpret_cast<SMOLTile const*>(f->getPointer() + (xtiles + 1)*(ytiles + 1) * sizeof(WmoLiquidVertex));
|
||||||
int last_liquid_id = 0;
|
int last_liquid_id = 0;
|
||||||
|
|
||||||
// generate vertices
|
// generate vertices
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ struct SMOMVert
|
|||||||
std::int16_t t;
|
std::int16_t t;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LiquidVertex {
|
struct WmoLiquidVertex {
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
SMOWVert water_vertex;
|
SMOWVert water_vertex;
|
||||||
|
|||||||
Reference in New Issue
Block a user