ground effect editor progress

support detail doodads exclusion painting
implement actions
This commit is contained in:
T1ti
2024-07-02 19:25:24 +02:00
parent beff88dc52
commit 887b7282e0
15 changed files with 476 additions and 156 deletions

View File

@@ -74,7 +74,7 @@ void Noggit::Action::undo(bool redo)
auto texture_set = pair.first->getTextureSet();
*texture_set->getAlphamaps() = pair.second.alphamaps;
*texture_set->getTempAlphamaps() = pair.second.tmp_edit_values;
std::memcpy(texture_set->getMCLYEntries(), &pair.second.layers_info, sizeof(ENTRY_MCLY) * 4);
std::memcpy(texture_set->getMCLYEntries(), &pair.second.layers_info, sizeof(layer_info) * 4);
texture_set->setNTextures(pair.second.n_textures);
auto textures = texture_set->getTextures();
@@ -88,6 +88,7 @@ void Noggit::Action::undo(bool redo)
texture_set->markDirty();
texture_set->apply_alpha_changes();
pair.first->registerChunkUpdate(ChunkUpdateFlags::FLAGS); // for texture anim flags
}
}
if (_flags & ActionFlags::eCHUNKS_VERTEX_COLOR)
@@ -200,6 +201,28 @@ void Noggit::Action::undo(bool redo)
pair.first->update_shadows();
}
}
if (_flags & ActionFlags::eCHUNK_DOODADS_EXCLUSION)
{
for (auto& pair : redo ? _chunk_detaildoodad_exclusion_post : _chunk_detaildoodad_exclusion_pre)
{
std::memcpy(&pair.first->texture_set->_doodadStencil, pair.second.data(), 8 * sizeof(std::uint8_t));
pair.first->registerChunkUpdate(ChunkUpdateFlags::DETAILDOODADS_EXCLUSION);
}
}
if (_flags & ActionFlags::eCHUNKS_LAYERINFO)
{
for (auto& pair : redo ? _chunk_layerinfos_post : _chunk_layerinfos_pre)
{
auto texture_set = pair.first->getTextureSet();
std::memcpy(texture_set->getMCLYEntries(), &pair.second, sizeof(layer_info) * 4);
// TODO, enable this if texture flags get moved to this action flag.
// pair.first->registerChunkUpdate(ChunkUpdateFlags::FLAGS); // for texture anim flags.
pair.first->registerChunkUpdate(ChunkUpdateFlags::GROUND_EFFECT);
}
}
}
@@ -386,7 +409,7 @@ void Noggit::Action::finish()
cache.n_textures = texture_set->num();
cache.alphamaps = *texture_set->getAlphamaps();
cache.tmp_edit_values = *texture_set->getTempAlphamaps();
std::memcpy(&cache.layers_info, texture_set->getMCLYEntries(), sizeof(ENTRY_MCLY) * 4);
std::memcpy(&cache.layers_info, texture_set->getMCLYEntries(), sizeof(layer_info) * 4);
for (int j = 0; j < cache.n_textures; ++j)
{
@@ -578,14 +601,16 @@ void Noggit::Action::registerChunkTextureChange(MapChunk* chunk)
cache.n_textures = texture_set->num();
cache.alphamaps = *texture_set->getAlphamaps();
cache.tmp_edit_values = *texture_set->getTempAlphamaps();
std::memcpy(&cache.layers_info, texture_set->getMCLYEntries(), sizeof(ENTRY_MCLY) * 4);
std::memcpy(&cache.layers_info, texture_set->getMCLYEntries(), sizeof(layer_info) * 4);
for (int i = 0; i < cache.n_textures; ++i)
{
cache.textures.push_back(texture_set->filename(i));
}
// _chunk_texture_pre.emplace_back(std::make_pair(chunk, std::move( cache)));
_chunk_texture_pre.emplace_back(std::make_pair(chunk, std::move(cache)));
auto cache_pair = std::make_pair(chunk, std::move(cache));
_chunk_texture_pre.emplace_back(std::move(cache_pair));
}
void Noggit::Action::registerChunkVertexColorChange(MapChunk* chunk)
@@ -742,6 +767,36 @@ void Noggit::Action::registerChunkShadowChange(MapChunk *chunk)
_chunk_shadow_map_pre.emplace_back(std::make_pair(chunk, std::move(data)));
}
void Noggit::Action::registerChunkLayerInfoChange(MapChunk* chunk)
{
_flags |= ActionFlags::eCHUNKS_LAYERINFO;
for (auto& pair : _chunk_layerinfos_pre)
{
if (pair.first == chunk)
return;
}
std::array<layer_info, 4> layer_infos{};
std::memcpy(&layer_infos, chunk->texture_set->getMCLYEntries(), sizeof(layer_info) * 4);
_chunk_layerinfos_pre.emplace_back(chunk, std::move(layer_infos));
}
void Noggit::Action::registerChunkDetailDoodadExclusionChange(MapChunk* chunk)
{
_flags |= ActionFlags::eCHUNK_DOODADS_EXCLUSION;
for (auto& pair : _chunk_detaildoodad_exclusion_pre)
{
if (pair.first == chunk)
return;
}
std::array<std::uint8_t, 8> data{};
std::memcpy(&data, chunk->texture_set->getDoodadStencilBase(), sizeof(std::uint8_t) * 8);
_chunk_detaildoodad_exclusion_pre.emplace_back(std::make_pair(chunk, data));
}
void Noggit::Action::registerAllChunkChanges(MapChunk* chunk)
{
registerChunkTerrainChange(chunk);
@@ -753,6 +808,8 @@ void Noggit::Action::registerAllChunkChanges(MapChunk* chunk)
registerChunkLiquidChange(chunk);
registerVertexSelectionChange();
registerChunkShadowChange(chunk);
registerChunkLayerInfoChange(chunk);
registerChunkDetailDoodadExclusionChange(chunk);
}
Noggit::Action::~Action()

View File

@@ -39,7 +39,9 @@ namespace Noggit
eCHUNKS_FLAGS = 0x200,
eVERTEX_SELECTION = 0x400,
eCHUNK_SHADOWS = 0x800,
eDO_NOT_WRITE_HISTORY= 0x1000
eDO_NOT_WRITE_HISTORY= 0x1000,
eCHUNK_DOODADS_EXCLUSION = 0x2000, // ground effects exclusion mapping
eCHUNKS_LAYERINFO = 0x4000 // ground effect id and texture flags
};
enum ActionModalityControllers
@@ -71,7 +73,7 @@ namespace Noggit
std::vector<std::string> textures;
std::array<std::optional<Alphamap>, 3> alphamaps;
std::optional<tmp_edit_alpha_values> tmp_edit_values;
ENTRY_MCLY layers_info[4];
layer_info layers_info[4];
};
struct ObjectInstanceCache
@@ -135,6 +137,8 @@ namespace Noggit
void registerChunkLiquidChange(MapChunk* chunk);
void registerVertexSelectionChange();
void registerChunkShadowChange(MapChunk* chunk);
void registerChunkLayerInfoChange(MapChunk* chunk);
void registerChunkDetailDoodadExclusionChange(MapChunk* chunk);
void registerAllChunkChanges(MapChunk* chunk);
@@ -161,6 +165,10 @@ namespace Noggit
std::vector<std::pair<MapChunk*, int>> _chunk_holes_post;
std::vector<std::pair<MapChunk*, int>> _chunk_area_id_pre;
std::vector<std::pair<MapChunk*, int>> _chunk_area_id_post;
std::vector<std::pair<MapChunk*, std::array<layer_info, 4>>> _chunk_layerinfos_pre;
std::vector<std::pair<MapChunk*, std::array<layer_info, 4>>> _chunk_layerinfos_post;
std::vector<std::pair<MapChunk*, std::array<std::uint8_t, 8>>> _chunk_detaildoodad_exclusion_pre;
std::vector<std::pair<MapChunk*, std::array<std::uint8_t, 8>>> _chunk_detaildoodad_exclusion_post;
std::vector<std::pair<MapChunk*, mcnk_flags>> _chunk_flags_pre;
std::vector<std::pair<MapChunk*, mcnk_flags>> _chunk_flags_post;
std::vector<std::pair<MapChunk*, std::vector<liquid_layer>>> _chunk_liquid_pre;

View File

@@ -36,7 +36,7 @@ MapChunk::MapChunk(MapTile* maintile, BlizzardArchive::ClientFile* f, bool bigAl
| ChunkUpdateFlags::SHADOW | ChunkUpdateFlags::MCCV
| ChunkUpdateFlags::NORMALS| ChunkUpdateFlags::HOLES
| ChunkUpdateFlags::AREA_ID| ChunkUpdateFlags::FLAGS
| ChunkUpdateFlags::GROUND_EFFECT)
| ChunkUpdateFlags::GROUND_EFFECT | ChunkUpdateFlags::DETAILDOODADS_EXCLUSION)
{
@@ -1352,6 +1352,11 @@ void MapChunk::clear_shadows()
registerChunkUpdate(ChunkUpdateFlags::SHADOW);
}
void MapChunk::paintDetailDoodadsExclusion(glm::vec3 const& pos, float radius, bool exclusion)
{
texture_set->setDetailDoodadsExclusion(xbase, zbase, pos, radius, false, exclusion);
}
bool MapChunk::isHole(int i, int j)
{
return (holes & ((1 << ((j * 4) + i)))) != 0;
@@ -1956,7 +1961,7 @@ void MapChunk::unload()
| ChunkUpdateFlags::SHADOW | ChunkUpdateFlags::MCCV
| ChunkUpdateFlags::NORMALS| ChunkUpdateFlags::HOLES
| ChunkUpdateFlags::AREA_ID| ChunkUpdateFlags::FLAGS
| ChunkUpdateFlags::GROUND_EFFECT;
| ChunkUpdateFlags::GROUND_EFFECT | ChunkUpdateFlags::DETAILDOODADS_EXCLUSION;
}
void MapChunk::setAlphamapImage(const QImage &image, unsigned int layer)

View File

@@ -46,8 +46,9 @@ enum ChunkUpdateFlags
NORMALS = 0x10,
HOLES = 0x20,
AREA_ID = 0x40,
FLAGS = 0x80,
GROUND_EFFECT = 0x100
FLAGS = 0x80, // both chunk and texture layers flags
GROUND_EFFECT = 0x100,
DETAILDOODADS_EXCLUSION = 0x200
};
class MapChunk
@@ -110,7 +111,7 @@ private:
public:
TextureSet* getTextureSet() { return texture_set.get(); };
TextureSet* getTextureSet() const { return texture_set.get(); };
void draw ( math::frustum const& frustum
, OpenGL::Scoped::use_program& mcnk_shader
@@ -173,6 +174,8 @@ public:
void clear_shadows();
void paintDetailDoodadsExclusion(glm::vec3 const& pos, float radius, bool exclusion);
bool isHole(int i, int j);
void setHole(glm::vec3 const& pos, float radius, bool big, bool add);

View File

@@ -62,7 +62,7 @@ MapTile::MapTile( int pX
| ChunkUpdateFlags::SHADOW | ChunkUpdateFlags::MCCV
| ChunkUpdateFlags::NORMALS| ChunkUpdateFlags::HOLES
| ChunkUpdateFlags::AREA_ID| ChunkUpdateFlags::FLAGS
| ChunkUpdateFlags::GROUND_EFFECT)
| ChunkUpdateFlags::GROUND_EFFECT | ChunkUpdateFlags::DETAILDOODADS_EXCLUSION)
, _extents{glm::vec3{pX * TILESIZE, std::numeric_limits<float>::max(), pZ * TILESIZE},
glm::vec3{pX * TILESIZE + TILESIZE, std::numeric_limits<float>::lowest(), pZ * TILESIZE + TILESIZE}}
, _combined_extents{glm::vec3{pX * TILESIZE, std::numeric_limits<float>::max(), pZ * TILESIZE},

View File

@@ -49,6 +49,7 @@
#include <limits>
#include <variant>
#include <noggit/Selection.h>
#include <noggit/ui/FontAwesome.hpp>
#ifdef USE_MYSQL_UID_STORAGE
#include <mysql/mysql.h>
@@ -106,7 +107,7 @@ NOGGIT_ACTION_MGR->purge();
ACTION_CODE \
} \
// add action no shortcut
#define ADD_ACTION_NS(menu, name, on_action) \
{ \
auto action (menu->addAction (name)); \
@@ -258,7 +259,12 @@ void MapView::set_editing_mode(editing_mode mode)
_world->renderer()->getTerrainParamsUniformBlock()->draw_noeffectdoodad_overlay = false;
_minimap->use_selection(nullptr);
bool use_classic_ui = _settings->value("classicUI", true).toBool();
bool use_classic_ui = _settings->value("classicUI", false).toBool();
if (mode != editing_mode::paint)
{
getGroundEffectsTool()->hide();
}
switch (mode)
{
@@ -276,12 +282,8 @@ void MapView::set_editing_mode(editing_mode mode)
else if (texturingTool->getTexturingMode() == Noggit::Ui::texturing_mode::ground_effect)
{
getGroundEffectsTool()->updateTerrainUniformParams();
// _world->renderer()->getTerrainParamsUniformBlock()->draw_groundeffectid_overlay = getGroundEffectsTool()->show_active_sets_overlay();
// _world->renderer()->getTerrainParamsUniformBlock()->draw_groundeffect_layerid_overlay = getGroundEffectsTool()->show_placement_map_overlay();
// _world->renderer()->getTerrainParamsUniformBlock()->draw_noeffectdoodad_overlay = getGroundEffectsTool()->show_exclusion_map_overlay();
}
if (use_classic_ui)
{
if (texturingTool->show_unpaintable_chunks())
@@ -2854,6 +2856,75 @@ void MapView::createGUI()
setupHelpMenu();
setupHotkeys();
// temp test, move to a function later
auto separator(_main_window->_menuBar->addSeparator());
#if defined(_WIN32) || defined(WIN32)
QAction* start_wow_action(_main_window->_menuBar->addAction("Launch WoW"));
start_wow_action->setIconVisibleInMenu(true);
start_wow_action->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::playcircle));
start_wow_action->setIconText("test icon text");
connect(start_wow_action, &QAction::triggered,
[&]
{
std::filesystem::path WoW_path = std::filesystem::path(Noggit::Project::CurrentProject::get()->ClientPath) / "Wow.exe";
QString program_path = WoW_path.string().c_str();
QFileInfo checkFile(program_path);
QStringList arguments;
// arguments << "-console"; // deosn't seem to work
if (checkFile.exists() && checkFile.isFile())
{
QProcess* process = new QProcess(); // this parent?
process->start(program_path, arguments);
if (!process->waitForStarted()) {
qWarning("Failed to start process");
QMessageBox::information(this, "Error", "Failed to start process");
}
}
else
{
// Handle file not existing
qWarning("File does not exist");
QMessageBox::critical(this, "Error", "The specified file does not exist");
}
// ShellExecute(nullptr
// , "open"
// , WoW_path.string().c_str()
// , nullptr
// , nullptr
// , SW_SHOWNORMAL
// );
});
QAction* build_data_action(_main_window->_menuBar->addAction("Build Game Data"));
build_data_action->setToolTip("Save content of project folder as MPQ patch in the client.");
build_data_action->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::filearchive));
QAction* start_server_action(_main_window->_menuBar->addAction("Start Server"));
start_server_action->setToolTip("Start World and Auth servers.");
start_server_action->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::server));
QAction* extract_server_map_action(_main_window->_menuBar->addAction("Extract Server Map"));
extract_server_map_action->setToolTip("Start server extractors for this map.");
// TODO idea : detect modified tiles and only extract those.
extract_server_map_action->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::map));
// TODO : restart button while WoW is running?
#endif
// IDEAs : various client utils like synchronize client view with noggit, reload, patch WoW.exe with community patches like unlock md5 check, set WoW client version
/////////////////////////////////////////////////////////////////
connect(_main_window, &Noggit::Ui::Windows::NoggitWindow::exitPromptOpened, this, &MapView::on_exit_prompt);
set_editing_mode (editing_mode::ground);
@@ -3598,7 +3669,10 @@ MapView::~MapView()
{
delete TexturePicker; // explicitly delete this here to avoid opengl context related crash
delete objectEditor;
delete texturingTool;
// since the ground effect tool preview renderer got added, this causes crashing on exit to menu.
// Now it crashes in application exit.
// delete texturingTool;
}
if (_force_uid_check)
@@ -4033,54 +4107,86 @@ void MapView::tick (float dt)
}
break;
case editing_mode::paint:
if (_mod_shift_down && _mod_ctrl_down && _mod_alt_down)
{
// clear chunk texture
if (!underMap)
if (texturingTool->getTexturingMode() == Noggit::Ui::texturing_mode::ground_effect)
{
NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_TEXTURE,
Noggit::ActionModalityControllers::eSHIFT
| Noggit::ActionModalityControllers::eCTRL
| Noggit::ActionModalityControllers::eALT
| Noggit::ActionModalityControllers::eLMB);
if (_mod_shift_down)
{
if (texturingTool->getGroundEffectsTool()->brush_mode() == Noggit::Ui::ground_effect_brush_mode::exclusion)
{
NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNK_DOODADS_EXCLUSION,
Noggit::ActionModalityControllers::eSHIFT
| Noggit::ActionModalityControllers::eLMB);
_world->paintGroundEffectExclusion(_cursor_pos, texturingTool->getGroundEffectsTool()->radius(), true);
// _world->setHole(_cursor_pos, holeTool->brushRadius(), _mod_alt_down, false);
}
else if (texturingTool->getGroundEffectsTool()->brush_mode() == Noggit::Ui::ground_effect_brush_mode::effect)
{
_world->eraseTextures(_cursor_pos);
}
}
else if (_mod_ctrl_down && !underMap)
{
NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNK_DOODADS_EXCLUSION,
Noggit::ActionModalityControllers::eCTRL
| Noggit::ActionModalityControllers::eLMB);
_world->paintGroundEffectExclusion(_cursor_pos, texturingTool->getGroundEffectsTool()->radius(), false);
}
}
}
else if (_mod_ctrl_down && !ui_hidden)
{
_texture_picker_need_update = true;
// Pick texture
// _texture_picker_dock->setVisible(true);
// TexturePicker->setMainTexture(texturingTool->_current_texture);
// TexturePicker->getTextures(selection);
}
else if (_mod_shift_down && !!Noggit::Ui::selected_texture::get())
{
if ((_display_mode == display_mode::in_3D && !underMap) || _display_mode == display_mode::in_2D)
else
{
auto image_mask_selector = texturingTool->getImageMaskSelector();
if (_mod_shift_down && _mod_ctrl_down && _mod_alt_down)
{
// clear chunk texture
if (!underMap)
{
NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_TEXTURE,
Noggit::ActionModalityControllers::eSHIFT
| Noggit::ActionModalityControllers::eCTRL
| Noggit::ActionModalityControllers::eALT
| Noggit::ActionModalityControllers::eLMB);
if (NOGGIT_CUR_ACTION
&& texturingTool->getTexturingMode() == Noggit::Ui::texturing_mode::paint
&& image_mask_selector->isEnabled()
&& !image_mask_selector->getBrushMode())
break;
_world->eraseTextures(_cursor_pos);
}
}
else if (_mod_ctrl_down && !ui_hidden)
{
_texture_picker_need_update = true;
// Pick texture
// _texture_picker_dock->setVisible(true);
// TexturePicker->setMainTexture(texturingTool->_current_texture);
// TexturePicker->getTextures(selection);
}
else if (_mod_shift_down && !!Noggit::Ui::selected_texture::get())
{
if ((_display_mode == display_mode::in_3D && !underMap) || _display_mode == display_mode::in_2D)
{
auto image_mask_selector = texturingTool->getImageMaskSelector();
auto action = NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_TEXTURE,
Noggit::ActionModalityControllers::eSHIFT
| Noggit::ActionModalityControllers::eLMB);
if (NOGGIT_CUR_ACTION
&& texturingTool->getTexturingMode() == Noggit::Ui::texturing_mode::paint
&& image_mask_selector->isEnabled()
&& !image_mask_selector->getBrushMode())
break;
action->setPostCallback(&MapView::randomizeTexturingRotation);
auto action = NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_TEXTURE,
Noggit::ActionModalityControllers::eSHIFT
| Noggit::ActionModalityControllers::eLMB);
if (texturingTool->getTexturingMode() == Noggit::Ui::texturing_mode::paint
&& image_mask_selector->isEnabled()
&& !image_mask_selector->getBrushMode())
action->setBlockCursor(true);
action->setPostCallback(&MapView::randomizeTexturingRotation);
texturingTool->paint(_world.get(), _cursor_pos, dt, *Noggit::Ui::selected_texture::get());
if (texturingTool->getTexturingMode() == Noggit::Ui::texturing_mode::paint
&& image_mask_selector->isEnabled()
&& !image_mask_selector->getBrushMode())
action->setBlockCursor(true);
texturingTool->paint(_world.get(), _cursor_pos, dt, *Noggit::Ui::selected_texture::get());
}
}
}
}
break;
case editing_mode::holes:
@@ -4804,7 +4910,7 @@ void MapView::draw_map()
_minimap->update();
}
bool classic_ui = _settings->value("classicUI", true).toBool();
bool classic_ui = _settings->value("classicUI", false).toBool();
bool show_unpaintable = classic_ui ? texturingTool->show_unpaintable_chunks() : _left_sec_toolbar->showUnpaintableChunk();
_world->renderer()->draw (
model_view()
@@ -5880,7 +5986,7 @@ void MapView::onSettingsSave()
void MapView::ShowContextMenu(QPoint pos)
{
// QApplication::startDragDistance() is 10
auto mouse_moved = QApplication::startDragDistance() < (_right_click_pos - pos).manhattanLength();;
auto mouse_moved = QApplication::startDragDistance() / 3 < (_right_click_pos - pos).manhattanLength();
// don't show context menu if dragging mouse
if (mouse_moved || ImGuizmo::IsUsing())

View File

@@ -1677,6 +1677,23 @@ void World::overwriteTextureAtCurrentChunk(glm::vec3 const& pos, scoped_blp_text
});
}
void World::paintGroundEffectExclusion(glm::vec3 const& pos, float radius, bool exclusion)
{
ZoneScoped;
for_all_chunks_in_range
(pos, radius
, [&](MapChunk* chunk)
{
// TODO action
NOGGIT_CUR_ACTION->registerChunkDetailDoodadExclusionChange(chunk);
// chunk->setHole(pos, radius, exclusion);
chunk->paintDetailDoodadsExclusion(pos, radius, exclusion);
return true;
}
);
}
void World::setHole(glm::vec3 const& pos, float radius, bool big, bool hole)
{
ZoneScoped;

View File

@@ -241,6 +241,7 @@ public:
void eraseTextures(glm::vec3 const& pos);
void overwriteTextureAtCurrentChunk(glm::vec3 const& pos, scoped_blp_texture_reference const& oldTexture, scoped_blp_texture_reference newTexture);
void paintGroundEffectExclusion(glm::vec3 const& pos, float radius, bool exclusion);
void setBaseTexture(glm::vec3 const& pos);
void clear_shadows(glm::vec3 const& pos);
void clearTextures(glm::vec3 const& pos);

View File

@@ -51,7 +51,7 @@ void TileRender::unload()
| ChunkUpdateFlags::SHADOW | ChunkUpdateFlags::MCCV
| ChunkUpdateFlags::NORMALS| ChunkUpdateFlags::HOLES
| ChunkUpdateFlags::AREA_ID| ChunkUpdateFlags::FLAGS
| ChunkUpdateFlags::GROUND_EFFECT;
| ChunkUpdateFlags::GROUND_EFFECT | ChunkUpdateFlags::DETAILDOODADS_EXCLUSION;
}
@@ -218,7 +218,15 @@ void TileRender::draw (OpenGL::Scoped::use_program& mcnk_shader
if (flags & ChunkUpdateFlags::GROUND_EFFECT)
{
setChunkGroundEffectData(chunk.get());
// TODO.
// currently directly handled in functions
// setChunkGroundEffectColor()
// setChunkGroundEffectActiveData()
}
if (flags & ChunkUpdateFlags::DETAILDOODADS_EXCLUSION)
{
setChunkDetaildoodadsExclusionData(chunk.get());
}
@@ -572,14 +580,14 @@ void TileRender::initChunkData(MapChunk* chunk)
chunk_render_instance.ChunkGroundEffectColor[2] = 0.0f;
chunk_render_instance.ChunkGroundEffectColor[3] = 0.0f;
// setChunkGroundEffectData(chunk);
// setChunkDetaildoodadsExclusionData(chunk);
chunk_render_instance.ChunkDoodadsEnabled2_ChunksLayerEnabled2[0] = 0;
chunk_render_instance.ChunkDoodadsEnabled2_ChunksLayerEnabled2[1] = 0;
chunk_render_instance.ChunkDoodadsEnabled2_ChunksLayerEnabled2[2] = 0;
chunk_render_instance.ChunkDoodadsEnabled2_ChunksLayerEnabled2[3] = 0;
}
void TileRender::setChunkGroundEffectData(MapChunk* chunk)
void TileRender::setChunkDetaildoodadsExclusionData(MapChunk* chunk)
{
auto doodadExclusionMap = chunk->texture_set->getDoodadStencilBase();

View File

@@ -43,7 +43,7 @@ namespace Noggit::Rendering
void initChunkData(MapChunk* chunk);
void setChunkGroundEffectData(MapChunk* chunk);
void setChunkDetaildoodadsExclusionData(MapChunk* chunk);
void setChunkGroundEffectActiveData(MapChunk* chunk, std::string active_texture);
[[nodiscard]]

View File

@@ -423,6 +423,36 @@ bool const TextureSet::getDoodadDisabledAt(int x, int y)
return is_enabled;
}
void TextureSet::setDetailDoodadsExclusion(float xbase, float zbase, glm::vec3 const& pos, float radius, bool big, bool add)
{
// big = fill chunk
if (big)
{
std::fill(_doodadStencil.begin(), _doodadStencil.end(), add ? 0xFF : 0x0);
}
else
{
for (int x = 0; x < 8; ++x)
{
for (int y = 0; y < 8; ++y)
{
if (misc::getShortestDist(pos.x, pos.z, xbase + (UNITSIZE * x),
zbase + (UNITSIZE * y), UNITSIZE) <= radius)
{
int v = (1 << (x));
if (add)
_doodadStencil[y] |= v;
else
_doodadStencil[y] &= ~v;
}
}
}
}
_chunk->registerChunkUpdate(ChunkUpdateFlags::DETAILDOODADS_EXCLUSION);
}
bool TextureSet::stampTexture(float xbase, float zbase, float x, float z, Brush* brush, float strength, float pressure, scoped_blp_texture_reference texture, QImage* image, bool paint)
{

View File

@@ -103,12 +103,19 @@ public:
std::optional<tmp_edit_alpha_values>* getTempAlphamaps() { return &tmp_edit_values; };
int get_texture_index_or_add (scoped_blp_texture_reference texture, float target);
auto getDoodadMappingBase(void) -> std::uint16_t* { return _doodadMapping.data(); }
std::array<std::uint16_t, 8> const& getDoodadMapping() { return _doodadMapping; }
std::array<std::array<std::uint8_t, 8>, 8> const getDoodadMappingReadable(); // get array of readable values
auto getDoodadStencilBase(void) -> std::uint8_t* { return _doodadStencil.data(); }
uint8_t const getDoodadActiveLayerIdAt(unsigned int x, unsigned int y); // max is 8
// TODO x and Y are swapped
std::array<std::uint8_t, 8> _doodadStencil; // doodads disabled if 1; WoD: may be an explicit MCDD chunk
// this is actually uint1_t[8][8] (8*8 -> 1 bit each)
auto getDoodadStencilBase(void) -> std::uint8_t* { return _doodadStencil.data(); }
bool const getDoodadDisabledAt(int x, int y); // max is 8
void setDetailDoodadsExclusion(float xbase, float zbase, glm::vec3 const& pos, float radius, bool big, bool add);
auto getEffectForLayer(std::size_t idx) const -> unsigned { return _layers_info[idx].effectID; }
layer_info* getMCLYEntries() { return &_layers_info[0]; };
void setNTextures(size_t n) { nTextures = n; };
@@ -138,9 +145,7 @@ private:
// this is actually uint2_t[8][8] (8*8 -> 2 bit each)
// getting the layer id from the two bits : MCLY textureLayer entry ID (can be only one of: 00 | 01 | 10 | 11)
// bool[8][8]
// TODO x and Y are swapped
std::array<std::uint8_t, 8> _doodadStencil; // doodads disabled if 1; WoD: may be an explicit MCDD chunk
// this is actually uint1_t[8][8] (8*8 -> 1 bit each)
bool _need_lod_texture_map_update = false;
// ENTRY_MCLY _layers_info[4]; // TODO rework this, don't need to store textureid and offset

View File

@@ -112,8 +112,13 @@ namespace Noggit
_brush_level_spin->setSingleStep(5);
slider_layout_right->addWidget(_brush_level_spin);
QSettings settings;
bool use_classic_ui = settings.value("classicUI", false).toBool();
_show_unpaintable_chunks_cb = new QCheckBox("Show unpaintable chunks", tool_widget);
_show_unpaintable_chunks_cb->setChecked(false);
if (!use_classic_ui)
_show_unpaintable_chunks_cb->hide();
tool_layout->addWidget(_show_unpaintable_chunks_cb);
connect(_show_unpaintable_chunks_cb, &QCheckBox::toggled, [=](bool checked)
@@ -326,7 +331,6 @@ namespace Noggit
connect(geffect_tools_btn, &QPushButton::clicked
, [=]()
{
_texturing_mode = texturing_mode::ground_effect;
_ground_effect_tool->show();
}
);
@@ -362,6 +366,12 @@ namespace Noggit
setMaximumWidth(250);
}
texturing_tool::~texturing_tool()
{
// _ground_effect_tool->delete_renderer();
// delete _ground_effect_tool;
}
void texturing_tool::updateMaskImage()
{
QPixmap* pixmap = _image_mask_group->getPixmap();
@@ -415,6 +425,7 @@ namespace Noggit
{
_radius_slider->setValue(radius);
_texture_switcher->change_radius(radius - _texture_switcher->radius());
_ground_effect_tool->change_radius(radius);
}
void texturing_tool::setHardness(float hardness)
@@ -432,6 +443,10 @@ namespace Noggit
{
_texture_switcher->change_radius(change);
}
else if (_texturing_mode == texturing_mode::ground_effect)
{
_ground_effect_tool->change_radius(change);
}
}
void texturing_tool::change_hardness(float change)
@@ -500,17 +515,18 @@ namespace Noggit
float texturing_tool::brush_radius() const
{
// show only a dot when using the anim / swap mode
switch (_texturing_mode)
switch (getTexturingMode())
{
case texturing_mode::paint: return static_cast<float>(_radius_slider->value());
case texturing_mode::swap: return (_texture_switcher->brush_mode() ? _texture_switcher->radius() : 0.f);
case texturing_mode::ground_effect: return (_ground_effect_tool->brush_mode() != ground_effect_brush_mode::none ? _ground_effect_tool->radius() : 0.f);
default: return 0.f;
}
}
float texturing_tool::hardness() const
{
switch (_texturing_mode)
switch (getTexturingMode())
{
case texturing_mode::paint: return static_cast<float>(_hardness_slider->value());
default: return 0.f;
@@ -519,7 +535,7 @@ namespace Noggit
bool texturing_tool::show_unpaintable_chunks() const
{
return _show_unpaintable_chunks && _texturing_mode == texturing_mode::paint;
return _show_unpaintable_chunks && getTexturingMode() == texturing_mode::paint;
}
void texturing_tool::paint (World* world, glm::vec3 const& pos, float dt, scoped_blp_texture_reference texture)
@@ -530,59 +546,80 @@ namespace Noggit
update_brush_hardness();
}
float strength = 1.0f - pow(1.0f - _pressure_slider->value(), dt * 10.0f);
if (_texturing_mode == texturing_mode::swap)
switch(getTexturingMode())
{
auto to_swap (_texture_switcher->texture_to_swap());
if (to_swap)
{
if (_texture_switcher->brush_mode())
case (texturing_mode::swap):
{
std::cout << _texture_switcher->radius() << std::endl;
world->replaceTexture(pos, _texture_switcher->radius(), to_swap.value(), texture, _texture_switcher->entireChunk(), _texture_switcher->entireTile());
auto to_swap(_texture_switcher->texture_to_swap());
if (to_swap)
{
if (_texture_switcher->brush_mode())
{
std::cout << _texture_switcher->radius() << std::endl;
world->replaceTexture(pos, _texture_switcher->radius(), to_swap.value(), texture, _texture_switcher->entireChunk(), _texture_switcher->entireTile());
}
else
{
world->overwriteTextureAtCurrentChunk(pos, to_swap.value(), texture);
}
}
break;
}
else
case (texturing_mode::paint):
{
world->overwriteTextureAtCurrentChunk(pos, to_swap.value(), texture);
}
}
}
else if (_texturing_mode == texturing_mode::paint)
{
if (_spray_mode_group->isChecked())
{
world->sprayTexture(pos, &_spray_brush, alpha_target(), strength, static_cast<float>(_radius_slider->value()), _spray_pressure, texture);
float strength = 1.0f - pow(1.0f - _pressure_slider->value(), dt * 10.0f);
if (_spray_mode_group->isChecked())
{
world->sprayTexture(pos, &_spray_brush, alpha_target(), strength, static_cast<float>(_radius_slider->value()), _spray_pressure, texture);
if (_inner_radius_cb->isChecked())
{
if (!_image_mask_group->isEnabled())
{
world->paintTexture(pos, &_inner_brush, alpha_target(), strength, texture);
}
else
{
world->stampTexture(pos, &_inner_brush, alpha_target(), strength, texture, &_mask_image, _image_mask_group->getBrushMode());
}
if (_inner_radius_cb->isChecked())
{
if (!_image_mask_group->isEnabled())
{
world->paintTexture(pos, &_inner_brush, alpha_target(), strength, texture);
}
else
{
world->stampTexture(pos, &_inner_brush, alpha_target(), strength, texture, &_mask_image, _image_mask_group->getBrushMode());
}
}
}
else
{
if (!_image_mask_group->isEnabled())
{
world->paintTexture(pos, &_texture_brush, alpha_target(), strength, texture);
}
else
{
world->stampTexture(pos, &_texture_brush, alpha_target(), strength, texture, &_mask_image, _image_mask_group->getBrushMode());
}
}
break;
}
}
else
case (texturing_mode::anim):
{
change_tex_flag(world, pos, _anim_prop.get(), texture);
break;
}
case (texturing_mode::ground_effect):
{
// handled directly in MapView::tick()
// if (_ground_effect_tool->brush_mode() == ground_effect_brush_mode::exclusion)
// {
// world->paintGroundEffectExclusion(pos, _ground_effect_tool->radius(), );
// }
// else if (_ground_effect_tool->brush_mode() == ground_effect_brush_mode::effect)
// {
//
// }
}
default:
{
if (!_image_mask_group->isEnabled())
{
world->paintTexture(pos, &_texture_brush, alpha_target(), strength, texture);
}
else
{
world->stampTexture(pos, &_texture_brush, alpha_target(), strength, texture, &_mask_image, _image_mask_group->getBrushMode());
}
}
}
else if (_texturing_mode == texturing_mode::anim)
{
change_tex_flag(world, pos, _anim_prop.get(), texture);
}
}
void texturing_tool::change_tex_flag(World* world, glm::vec3 const& pos, bool add, scoped_blp_texture_reference texture)
@@ -721,7 +758,7 @@ namespace Noggit
_render_group_box->setChecked(true);
left_side_layout->addWidget(_render_group_box);
auto render_layout(new QHBoxLayout(_render_group_box));
auto render_layout(new QGridLayout(_render_group_box));
_render_group_box->setLayout(render_layout);
_render_type_group = new QButtonGroup(_render_group_box);
@@ -729,17 +766,17 @@ namespace Noggit
_render_active_sets = new QRadioButton("Effect Id/Set", this);
_render_active_sets->setToolTip("Render all the loaded effect sets for this texture in matching colors");
_render_type_group->addButton(_render_active_sets);
render_layout->addWidget(_render_active_sets);
render_layout->addWidget(_render_active_sets, 0, 0);
_render_exclusion_map = new QRadioButton("Doodads Disabled", this);
_render_exclusion_map->setToolTip("Render chunk units where effect doodads are disabled as white, rest as black");
_render_type_group->addButton(_render_exclusion_map);
render_layout->addWidget(_render_exclusion_map);
render_layout->addWidget(_render_exclusion_map, 0, 1);
_render_placement_map = new QRadioButton("Selected Texture state", this); // if chunk contains texture/Effect : render as green or red if the effect layer is active or not
_render_placement_map->setToolTip("Render chunk unit as red if texture is present in the chunk and NOT the current active layer, render as green if it's active. \nThis defines which of the 4 textures' set is currently active, this is determined by which has the highest opacity.");
_render_type_group->addButton(_render_placement_map);
render_layout->addWidget(_render_placement_map);
render_layout->addWidget(_render_placement_map, 1, 0);
_render_active_sets->setChecked(true);
// _render_type_group->setAutoExclusive(true);
@@ -945,21 +982,30 @@ namespace Noggit
_brush_grup_box->setChecked(false);
left_side_layout->addWidget(_brush_grup_box);
QHBoxLayout* brush_layout = new QHBoxLayout(_brush_grup_box);
QVBoxLayout* brush_layout = new QVBoxLayout(_brush_grup_box);
_brush_grup_box->setLayout(brush_layout);
QHBoxLayout* brush_buttons_layout = new QHBoxLayout(_brush_grup_box);
brush_layout->addLayout(brush_buttons_layout);
_brush_type_group = new QButtonGroup(_brush_grup_box);
_paint_effect = new QRadioButton("Paint Effect", this);
_brush_type_group->addButton(_paint_effect);
brush_layout->addWidget(_paint_effect);
brush_buttons_layout->addWidget(_paint_effect);
_paint_exclusion = new QRadioButton("Paint Exclusion", this);
_brush_type_group->addButton(_paint_exclusion);
brush_layout->addWidget(_paint_exclusion);
brush_buttons_layout->addWidget(_paint_exclusion);
_paint_effect->setChecked(true);
_paint_effect->setAutoExclusive(true);
brush_layout->addWidget(new QLabel("Radius:", _brush_grup_box));
_effect_radius_slider = new Noggit::Ui::Tools::UiCommon::ExtendedSlider(_brush_grup_box);
_effect_radius_slider->setPrefix("");
_effect_radius_slider->setRange(0, 1000);
_effect_radius_slider->setDecimals(2);
_effect_radius_slider->setValue(_texturing_tool->texture_brush().getRadius());
brush_layout->addWidget(_effect_radius_slider);
}
left_side_layout->addSpacerItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding));
// adjustSize();
@@ -1081,20 +1127,19 @@ namespace Noggit
void ground_effect_tool::updateTerrainUniformParams()
{
if (_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_groundeffectid_overlay != show_active_sets_overlay())
if (_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_groundeffectid_overlay != render_active_sets_overlay())
{
_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_groundeffectid_overlay = show_active_sets_overlay();
_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_groundeffectid_overlay = render_active_sets_overlay();
_map_view->getWorld()->renderer()->markTerrainParamsUniformBlockDirty();
}
if (_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_groundeffect_layerid_overlay != show_placement_map_overlay())
if (_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_groundeffect_layerid_overlay != render_placement_map_overlay())
{
_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_groundeffect_layerid_overlay = show_placement_map_overlay();
_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_groundeffect_layerid_overlay = render_placement_map_overlay();
_map_view->getWorld()->renderer()->markTerrainParamsUniformBlockDirty();
}
if (_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_noeffectdoodad_overlay != show_exclusion_map_overlay())
if (_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_noeffectdoodad_overlay != render_exclusion_map_overlay())
{
_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_noeffectdoodad_overlay = show_exclusion_map_overlay();
_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_noeffectdoodad_overlay = render_exclusion_map_overlay();
_map_view->getWorld()->renderer()->markTerrainParamsUniformBlockDirty();
}
}
@@ -1396,6 +1441,20 @@ namespace Noggit
// _preview_renderer->deleteLater();
}
ground_effect_brush_mode ground_effect_tool::brush_mode() const
{
if (!_brush_grup_box->isChecked())
{
return ground_effect_brush_mode::none;
}
else if (_paint_effect->isChecked())
return ground_effect_brush_mode::effect;
else if (_paint_exclusion->isChecked())
return ground_effect_brush_mode::exclusion;
return ground_effect_brush_mode::none;
}
std::optional<ground_effect_set> ground_effect_tool::getSelectedGroundEffect()
{
//_effect_sets_list->currentItem

View File

@@ -87,6 +87,12 @@ namespace Noggit
unsigned int TerrainType = 0;
};
enum class ground_effect_brush_mode
{
none,
exclusion,
effect
};
class ground_effect_tool : public QWidget
{
@@ -99,37 +105,50 @@ namespace Noggit
~ground_effect_tool(); // delete renderer
float radius() const{ return _effect_radius_slider->value();}
ground_effect_brush_mode brush_mode() const; // { return _brush_grup_box->isChecked(); }
bool render_mode() const { return _render_group_box->isChecked(); }
void delete_renderer() { delete _preview_renderer; } // test to fix opengl crashes on exit
protected:
void showEvent(QShowEvent* event) {
void showEvent(QShowEvent* event) override {
QWidget::showEvent(event);
updateTerrainUniformParams();
}
void hideEvent(QHideEvent* event) {
void hideEvent(QHideEvent* event) override {
_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_groundeffectid_overlay = false;
_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_groundeffect_layerid_overlay = false;
_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_noeffectdoodad_overlay = false;
_map_view->getWorld()->renderer()->markTerrainParamsUniformBlockDirty();
QWidget::hideEvent(event);
// event->accept();
};
void closeEvent(QCloseEvent* event) override {
_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_groundeffectid_overlay = false;
_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_groundeffect_layerid_overlay = false;
_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_noeffectdoodad_overlay = false;
QWidget::closeEvent(event);
// event->accept();
};
// close event triggers hide event.
public:
void setDoodadSlotFromBrowser(QString doodad_path);
void TextureChanged(); // textureChanged
void TextureChanged(); // selected texture was changed
bool show_active_sets_overlay() const { return _render_active_sets->isChecked() && _render_group_box->isChecked(); };
bool show_placement_map_overlay() const { return _render_placement_map->isChecked() && _render_group_box->isChecked(); };
bool show_exclusion_map_overlay() const { return _render_exclusion_map->isChecked() && _render_group_box->isChecked(); };
private:
inline bool render_active_sets_overlay() const
{
return isVisible() && _render_active_sets->isChecked() && render_mode(); // _texturing_tool->getTexturingMode() == texturing_mode::ground_effect
};
inline bool render_placement_map_overlay() const
{
return isVisible() && _render_placement_map->isChecked() && render_mode();
};
inline bool render_exclusion_map_overlay() const
{
return isVisible() && _render_exclusion_map->isChecked() && render_mode();
};
void change_radius(float change) { _effect_radius_slider->setValue(static_cast<float>(_effect_radius_slider->value()) + change); };
private:
std::optional<ground_effect_set> getSelectedGroundEffect();
std::optional<glm::vec3> getSelectedEffectColor();
@@ -158,21 +177,17 @@ namespace Noggit
QGroupBox* _render_group_box;
QButtonGroup* _render_type_group;
// render all the loaded effect sets for this texture in various colors
QRadioButton* _render_active_sets;
// only for the active/selected set of the current texture :
// - render as red if set is present in the chunk and NOT the current active layer
// - render as green if set is present in the chunk and is the current active layer
// - render as black is set is not present
QRadioButton* _render_placement_map;
// render chunk units where effect doodads are disabled as white, rest as black
QRadioButton* _render_exclusion_map;
QCheckBox* _chkbox_merge_duplicates;
// QComboBox* _cbbox_effect_sets;
QListWidget* _effect_sets_list;
@@ -180,7 +195,6 @@ namespace Noggit
QListWidget* _object_list; // for render previews
QListWidget* _weight_list; // weight and percentage customization
// QPushButton* _button_effect_doodad[4];
QSpinBox* _spinbox_doodads_amount;
QComboBox* _cbbox_terrain_type;
@@ -190,10 +204,17 @@ namespace Noggit
QButtonGroup* _brush_type_group;
QRadioButton* _paint_effect;
QRadioButton* _paint_exclusion;
Noggit::Ui::Tools::UiCommon::ExtendedSlider* _effect_radius_slider;
};
/// <summary>
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
/// </summary>
///
///
///
///
class texturing_tool : public QWidget
{
public:
@@ -203,7 +224,7 @@ namespace Noggit
, QWidget* parent = nullptr
);
// ~texturing_tool() { _ground_effect_tool->deleteLater(); }; // { delete _ground_effect_tool; };
~texturing_tool(); // { _ground_effect_tool->deleteLater(); }; // { delete _ground_effect_tool; };
float brush_radius() const;
float hardness() const;
@@ -251,7 +272,7 @@ namespace Noggit
Noggit::Ui::Tools::ImageMaskSelector* getImageMaskSelector() { return _image_mask_group; };
QImage* getMaskImage() { return &_mask_image; }
texturing_mode getTexturingMode()
inline texturing_mode getTexturingMode() const
{
if (_ground_effect_tool->isVisible())
return texturing_mode::ground_effect;
@@ -286,7 +307,7 @@ namespace Noggit
unsigned_int_property _anim_rotation_prop;
BoolToggleProperty _overbright_prop;
texturing_mode _texturing_mode;
texturing_mode _texturing_mode; // use getTexturingMode() to check for ground effect mode
private:
QSlider* _brush_level_slider;

View File

@@ -167,7 +167,7 @@ void ChunkClipboard::copySelected(glm::vec3 const& pos, ChunkCopyFlags flags)
cache.n_textures = texture_set->num();
cache.alphamaps = *texture_set->getAlphamaps();
cache.tmp_edit_values = *texture_set->getTempAlphamaps();
std::memcpy(&cache.layers_info, texture_set->getMCLYEntries(), sizeof(ENTRY_MCLY) * 4);
std::memcpy(&cache.layers_info, texture_set->getMCLYEntries(), sizeof(layer_info) * 4);
for (int i = 0; i < cache.n_textures; ++i)
{