wip
This commit is contained in:
@@ -11,7 +11,9 @@ namespace Noggit
|
||||
OBJECT_PALETTE_PREVIEW,
|
||||
PRESET_EDITOR,
|
||||
PRESET_EDITOR_PREVIEW,
|
||||
BLP_RENDERER
|
||||
GROUND_EFFECT_PREVIEW,
|
||||
BLP_RENDERER,
|
||||
count
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ LightIntBandDB gLightIntBandDB;
|
||||
LightFloatBandDB gLightFloatBandDB;
|
||||
GroundEffectDoodadDB gGroundEffectDoodadDB;
|
||||
GroundEffectTextureDB gGroundEffectTextureDB;
|
||||
TerrainTypeDB gTerrainTypeDB;
|
||||
LiquidTypeDB gLiquidTypeDB;
|
||||
SoundProviderPreferencesDB gSoundProviderPreferencesDB;
|
||||
SoundAmbienceDB gSoundAmbienceDB;
|
||||
@@ -36,6 +37,7 @@ void OpenDBs(std::shared_ptr<BlizzardArchive::ClientData> clientData)
|
||||
gLightFloatBandDB.open(clientData);
|
||||
gGroundEffectDoodadDB.open(clientData);
|
||||
gGroundEffectTextureDB.open(clientData);
|
||||
gTerrainTypeDB.open(clientData);
|
||||
gLiquidTypeDB.open(clientData);
|
||||
gSoundProviderPreferencesDB.open(clientData);
|
||||
gSoundAmbienceDB.open(clientData);
|
||||
|
||||
@@ -175,6 +175,27 @@ public:
|
||||
static const size_t Flags = 2; // uint
|
||||
};
|
||||
|
||||
class TerrainTypeDB : public DBCFile
|
||||
{
|
||||
public:
|
||||
TerrainTypeDB() :
|
||||
DBCFile("DBFilesClient\\TerrainType.dbc")
|
||||
{ }
|
||||
|
||||
/// Fields
|
||||
// WDBX generates a fake id column. Real id start at 0.
|
||||
static const size_t TerrainId = 0; // uint // this is the real id referenced by groundeffecttexture
|
||||
static const size_t TerrainDesc = 1; // string
|
||||
static const size_t FootstepSprayRun = 2; // uint
|
||||
static const size_t FootstepSprayWalk = 3; // uint
|
||||
static const size_t Sound = 4; // uint
|
||||
static const size_t Flags = 5; // uint
|
||||
};
|
||||
|
||||
// TODO for terrain type editing:
|
||||
// TerrainTypeSounds, FootstepTerrainLookup, FootprintTextures
|
||||
|
||||
|
||||
class LiquidTypeDB : public DBCFile
|
||||
{
|
||||
public:
|
||||
@@ -336,6 +357,7 @@ extern LightIntBandDB gLightIntBandDB;
|
||||
extern LightFloatBandDB gLightFloatBandDB;
|
||||
extern GroundEffectDoodadDB gGroundEffectDoodadDB;
|
||||
extern GroundEffectTextureDB gGroundEffectTextureDB;
|
||||
extern TerrainTypeDB gTerrainTypeDB;
|
||||
extern LiquidTypeDB gLiquidTypeDB;
|
||||
extern SoundProviderPreferencesDB gSoundProviderPreferencesDB;
|
||||
extern SoundAmbienceDB gSoundAmbienceDB;
|
||||
|
||||
@@ -174,12 +174,14 @@ public:
|
||||
inline size_t getFieldCount() { return fieldCount; }
|
||||
inline Record getByID(unsigned int id, size_t field = 0)
|
||||
{
|
||||
for (Iterator i = begin(); i != end(); ++i)
|
||||
{
|
||||
if (i->getUInt(field) == id)
|
||||
return (*i);
|
||||
}
|
||||
throw NotFound();
|
||||
for (Iterator i = begin(); i != end(); ++i)
|
||||
{
|
||||
if (i->getUInt(field) == id)
|
||||
return (*i);
|
||||
}
|
||||
|
||||
LogError << "Tried to get a not existing row in " << filename << " (ID = " << id << ")!" << std::endl;
|
||||
return *begin(); // return the first entry if it failed
|
||||
}
|
||||
inline bool CheckIfIdExists(unsigned int id, size_t field = 0)
|
||||
{
|
||||
@@ -200,7 +202,8 @@ public:
|
||||
|
||||
row_id++;
|
||||
}
|
||||
throw NotFound();
|
||||
LogError << "Tried to get a not existing row in " << filename << " (ID = " << id << ")!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Record addRecord(size_t id, size_t id_field = 0);
|
||||
|
||||
@@ -35,7 +35,8 @@ MapChunk::MapChunk(MapTile* maintile, BlizzardArchive::ClientFile* f, bool bigAl
|
||||
, _chunk_update_flags(ChunkUpdateFlags::VERTEX | ChunkUpdateFlags::ALPHAMAP
|
||||
| ChunkUpdateFlags::SHADOW | ChunkUpdateFlags::MCCV
|
||||
| ChunkUpdateFlags::NORMALS| ChunkUpdateFlags::HOLES
|
||||
| ChunkUpdateFlags::AREA_ID| ChunkUpdateFlags::FLAGS)
|
||||
| ChunkUpdateFlags::AREA_ID| ChunkUpdateFlags::FLAGS
|
||||
| ChunkUpdateFlags::GROUND_EFFECT)
|
||||
{
|
||||
|
||||
|
||||
@@ -744,6 +745,16 @@ glm::vec3 MapChunk::getNeighborVertex(int i, unsigned dir)
|
||||
*/
|
||||
}
|
||||
|
||||
glm::uvec2 MapChunk::getUnitIndextAt(glm::vec3 pos)
|
||||
{
|
||||
glm::uvec2 unit_index = glm::uvec2(floor((pos.x - xbase) / UNITSIZE), floor((pos.z - zbase) / UNITSIZE));
|
||||
|
||||
if (unit_index.x > 8 || unit_index.y > 8)
|
||||
return glm::uvec2(8, 8);
|
||||
|
||||
return unit_index;
|
||||
}
|
||||
|
||||
void MapChunk::recalcNorms()
|
||||
{
|
||||
// 0 - up_left
|
||||
@@ -1905,7 +1916,8 @@ void MapChunk::unload()
|
||||
_chunk_update_flags = ChunkUpdateFlags::VERTEX | ChunkUpdateFlags::ALPHAMAP
|
||||
| ChunkUpdateFlags::SHADOW | ChunkUpdateFlags::MCCV
|
||||
| ChunkUpdateFlags::NORMALS| ChunkUpdateFlags::HOLES
|
||||
| ChunkUpdateFlags::AREA_ID| ChunkUpdateFlags::FLAGS;
|
||||
| ChunkUpdateFlags::AREA_ID| ChunkUpdateFlags::FLAGS
|
||||
| ChunkUpdateFlags::GROUND_EFFECT;
|
||||
}
|
||||
|
||||
void MapChunk::setAlphamapImage(const QImage &image, unsigned int layer)
|
||||
|
||||
@@ -39,14 +39,15 @@ static const int mapbufsize = 9 * 9 + 8 * 8; // chunk size
|
||||
|
||||
enum ChunkUpdateFlags
|
||||
{
|
||||
VERTEX = 0x1,
|
||||
SHADOW = 0x2,
|
||||
MCCV = 0x4,
|
||||
ALPHAMAP = 0x8,
|
||||
NORMALS = 0x10,
|
||||
HOLES = 0x20,
|
||||
AREA_ID = 0x40,
|
||||
FLAGS = 0x80
|
||||
VERTEX = 0x1,
|
||||
SHADOW = 0x2,
|
||||
MCCV = 0x4,
|
||||
ALPHAMAP = 0x8,
|
||||
NORMALS = 0x10,
|
||||
HOLES = 0x20,
|
||||
AREA_ID = 0x40,
|
||||
FLAGS = 0x80,
|
||||
GROUND_EFFECT = 0x100
|
||||
};
|
||||
|
||||
class MapChunk
|
||||
@@ -73,7 +74,7 @@ public:
|
||||
|
||||
MapChunkHeader header;
|
||||
|
||||
float xbase, ybase, zbase;
|
||||
float xbase, ybase, zbase; // global coords
|
||||
|
||||
mcnk_flags header_flags;
|
||||
bool use_big_alphamap;
|
||||
@@ -139,6 +140,8 @@ public:
|
||||
void updateNormalsData();
|
||||
glm::vec3 getNeighborVertex(int i, unsigned dir);
|
||||
|
||||
glm::uvec2 getUnitIndextAt(glm::vec3 pos);
|
||||
|
||||
//! \todo implement Action stack for these
|
||||
bool changeTerrain(glm::vec3 const& pos, float change, float radius, int BrushType, float inner_radius);
|
||||
bool flattenTerrain(glm::vec3 const& pos, float remain, float radius, int BrushType, flatten_mode const& mode, const glm::vec3& origin, math::degrees angle, math::degrees orientation);
|
||||
|
||||
@@ -61,7 +61,8 @@ MapTile::MapTile( int pX
|
||||
, _chunk_update_flags(ChunkUpdateFlags::VERTEX | ChunkUpdateFlags::ALPHAMAP
|
||||
| ChunkUpdateFlags::SHADOW | ChunkUpdateFlags::MCCV
|
||||
| ChunkUpdateFlags::NORMALS| ChunkUpdateFlags::HOLES
|
||||
| ChunkUpdateFlags::AREA_ID| ChunkUpdateFlags::FLAGS)
|
||||
| ChunkUpdateFlags::AREA_ID| ChunkUpdateFlags::FLAGS
|
||||
| ChunkUpdateFlags::GROUND_EFFECT)
|
||||
, _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},
|
||||
|
||||
@@ -253,6 +253,9 @@ void MapView::set_editing_mode(editing_mode mode)
|
||||
_world->renderer()->getTerrainParamsUniformBlock()->draw_impass_overlay = false;
|
||||
_world->renderer()->getTerrainParamsUniformBlock()->draw_paintability_overlay = false;
|
||||
_world->renderer()->getTerrainParamsUniformBlock()->draw_selection_overlay = false;
|
||||
_world->renderer()->getTerrainParamsUniformBlock()->draw_groundeffectid_overlay = false;
|
||||
_world->renderer()->getTerrainParamsUniformBlock()->draw_groundeffect_layerid_overlay = false;
|
||||
_world->renderer()->getTerrainParamsUniformBlock()->draw_noeffectdoodad_overlay = false;
|
||||
_minimap->use_selection(nullptr);
|
||||
|
||||
bool use_classic_ui = _settings->value("classicUI", true).toBool();
|
||||
@@ -270,6 +273,14 @@ void MapView::set_editing_mode(editing_mode mode)
|
||||
{
|
||||
texturingTool->updateMaskImage();
|
||||
}
|
||||
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)
|
||||
{
|
||||
@@ -301,7 +312,7 @@ void MapView::set_editing_mode(editing_mode mode)
|
||||
case editing_mode::areaid:
|
||||
_world->renderer()->getTerrainParamsUniformBlock()->draw_areaid_overlay = true;
|
||||
break;
|
||||
case editing_mode::flags:
|
||||
case editing_mode::impass:
|
||||
_world->renderer()->getTerrainParamsUniformBlock()->draw_impass_overlay = true;
|
||||
break;
|
||||
case editing_mode::minimap:
|
||||
@@ -721,6 +732,7 @@ void MapView::setupTexturePainterUi()
|
||||
, [=]()
|
||||
{
|
||||
_world->notifyTileRendererOnSelectedTextureChange();
|
||||
getGroundEffectsTool()->TextureChanged();
|
||||
}
|
||||
);
|
||||
|
||||
@@ -2511,7 +2523,7 @@ void MapView::setupHotkeys()
|
||||
, [this] { return !_mod_num_down && !NOGGIT_CUR_ACTION; });
|
||||
addHotkey (Qt::Key_5, MOD_none, [this] { set_editing_mode (editing_mode::areaid); }
|
||||
, [this] { return !_mod_num_down && !NOGGIT_CUR_ACTION; });
|
||||
addHotkey (Qt::Key_6, MOD_none, [this] { set_editing_mode (editing_mode::flags); }
|
||||
addHotkey (Qt::Key_6, MOD_none, [this] { set_editing_mode (editing_mode::impass); }
|
||||
, [this] { return !_mod_num_down && !NOGGIT_CUR_ACTION; });
|
||||
addHotkey (Qt::Key_7, MOD_none, [this] { set_editing_mode (editing_mode::water); }
|
||||
, [this] { return !_mod_num_down && !NOGGIT_CUR_ACTION; });
|
||||
@@ -2633,6 +2645,7 @@ void MapView::createGUI()
|
||||
// End combined dock
|
||||
|
||||
setupViewportOverlay();
|
||||
// texturingTool->setup_ge_tool_renderer();
|
||||
setupNodeEditor();
|
||||
setupAssetBrowser();
|
||||
setupDetailInfos();
|
||||
@@ -3110,6 +3123,12 @@ void MapView::saveMinimap(MinimapRenderSettings* settings)
|
||||
progress->setValue(value);
|
||||
});
|
||||
|
||||
connect(this, &MapView::selectionUpdated, [this]()
|
||||
{
|
||||
updateDetailInfos(true);
|
||||
_world->selection_updated = false;
|
||||
});
|
||||
|
||||
// setup combined image if necessary
|
||||
if (settings->combined_minimap)
|
||||
{
|
||||
@@ -3428,7 +3447,7 @@ void MapView::tick (float dt)
|
||||
switch (terrainMode)
|
||||
{
|
||||
case editing_mode::areaid:
|
||||
case editing_mode::flags:
|
||||
case editing_mode::impass:
|
||||
case editing_mode::holes:
|
||||
case editing_mode::object:
|
||||
update_cursor_pos();
|
||||
@@ -3876,7 +3895,7 @@ void MapView::tick (float dt)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case editing_mode::flags:
|
||||
case editing_mode::impass:
|
||||
if (!underMap)
|
||||
{
|
||||
// todo: replace this
|
||||
@@ -4154,8 +4173,14 @@ void MapView::tick (float dt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateDetailInfos();
|
||||
if (_world->selection_updated)
|
||||
{
|
||||
updateDetailInfos(true);
|
||||
_world->selection_updated = false;
|
||||
}
|
||||
else
|
||||
updateDetailInfos();
|
||||
// emit selectionUpdated();
|
||||
|
||||
_status_area->setText
|
||||
(QString::fromStdString (gAreaDB.getAreaName (_world->getAreaID (_camera.position))));
|
||||
@@ -5093,6 +5118,12 @@ void MapView::mouseMoveEvent (QMouseEvent* event)
|
||||
doSelection(false, true); // Required for radius selection in Object mode
|
||||
}
|
||||
}
|
||||
// drag selection, only do it when not using brush
|
||||
else if (!_mod_alt_down && leftMouse && terrainMode == editing_mode::object && _display_mode == display_mode::in_3D && !ImGuizmo::IsUsing())
|
||||
{
|
||||
_needs_redraw = true;
|
||||
_area_selection->setGeometry(QRect(_drag_start_pos, event->pos()).normalized());
|
||||
}
|
||||
|
||||
if (leftMouse && _mod_shift_down)
|
||||
{
|
||||
@@ -5125,12 +5156,6 @@ void MapView::mouseMoveEvent (QMouseEvent* event)
|
||||
|
||||
}
|
||||
|
||||
if (leftMouse && terrainMode == editing_mode::object && _display_mode == display_mode::in_3D && !ImGuizmo::IsUsing())
|
||||
{
|
||||
_needs_redraw = true;
|
||||
_area_selection->setGeometry(QRect(_drag_start_pos, event->pos()).normalized());
|
||||
}
|
||||
|
||||
if (_display_mode == display_mode::in_2D && leftMouse && _mod_alt_down && _mod_shift_down)
|
||||
{
|
||||
strafing = ((relative_movement.dx() / XSENS) / -1) * 5.0f;
|
||||
@@ -5582,6 +5607,11 @@ QWidget* MapView::getActiveStampModeItem()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Noggit::Ui::ground_effect_tool* MapView::getGroundEffectsTool()
|
||||
{
|
||||
return texturingTool->getGroundEffectsTool();
|
||||
}
|
||||
|
||||
void MapView::onSettingsSave()
|
||||
{
|
||||
OpenGL::TerrainParamsUniformBlock* params = _world->renderer()->getTerrainParamsUniformBlock();
|
||||
@@ -5712,6 +5742,7 @@ void MapView::ShowContextMenu(QPoint pos)
|
||||
auto model_name = obj->instance_model()->file_key().filepath();
|
||||
// auto models = _world->get_models_by_filename()[model_name];
|
||||
|
||||
// if changing this, make sure to check for duplicate instead // if (!_world->is_selected(instance))
|
||||
_world->reset_selection();
|
||||
|
||||
if (obj->which() == eMODEL)
|
||||
@@ -5720,7 +5751,6 @@ void MapView::ShowContextMenu(QPoint pos)
|
||||
{
|
||||
if (model_instance.instance_model()->file_key().filepath() == model_name)
|
||||
{
|
||||
// objects_to_select.push_back(model_instance.uid);
|
||||
_world->add_to_selection(&model_instance);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -93,6 +93,7 @@ namespace Noggit
|
||||
class hole_tool;
|
||||
struct tileset_chooser;
|
||||
class ObjectPalette;
|
||||
class ground_effect_tool;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,6 +252,7 @@ signals:
|
||||
void resized();
|
||||
void saved();
|
||||
void updateProgress(int value);
|
||||
void selectionUpdated();
|
||||
public slots:
|
||||
void on_exit_prompt();
|
||||
void ShowContextMenu(QPoint pos);
|
||||
@@ -302,6 +304,9 @@ public:
|
||||
[[nodiscard]]
|
||||
Noggit::Ui::flatten_blur_tool* getFlattenTool() { return flattenTool; };
|
||||
|
||||
[[nodiscard]]
|
||||
Noggit::Ui::ground_effect_tool* getGroundEffectsTool();
|
||||
|
||||
[[nodiscard]]
|
||||
Noggit::NoggitRenderContext getRenderContext() { return _context; };
|
||||
|
||||
@@ -311,6 +316,9 @@ public:
|
||||
[[nodiscard]]
|
||||
QDockWidget* getAssetBrowser() {return _asset_browser_dock; };
|
||||
|
||||
[[nodiscard]]
|
||||
Noggit::Ui::Tools::AssetBrowser::Ui::AssetBrowserWidget* getAssetBrowserWidget() { return _asset_browser; };
|
||||
|
||||
[[nodiscard]]
|
||||
Noggit::Ui::object_editor* getObjectEditor() { return objectEditor; };
|
||||
|
||||
|
||||
@@ -6,6 +6,14 @@
|
||||
#include <sstream>
|
||||
|
||||
|
||||
selected_chunk_type::selected_chunk_type(MapChunk* _chunk, std::tuple<int, int, int> _triangle, glm::vec3 _position)
|
||||
: chunk(_chunk)
|
||||
, triangle(_triangle)
|
||||
, position(_position)
|
||||
{
|
||||
unit_index = chunk->getUnitIndextAt(position);
|
||||
}
|
||||
|
||||
void selected_chunk_type::updateDetails(Noggit::Ui::detail_infos* detail_widget)
|
||||
{
|
||||
std::stringstream select_info;
|
||||
@@ -13,17 +21,21 @@ void selected_chunk_type::updateDetails(Noggit::Ui::detail_infos* detail_widget)
|
||||
mcnk_flags const& flags = chunk->header_flags;
|
||||
|
||||
select_info << "<b>Chunk</b> (" << chunk->px << ", " << chunk->py << ") flat index: (" << chunk->py * 16 + chunk->px
|
||||
<< ") of <b>tile</b> (" << chunk->mt->index.x << " , " << chunk->mt->index.z << ")"
|
||||
<< "<br><b>area ID:</b> " << chunk->getAreaID() << " (\"" << gAreaDB.getAreaName(chunk->getAreaID()) << "\")"
|
||||
<< "<br><b>flags</b>: "
|
||||
<< (flags.flags.has_mcsh ? "<br>shadows " : "")
|
||||
<< (flags.flags.impass ? "<br>impassable " : "")
|
||||
<< (flags.flags.lq_river ? "<br>river " : "")
|
||||
<< (flags.flags.lq_ocean ? "<br>ocean " : "")
|
||||
<< (flags.flags.lq_magma ? "<br>lava" : "")
|
||||
<< (flags.flags.lq_slime ? "<br>slime" : "")
|
||||
<< "<br><b>textures used:</b> " << chunk->texture_set->num()
|
||||
<< "<br><b>textures:</b><span>";
|
||||
<< ") of <b>tile</b> (" << chunk->mt->index.x << " , " << chunk->mt->index.z << ")"
|
||||
<< "<br><b>area ID:</b> " << chunk->getAreaID() << " (\"" << gAreaDB.getAreaName(chunk->getAreaID()) << "\")"
|
||||
<< "<br><b>flags</b>: "
|
||||
<< (flags.flags.has_mcsh ? "<br>shadows " : "")
|
||||
<< (flags.flags.impass ? "<br>impassable " : "")
|
||||
<< (flags.flags.lq_river ? "<br>river " : "")
|
||||
<< (flags.flags.lq_ocean ? "<br>ocean " : "")
|
||||
<< (flags.flags.lq_magma ? "<br>lava" : "")
|
||||
<< (flags.flags.lq_slime ? "<br>slime" : "");
|
||||
|
||||
select_info << "<br><b>Chunk Unit</b> (" << unit_index.x << ", " << unit_index.y << ")"
|
||||
<< "<br><b>Chunk Unit Effect Doodads disabled</b>: "
|
||||
<< (chunk->getTextureSet()->getDoodadEnabledAt(unit_index.y, unit_index.x) ? "True" : "False")
|
||||
<< "<br><b>Chunk Unit Active Doodad Effect Layer </b>: "
|
||||
<< int(chunk->getTextureSet()->getDoodadActiveLayerIdAt(unit_index.x, unit_index.y));
|
||||
|
||||
// liquid details if the chunk has liquid data
|
||||
if (chunk->mt->Water.hasData(0))
|
||||
@@ -38,8 +50,8 @@ 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 ?
|
||||
int liquid_flags = liquid.getSubchunks();
|
||||
|
||||
select_info << "\nliquid type: " << liquid.liquidID() << " (\"" << gLiquidTypeDB.getLiquidName(liquid.liquidID()) << "\")"
|
||||
<< "\nliquid flags: "
|
||||
select_info << "<br><b>liquid type</b>: " << liquid.liquidID() << " (\"" << gLiquidTypeDB.getLiquidName(liquid.liquidID()) << "\")"
|
||||
<< "<br><b>liquid flags</b>: "
|
||||
// getting flags from the center tile
|
||||
<< ((liquid_render.fishable >> (4 * 8 + 4)) & 1 ? "fishable " : "")
|
||||
<< ((liquid_render.fatigue >> (4 * 8 + 4)) & 1 ? "fatigue" : "");
|
||||
@@ -47,9 +59,12 @@ void selected_chunk_type::updateDetails(Noggit::Ui::detail_infos* detail_widget)
|
||||
}
|
||||
else
|
||||
{
|
||||
select_info << "\nno liquid data";
|
||||
select_info << "<br><b>no liquid data</b>";
|
||||
}
|
||||
|
||||
select_info << "<br><b>textures used:</b> " << chunk->texture_set->num()
|
||||
<< "<br><b>textures:</b><span>";
|
||||
|
||||
unsigned counter = 0;
|
||||
for (auto& tex : *(chunk->texture_set->getTextures()))
|
||||
{
|
||||
@@ -68,6 +83,8 @@ void selected_chunk_type::updateDetails(Noggit::Ui::detail_infos* detail_widget)
|
||||
|
||||
if (stuck || error)
|
||||
select_info << "</font>";
|
||||
select_info << "<br><b>Ground Effect</b>: " << chunk->getTextureSet()->getEffectForLayer(counter);
|
||||
counter++;
|
||||
}
|
||||
|
||||
//! \todo get a list of textures and their flags as well as detail doodads.
|
||||
|
||||
@@ -24,19 +24,22 @@ public:
|
||||
|
||||
struct selected_chunk_type : Selectable
|
||||
{
|
||||
selected_chunk_type(MapChunk* _chunk, std::tuple<int, int, int> _triangle, glm::vec3 _position)
|
||||
: chunk(_chunk)
|
||||
, triangle(_triangle)
|
||||
, position(_position)
|
||||
{}
|
||||
selected_chunk_type(MapChunk* _chunk, std::tuple<int, int, int> _triangle, glm::vec3 _position);
|
||||
// : chunk(_chunk)
|
||||
// , triangle(_triangle)
|
||||
// , position(_position)
|
||||
// {}
|
||||
|
||||
MapChunk* chunk;
|
||||
std::tuple<int,int,int> triangle; // mVertices[i] points of the hit triangle
|
||||
glm::vec3 position;
|
||||
glm::uvec2 unit_index;
|
||||
|
||||
bool operator== (selected_chunk_type const& other) const
|
||||
{
|
||||
return chunk == other.chunk;
|
||||
return chunk == other.chunk
|
||||
&& unit_index == other.unit_index
|
||||
&& triangle == other.triangle;
|
||||
}
|
||||
|
||||
virtual void updateDetails(Noggit::Ui::detail_infos* detail_widget) override;
|
||||
|
||||
@@ -110,7 +110,7 @@ public:
|
||||
private:
|
||||
friend struct scoped_blp_texture_reference;
|
||||
static Noggit::AsyncObjectMultimap<blp_texture> _;
|
||||
static std::array<std::unordered_map<std::tuple<GLint, int, int, int>, TexArrayParams, tuple_hash>, 7> _tex_arrays;
|
||||
static std::array<std::unordered_map<std::tuple<GLint, int, int, int>, TexArrayParams, tuple_hash>, Noggit::NoggitRenderContext::count> _tex_arrays;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -396,6 +396,7 @@ void World::rotate_selected_models_to_ground_normal(bool smoothNormals)
|
||||
ZoneScoped;
|
||||
if (!_selected_model_count)
|
||||
return;
|
||||
selection_updated = true;
|
||||
for (auto& entry : _current_selection)
|
||||
{
|
||||
auto type = entry.index();
|
||||
@@ -546,6 +547,7 @@ void World::set_current_selection(selection_type entry)
|
||||
void World::add_to_selection(selection_type entry, bool skip_group)
|
||||
{
|
||||
ZoneScoped;
|
||||
selection_updated = true;
|
||||
if (entry.index() == eEntry_Object)
|
||||
{
|
||||
_selected_model_count++;
|
||||
@@ -558,9 +560,11 @@ void World::add_to_selection(selection_type entry, bool skip_group)
|
||||
{
|
||||
if (group.contains_object(obj))
|
||||
{
|
||||
// make sure to add it to selection before donig group selection so it doesn't get selected twice
|
||||
_current_selection.push_back(entry);
|
||||
// this then calls add_to_selection() with skip_group = true to avoid repetition
|
||||
group.select_group();
|
||||
break;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -597,6 +601,7 @@ void World::remove_from_selection(selection_type entry, bool skip_group)
|
||||
|
||||
_current_selection.erase(position);
|
||||
update_selection_pivot();
|
||||
selection_updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -630,6 +635,7 @@ void World::remove_from_selection(std::uint32_t uid, bool skip_group)
|
||||
}
|
||||
|
||||
update_selection_pivot();
|
||||
selection_updated = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -640,6 +646,7 @@ void World::remove_from_selection(std::uint32_t uid, bool skip_group)
|
||||
void World::reset_selection()
|
||||
{
|
||||
ZoneScoped;
|
||||
selection_updated = true;
|
||||
_current_selection.clear();
|
||||
_multi_select_pivot = std::nullopt;
|
||||
_selected_model_count = 0;
|
||||
@@ -722,7 +729,7 @@ void World::snap_selected_models_to_the_ground()
|
||||
|
||||
updateTilesEntry(entry, model_update::add);
|
||||
}
|
||||
|
||||
selection_updated = true;
|
||||
update_selection_pivot();
|
||||
update_selected_model_groups();
|
||||
}
|
||||
@@ -802,7 +809,7 @@ void World::move_selected_models(float dx, float dy, float dz)
|
||||
|
||||
updateTilesEntry(entry, model_update::add);
|
||||
}
|
||||
|
||||
selection_updated = true;
|
||||
update_selection_pivot();
|
||||
update_selected_model_groups();
|
||||
}
|
||||
@@ -871,7 +878,7 @@ void World::set_selected_models_pos(glm::vec3 const& pos, bool change_height)
|
||||
|
||||
updateTilesEntry(entry, model_update::add);
|
||||
}
|
||||
|
||||
selection_updated = true;
|
||||
update_selection_pivot();
|
||||
update_selected_model_groups();
|
||||
}
|
||||
@@ -2882,7 +2889,8 @@ void World::range_add_to_selection(glm::vec3 const& pos, float radius, bool remo
|
||||
}
|
||||
else
|
||||
{
|
||||
add_to_selection(obj);
|
||||
if (!is_selected(obj))
|
||||
add_to_selection(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,8 @@ protected:
|
||||
public:
|
||||
std::vector<selection_group> _selection_groups;
|
||||
|
||||
bool selection_updated = false; // for mapview
|
||||
|
||||
MapIndex mapIndex;
|
||||
Noggit::map_horizon horizon;
|
||||
|
||||
|
||||
@@ -50,7 +50,8 @@ void TileRender::unload()
|
||||
_map_tile->_chunk_update_flags = ChunkUpdateFlags::VERTEX | ChunkUpdateFlags::ALPHAMAP
|
||||
| ChunkUpdateFlags::SHADOW | ChunkUpdateFlags::MCCV
|
||||
| ChunkUpdateFlags::NORMALS| ChunkUpdateFlags::HOLES
|
||||
| ChunkUpdateFlags::AREA_ID| ChunkUpdateFlags::FLAGS;
|
||||
| ChunkUpdateFlags::AREA_ID| ChunkUpdateFlags::FLAGS
|
||||
| ChunkUpdateFlags::GROUND_EFFECT;
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +111,7 @@ void TileRender::draw (OpenGL::Scoped::use_program& mcnk_shader
|
||||
}
|
||||
|
||||
// run chunk updates. running this when splitdraw call detected unused sampler configuration as well.
|
||||
if (_map_tile->_chunk_update_flags || is_selected != _selected || need_paintability_update || _requires_sampler_reset || _texture_not_loaded)
|
||||
if (_map_tile->_chunk_update_flags || is_selected != _selected || need_paintability_update || _requires_sampler_reset || _texture_not_loaded || _requires_ground_effect_color_recalc)
|
||||
{
|
||||
|
||||
gl.bindBuffer(GL_UNIFORM_BUFFER, _chunk_instance_data_ubo);
|
||||
@@ -211,9 +212,16 @@ void TileRender::draw (OpenGL::Scoped::use_program& mcnk_shader
|
||||
|
||||
if (flags & ChunkUpdateFlags::AREA_ID)
|
||||
{
|
||||
|
||||
_chunk_instance_data[i].AreaIDColor_Pad2_DrawSelection[0] = chunk->areaID;
|
||||
}
|
||||
|
||||
if (flags & ChunkUpdateFlags::GROUND_EFFECT)
|
||||
{
|
||||
setChunkGroundEffectData(chunk.get());
|
||||
}
|
||||
|
||||
|
||||
_chunk_instance_data[i].AreaIDColor_Pad2_DrawSelection[3] = _selected;
|
||||
|
||||
chunk->endChunkUpdates();
|
||||
@@ -224,7 +232,7 @@ void TileRender::draw (OpenGL::Scoped::use_program& mcnk_shader
|
||||
}
|
||||
|
||||
_requires_sampler_reset = false;
|
||||
|
||||
_requires_ground_effect_color_recalc = false;
|
||||
|
||||
if (_split_drawcall)
|
||||
{
|
||||
@@ -530,6 +538,23 @@ bool TileRender::fillSamplers(MapChunk* chunk, unsigned chunk_index, unsigned i
|
||||
return true;
|
||||
}
|
||||
|
||||
void Noggit::Rendering::TileRender::setChunkGroundEffectColor(unsigned int chunkid, glm::vec3 color)
|
||||
{
|
||||
if (chunkid > 255)
|
||||
return;
|
||||
|
||||
// int chunk_x = chunkid / 16;
|
||||
// int chunk_y = chunkid % 16;
|
||||
// auto& chunk = _map_tile->mChunks[chunk_y][chunk_x];
|
||||
// chunk->registerChunkUpdate(ChunkUpdateFlags::GROUND_EFFECT);
|
||||
|
||||
_requires_ground_effect_color_recalc = true;
|
||||
|
||||
_chunk_instance_data[chunkid].ChunkGroundEffectColor[0] = color.r;
|
||||
_chunk_instance_data[chunkid].ChunkGroundEffectColor[1] = color.g;
|
||||
_chunk_instance_data[chunkid].ChunkGroundEffectColor[2] = color.b;
|
||||
}
|
||||
|
||||
void TileRender::initChunkData(MapChunk* chunk)
|
||||
{
|
||||
auto& chunk_render_instance = _chunk_instance_data[chunk->px * 16 + chunk->py];
|
||||
@@ -540,4 +565,43 @@ void TileRender::initChunkData(MapChunk* chunk)
|
||||
chunk_render_instance.ChunkHoles_DrawImpass_TexLayerCount_CantPaint[3] = 0;
|
||||
chunk_render_instance.AreaIDColor_Pad2_DrawSelection[0] = chunk->areaID;
|
||||
chunk_render_instance.AreaIDColor_Pad2_DrawSelection[3] = 0;
|
||||
|
||||
chunk_render_instance.ChunkGroundEffectColor[0] = 0.0f;
|
||||
chunk_render_instance.ChunkGroundEffectColor[1] = 0.0f;
|
||||
chunk_render_instance.ChunkGroundEffectColor[2] = 0.0f;
|
||||
|
||||
// setChunkGroundEffectData(chunk);
|
||||
}
|
||||
|
||||
void TileRender::setChunkGroundEffectData(MapChunk* chunk)
|
||||
{
|
||||
auto& chunk_render_instance = _chunk_instance_data[chunk->px * 16 + chunk->py];
|
||||
|
||||
// chunk_render_instance.ChunkGroundEffectColor;
|
||||
auto doodadMapping = chunk->texture_set->getDoodadMappingBase();
|
||||
auto doodadExclusionMap = chunk->texture_set->getDoodadStencilBase();
|
||||
|
||||
// convert layer id to bool (IsCurrent)
|
||||
// TODO
|
||||
for (unsigned int x = 0; x < 8; x++)
|
||||
{
|
||||
for (unsigned int y = 0; y < 8; y++)
|
||||
{
|
||||
uint8_t layer_id = chunk->texture_set->getDoodadActiveLayerIdAt(x, y);
|
||||
unsigned int effect_id = chunk->getTextureSet()->getEffectForLayer(layer_id);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// pack it to int32s
|
||||
|
||||
int32_t exclusionmap1 = (int32_t)((uint32_t)(doodadExclusionMap[0] << 0) | (uint32_t)(doodadExclusionMap[1] << 8)
|
||||
| (uint32_t)(doodadExclusionMap[2] << 16) | (uint32_t)(doodadExclusionMap[3] << 24));
|
||||
|
||||
int32_t exclusionmap2 = (int32_t)((uint32_t)(doodadExclusionMap[4] << 0) | (uint32_t)(doodadExclusionMap[5] << 8)
|
||||
| (uint32_t)(doodadExclusionMap[6] << 16) | (uint32_t)(doodadExclusionMap[7] << 24));
|
||||
|
||||
// (a << 0) | (b << 8) | (c << 16) | (d << 24);
|
||||
chunk_render_instance.ChunkDoodadsEnabled2_ChunksLayerEnabled2[0] = exclusionmap1;
|
||||
chunk_render_instance.ChunkDoodadsEnabled2_ChunksLayerEnabled2[1] = exclusionmap2;
|
||||
}
|
||||
|
||||
@@ -39,9 +39,12 @@ namespace Noggit::Rendering
|
||||
bool getTileOcclusionQueryResult(glm::vec3 const& camera);
|
||||
void discardTileOcclusionQuery() { _tile_occlusion_query_in_use = false; }
|
||||
void notifyTileRendererOnSelectedTextureChange() { _requires_paintability_recalc = true; };
|
||||
void setChunkGroundEffectColor(unsigned int chunkid, glm::vec3 color);
|
||||
|
||||
void initChunkData(MapChunk* chunk);
|
||||
|
||||
void setChunkGroundEffectData(MapChunk* chunk);
|
||||
|
||||
[[nodiscard]]
|
||||
unsigned objectsFrustumCullTest() const { return _objects_frustum_cull_test; };
|
||||
void setObjectsFrustumCullTest(unsigned state) { _objects_frustum_cull_test = state; };
|
||||
@@ -70,6 +73,7 @@ namespace Noggit::Rendering
|
||||
bool _split_drawcall = false;
|
||||
bool _requires_sampler_reset = false;
|
||||
bool _requires_paintability_recalc = true;
|
||||
bool _requires_ground_effect_color_recalc = true;
|
||||
bool _texture_not_loaded = false;
|
||||
|
||||
// culling
|
||||
|
||||
@@ -90,6 +90,9 @@ void WorldRender::draw (glm::mat4x4 const& model_view
|
||||
_terrain_params_ubo_data.draw_paintability_overlay = false;
|
||||
_terrain_params_ubo_data.draw_selection_overlay = false;
|
||||
_terrain_params_ubo_data.draw_wireframe = false;
|
||||
_terrain_params_ubo_data.draw_groundeffectid_overlay = false;
|
||||
_terrain_params_ubo_data.draw_groundeffect_layerid_overlay = false;
|
||||
_terrain_params_ubo_data.draw_noeffectdoodad_overlay = false;
|
||||
_need_terrain_params_ubo_update = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,9 @@ layout (std140) uniform overlay_params
|
||||
int climb_use_smooth_interpolation;
|
||||
float climb_value;
|
||||
int draw_vertex_color;
|
||||
int padding[3];
|
||||
int draw_groundeffectid_overlay;
|
||||
int draw_groundeffect_layerid_overlay;
|
||||
int draw_noeffectdoodad_overlay;
|
||||
};
|
||||
|
||||
struct ChunkInstanceData
|
||||
@@ -46,6 +48,10 @@ struct ChunkInstanceData
|
||||
ivec4 AreaIDColor_Pad2_DrawSelection;
|
||||
ivec4 ChunkXZ_TileXZ;
|
||||
ivec4 ChunkTexAnimDir;
|
||||
vec4 ChunkGroundEffectColor;
|
||||
// pack 8x8 bools in two ints. Simplified ChunksLayerEnabled to a bool instead of 2 bits id.
|
||||
// If those modes are mutually exclusive, we can do it in ChunkGroundEffectColor for now.
|
||||
ivec4 ChunkDoodadsEnabled2_ChunksLayerEnabled2;
|
||||
};
|
||||
|
||||
layout (std140) uniform chunk_instances
|
||||
@@ -274,6 +280,57 @@ void main()
|
||||
out_color.rgb = out_color.rgb * 0.3 + random_color(instances[instanceID].AreaIDColor_Pad2_DrawSelection.r);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(draw_groundeffectid_overlay != 0)
|
||||
{
|
||||
out_color.rgb = out_color.rgb * 0.3 + instances[instanceID].ChunkGroundEffectColor.rgb;
|
||||
}
|
||||
|
||||
if(draw_groundeffect_layerid_overlay != 0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if(draw_noeffectdoodad_overlay != 0)
|
||||
{
|
||||
uint no_doodad = 0;
|
||||
|
||||
uvec2 tile_index = uvec2(uint(floor(vary_position.x / TILESIZE)), uint(floor(vary_position.z / TILESIZE)));
|
||||
vec2 tile_base_pos = vec2(float(tile_index.x * TILESIZE), float(tile_index.y * TILESIZE));
|
||||
|
||||
uvec2 chunk_index = uvec2(uint(floor(instanceID / 16)), uint(floor(instanceID % 16)));
|
||||
// uint chunk_x = uint(floor( (vary_position.x - tile_base_pos.x) / CHUNKSIZE));
|
||||
// uint chunk_y = uint(floor( (vary_position.z - tile_base_pos.y) / CHUNKSIZE));
|
||||
|
||||
vec2 chunk_base_pos = vec2(float(chunk_index.x * CHUNKSIZE), float(chunk_index.y * CHUNKSIZE));
|
||||
|
||||
uint unit_x = uint(floor((vary_position.x - (tile_base_pos.x + chunk_base_pos.x)) / UNITSIZE));
|
||||
uint unit_z = uint(floor((vary_position.z - (tile_base_pos.y + chunk_base_pos.y)) / UNITSIZE));
|
||||
|
||||
// swapped x and y order, the data is wrongly ordered when loaded
|
||||
if (unit_z < 4)
|
||||
{
|
||||
no_doodad = uint(instances[instanceID].ChunkDoodadsEnabled2_ChunksLayerEnabled2.r) & (1 << ((unit_z * 8) + unit_x) );
|
||||
}
|
||||
else
|
||||
{
|
||||
no_doodad = uint(instances[instanceID].ChunkDoodadsEnabled2_ChunksLayerEnabled2.g) & (1 << ((unit_z * 8) + unit_x) - 32 ); // (unit_x-4) * 8 + unit_z)
|
||||
}
|
||||
|
||||
if (no_doodad != 0)
|
||||
{
|
||||
// if set, draw chunk in white
|
||||
out_color.rgb = mix(vec3(1.0), out_color.rgb, 0.5);
|
||||
}
|
||||
else
|
||||
{
|
||||
// else, draw in black(default)
|
||||
out_color.rgb = mix(vec3(0.0), out_color.rgb, 0.5);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(draw_impass_overlay != 0 && instances[instanceID].ChunkHoles_DrawImpass_TexLayerCount_CantPaint.g != 0)
|
||||
{
|
||||
out_color.rgb = mix(vec3(1.0), out_color.rgb, 0.5);
|
||||
|
||||
@@ -23,6 +23,8 @@ struct ChunkInstanceData
|
||||
ivec4 AreaIDColor_Pad2_DrawSelection;
|
||||
ivec4 ChunkXZ_TileXZ;
|
||||
ivec4 ChunkTexAnimDir;
|
||||
vec4 ChunkGroundEffectColor;
|
||||
ivec4 ChunkDoodadsEnabled2_ChunksLayerEnabled2;
|
||||
};
|
||||
|
||||
layout (std140) uniform chunk_instances
|
||||
|
||||
@@ -372,6 +372,32 @@ int TextureSet::get_texture_index_or_add (scoped_blp_texture_reference texture,
|
||||
return addTexture (std::move (texture));
|
||||
}
|
||||
|
||||
uint8_t const TextureSet::getDoodadActiveLayerIdAt(unsigned int x, unsigned int y)
|
||||
{
|
||||
if (x >= 8 || y >= 8)
|
||||
return 0; // not valid
|
||||
|
||||
unsigned int firstbit_pos = y * 2;
|
||||
|
||||
bool first_bit = _doodadMapping[x] & (1 << firstbit_pos);
|
||||
bool second_bit = _doodadMapping[x] & (1 << (firstbit_pos + 1) );
|
||||
|
||||
uint8_t layer_id = first_bit + second_bit * 2;
|
||||
|
||||
return layer_id;
|
||||
}
|
||||
|
||||
bool const TextureSet::getDoodadEnabledAt(int x, int y)
|
||||
{
|
||||
if (x >= 8 || y >= 8)
|
||||
return true; // not valid. default to enabled
|
||||
|
||||
// X and Y are swapped
|
||||
bool is_enabled = _doodadStencil[y] & (1 << (x));
|
||||
|
||||
return is_enabled;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
|
||||
@@ -97,6 +97,8 @@ public:
|
||||
int get_texture_index_or_add (scoped_blp_texture_reference texture, float target);
|
||||
auto getDoodadMappingBase(void) -> std::uint16_t* { return _doodadMapping.data(); }
|
||||
auto getDoodadStencilBase(void) -> std::uint8_t* { return _doodadStencil.data(); }
|
||||
uint8_t const getDoodadActiveLayerIdAt(unsigned int x, unsigned int y); // max is 8
|
||||
bool const getDoodadEnabledAt(int x, int y); // max is 8
|
||||
auto getEffectForLayer(std::size_t idx) const -> unsigned { return _layers_info[idx].effectID; }
|
||||
ENTRY_MCLY* getMCLYEntries() { return &_layers_info[0]; };
|
||||
void setNTextures(size_t n) { nTextures = n; };
|
||||
@@ -118,8 +120,14 @@ private:
|
||||
std::array<std::optional<Alphamap>, 3> alphamaps;
|
||||
size_t nTextures;
|
||||
|
||||
std::array<std::uint16_t, 8> _doodadMapping;
|
||||
std::array<std::uint8_t, 8> _doodadStencil;
|
||||
// byte[8][8] // can store the 2bits value in a byte, but might never be higher than 3 or layer count.
|
||||
std::array<std::uint16_t, 8> _doodadMapping; // "predTex", It is used to determine which detail doodads to show.Values are an array of two bit unsigned integers, naming the layer.
|
||||
// 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];
|
||||
|
||||
@@ -67,7 +67,7 @@ enum class editing_mode
|
||||
paint = 2,
|
||||
holes = 3,
|
||||
areaid = 4,
|
||||
flags = 5,
|
||||
impass = 5,
|
||||
water = 6,
|
||||
mccv = 7,
|
||||
object = 8,
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Noggit
|
||||
add_tool_icon(editing_mode::paint, tr("Texture Painter"), FontNoggit::TOOL_TEXTURE_PAINT);
|
||||
add_tool_icon(editing_mode::holes, tr("Hole Cutter"), FontNoggit::TOOL_HOLE_CUTTER);
|
||||
add_tool_icon(editing_mode::areaid, tr("Area Designator"), FontNoggit::TOOL_AREA_DESIGNATOR);
|
||||
add_tool_icon(editing_mode::flags, tr("Impass Designator"), FontNoggit::TOOL_IMPASS_DESIGNATOR);
|
||||
add_tool_icon(editing_mode::impass, tr("Impass Designator"), FontNoggit::TOOL_IMPASS_DESIGNATOR);
|
||||
add_tool_icon(editing_mode::water, tr("Water Editor"), FontNoggit::TOOL_WATER_EDITOR);
|
||||
add_tool_icon(editing_mode::mccv, tr("Vertex Painter"), FontNoggit::TOOL_VERTEX_PAINT);
|
||||
add_tool_icon(editing_mode::object, tr("Object Editor"), FontNoggit::TOOL_OBJECT_EDITOR);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#include <noggit/ui/texturing_tool.hpp>
|
||||
#include <noggit/TabletManager.hpp>
|
||||
@@ -10,7 +10,9 @@
|
||||
#include <noggit/ui/Checkbox.hpp>
|
||||
#include <noggit/ui/CurrentTexture.h>
|
||||
#include <noggit/ui/texture_swapper.hpp>
|
||||
#include <noggit/DBC.h>
|
||||
#include <util/qt/overload.hpp>
|
||||
#include <noggit/ui/tools/AssetBrowser/Ui/AssetBrowser.hpp>
|
||||
|
||||
#include <QtWidgets/QFormLayout>
|
||||
#include <QtWidgets/QPushButton>
|
||||
@@ -155,6 +157,8 @@ namespace Noggit
|
||||
_texture_switcher = new texture_swapper(tool_widget, camera_pos, map_view);
|
||||
_texture_switcher->hide();
|
||||
|
||||
_ground_effect_tool = new ground_effect_tool(this, map_view, this);
|
||||
|
||||
_image_mask_group = new Noggit::Ui::Tools::ImageMaskSelector(map_view, this);
|
||||
_image_mask_group->setContinuousActionName("Paint");
|
||||
_image_mask_group->setBrushModeVisible(parent == map_view);
|
||||
@@ -173,6 +177,11 @@ namespace Noggit
|
||||
tool_layout->addWidget(quick_palette_btn);
|
||||
tool_layout->setAlignment(quick_palette_btn, Qt::AlignTop);
|
||||
|
||||
|
||||
auto geffect_tools_btn(new QPushButton("Ground Effect Tools", this));
|
||||
tool_layout->addWidget(geffect_tools_btn);
|
||||
tool_layout->setAlignment(geffect_tools_btn, Qt::AlignTop);
|
||||
|
||||
auto anim_widget (new QWidget (this));
|
||||
auto anim_layout (new QFormLayout (anim_widget));
|
||||
|
||||
@@ -308,10 +317,17 @@ namespace Noggit
|
||||
, [=] ()
|
||||
{
|
||||
_map_view->getTexturePalette()->setVisible(_map_view->getTexturePalette()->isHidden());
|
||||
// show_quick_palette->set(!show_quick_palette);
|
||||
}
|
||||
);
|
||||
|
||||
connect(geffect_tools_btn, &QPushButton::clicked
|
||||
, [=]()
|
||||
{
|
||||
_texturing_mode = texturing_mode::ground_effect;
|
||||
_ground_effect_tool->show();
|
||||
}
|
||||
);
|
||||
|
||||
connect ( _radius_slider, &Noggit::Ui::Tools::UiCommon::ExtendedSlider::valueChanged
|
||||
, [&] (double v)
|
||||
{
|
||||
@@ -667,5 +683,658 @@ namespace Noggit
|
||||
_texture_switcher->set_texture(tex_to_swap_path.toStdString());
|
||||
|
||||
}
|
||||
|
||||
ground_effect_tool::ground_effect_tool(texturing_tool* texturing_tool, MapView* map_view, QWidget* parent)
|
||||
: QWidget(parent, Qt::Window)
|
||||
// , layout(new ::QGridLayout(this))
|
||||
// , _chunk(nullptr)
|
||||
, _texturing_tool(texturing_tool)
|
||||
, _map_view(map_view)
|
||||
{
|
||||
setWindowTitle("Ground Effects Tools");
|
||||
setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
|
||||
// setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
|
||||
auto layout(new QVBoxLayout(this));
|
||||
layout->setAlignment(Qt::AlignTop);
|
||||
|
||||
// auto tool_widget(new QWidget(this));
|
||||
// tool_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
|
||||
// auto layout(new QVBoxLayout(tool_widget));
|
||||
// layout->setAlignment(Qt::AlignTop);
|
||||
|
||||
// render modes /////////
|
||||
// layout->addWidget(_render_group_box);
|
||||
|
||||
// auto render_modes_layout(new QHBoxLayout(_render_group_box));
|
||||
// _render_group_box->setLayout(render_modes_layout);
|
||||
|
||||
// render modes
|
||||
{
|
||||
_render_group_box = new QGroupBox("Render Mode", this);
|
||||
_render_group_box->setCheckable(true);
|
||||
_render_group_box->setChecked(true);
|
||||
layout->addWidget(_render_group_box);
|
||||
|
||||
auto render_layout(new QHBoxLayout(_render_group_box));
|
||||
_render_group_box->setLayout(render_layout);
|
||||
|
||||
_render_type_group = new QButtonGroup(_render_group_box);
|
||||
|
||||
_render_active_sets = new QRadioButton("Effect Id/Set", this);
|
||||
_render_type_group->addButton(_render_active_sets);
|
||||
render_layout->addWidget(_render_active_sets);
|
||||
|
||||
_render_exclusion_map = new QRadioButton("Doodads Disabled", this);
|
||||
_render_type_group->addButton(_render_exclusion_map);
|
||||
render_layout->addWidget(_render_exclusion_map);
|
||||
|
||||
_render_placement_map = new QRadioButton("Active layer", this); // if chunk contains texture/Effect : render as green or red if the effect layer is active or not
|
||||
_render_type_group->addButton(_render_placement_map);
|
||||
render_layout->addWidget(_render_placement_map);
|
||||
|
||||
_render_active_sets->setChecked(true);
|
||||
// _render_type_group->setAutoExclusive(true);
|
||||
}
|
||||
|
||||
////// Scan /////////
|
||||
_chkbox_merge_duplicates = new QCheckBox("Ignore duplicates", this);
|
||||
_chkbox_merge_duplicates->setChecked(true);
|
||||
layout->addWidget(_chkbox_merge_duplicates);
|
||||
|
||||
auto button_scan_adt = new QPushButton("Scan for sets in curr tile", this);
|
||||
layout->addWidget(button_scan_adt);
|
||||
|
||||
auto button_scan_adt_loaded = new QPushButton("Scan for sets in loaded Tiles", this);
|
||||
layout->addWidget(button_scan_adt_loaded);
|
||||
|
||||
|
||||
// selection
|
||||
auto selection_group = new QGroupBox("Effect Set Selection", this);
|
||||
layout->addWidget(selection_group);
|
||||
auto selection_layout(new QFormLayout(selection_group));
|
||||
selection_group->setLayout(selection_layout);
|
||||
|
||||
auto button_create_new = new QPushButton("Create New", this);
|
||||
selection_layout->addRow(button_create_new);
|
||||
|
||||
// _cbbox_effect_sets = new QComboBox(this);
|
||||
// _cbbox_effect_sets->addItem("Noggit Default");
|
||||
// _cbbox_effect_sets->setItemData(0, QVariant(0)); // index = _cbbox_effect_sets->count()
|
||||
// selection_layout->addRow("Active Set : ", _cbbox_effect_sets);
|
||||
|
||||
_effect_sets_list = new QListWidget(this);
|
||||
selection_layout->addRow(_effect_sets_list);
|
||||
_effect_sets_list->setViewMode(QListView::ListMode);
|
||||
_effect_sets_list->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);
|
||||
_effect_sets_list->setSelectionBehavior(QAbstractItemView::SelectItems);
|
||||
_effect_sets_list->setUniformItemSizes(true);
|
||||
|
||||
_effect_sets_list->setMinimumHeight(_object_list->iconSize().height() * 6);
|
||||
|
||||
// effect settings
|
||||
{
|
||||
auto settings_group = new QGroupBox("Selected Set Settings", this);
|
||||
// settings_group->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
|
||||
// settings_group->setCheckable(true);
|
||||
layout->addWidget(settings_group);
|
||||
|
||||
// auto settings_content = new QWidget(settings_group);
|
||||
auto settings_layout(new QFormLayout(settings_group));
|
||||
settings_group->setLayout(settings_layout);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
_button_effect_doodad[i] = new QPushButton(" -NONE- ", this);
|
||||
settings_layout->addRow(("Effect Doodad " + std::to_string(i) + " : ").c_str(), _button_effect_doodad[i]);
|
||||
}
|
||||
|
||||
_object_list = new ObjectList(this);
|
||||
_object_list->setItemAlignment(Qt::AlignLeft);
|
||||
_object_list->setViewMode(QListView::IconMode);
|
||||
settings_layout->addRow(_object_list);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
QListWidgetItem* list_item = new QListWidgetItem(_object_list);
|
||||
list_item->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::plus));
|
||||
list_item->setText(" -NONE- ");
|
||||
_object_list->addItem(list_item);
|
||||
}
|
||||
|
||||
_preview_renderer = new Tools::PreviewRenderer(_object_list->iconSize().width(),
|
||||
_object_list->iconSize().height(),
|
||||
Noggit::NoggitRenderContext::GROUND_EFFECT_PREVIEW, this);
|
||||
_preview_renderer->setVisible(false);
|
||||
// init renderer
|
||||
_preview_renderer->setModelOffscreen("world/wmo/azeroth/buildings/human_farm/farm.wmo");
|
||||
_preview_renderer->renderToPixmap();
|
||||
|
||||
// disable this if no active doodad
|
||||
//
|
||||
// density: 0 → 8. > 24 → 24. This value is for the amount of doodads and on higher values for coverage.
|
||||
// Till an amount of around 24 it just increases the amount.After this the doodads begin to group.
|
||||
// In WOTLK, only 4 entries out of 25k use more than 20.In retail only 5 use more than 25. 16 or less seems standard
|
||||
// TODO : if we end up limiting, a slider could be more apropriate
|
||||
_spinbox_doodads_amount = new QSpinBox(this);
|
||||
_spinbox_doodads_amount->setRange(0, 24);
|
||||
_spinbox_doodads_amount->setValue(8);
|
||||
settings_layout->addRow("Doodads amount : ", _spinbox_doodads_amount);
|
||||
|
||||
|
||||
_cbbox_terrain_type = new QComboBox(this);
|
||||
settings_layout->addRow("Terrain Type", _cbbox_terrain_type);
|
||||
|
||||
for (auto it = gTerrainTypeDB.begin(); it != gTerrainTypeDB.end(); ++it)
|
||||
{
|
||||
auto terrain_type_record = *it;
|
||||
|
||||
_cbbox_terrain_type->addItem(QString(terrain_type_record.getString(TerrainTypeDB::TerrainDesc)));
|
||||
_cbbox_terrain_type->setItemData(_cbbox_terrain_type->count(), QVariant(terrain_type_record.getUInt(TerrainTypeDB::TerrainId)));
|
||||
}
|
||||
|
||||
auto button_save_settings = new QPushButton("Save Set", this);
|
||||
settings_layout->addRow(button_save_settings);
|
||||
button_save_settings->setBaseSize(button_save_settings->size() / 2.0);
|
||||
}
|
||||
|
||||
|
||||
/// Apply group
|
||||
auto apply_group = new QGroupBox("Apply Ground Effect", this);
|
||||
layout->addWidget(apply_group);
|
||||
|
||||
auto apply_layout(new QVBoxLayout(apply_group));
|
||||
apply_group->setLayout(apply_layout);
|
||||
|
||||
_apply_override_cb = new QCheckBox("Override", this);
|
||||
apply_layout->addWidget(_apply_override_cb);
|
||||
|
||||
auto button_generate_adt = new QPushButton("Generate for current ADT", this);
|
||||
apply_layout->addWidget(button_generate_adt);
|
||||
|
||||
auto button_generate_global = new QPushButton("Generate Global(entire map)", this);
|
||||
apply_layout->addWidget(button_generate_global);
|
||||
|
||||
// brush modes
|
||||
{
|
||||
_brush_grup_box = new QGroupBox("Brush Mode", this);
|
||||
_brush_grup_box->setCheckable(true);
|
||||
_brush_grup_box->setChecked(false);
|
||||
layout->addWidget(_brush_grup_box);
|
||||
|
||||
auto brush_layout(new QHBoxLayout(_brush_grup_box));
|
||||
_brush_grup_box->setLayout(brush_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);
|
||||
|
||||
_paint_exclusion = new QRadioButton("Paint Exclusion", this);
|
||||
_brush_type_group->addButton(_paint_exclusion);
|
||||
brush_layout->addWidget(_paint_exclusion);
|
||||
|
||||
_paint_effect->setChecked(true);
|
||||
_paint_effect->setAutoExclusive(true);
|
||||
}
|
||||
//adjustSize();
|
||||
|
||||
connect(_render_group_box, &QGroupBox::clicked,
|
||||
[this](bool checked)
|
||||
{
|
||||
updateTerrainUniformParams(); // checks if is checked
|
||||
});
|
||||
|
||||
connect(_render_active_sets, &QRadioButton::clicked,
|
||||
[this](bool checked)
|
||||
{
|
||||
updateTerrainUniformParams();
|
||||
});
|
||||
|
||||
connect(_render_placement_map, &QRadioButton::clicked,
|
||||
[this](bool checked)
|
||||
{
|
||||
updateTerrainUniformParams();
|
||||
});
|
||||
|
||||
connect(_render_exclusion_map, &QRadioButton::clicked,
|
||||
[this](bool checked)
|
||||
{
|
||||
updateTerrainUniformParams();
|
||||
});
|
||||
|
||||
// get list of ground effect id this texture uses in this ADT
|
||||
connect(button_scan_adt, &QPushButton::clicked
|
||||
, [=]()
|
||||
{
|
||||
// don't need to clear if we check for duplicates
|
||||
// if (!_chkbox_merge_duplicates->isChecked())
|
||||
// {
|
||||
// _loaded_effects.clear();
|
||||
// }
|
||||
_loaded_effects.clear();
|
||||
scanTileForEffects(TileIndex(_map_view->getCamera()->position));
|
||||
|
||||
updateSetsList();
|
||||
}
|
||||
);
|
||||
|
||||
connect(button_scan_adt_loaded, &QPushButton::clicked
|
||||
, [=]()
|
||||
{
|
||||
// if (!_chkbox_merge_duplicates->isChecked())
|
||||
// {
|
||||
// _loaded_effects.clear();
|
||||
// }
|
||||
_loaded_effects.clear();
|
||||
|
||||
for (MapTile* tile : _map_view->getWorld()->mapIndex.loaded_tiles())
|
||||
{
|
||||
scanTileForEffects(TileIndex(tile->index));
|
||||
}
|
||||
updateSetsList();
|
||||
}
|
||||
);
|
||||
/*
|
||||
connect(_cbbox_effect_sets, qOverload<int>(&QComboBox::currentIndexChanged)
|
||||
, [this](int index)
|
||||
{
|
||||
// unsigned int effect_id = _cbbox_effect_sets->currentData().toUInt();
|
||||
|
||||
// TODO
|
||||
// if (effect_id)
|
||||
if (_loaded_effects.empty() || !_cbbox_effect_sets->count() || index == -1)
|
||||
return;
|
||||
|
||||
auto effect = _loaded_effects[index];
|
||||
|
||||
SetActiveGroundEffect(effect);
|
||||
|
||||
// _cbbox_effect_sets->setStyleSheet
|
||||
QPalette pal = _cbbox_effect_sets->palette();
|
||||
pal.setColor(_cbbox_effect_sets->backgroundRole(), QColor::fromRgbF(_effects_colors[index].r, _effects_colors[index].g, _effects_colors[index].b));
|
||||
_cbbox_effect_sets->setPalette(pal);
|
||||
});
|
||||
*/
|
||||
QObject::connect(_effect_sets_list, &QListWidget::itemClicked, [this](QListWidgetItem* item)
|
||||
{
|
||||
//_effect_sets_list->currentItem
|
||||
int index = _effect_sets_list->currentIndex().row();
|
||||
|
||||
if (_loaded_effects.empty() || !_effect_sets_list->count() || index == -1)
|
||||
return;
|
||||
|
||||
auto effect = _loaded_effects[index];
|
||||
|
||||
SetActiveGroundEffect(effect);
|
||||
|
||||
// _cbbox_effect_sets->setStyleSheet
|
||||
QPalette pal = _effect_sets_list->palette();
|
||||
pal.setColor(_effect_sets_list->backgroundRole(), QColor::fromRgbF(_effects_colors[index].r, _effects_colors[index].g, _effects_colors[index].b));
|
||||
_effect_sets_list->setPalette(pal);
|
||||
});
|
||||
|
||||
// TODO fix this shit
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
connect(_button_effect_doodad[i], &QPushButton::clicked
|
||||
, [=]()
|
||||
{
|
||||
active_doodad_widget = i;
|
||||
_map_view->getAssetBrowserWidget()->set_browse_mode(Tools::AssetBrowser::asset_browse_mode::detail_doodads);
|
||||
_map_view->getAssetBrowser()->setVisible(true);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void ground_effect_tool::updateTerrainUniformParams()
|
||||
{
|
||||
if (_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_groundeffectid_overlay != show_active_sets_overlay())
|
||||
{
|
||||
_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_groundeffectid_overlay = show_active_sets_overlay();
|
||||
_map_view->getWorld()->renderer()->markTerrainParamsUniformBlockDirty();
|
||||
}
|
||||
|
||||
if (_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_groundeffect_layerid_overlay != show_placement_map_overlay())
|
||||
{
|
||||
_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_groundeffect_layerid_overlay = show_placement_map_overlay();
|
||||
_map_view->getWorld()->renderer()->markTerrainParamsUniformBlockDirty();
|
||||
}
|
||||
if (_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_noeffectdoodad_overlay != show_exclusion_map_overlay())
|
||||
{
|
||||
_map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_noeffectdoodad_overlay = show_exclusion_map_overlay();
|
||||
_map_view->getWorld()->renderer()->markTerrainParamsUniformBlockDirty();
|
||||
}
|
||||
}
|
||||
|
||||
void ground_effect_tool::scanTileForEffects(TileIndex tile_index)
|
||||
{
|
||||
std::string active_texture = _texturing_tool->_current_texture->filename();
|
||||
|
||||
if (active_texture.empty() || active_texture == "tileset\\generic\\black.blp")
|
||||
return;
|
||||
|
||||
// could use a map to store number of users.
|
||||
// std::unordered_set<unsigned int> texture_effect_ids;
|
||||
// std::unordered_map<unsigned int, int> texture_effect_ids;
|
||||
|
||||
MapTile* tile(_map_view->getWorld()->mapIndex.getTile(tile_index));
|
||||
for (int x = 0; x < 16; x++)
|
||||
{
|
||||
for (int y = 0; y < 16; y++)
|
||||
{
|
||||
auto chunk = tile->getChunk(x, y);
|
||||
for (int layer_id = 0; layer_id < chunk->getTextureSet()->num(); layer_id++)
|
||||
{
|
||||
auto texture_name = chunk->getTextureSet()->filename(layer_id);
|
||||
if (texture_name == active_texture)
|
||||
{
|
||||
unsigned int const effect_id = chunk->getTextureSet()->getEffectForLayer(layer_id);
|
||||
|
||||
if (effect_id && !(effect_id == 0xFFFFFFFF))
|
||||
{
|
||||
ground_effect_set ground_effect;
|
||||
|
||||
if (_ground_effect_cache.contains(effect_id)) {
|
||||
ground_effect = _ground_effect_cache.at(effect_id);
|
||||
}
|
||||
else {
|
||||
ground_effect.load_from_id(effect_id);
|
||||
_ground_effect_cache[effect_id] = ground_effect;
|
||||
}
|
||||
|
||||
if (ground_effect.empty())
|
||||
continue;
|
||||
|
||||
bool is_duplicate = false;
|
||||
|
||||
for (int i = 0; i < _loaded_effects.size(); i++)
|
||||
// for (auto& effect_set : _loaded_effects)
|
||||
{
|
||||
auto effect_set = &_loaded_effects[i];
|
||||
// always filter identical ids
|
||||
if (effect_id == effect_set->ID
|
||||
|| (_chkbox_merge_duplicates->isChecked() && ground_effect == effect_set))
|
||||
{
|
||||
is_duplicate = true;
|
||||
// _duplicate_effects[i].push_back(ground_effect); // mapped by loaded index, could use effect id ?
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!is_duplicate)
|
||||
{
|
||||
_loaded_effects.push_back(ground_effect);
|
||||
// give it a name
|
||||
// Area is probably useless if we merge since duplictes are per area.
|
||||
_loaded_effects.back().Name += " - " + gAreaDB.getAreaName(chunk->getAreaID());
|
||||
}
|
||||
|
||||
// _texture_effect_ids[effect_id]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ground_effect_tool::updateSetsList()
|
||||
{
|
||||
genEffectColors();
|
||||
|
||||
// _cbbox_effect_sets->clear();
|
||||
_effect_sets_list->clear();
|
||||
|
||||
int count = 0;
|
||||
for (auto& effect_set : _loaded_effects)
|
||||
{
|
||||
// we already check for id validity earlier
|
||||
|
||||
unsigned int tex_ge_id = effect_set.ID;
|
||||
QColor color = QColor::fromRgbF(_effects_colors[count].r, _effects_colors[count].g, _effects_colors[count].b);
|
||||
|
||||
// _cbbox_effect_sets->addItem((std::to_string(tex_ge_id) + " (" + std::to_string(pair.second) + " users)").c_str());
|
||||
// _cbbox_effect_sets->addItem(effect_set.Name.c_str());
|
||||
// _cbbox_effect_sets->setItemData(count, QColor::fromRgbF(_effects_colors[count].r, _effects_colors[count].g, _effects_colors[count].b), Qt::BackgroundRole);
|
||||
// QModelIndex model_idx = _cbbox_effect_sets->model()->index(count, 0);
|
||||
// _cbbox_effect_sets->model()->setData(model_idx, color, Qt::BackgroundRole);
|
||||
// _cbbox_effect_sets->setItemData(count, QVariant(tex_ge_id)); // probably useless now, can iterate vector if it's synched with the dropdown
|
||||
|
||||
|
||||
QListWidgetItem* list_item = new QListWidgetItem(effect_set.Name.c_str());
|
||||
|
||||
list_item->setData(Qt::BackgroundRole, color);
|
||||
list_item->setBackground(color);
|
||||
list_item->setBackgroundColor(color);
|
||||
QPixmap pixmap(50, 50);
|
||||
pixmap.fill(color);
|
||||
QIcon icon(pixmap);
|
||||
list_item->setIcon(icon);
|
||||
_effect_sets_list->addItem(list_item);
|
||||
|
||||
// test
|
||||
QPalette pal = _effect_sets_list->palette();
|
||||
pal.setColor(_effect_sets_list->backgroundRole(), color);
|
||||
_effect_sets_list->setPalette(pal);
|
||||
|
||||
|
||||
count++;
|
||||
}
|
||||
// if (_cbbox_effect_sets->count())
|
||||
// _cbbox_effect_sets->setCurrentIndex(0);
|
||||
auto first_item = _effect_sets_list->itemAt(0, 0);
|
||||
if (_effect_sets_list->count() && first_item)
|
||||
_effect_sets_list->setCurrentItem(first_item);
|
||||
}
|
||||
|
||||
void ground_effect_tool::genEffectColors()
|
||||
{
|
||||
_effects_colors.clear();
|
||||
|
||||
int count = 1;
|
||||
for (auto& effect : _loaded_effects)
|
||||
{
|
||||
// same formula as in the shader
|
||||
float partr, partg, partb;
|
||||
// TODO : can use id instead of count ?
|
||||
float r = modf(sin(glm::dot(glm::vec2(count), glm::vec2(12.9898, 78.233))) * 43758.5453, &partr);
|
||||
float g = modf(sin(glm::dot(glm::vec2(count), glm::vec2(11.5591, 70.233))) * 43569.5451, &partg);
|
||||
float b = modf(sin(glm::dot(glm::vec2(count), glm::vec2(13.1234, 76.234))) * 43765.5452, &partg);
|
||||
|
||||
// return vec3(r, g, b);
|
||||
count++;
|
||||
|
||||
_effects_colors.push_back(glm::vec3(r, g, b));
|
||||
}
|
||||
|
||||
std::string active_texture = _texturing_tool->_current_texture->filename();
|
||||
|
||||
if (active_texture.empty() || active_texture == "tileset\\generic\\black.blp")
|
||||
return;
|
||||
|
||||
std::unordered_map<unsigned int, ground_effect_set> ground_effect_cache;
|
||||
|
||||
for (MapTile* tile : _map_view->getWorld()->mapIndex.loaded_tiles())
|
||||
{
|
||||
for (int x = 0; x < 16; x++)
|
||||
{
|
||||
for (int y = 0; y < 16; y++)
|
||||
{
|
||||
auto chunk = tile->getChunk(x, y);
|
||||
// reset to black by default
|
||||
tile->renderer()->setChunkGroundEffectColor(chunk->px * 16 + chunk->py, glm::vec3(0.0, 0.0, 0.0));
|
||||
|
||||
for (int layer_id = 0; layer_id < chunk->getTextureSet()->num(); layer_id++)
|
||||
{
|
||||
auto texture_name = chunk->getTextureSet()->filename(layer_id);
|
||||
if (texture_name == active_texture)
|
||||
{
|
||||
unsigned int const effect_id = chunk->getTextureSet()->getEffectForLayer(layer_id);
|
||||
|
||||
if (effect_id && !(effect_id == 0xFFFFFFFF))
|
||||
{
|
||||
ground_effect_set ground_effect;
|
||||
|
||||
if (_ground_effect_cache.contains(effect_id)) {
|
||||
ground_effect = _ground_effect_cache.at(effect_id);
|
||||
}
|
||||
else {
|
||||
ground_effect.load_from_id(effect_id);
|
||||
_ground_effect_cache[effect_id] = ground_effect;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (auto& effect_set : _loaded_effects)
|
||||
{
|
||||
if (effect_id == effect_set.ID)
|
||||
{
|
||||
tile->renderer()->setChunkGroundEffectColor(chunk->px * 16 + chunk->py, _effects_colors[count]);
|
||||
break;
|
||||
}
|
||||
if (_chkbox_merge_duplicates->isChecked() && (ground_effect == &effect_set)) // do deep comparison, find those that have the same effect as loaded effects, but diff id.
|
||||
{
|
||||
if (ground_effect.empty())
|
||||
continue;
|
||||
// same color
|
||||
tile->renderer()->setChunkGroundEffectColor(chunk->px * 16 + chunk->py, _effects_colors[count]);
|
||||
break;
|
||||
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void ground_effect_tool::TextureChanged()
|
||||
{
|
||||
// TODO : maybe load saved sets for the new texture
|
||||
|
||||
active_doodad_widget = 0;
|
||||
|
||||
_loaded_effects.clear();
|
||||
_ground_effect_cache.clear();
|
||||
|
||||
updateSetsList();
|
||||
|
||||
// _cbbox_effect_sets->clear(); // done by updateSetsList
|
||||
|
||||
_spinbox_doodads_amount->setValue(8);
|
||||
_cbbox_terrain_type->setCurrentIndex(0);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
_button_effect_doodad[i]->setText(" -NONE- ");
|
||||
updateDoodadPreviewRender(i);
|
||||
}
|
||||
}
|
||||
|
||||
void ground_effect_tool::setDoodadSlotFromBrowser(QString doodad_path)
|
||||
{
|
||||
const QFileInfo info(doodad_path);
|
||||
const QString filename(info.fileName());
|
||||
|
||||
_button_effect_doodad[active_doodad_widget]->setText(filename);
|
||||
|
||||
updateDoodadPreviewRender(active_doodad_widget);
|
||||
}
|
||||
|
||||
void ground_effect_tool::updateDoodadPreviewRender(int slot_index)
|
||||
{
|
||||
QString filename = _button_effect_doodad[slot_index]->text();
|
||||
|
||||
QListWidgetItem* list_item = _object_list->item(slot_index); // new QListWidgetItem(_object_list);
|
||||
|
||||
if (filename.isEmpty() || filename == " -NONE- ")
|
||||
{
|
||||
list_item->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::plus)); // (Noggit::Ui::FontNoggitIcon(Noggit::Ui::FontNoggit::Icons::VISIBILITY_GROUNDEFFECTS));
|
||||
}
|
||||
else
|
||||
{
|
||||
// load preview render
|
||||
QString filepath(("world/nodxt/detail/" + filename.toStdString()).c_str());
|
||||
_preview_renderer->setModelOffscreen(filepath.toStdString());
|
||||
list_item->setIcon(*_preview_renderer->renderToPixmap());
|
||||
|
||||
_button_effect_doodad[slot_index]->setIcon(*_preview_renderer->renderToPixmap());
|
||||
// list_item->setData(Qt::DisplayRole, filepath);
|
||||
// list_item->setToolTip(filepath);
|
||||
|
||||
}
|
||||
list_item->setText(filename);
|
||||
}
|
||||
|
||||
ground_effect_tool::~ground_effect_tool()
|
||||
{
|
||||
delete _preview_renderer;
|
||||
}
|
||||
|
||||
void ground_effect_tool::SetActiveGroundEffect(ground_effect_set const& effect)
|
||||
{
|
||||
// sets a ground effect to be actively selected in the UI.
|
||||
|
||||
_spinbox_doodads_amount->setValue(effect.Amount);
|
||||
_cbbox_terrain_type->setCurrentIndex(effect.TerrainType);
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
QString filename(effect.Doodads[i].filename.c_str());
|
||||
// replace old extensions in the dbc
|
||||
filename = filename.replace(".mdx", ".m2", Qt::CaseInsensitive);
|
||||
filename = filename.replace(".mdl", ".m2", Qt::CaseInsensitive);
|
||||
|
||||
// TODO turn this into an array of elements
|
||||
|
||||
if (filename.isEmpty())
|
||||
_button_effect_doodad[i]->setText(" -NONE- ");
|
||||
else
|
||||
_button_effect_doodad[i]->setText(filename);
|
||||
|
||||
updateDoodadPreviewRender(i);
|
||||
}
|
||||
}
|
||||
|
||||
void ground_effect_set::load_from_id(unsigned int effect_id)
|
||||
{
|
||||
if (!effect_id || (effect_id == 0xFFFFFFFF))
|
||||
return;
|
||||
|
||||
if (!gGroundEffectTextureDB.CheckIfIdExists(effect_id))
|
||||
return;
|
||||
|
||||
DBCFile::Record GErecord{ gGroundEffectTextureDB.getByID(effect_id) };
|
||||
|
||||
Name = std::to_string(effect_id);
|
||||
|
||||
ID = GErecord.getUInt(GroundEffectTextureDB::ID);
|
||||
Amount = GErecord.getUInt(GroundEffectTextureDB::Amount);
|
||||
TerrainType = GErecord.getUInt(GroundEffectTextureDB::TerrainType);
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
Weights[i] = GErecord.getUInt(GroundEffectTextureDB::Weights + i);
|
||||
|
||||
unsigned const curDoodadId{ GErecord.getUInt(GroundEffectTextureDB::Doodads + i) };
|
||||
|
||||
if (!curDoodadId)
|
||||
continue;
|
||||
if (!gGroundEffectDoodadDB.CheckIfIdExists(curDoodadId))
|
||||
continue;
|
||||
|
||||
Doodads[i].ID = curDoodadId;
|
||||
QString filename = gGroundEffectDoodadDB.getByID(curDoodadId).getString(GroundEffectDoodadDB::Filename);
|
||||
|
||||
filename.replace(".mdx", ".m2", Qt::CaseInsensitive);
|
||||
filename.replace(".mdl", ".m2", Qt::CaseInsensitive);
|
||||
|
||||
Doodads[i].filename = filename.toStdString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include <noggit/unsigned_int_property.hpp>
|
||||
#include <noggit/ui/tools/UiCommon/ExtendedSlider.hpp>
|
||||
#include <noggit/ui/tools/UiCommon/ImageMaskSelector.hpp>
|
||||
#include <noggit/ui/widget.hpp>
|
||||
#include <noggit/ui/tools/PreviewRenderer/PreviewRenderer.hpp>
|
||||
|
||||
#include <QtWidgets/QCheckBox>
|
||||
#include <QtWidgets/QDial>
|
||||
@@ -18,6 +20,7 @@
|
||||
|
||||
class World;
|
||||
class MapView;
|
||||
class DBCFile::Record;
|
||||
|
||||
namespace Noggit
|
||||
{
|
||||
@@ -31,7 +34,146 @@ namespace Noggit
|
||||
{
|
||||
paint,
|
||||
swap,
|
||||
anim
|
||||
anim,
|
||||
ground_effect
|
||||
};
|
||||
|
||||
struct ground_effect_doodad
|
||||
{
|
||||
unsigned int ID = 0;
|
||||
std::string filename = "";
|
||||
// weight
|
||||
// flag (useless in 3.3.5)
|
||||
|
||||
bool empty() { return filename.empty(); };
|
||||
|
||||
bool operator== (ground_effect_doodad* doodad2)
|
||||
{
|
||||
return filename == doodad2->filename;
|
||||
}
|
||||
};
|
||||
|
||||
struct ground_effect_set
|
||||
{
|
||||
public:
|
||||
void load_from_id(unsigned int effect_id);
|
||||
|
||||
bool empty() { return !ID; };
|
||||
|
||||
// only ignores id and name (use filename to compare doodads)
|
||||
bool operator== ( ground_effect_set* effect2)
|
||||
{
|
||||
return (TerrainType == effect2->TerrainType && Amount == effect2->Amount
|
||||
&& Doodads[0] == &effect2->Doodads[0] && Doodads[1] == &effect2->Doodads[1]
|
||||
&& Doodads[2] == &effect2->Doodads[2] && Doodads[3] == &effect2->Doodads[3]
|
||||
&& Weights[0] == effect2->Weights[0] && Weights[1] == effect2->Weights[1]
|
||||
&& Weights[2] == effect2->Weights[2] && Weights[3] == effect2->Weights[3]
|
||||
);
|
||||
}
|
||||
|
||||
std::string Name = ""; // created by the user or auto generated
|
||||
|
||||
unsigned int ID = 0;
|
||||
// unsigned int Doodads[4];
|
||||
// TODO: can pack doodad and weight in a struct
|
||||
ground_effect_doodad Doodads[4];
|
||||
unsigned int Weights[4]{ 1, 1, 1, 1 };
|
||||
unsigned int Amount = 0;
|
||||
unsigned int TerrainType = 0;
|
||||
};
|
||||
|
||||
|
||||
class ground_effect_tool : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ground_effect_tool(texturing_tool* texturing_tool, MapView* map_view, QWidget* parent = nullptr);
|
||||
|
||||
void updateTerrainUniformParams();
|
||||
|
||||
~ground_effect_tool(); // delete renderer
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent* event) {
|
||||
QWidget::showEvent(event);
|
||||
updateTerrainUniformParams();
|
||||
}
|
||||
|
||||
void hideEvent(QHideEvent* event) {
|
||||
_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::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();
|
||||
};
|
||||
|
||||
public:
|
||||
void setDoodadSlotFromBrowser(QString doodad_path);
|
||||
|
||||
void TextureChanged(); // textureChanged
|
||||
|
||||
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:
|
||||
void SetActiveGroundEffect(ground_effect_set const& effect);
|
||||
|
||||
void updateDoodadPreviewRender(int slot_index);
|
||||
|
||||
void scanTileForEffects(TileIndex tile_index);
|
||||
void updateSetsList();
|
||||
|
||||
void genEffectColors();
|
||||
|
||||
int active_doodad_widget = 0;
|
||||
// std::unordered_map<unsigned int, int> _texture_effect_ids;
|
||||
|
||||
std::vector< ground_effect_set> _loaded_effects;
|
||||
|
||||
std::unordered_map<unsigned int, ground_effect_set> _ground_effect_cache; // store them for faster iteration on duplicates
|
||||
|
||||
std::vector < glm::vec3> _effects_colors;
|
||||
|
||||
texturing_tool* _texturing_tool;
|
||||
MapView* _map_view;
|
||||
|
||||
Tools::PreviewRenderer* _preview_renderer;
|
||||
|
||||
QGroupBox* _render_group_box;
|
||||
QButtonGroup* _render_type_group;
|
||||
QRadioButton* _render_active_sets;
|
||||
QRadioButton* _render_placement_map;
|
||||
QRadioButton* _render_exclusion_map;
|
||||
|
||||
QCheckBox* _chkbox_merge_duplicates;
|
||||
|
||||
// QComboBox* _cbbox_effect_sets;
|
||||
QListWidget* _effect_sets_list;
|
||||
|
||||
// TODO create some nice UI for doodads
|
||||
QListWidget* _object_list; // for render previews
|
||||
QPushButton* _button_effect_doodad[4];
|
||||
|
||||
QSpinBox* _spinbox_doodads_amount;
|
||||
QComboBox* _cbbox_terrain_type;
|
||||
|
||||
QCheckBox* _apply_override_cb;
|
||||
|
||||
QGroupBox* _brush_grup_box;
|
||||
QButtonGroup* _brush_type_group;
|
||||
QRadioButton* _paint_effect;
|
||||
QRadioButton* _paint_exclusion;
|
||||
|
||||
|
||||
};
|
||||
|
||||
class texturing_tool : public QWidget
|
||||
@@ -43,6 +185,8 @@ namespace Noggit
|
||||
, QWidget* parent = nullptr
|
||||
);
|
||||
|
||||
~texturing_tool() { delete _ground_effect_tool; };
|
||||
|
||||
float brush_radius() const;
|
||||
float hardness() const;
|
||||
bool show_unpaintable_chunks() const;
|
||||
@@ -51,6 +195,8 @@ namespace Noggit
|
||||
|
||||
void toggle_tool();
|
||||
|
||||
ground_effect_tool* getGroundEffectsTool() { return _ground_effect_tool; };
|
||||
|
||||
void change_radius (float change);
|
||||
void setRadius(float radius);
|
||||
void setHardness(float hardness);
|
||||
@@ -58,7 +204,7 @@ namespace Noggit
|
||||
void change_pressure (float change);
|
||||
void change_brush_level (float change);
|
||||
void set_pressure (float pressure);
|
||||
void toggle_brush_level_min_max();
|
||||
void toggle_brush_level_min_max();
|
||||
void change_spray_size (float change);
|
||||
void change_spray_pressure (float change);
|
||||
|
||||
@@ -87,7 +233,13 @@ namespace Noggit
|
||||
|
||||
Noggit::Ui::Tools::ImageMaskSelector* getImageMaskSelector() { return _image_mask_group; };
|
||||
QImage* getMaskImage() { return &_mask_image; }
|
||||
texturing_mode getTexturingMode() { return _texturing_mode; };
|
||||
texturing_mode getTexturingMode()
|
||||
{
|
||||
if (_ground_effect_tool->isVisible())
|
||||
return texturing_mode::ground_effect;
|
||||
else
|
||||
return _texturing_mode;
|
||||
};
|
||||
void updateMaskImage();
|
||||
|
||||
QJsonObject toJSON();
|
||||
@@ -139,6 +291,8 @@ namespace Noggit
|
||||
|
||||
texture_swapper* _texture_switcher;
|
||||
|
||||
ground_effect_tool* _ground_effect_tool;
|
||||
|
||||
Noggit::Ui::Tools::ImageMaskSelector* _image_mask_group;
|
||||
|
||||
QTabWidget* tabs;
|
||||
|
||||
@@ -35,7 +35,8 @@ AssetBrowserWidget::AssetBrowserWidget(MapView* map_view, QWidget *parent)
|
||||
setWindowFlags(windowFlags() | Qt::Tool | Qt::WindowStaysOnTopHint);
|
||||
|
||||
_model = new QStandardItemModel(this);
|
||||
_sort_model = new QSortFilterProxyModel(this);
|
||||
// _sort_model = new QSortFilterProxyModel(this);
|
||||
_sort_model = new NoggitExpendableFilterProxyModel;
|
||||
_sort_model->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||
_sort_model->setFilterRole(Qt::UserRole);
|
||||
_sort_model->setRecursiveFilteringEnabled(true);
|
||||
@@ -91,15 +92,24 @@ AssetBrowserWidget::AssetBrowserWidget(MapView* map_view, QWidget *parent)
|
||||
connect(ui->listfileTree->selectionModel(), &QItemSelectionModel::selectionChanged
|
||||
,[=] (const QItemSelection& selected, const QItemSelection& deselected)
|
||||
{
|
||||
for (auto index : selected.indexes())
|
||||
for (auto const& index : selected.indexes())
|
||||
{
|
||||
auto path = index.data(Qt::UserRole).toString();
|
||||
if (path.endsWith(".m2") || path.endsWith(".wmo"))
|
||||
{
|
||||
auto str_path = path.toStdString();
|
||||
|
||||
ui->viewport->setModel(str_path);
|
||||
_map_view->getObjectEditor()->copy(str_path);
|
||||
_selected_path = str_path;
|
||||
|
||||
if (_browse_mode == asset_browse_mode::detail_doodads && _map_view->get_editing_mode() == editing_mode::paint)
|
||||
{
|
||||
_map_view->getGroundEffectsTool()->setDoodadSlotFromBrowser(str_path.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
_map_view->getObjectEditor()->copy(str_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,6 +273,80 @@ void AssetBrowserWidget::setupConnectsCommon()
|
||||
[this](bool state) {ui->viewport->_draw_grid.set(state);});
|
||||
}
|
||||
|
||||
bool AssetBrowserWidget::validateBrowseMode(QString wow_file_path)
|
||||
{
|
||||
// TODO : do it in sort model instead?
|
||||
switch (_browse_mode)
|
||||
{
|
||||
case asset_browse_mode::ALL:
|
||||
return true;
|
||||
case asset_browse_mode::world:
|
||||
{
|
||||
if (wow_file_path.startsWith("World", Qt::CaseInsensitive))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
case asset_browse_mode::detail_doodads:
|
||||
{
|
||||
if (wow_file_path.startsWith("world/nodxt/detail/", Qt::CaseInsensitive)
|
||||
&& wow_file_path.endsWith(".m2"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
case asset_browse_mode::skybox:
|
||||
{
|
||||
if (wow_file_path.startsWith("environments/stars", Qt::CaseInsensitive)
|
||||
&& wow_file_path.endsWith(".m2"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
case asset_browse_mode::creatures:
|
||||
{
|
||||
if (wow_file_path.startsWith("creature", Qt::CaseInsensitive)
|
||||
&& wow_file_path.endsWith(".m2"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
case asset_browse_mode::characters:
|
||||
{
|
||||
if (wow_file_path.startsWith("character", Qt::CaseInsensitive)
|
||||
&& wow_file_path.endsWith(".m2"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
case asset_browse_mode::particles:
|
||||
{
|
||||
if (wow_file_path.startsWith("particles", Qt::CaseInsensitive)
|
||||
&& wow_file_path.endsWith(".m2"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
case asset_browse_mode::cameras:
|
||||
{
|
||||
if (wow_file_path.startsWith("cameras", Qt::CaseInsensitive)
|
||||
&& wow_file_path.endsWith(".m2"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
case asset_browse_mode::items:
|
||||
{
|
||||
if (wow_file_path.startsWith("item", Qt::CaseInsensitive)
|
||||
&& wow_file_path.endsWith(".m2"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
case asset_browse_mode::spells:
|
||||
{
|
||||
if (wow_file_path.startsWith("SPELLS", Qt::CaseInsensitive)
|
||||
&& wow_file_path.endsWith(".m2"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return false; // ?
|
||||
}
|
||||
}
|
||||
|
||||
// Add WMOs and M2s from project directory recursively
|
||||
void AssetBrowserWidget::recurseDirectory(Model::TreeManager& tree_mgr, const QString& s_dir, const QString& project_dir)
|
||||
{
|
||||
@@ -286,13 +370,19 @@ void AssetBrowserWidget::recurseDirectory(Model::TreeManager& tree_mgr, const QS
|
||||
|| q_path.endsWith(".m2")))
|
||||
continue;
|
||||
|
||||
tree_mgr.addItem(QDir(project_dir).relativeFilePath(q_path.toStdString().c_str()));
|
||||
QString rel_path = QDir(project_dir).relativeFilePath(q_path.toStdString().c_str());
|
||||
|
||||
if (!validateBrowseMode(rel_path))
|
||||
continue;
|
||||
|
||||
tree_mgr.addItem(rel_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssetBrowserWidget::updateModelData()
|
||||
{
|
||||
_model->clear();
|
||||
Model::TreeManager tree_mgr = Model::TreeManager(_model);
|
||||
for (auto& key_pair : Noggit::Application::NoggitApplication::instance()->clientData()->listfile()->pathToFileDataIDMap())
|
||||
{
|
||||
@@ -304,6 +394,9 @@ void AssetBrowserWidget::updateModelData()
|
||||
|| q_path.endsWith(".m2")))
|
||||
continue;
|
||||
|
||||
if (!validateBrowseMode(q_path))
|
||||
continue;
|
||||
|
||||
tree_mgr.addItem(filename.c_str());
|
||||
}
|
||||
|
||||
@@ -314,6 +407,12 @@ void AssetBrowserWidget::updateModelData()
|
||||
|
||||
_sort_model->setSortRole(Qt::UserRole);
|
||||
_sort_model->sort(0, Qt::AscendingOrder);
|
||||
|
||||
// TODO : set default layout for the modes
|
||||
if (_browse_mode != asset_browse_mode::ALL)
|
||||
{
|
||||
// expend base directories
|
||||
}
|
||||
}
|
||||
|
||||
AssetBrowserWidget::~AssetBrowserWidget()
|
||||
@@ -322,10 +421,52 @@ AssetBrowserWidget::~AssetBrowserWidget()
|
||||
delete _preview_renderer;
|
||||
}
|
||||
|
||||
void AssetBrowserWidget::set_browse_mode(asset_browse_mode browse_mode)
|
||||
{
|
||||
_browse_mode = browse_mode;
|
||||
updateModelData();
|
||||
// if (_browse_mode == asset_browse_mode::detail_doodads)
|
||||
// {
|
||||
// _sort_model->setFilterFixedString("world/nodxt/detail");
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
void AssetBrowserWidget::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return)
|
||||
{
|
||||
QString text = ui->searchField->text();
|
||||
_sort_model->setFilterFixedString(ui->searchField->text());
|
||||
ui->listfileTree->collapseAll();
|
||||
if (text.isEmpty() || text.length() < 3) // too few characters is too performance expensive, require 3
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// todo : crashes when typics something like creature
|
||||
|
||||
ui->listfileTree->expandAll();
|
||||
|
||||
// QList<QModelIndex> acceptedIndices = _sort_model->findIndices();
|
||||
// for (auto& index : acceptedIndices)
|
||||
// {
|
||||
// if (!index.isValid())
|
||||
// continue;
|
||||
// ui->listfileTree->expand(index);
|
||||
//
|
||||
// auto expanderIndex = index.parent();
|
||||
// while (expanderIndex.isValid())
|
||||
// {
|
||||
// if (!ui->listfileTree->isExpanded(expanderIndex))
|
||||
// {
|
||||
// ui->listfileTree->expand(expanderIndex);
|
||||
// expanderIndex = expanderIndex.parent();
|
||||
// }
|
||||
// else
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,65 @@
|
||||
|
||||
class MapView;
|
||||
|
||||
// custom model that makes the searched children expend, credit to https://stackoverflow.com/questions/56781145/expand-specific-items-in-a-treeview-during-filtering
|
||||
class NoggitExpendableFilterProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QList<QModelIndex> findIndices() const
|
||||
{
|
||||
QList<QModelIndex> ret;
|
||||
for (auto iter = 0; iter < rowCount(); iter++)
|
||||
{
|
||||
auto childIndex = index(iter, 0, QModelIndex());
|
||||
ret << recursivelyFindIndices(childIndex);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool rowAccepted(int source_row, const QModelIndex& source_parent) const
|
||||
{
|
||||
return filterAcceptsRow(source_row, source_parent);
|
||||
}
|
||||
private:
|
||||
QList<QModelIndex> recursivelyFindIndices(const QModelIndex& ind) const
|
||||
{
|
||||
QList<QModelIndex> ret;
|
||||
if (rowAccepted(ind.row(), ind.parent()))
|
||||
{
|
||||
ret << ind;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto iter = 0; iter < rowCount(ind); iter++)
|
||||
{
|
||||
ret << recursivelyFindIndices(index(iter, 0, ind));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
namespace Noggit::Ui::Tools::AssetBrowser
|
||||
{
|
||||
enum class asset_browse_mode
|
||||
{
|
||||
world, // any wmo and m2 in world folder. exclude detail doodads?
|
||||
detail_doodads, // "world/nodxt/detail/
|
||||
skybox, // environements folder. used by LightSkybox
|
||||
creatures,
|
||||
characters,
|
||||
particles,
|
||||
cameras,
|
||||
items,
|
||||
spells,
|
||||
ALL
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
namespace Noggit
|
||||
{
|
||||
namespace Ui::Tools::AssetBrowser::Ui
|
||||
@@ -26,6 +85,9 @@ namespace Noggit
|
||||
~AssetBrowserWidget();
|
||||
std::string const& getFilename() { return _selected_path; };
|
||||
|
||||
void set_browse_mode(asset_browse_mode browse_mode);
|
||||
|
||||
asset_browse_mode _browse_mode = asset_browse_mode::world;
|
||||
signals:
|
||||
void gl_data_unloaded();
|
||||
|
||||
@@ -33,7 +95,7 @@ namespace Noggit
|
||||
::Ui::AssetBrowser* ui;
|
||||
::Ui::AssetBrowserOverlay* viewport_overlay_ui;
|
||||
QStandardItemModel* _model;
|
||||
QSortFilterProxyModel* _sort_model;
|
||||
NoggitExpendableFilterProxyModel* _sort_model;
|
||||
PreviewRenderer* _preview_renderer;
|
||||
QRegularExpression _wmo_group_and_lod_regex;
|
||||
MapView* _map_view;
|
||||
@@ -41,6 +103,7 @@ namespace Noggit
|
||||
|
||||
void updateModelData();
|
||||
void recurseDirectory(Model::TreeManager& tree_mgr, const QString& s_dir, const QString& project_dir);
|
||||
bool validateBrowseMode(QString wow_file_path);
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent* event) override;
|
||||
|
||||
@@ -329,6 +329,7 @@ void ChunkAddDetailDoodads::compute()
|
||||
+ std::string{gGroundEffectDoodadDB.getByID(curDoodadId)
|
||||
.getString(GroundEffectDoodadDB::Filename)}).c_str()};
|
||||
filename = filename.replace(".mdx", ".m2", Qt::CaseInsensitive);
|
||||
filename = filename.replace(".mdl", ".m2", Qt::CaseInsensitive);
|
||||
|
||||
world->addM2(filename.toStdString(), {chunk->xbase - inMinichunkCoords[0]
|
||||
, 0, chunk->zbase - inMinichunkCoords[1]}, 1.0, {math::degrees(0)._, math::degrees(0)._, math::degrees(0)._ }, nullptr);
|
||||
|
||||
@@ -28,7 +28,8 @@ void AddObjectInstanceToSelectionNode::compute()
|
||||
|
||||
SceneObject* obj = defaultPortData<ObjectInstanceData>(PortType::In, 1)->value();
|
||||
|
||||
world->add_to_selection(obj);
|
||||
if (!world->is_selected(obj))
|
||||
world->add_to_selection(obj);
|
||||
|
||||
_out_ports[0].out_value = std::make_shared<LogicData>(true);
|
||||
_node->onDataUpdated(0);
|
||||
|
||||
@@ -38,7 +38,7 @@ void ViewportGizmo::handleTransformGizmo(MapView* map_view
|
||||
|
||||
int n_selected = static_cast<int>(selection.size());
|
||||
|
||||
if (!n_selected || (n_selected == 1 & selection[0].index() != eEntry_Object))
|
||||
if (!n_selected || (n_selected == 1 && selection[0].index() != eEntry_Object))
|
||||
return;
|
||||
|
||||
if (n_selected == 1)
|
||||
|
||||
@@ -58,7 +58,10 @@ namespace OpenGL
|
||||
int climb_use_smooth_interpolation = false;
|
||||
float climb_value;
|
||||
int draw_vertex_color = true;
|
||||
int padding[3];
|
||||
int draw_groundeffectid_overlay = false;
|
||||
int draw_groundeffect_layerid_overlay = false;
|
||||
int draw_noeffectdoodad_overlay = false;
|
||||
// int padding[3];
|
||||
};
|
||||
|
||||
struct ChunkInstanceDataUniformBlock
|
||||
@@ -71,6 +74,8 @@ namespace OpenGL
|
||||
int AreaIDColor_Pad2_DrawSelection[4];
|
||||
int ChunkXZ_TileXZ[4];
|
||||
int ChunkTexAnimDir[4];
|
||||
float ChunkGroundEffectColor[4];
|
||||
int ChunkDoodadsEnabled2_ChunksLayerEnabled2[4];
|
||||
};
|
||||
|
||||
struct LiquidChunkInstanceDataUniformBlock
|
||||
|
||||
Reference in New Issue
Block a user