From d93dbc55adbee85614016bcbc5aa75b3ccc1e1e8 Mon Sep 17 00:00:00 2001 From: Martin Benjamins Date: Fri, 1 Nov 2024 02:48:08 +0000 Subject: [PATCH] Modern features (height texturing, WMO scaling, maptexture generation) --- src/math/ray.hpp | 1 + src/noggit/Action.cpp | 4 +- src/noggit/MapChunk.cpp | 2 +- src/noggit/MapHeaders.h | 2 +- src/noggit/MapTile.cpp | 27 +++- src/noggit/MapTile.h | 4 + src/noggit/MapView.cpp | 20 ++- src/noggit/MinimapRenderSettings.hpp | 12 +- src/noggit/TextureManager.cpp | 32 ++++- src/noggit/TextureManager.h | 20 +++ src/noggit/WMO.cpp | 2 +- src/noggit/WMO.h | 2 +- src/noggit/WMOInstance.cpp | 15 +- src/noggit/WMOInstance.h | 5 +- src/noggit/World.cpp | 127 +++++++++++++---- src/noggit/World.h | 8 +- src/noggit/project/ApplicationProject.cpp | 93 ++++++++++++ src/noggit/project/ApplicationProject.h | 33 +++++ src/noggit/rendering/ModelRender.cpp | 6 + src/noggit/rendering/TileRender.cpp | 70 ++++++++-- src/noggit/rendering/WMOGroupRender.cpp | 30 +++- src/noggit/rendering/WorldRender.cpp | 48 ++++++- src/noggit/rendering/glsl/terrain_frag.glsl | 94 ++++++++++++- src/noggit/rendering/glsl/terrain_vert.glsl | 8 ++ src/noggit/rendering/glsl/wmo_frag.glsl | 4 + src/noggit/scripting/script_global.cpp | 8 ++ src/noggit/scripting/script_model.cpp | 5 +- src/noggit/texture_set.cpp | 7 + src/noggit/texture_set.hpp | 5 + src/noggit/tools/MinimapTool.cpp | 22 +++ src/noggit/tools/ObjectTool.cpp | 8 +- src/noggit/ui/CurrentTexture.cpp | 1 + src/noggit/ui/MinimapCreator.cpp | 28 +++- src/noggit/ui/MinimapCreator.hpp | 0 src/noggit/ui/ObjectEditor.cpp | 8 +- src/noggit/ui/RotationEditor.cpp | 22 ++- src/noggit/ui/ShaderTool.cpp | 2 +- src/noggit/ui/TexturePicker.cpp | 0 src/noggit/ui/TexturingGUI.cpp | 40 +++--- src/noggit/ui/texturing_tool.cpp | 132 +++++++++++++++++- src/noggit/ui/texturing_tool.hpp | 10 ++ .../ui/tools/LightEditor/LightEditor.cpp | 10 +- .../ui/tools/LightEditor/LightEditor.hpp | 0 .../Nodes/World/Object/AddObjectInstance.cpp | 2 +- .../Nodes/World/Object/ObjectInstanceInfo.cpp | 2 +- .../World/Object/ObjectInstanceSetScale.cpp | 14 +- .../ScaleSelectedObjectInstances.cpp | 6 +- .../ui/tools/ViewportGizmo/ViewportGizmo.cpp | 21 ++- .../windows/settingsPanel/SettingsPanel.cpp | 2 + .../ui/windows/settingsPanel/SettingsPanel.ui | 23 +++ src/opengl/types.hpp | 11 +- 51 files changed, 928 insertions(+), 130 deletions(-) mode change 100755 => 100644 src/noggit/Action.cpp mode change 100755 => 100644 src/noggit/MapChunk.cpp mode change 100755 => 100644 src/noggit/MapTile.cpp mode change 100755 => 100644 src/noggit/MapTile.h mode change 100755 => 100644 src/noggit/MapView.cpp mode change 100755 => 100644 src/noggit/TextureManager.h mode change 100755 => 100644 src/noggit/World.cpp mode change 100755 => 100644 src/noggit/World.h mode change 100755 => 100644 src/noggit/rendering/glsl/terrain_frag.glsl mode change 100755 => 100644 src/noggit/scripting/script_global.cpp mode change 100755 => 100644 src/noggit/scripting/script_model.cpp mode change 100755 => 100644 src/noggit/texture_set.cpp mode change 100755 => 100644 src/noggit/texture_set.hpp mode change 100755 => 100644 src/noggit/ui/MinimapCreator.hpp mode change 100755 => 100644 src/noggit/ui/ObjectEditor.cpp mode change 100755 => 100644 src/noggit/ui/TexturePicker.cpp mode change 100755 => 100644 src/noggit/ui/TexturingGUI.cpp mode change 100755 => 100644 src/noggit/ui/texturing_tool.cpp mode change 100755 => 100644 src/noggit/ui/texturing_tool.hpp mode change 100755 => 100644 src/noggit/ui/tools/LightEditor/LightEditor.cpp mode change 100755 => 100644 src/noggit/ui/tools/LightEditor/LightEditor.hpp mode change 100755 => 100644 src/noggit/ui/tools/NodeEditor/Nodes/World/Object/AddObjectInstance.cpp mode change 100755 => 100644 src/noggit/ui/windows/settingsPanel/SettingsPanel.cpp diff --git a/src/math/ray.hpp b/src/math/ray.hpp index 25f22f1b..92919987 100755 --- a/src/math/ray.hpp +++ b/src/math/ray.hpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace math { diff --git a/src/noggit/Action.cpp b/src/noggit/Action.cpp old mode 100755 new mode 100644 index 40609aea..126ca36e --- a/src/noggit/Action.cpp +++ b/src/noggit/Action.cpp @@ -246,7 +246,7 @@ unsigned Noggit::Action::handleObjectAdded(unsigned uid, bool redo) unsigned old_uid = pair.first; SceneObject* obj; if (pair.second.type == ActionObjectTypes::WMO) - obj = _map_view->getWorld()->addWMOAndGetInstance(pair.second.file_key, pair.second.pos, pair.second.dir, false); + obj = _map_view->getWorld()->addWMOAndGetInstance(pair.second.file_key, pair.second.pos, pair.second.dir, pair.second.scale, false); else obj = _map_view->getWorld()->addM2AndGetInstance(pair.second.file_key, pair.second.pos, pair.second.scale, pair.second.dir, nullptr, false, false); @@ -310,7 +310,7 @@ unsigned Noggit::Action::handleObjectRemoved(unsigned uid, bool redo) unsigned old_uid = pair.first; SceneObject* obj; if (pair.second.type == ActionObjectTypes::WMO) - obj = _map_view->getWorld()->addWMOAndGetInstance(pair.second.file_key, pair.second.pos, pair.second.dir, false); + obj = _map_view->getWorld()->addWMOAndGetInstance(pair.second.file_key, pair.second.pos, pair.second.dir, pair.second.scale, false); else obj = _map_view->getWorld()->addM2AndGetInstance(pair.second.file_key, pair.second.pos, pair.second.scale, pair.second.dir, nullptr, false, false); diff --git a/src/noggit/MapChunk.cpp b/src/noggit/MapChunk.cpp old mode 100755 new mode 100644 index 98e23e52..21fb32ed --- a/src/noggit/MapChunk.cpp +++ b/src/noggit/MapChunk.cpp @@ -1762,7 +1762,7 @@ void MapChunk::save(util::sExtendableArray& lADTFile header_ptr->ofsLiquid = lCurrentPosition - lMCNK_Position; // When saving a tile that had MLCQ, also remove flags in MCNK - // Client sees the flag and loads random data as if it were MCLQ, which we dont save. + // Client sees the flag and loads random data as if it were MCLQ, which we dont save. // clear MCLQ liquid flags (0x4, 0x8, 0x10, 0x20) header_ptr->flags.value &= 0xFFFFFFC3; diff --git a/src/noggit/MapHeaders.h b/src/noggit/MapHeaders.h index 5bc86fe0..f3bbace9 100755 --- a/src/noggit/MapHeaders.h +++ b/src/noggit/MapHeaders.h @@ -121,7 +121,7 @@ struct ENTRY_MODF uint16_t flags; uint16_t doodadSet; uint16_t nameSet; - uint16_t unknown; + uint16_t scale; }; struct MapChunkHeader { diff --git a/src/noggit/MapTile.cpp b/src/noggit/MapTile.cpp old mode 100755 new mode 100644 index 8b113078..031c0e5e --- a/src/noggit/MapTile.cpp +++ b/src/noggit/MapTile.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -259,6 +260,8 @@ void MapTile::finishLoading() for (unsigned int i = 0; i < size / sizeof(ENTRY_MODF); ++i) { lWMOInstances.push_back(modf_ptr[i]); + if(lWMOInstances[i].scale == 0.0f) + lWMOInstances[i].scale = 1024.0f; } } @@ -860,7 +863,7 @@ void MapTile::save(World* world, bool save_using_mclq_liquids) lMODF_Data[lID].flags = object->mFlags; lMODF_Data[lID].doodadSet = object->doodadset(); lMODF_Data[lID].nameSet = object->mNameset; - lMODF_Data[lID].unknown = object->mUnknown; + lMODF_Data[lID].scale = (uint16_t)(object->scale * 1024); lID++; } @@ -1777,6 +1780,24 @@ void MapTile::calcCamDist(glm::vec3 const& camera) _cam_dist = glm::distance(camera, _center); } +const texture_heightmapping_data& MapTile::GetTextureHeightMappingData(const std::string& name) const +{ + return Noggit::Project::CurrentProject::get()->ExtraMapData.GetTextureHeightDataForADT(_world->mapIndex._map_id, index,name); +} + +void MapTile::forceAlphaUpdate() +{ + for (int i = 0; i < 16; ++i) + { + for (int j = 0; j < 16; ++j) + { + auto chunk = mChunks[i][j].get(); + auto texSet = chunk->getTextureSet(); + texSet->markDirty(); + } + } +} + bool MapTile::childrenFinishedLoading() { if (!objectsFinishedLoading()) @@ -1864,6 +1885,4 @@ void MapTile::recalcCombinedExtents() } _combined_extents_dirty = false; -} - - +} \ No newline at end of file diff --git a/src/noggit/MapTile.h b/src/noggit/MapTile.h old mode 100755 new mode 100644 index 8dbf92da..c577a45e --- a/src/noggit/MapTile.h +++ b/src/noggit/MapTile.h @@ -177,6 +177,9 @@ public: Noggit::Rendering::TileRender* renderer() { return &_renderer; }; Noggit::Rendering::FlightBoundsRender* flightBoundsRenderer() { return &_fl_bounds_render; }; + const texture_heightmapping_data& GetTextureHeightMappingData(const std::string& name) const; + + void forceAlphaUpdate(); bool childrenFinishedLoading(); bool texturesFinishedLoading(); bool objectsFinishedLoading(); @@ -191,6 +194,7 @@ private: bool _requires_object_extents_recalc = true; + std::array _extents; std::array _object_instance_extents; std::array _combined_extents; diff --git a/src/noggit/MapView.cpp b/src/noggit/MapView.cpp old mode 100755 new mode 100644 index 766ba751..ef91edaa --- a/src/noggit/MapView.cpp +++ b/src/noggit/MapView.cpp @@ -103,6 +103,7 @@ #include #include #include +#include #include #include @@ -267,6 +268,8 @@ void MapView::set_editing_mode(editing_mode mode) _world->renderer()->getTerrainParamsUniformBlock()->draw_groundeffectid_overlay = false; _world->renderer()->getTerrainParamsUniformBlock()->draw_groundeffect_layerid_overlay = false; _world->renderer()->getTerrainParamsUniformBlock()->draw_noeffectdoodad_overlay = false; + _world->renderer()->getTerrainParamsUniformBlock()->draw_only_normals = false; + _world->renderer()->getTerrainParamsUniformBlock()->point_normals_up = false; _minimap->use_selection(nullptr); if (terrainMode != mode) @@ -331,6 +334,7 @@ void MapView::ResetSelectedObjectRotation() WMOInstance* wmo = static_cast(obj); _world->updateTilesWMO(wmo, model_update::remove); wmo->resetDirection(); + wmo->recalcExtents(); _world->updateTilesWMO(wmo, model_update::add); } else if (obj->which() == eMODEL) @@ -3148,12 +3152,12 @@ void MapView::tick (float dt) . arg (std::floor (_camera.position.z / TILESIZE)) ); status += ( QString ("; coordinates client: (%1, %2, %3), server: (%4, %5, %6)") - . arg (_camera.position.x) - . arg (_camera.position.z) - . arg (_camera.position.y) - . arg (ZEROPOINT - _camera.position.z) - . arg (ZEROPOINT - _camera.position.x) - . arg (_camera.position.y) + . arg (_camera.position.x, 0, 'f', 2) + . arg (_camera.position.z, 0, 'f', 2) + . arg (_camera.position.y, 0, 'f', 2) + . arg (ZEROPOINT - _camera.position.z, 0, 'f', 2) + . arg (ZEROPOINT - _camera.position.x, 0, 'f', 2) + . arg (_camera.position.y, 0, 'f', 2) ); _status_position->setText (status); @@ -3200,6 +3204,10 @@ void MapView::tick (float dt) } } } + else + { + _status_selection->setText(QString::number(currentSelection.size()) + " objects selected"); + } if (selection_changed || NOGGIT_CUR_ACTION) updateDetailInfos(); // checks if sel changed diff --git a/src/noggit/MinimapRenderSettings.hpp b/src/noggit/MinimapRenderSettings.hpp index 4a812c33..f4c14e18 100644 --- a/src/noggit/MinimapRenderSettings.hpp +++ b/src/noggit/MinimapRenderSettings.hpp @@ -13,13 +13,15 @@ enum MinimapGenMode { CURRENT_ADT, SELECTED_ADTS, - MAP + MAP, + LOD_MAPTEXTURES, + LOD_MAPTEXTURES_N, }; struct MinimapRenderSettings { MinimapGenMode export_mode = CURRENT_ADT; - std::string file_format = ".blp"; + std::string file_format = ".blp (DXT1)"; // Render settings int resolution = 512; @@ -31,11 +33,13 @@ struct MinimapRenderSettings bool draw_shadows = false; bool use_filters = false; bool combined_minimap = false; + bool draw_only_normals = false; + bool point_normals_up = false; // Selection - // std::array selected_tiles = {false}; + // std::array selected_tiles = {false}; - std::vector selected_tiles = std::vector( size_t{4096}, false, {} ); + std::vector selected_tiles = std::vector(size_t{ 4096 }, false, {}); // Filtering QListWidget* m2_model_filter_include = nullptr; diff --git a/src/noggit/TextureManager.cpp b/src/noggit/TextureManager.cpp index 6c0f3b98..1d897cee 100755 --- a/src/noggit/TextureManager.cpp +++ b/src/noggit/TextureManager.cpp @@ -269,6 +269,16 @@ void blp_texture::upload() void blp_texture::unload() { _uploaded = false; + finished = false; + if (hasHeightMap() && heightMap) + { + heightMap->unload(); + } + _compression_format.reset(); + _texture_array = 0; + _array_index = -1; + _data.clear(); + _compressed_data.clear(); // load data back from file. pretty sad. maybe keep it after loading? finishLoading(); @@ -402,10 +412,10 @@ void blp_texture::finishLoading() LogError << "file not found: '" << _file_key.stringRepr() << "'" << std::endl; } - std::string spec_filename; - bool has_specular = false; + std::string spec_filename = "", height_filename = ""; + bool has_specular = false, has_height = false; - if (_file_key.filepath().starts_with("tileset/")) + if (_file_key.filepath().starts_with("tileset/") ) { _is_tileset = true; @@ -416,6 +426,22 @@ void blp_texture::finishLoading() { _is_specular = true; } + + QSettings settings; + bool modern_features = settings.value("modern_features", false).toBool(); + + // Only load _h in map view when modern features are enabled + if(_context == Noggit::NoggitRenderContext::MAP_VIEW && modern_features) + { + height_filename = _file_key.filepath().substr(0, _file_key.filepath().find_last_of(".")) + "_h.blp"; + has_height = Noggit::Application::NoggitApplication::instance()->clientData()->exists(height_filename); + if (has_height) + { + _has_heightmap = true; + heightMap = std::make_unique(height_filename,_context); + heightMap->finishLoading(); + } + } } BlizzardArchive::ClientFile f( diff --git a/src/noggit/TextureManager.h b/src/noggit/TextureManager.h old mode 100755 new mode 100644 index 778090ef..e6b3f929 --- a/src/noggit/TextureManager.h +++ b/src/noggit/TextureManager.h @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -23,6 +24,19 @@ #include +struct texture_heightmapping_data +{ + texture_heightmapping_data(uint32_t scale = 0, float heightscale = 0, float heightoffset = 1.0f) + { + uvScale = scale; + heightScale = heightscale; + heightOffset = heightoffset; + } + uint32_t uvScale = 0; + float heightScale = 0.0f; + float heightOffset = 1.0f; +}; + struct tuple_hash { template @@ -73,7 +87,10 @@ struct blp_texture : public AsyncObject { return async_priority::high; } + // Mists HeightMapping + bool hasHeightMap() {return _has_heightmap; }; + blp_texture* getHeightMap() { return heightMap.get(); }; private: bool _uploaded = false; @@ -84,6 +101,7 @@ private: bool _is_specular = false; bool _is_tileset = false; + bool _has_heightmap = false; private: std::map> _data; @@ -91,6 +109,8 @@ private: std::optional _compression_format; int _array_index = -1; GLuint _texture_array = 0; + + std::unique_ptr heightMap; }; struct TexArrayParams diff --git a/src/noggit/WMO.cpp b/src/noggit/WMO.cpp index c586634c..46af4ba7 100755 --- a/src/noggit/WMO.cpp +++ b/src/noggit/WMO.cpp @@ -131,7 +131,7 @@ void WMO::finishLoading () f.read(&materials[i], sizeof(WMOMaterial)); uint32_t shader = materials[i].shader; - bool use_second_texture = (shader == 6 || shader == 5 || shader == 3); + bool use_second_texture = (shader == 6 || shader == 5 || shader == 3 || shader == 21 || shader == 23); materials[i].texture1 = load_texture(materials[i].texture_offset_1); if (use_second_texture) diff --git a/src/noggit/WMO.h b/src/noggit/WMO.h index 3e554176..eb72a003 100755 --- a/src/noggit/WMO.h +++ b/src/noggit/WMO.h @@ -38,7 +38,7 @@ namespace Noggit::Rendering struct wmo_batch { - int8_t unused[12]; + int16_t unused[6]; uint32_t index_start; uint16_t index_count; diff --git a/src/noggit/WMOInstance.cpp b/src/noggit/WMOInstance.cpp index cbcef090..15853590 100755 --- a/src/noggit/WMOInstance.cpp +++ b/src/noggit/WMOInstance.cpp @@ -13,11 +13,13 @@ #include +#include + WMOInstance::WMOInstance(BlizzardArchive::Listfile::FileKey const& file_key, ENTRY_MODF const* d, Noggit::NoggitRenderContext context) : SceneObject(SceneObjectTypes::eWMO, context) , wmo(file_key, context) , mFlags(d->flags) - , mUnknown(d->unknown), mNameset(d->nameSet) + , mNameset(d->nameSet) , _doodadset(d->doodadSet) { pos = glm::vec3(d->pos[0], d->pos[1], d->pos[2]); @@ -25,6 +27,16 @@ WMOInstance::WMOInstance(BlizzardArchive::Listfile::FileKey const& file_key, ENT uid = d->uniqueID; + QSettings settings; + bool modern_features = settings.value("modern_features", false).toBool(); + + if (modern_features) { + scale = static_cast(d->scale) / 1024.0f; + } + else { + scale = 1.0f; + } + extents[0] = glm::vec3(d->extents[0][0], d->extents[0][1], d->extents[0][2]); extents[1] = glm::vec3(d->extents[1][0], d->extents[1][1], d->extents[1][2]); @@ -37,7 +49,6 @@ WMOInstance::WMOInstance(BlizzardArchive::Listfile::FileKey const& file_key, Nog : SceneObject(SceneObjectTypes::eWMO, context) , wmo(file_key, context) , mFlags(0) - , mUnknown(0) , mNameset(0) , _doodadset(0) { diff --git a/src/noggit/WMOInstance.h b/src/noggit/WMOInstance.h index 228ffa9b..ab32d9fe 100755 --- a/src/noggit/WMOInstance.h +++ b/src/noggit/WMOInstance.h @@ -16,7 +16,6 @@ public: scoped_wmo_reference wmo; uint16_t mFlags; - uint16_t mUnknown; uint16_t mNameset; uint16_t doodadset() const { return _doodadset; } @@ -48,7 +47,6 @@ public: , wmo (std::move (other.wmo)) , group_extents(other.group_extents) , mFlags (other.mFlags) - , mUnknown (other.mUnknown) , mNameset (other.mNameset) , _doodadset (other._doodadset) , _doodads_per_group(other._doodads_per_group) @@ -57,6 +55,7 @@ public: { std::swap (extents, other.extents); pos = other.pos; + scale = other.scale; dir = other.dir; _context = other._context; uid = other.uid; @@ -73,8 +72,8 @@ public: std::swap(group_extents, other.group_extents); std::swap(dir, other.dir); std::swap(uid, other.uid); + std::swap(scale, other.scale); std::swap(mFlags, other.mFlags); - std::swap(mUnknown, other.mUnknown); std::swap(mNameset, other.mNameset); std::swap(_doodadset, other._doodadset); std::swap(_doodads_per_group, other._doodads_per_group); diff --git a/src/noggit/World.cpp b/src/noggit/World.cpp old mode 100755 new mode 100644 index 12c6d003..2033956a --- a/src/noggit/World.cpp +++ b/src/noggit/World.cpp @@ -772,11 +772,15 @@ void World::snap_selected_models_to_the_ground() update_selected_model_groups(); } -void World::scale_selected_models(float v, m2_scaling_type type) +void World::scale_selected_models(float v, object_scaling_type type) { ZoneScoped; if (!_selected_model_count) return; + + QSettings settings; + bool modern_features = settings.value("modern_features", false).toBool(); + for (auto& entry : _current_selection) { if (entry.index() == eEntry_Object) @@ -784,37 +788,72 @@ void World::scale_selected_models(float v, m2_scaling_type type) auto obj = std::get(entry); if (obj->which() != eMODEL) - continue; - - ModelInstance* mi = static_cast(obj); - - NOGGIT_CUR_ACTION->registerObjectTransformed(mi); - - float scale = mi->scale; - - switch (type) { - case World::m2_scaling_type::set: - scale = v; - break; - case World::m2_scaling_type::add: - scale += v; - break; - case World::m2_scaling_type::mult: - scale *= v; - break; - } + // If we are not using modern features, we don't want to scale WMOs + if(!modern_features) + continue; - // if the change is too small, do nothing - if (std::abs(scale - mi->scale) < ModelInstance::min_scale()) - { - continue; - } + WMOInstance* wi = static_cast(obj); - updateTilesModel(mi, model_update::remove); - mi->scale = std::min(ModelInstance::max_scale(), std::max(ModelInstance::min_scale(), scale)); - mi->recalcExtents(); - updateTilesModel(mi, model_update::add); + NOGGIT_CUR_ACTION->registerObjectTransformed(wi); + + float scale = wi->scale; + + switch (type) + { + case World::object_scaling_type::set: + scale = v; + break; + case World::object_scaling_type::add: + scale += v; + break; + case World::object_scaling_type::mult: + scale *= v; + break; + } + + // if the change is too small, do nothing + if (std::abs(scale - wi->scale) < ModelInstance::min_scale()) + { + continue; + } + + updateTilesWMO(wi, model_update::remove); + wi->scale = std::min(ModelInstance::max_scale(), std::max(ModelInstance::min_scale(), scale)); + wi->recalcExtents(); + updateTilesWMO(wi, model_update::add); + } + else { + ModelInstance* mi = static_cast(obj); + + NOGGIT_CUR_ACTION->registerObjectTransformed(mi); + + float scale = mi->scale; + + switch (type) + { + case World::object_scaling_type::set: + scale = v; + break; + case World::object_scaling_type::add: + scale += v; + break; + case World::object_scaling_type::mult: + scale *= v; + break; + } + + // if the change is too small, do nothing + if (std::abs(scale - mi->scale) < ModelInstance::min_scale()) + { + continue; + } + + updateTilesModel(mi, model_update::remove); + mi->scale = std::min(ModelInstance::max_scale(), std::max(ModelInstance::min_scale(), scale)); + mi->recalcExtents(); + updateTilesModel(mi, model_update::add); + } } } update_selected_model_groups(); @@ -2026,7 +2065,9 @@ ModelInstance* World::addM2AndGetInstance ( BlizzardArchive::Listfile::FileKey c void World::addWMO ( BlizzardArchive::Listfile::FileKey const& file_key , glm::vec3 newPos + , float scale , math::degrees::vec3 rotation + , Noggit::object_paste_params* paste_params , bool action ) { @@ -2037,6 +2078,32 @@ void World::addWMO ( BlizzardArchive::Listfile::FileKey const& file_key wmo_instance.pos = newPos; wmo_instance.dir = rotation; + if (paste_params) + { + if (_settings->value("model/random_rotation", false).toBool()) + { + float min = paste_params->minRotation; + float max = paste_params->maxRotation; + wmo_instance.dir.y += math::degrees(misc::randfloat(min, max))._; + } + + if (_settings->value("model/random_tilt", false).toBool()) + { + float min = paste_params->minTilt; + float max = paste_params->maxTilt; + wmo_instance.dir.x += math::degrees(misc::randfloat(min, max))._; + wmo_instance.dir.z += math::degrees(misc::randfloat(min, max))._; + } + + if (_settings->value("model/random_size", false).toBool()) + { + float min = paste_params->minScale; + float max = paste_params->maxScale; + wmo_instance.scale = misc::randfloat(min, max); + } + } + + // to ensure the tiles are updated correctly wmo_instance.wmo->wait_until_loaded(); wmo_instance.recalcExtents(); @@ -2047,6 +2114,7 @@ void World::addWMO ( BlizzardArchive::Listfile::FileKey const& file_key WMOInstance* World::addWMOAndGetInstance ( BlizzardArchive::Listfile::FileKey const& file_key , glm::vec3 newPos , math::degrees::vec3 rotation + , float scale , bool action ) { @@ -2056,6 +2124,7 @@ WMOInstance* World::addWMOAndGetInstance ( BlizzardArchive::Listfile::FileKey co wmo_instance.uid = mapIndex.newGUID(); wmo_instance.pos = newPos; wmo_instance.dir = rotation; + wmo_instance.scale = scale; // to ensure the tiles are updated correctly wmo_instance.wmo->wait_until_loaded(); diff --git a/src/noggit/World.h b/src/noggit/World.h old mode 100755 new mode 100644 index 3ebd2812..2804ba55 --- a/src/noggit/World.h +++ b/src/noggit/World.h @@ -147,7 +147,7 @@ public: void range_add_to_selection(glm::vec3 const& pos, float radius, bool remove); Noggit::world_model_instances_storage& getModelInstanceStorage() { return _model_instance_storage; }; - enum class m2_scaling_type + enum class object_scaling_type { set, add, @@ -155,7 +155,7 @@ public: }; void snap_selected_models_to_the_ground(); - void scale_selected_models(float v, m2_scaling_type type); + void scale_selected_models(float v, object_scaling_type type); void move_selected_models(float dx, float dy, float dz); void move_model(selection_type entry, float dx, float dy, float dz); void move_selected_models(glm::vec3 const& delta) @@ -289,7 +289,8 @@ public: ); void addWMO ( BlizzardArchive::Listfile::FileKey const& file_key , glm::vec3 newPos - , math::degrees::vec3 rotation + , float scale, math::degrees::vec3 rotation + , Noggit::object_paste_params* , bool action ); @@ -304,6 +305,7 @@ public: WMOInstance* addWMOAndGetInstance ( BlizzardArchive::Listfile::FileKey const& file_key , glm::vec3 newPos , math::degrees::vec3 rotation + , float scale , bool action ); diff --git a/src/noggit/project/ApplicationProject.cpp b/src/noggit/project/ApplicationProject.cpp index e69de29b..085056fa 100755 --- a/src/noggit/project/ApplicationProject.cpp +++ b/src/noggit/project/ApplicationProject.cpp @@ -0,0 +1,93 @@ +#include "ApplicationProject.h" +#include + +namespace Noggit::Project +{ + + + void ApplicationProject::loadExtraData(NoggitProject& project) + { + std::filesystem::path extraDataFolder = (project.ProjectPath); + extraDataFolder /= "extraData"; + + Log << "Loading extra data from " << extraDataFolder << std::endl; + + if (std::filesystem::exists(extraDataFolder) && std::filesystem::is_directory(extraDataFolder)) + { + for (const auto& entry : std::filesystem::directory_iterator(extraDataFolder)) + { + if (entry.path().extension() == ".cfg") + { + QFile input_file(QString::fromStdString(entry.path().generic_string())); + input_file.open(QIODevice::ReadOnly); + QJsonParseError err; + auto document = QJsonDocument().fromJson(input_file.readAll(), &err); + auto root = document.object(); + auto keys = root.keys(); + if (entry.path().stem() == "global") + { + for (auto const& entry : keys) + { + texture_heightmapping_data newData; + newData.uvScale = root[entry].toObject()["Scale"].toInt(); + newData.heightOffset = root[entry].toObject()["HeightOffset"].toDouble(); + newData.heightScale = root[entry].toObject()["HeightScale"].toDouble(); + project.ExtraMapData.SetTextureHeightData_Global(entry.toStdString(), newData); + } + } + } + } + } + } + void NoggitExtraMapData::SetTextureHeightData_Global(const std::string& texture, texture_heightmapping_data data, World* worldToUpdate) + { + TextureHeightData_Global[texture] = data; + if (worldToUpdate) + { + for (MapTile* tile : worldToUpdate->mapIndex.loaded_tiles()) + { + tile->registerChunkUpdate(ChunkUpdateFlags::ALPHAMAP); + tile->forceAlphaUpdate(); + tile->forceRecalcExtents(); + } + } + } + void NoggitExtraMapData::SetTextureHeightDataForADT(int mapID, const TileIndex& ti, const std::string& texture, texture_heightmapping_data data, World* worldToUpdate) + { + TextureHeightData_ADT[mapID][ti.x][ti.z][texture] = data; + if (worldToUpdate) + { + MapTile* tile = worldToUpdate->mapIndex.getTile(ti); + tile->registerChunkUpdate(ChunkUpdateFlags::ALPHAMAP); + tile->forceAlphaUpdate(); + tile->forceRecalcExtents(); + } + } + const texture_heightmapping_data NoggitExtraMapData::GetTextureHeightDataForADT(int mapID, const TileIndex& tileIndex, const std::string& texture) const + { + static texture_heightmapping_data defaultValue; + auto foundMapIter = TextureHeightData_ADT.find(mapID); + if (foundMapIter != TextureHeightData_ADT.end()) + { + auto foundXIter = foundMapIter->second.find(tileIndex.x); + if (foundXIter != foundMapIter->second.end()) + { + auto foundYIter = foundXIter->second.find(tileIndex.z); + if (foundYIter != foundXIter->second.end()) + { + auto foundTexData = foundYIter->second.find(texture); + if (foundTexData != foundYIter->second.end()) + { + return foundTexData->second; + } + } + } + } + auto foundGenericSettings = TextureHeightData_Global.find(texture); + if (foundGenericSettings != TextureHeightData_Global.end()) + { + return foundGenericSettings->second; + } + return defaultValue; + } +}; \ No newline at end of file diff --git a/src/noggit/project/ApplicationProject.h b/src/noggit/project/ApplicationProject.h index 9e3009a7..71b930dc 100755 --- a/src/noggit/project/ApplicationProject.h +++ b/src/noggit/project/ApplicationProject.h @@ -9,6 +9,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -85,6 +88,22 @@ namespace Noggit::Project std::string MapName; }; + struct NoggitExtraMapData + { + public: + //Mists Heightmapping + // Valid for every map that doesn't override its specific data + tsl::robin_map< std::string, texture_heightmapping_data > TextureHeightData_Global; + // MapID,TileX,TileY, SMTextureParams for this specific ADT, fallback to global otherwise. + tsl::robin_map >>> TextureHeightData_ADT; + + void SetTextureHeightData_Global(const std::string& texture, texture_heightmapping_data data, World* worldToUpdate = nullptr); + void SetTextureHeightDataForADT(int mapID, const TileIndex& ti, const std::string& texture, texture_heightmapping_data data, World* worldToUpdate = nullptr); + + const texture_heightmapping_data GetTextureHeightDataForADT(int mapID, const TileIndex& ti, const std::string& texture) const; + }; + struct NoggitProjectObjectPalette { int MapId; @@ -120,6 +139,7 @@ namespace Noggit::Project std::vector TexturePalettes; std::vector ObjectSelectionGroups; + NoggitExtraMapData ExtraMapData; NoggitProject() { PinnedMaps = std::vector(); @@ -330,7 +350,20 @@ namespace Noggit::Project return {}; } + QSettings settings; + bool modern_features = settings.value("modern_features", false).toBool(); + if (modern_features) + { + Log << "Modern Features Enabled" << std::endl; + loadExtraData(project.value()); + } + else + { + Log << "Modern Features Disabled" << std::endl; + } return std::make_shared(project.value()); } + + void loadExtraData(NoggitProject& project); }; } diff --git a/src/noggit/rendering/ModelRender.cpp b/src/noggit/rendering/ModelRender.cpp index 8470bbf7..28e67079 100755 --- a/src/noggit/rendering/ModelRender.cpp +++ b/src/noggit/rendering/ModelRender.cpp @@ -1007,6 +1007,12 @@ void ModelRenderPass::bindTexture(size_t index, Model* m, OpenGL::M2RenderState& } else { + if (m->_specialTextures[tex] >= m->_replaceTextures.size()) + { + LogError << "model: special texture index out of range " << m->file_key().stringRepr() << std::endl; + return; + } + auto& texture = m->_replaceTextures.at (m->_specialTextures[tex]); texture->upload(); GLuint tex_array = texture->texture_array(); diff --git a/src/noggit/rendering/TileRender.cpp b/src/noggit/rendering/TileRender.cpp index 0c043a37..fd565122 100755 --- a/src/noggit/rendering/TileRender.cpp +++ b/src/noggit/rendering/TileRender.cpp @@ -5,6 +5,7 @@ #include #include #include +#include using namespace Noggit::Rendering; @@ -520,18 +521,23 @@ bool TileRender::fillSamplers(MapChunk* chunk, unsigned chunk_index, unsigned i static constexpr unsigned NUM_SAMPLERS = 11; - _chunk_instance_data[chunk_index].ChunkTextureSamplers[0] = 0; - _chunk_instance_data[chunk_index].ChunkTextureSamplers[1] = 0; - _chunk_instance_data[chunk_index].ChunkTextureSamplers[2] = 0; - _chunk_instance_data[chunk_index].ChunkTextureSamplers[3] = 0; + for (int i = 0; i < 4; i++) + { + _chunk_instance_data[chunk_index].ChunkTextureSamplers[i] = 0; + _chunk_instance_data[chunk_index].ChunkTextureArrayIDs[i] = -1; - _chunk_instance_data[chunk_index].ChunkTextureArrayIDs[0] = -1; - _chunk_instance_data[chunk_index].ChunkTextureArrayIDs[1] = -1; - _chunk_instance_data[chunk_index].ChunkTextureArrayIDs[2] = -1; - _chunk_instance_data[chunk_index].ChunkTextureArrayIDs[3] = -1; + // Mists Heightmapping + _chunk_instance_data[chunk_index].ChunkHeightTextureSamplers[i] = 0; + _chunk_instance_data[chunk_index].ChunkTextureUVScale[i] = 0; + _chunk_instance_data[chunk_index].ChunkTextureHeightScale[i] = 0; + _chunk_instance_data[chunk_index].ChunkTextureHeightOffset[i] = 1.0f; + } auto& chunk_textures = (*chunk->texture_set->getTextures()); + QSettings settings; + bool modern_features = settings.value("modern_features", false).toBool(); + for (int k = 0; k < chunk->texture_set->num(); ++k) { chunk_textures[k]->upload(); @@ -542,6 +548,26 @@ bool TileRender::fillSamplers(MapChunk* chunk, unsigned chunk_index, unsigned i continue; } + auto heightRef = chunk_textures[k]->getHeightMap(); + if (chunk_textures[k]->hasHeightMap() && heightRef) + { + heightRef->upload(); + + if(!heightRef->is_uploaded()) + { + _texture_not_loaded = true; + continue; + } + } + + if (modern_features) { + // Mists Heightmapping + auto hData = chunk->mt->GetTextureHeightMappingData(chunk_textures[k]->file_key().filepath()); + _chunk_instance_data[chunk_index].ChunkTextureUVScale[k] = hData.uvScale; + _chunk_instance_data[chunk_index].ChunkTextureHeightScale[k] = hData.heightScale; + _chunk_instance_data[chunk_index].ChunkTextureHeightOffset[k] = hData.heightOffset; + } + GLuint tex_array = (*chunk->texture_set->getTextures())[k]->texture_array(); int tex_index = (*chunk->texture_set->getTextures())[k]->array_index(); @@ -572,7 +598,35 @@ bool TileRender::fillSamplers(MapChunk* chunk, unsigned chunk_index, unsigned i _chunk_instance_data[chunk_index].ChunkTextureSamplers[k] = sampler_id; _chunk_instance_data[chunk_index].ChunkTextureArrayIDs[k] = (*chunk->texture_set->getTextures())[k]->is_specular() ? tex_index : -tex_index; + + if(modern_features && heightRef) + { + GLuint hTex_array = (*chunk->texture_set->getTextures())[k]->getHeightMap()->texture_array(); + sampler_id = -1; + for (int n = 0; n < draw_call.samplers.size(); ++n) + { + if (draw_call.samplers[n] == hTex_array) + { + sampler_id = n; + break; + } + else if (draw_call.samplers[n] < 0) + { + draw_call.samplers[n] = hTex_array; + sampler_id = n; + break; + } + } + + if (sampler_id < 0) + [[unlikely]] + { + return false; + } + + _chunk_instance_data[chunk_index].ChunkHeightTextureSamplers[k] = sampler_id; + } } return true; diff --git a/src/noggit/rendering/WMOGroupRender.cpp b/src/noggit/rendering/WMOGroupRender.cpp index 9a2c29ab..6ef872ef 100755 --- a/src/noggit/rendering/WMOGroupRender.cpp +++ b/src/noggit/rendering/WMOGroupRender.cpp @@ -3,6 +3,7 @@ #include "WMOGroupRender.hpp" #include #include // LogDebug +#include using namespace Noggit::Rendering; @@ -21,7 +22,11 @@ void WMOGroupRender::upload() std::size_t batch_counter = 0; for (auto& batch : _wmo_group->_batches) { - WMOMaterial const& mat (_wmo_group->wmo->materials.at (batch.texture)); + std::uint16_t material_to_use = batch.texture; + if (batch.flags == 2) + material_to_use = batch.unused[5]; + + WMOMaterial const& mat(_wmo_group->wmo->materials.at(material_to_use)); auto& tex1 = _wmo_group->wmo->textures.at(mat.texture1); @@ -33,7 +38,8 @@ void WMOGroupRender::upload() std::uint32_t tex_array1 = 0; std::uint32_t array_index1 = 0; - bool use_tex2 = mat.shader == 6 || mat.shader == 5 || mat.shader == 3; + + bool use_tex2 = mat.shader == 6 || mat.shader == 5 || mat.shader == 3 || mat.shader == 21 || mat.shader == 23; if (use_tex2) { @@ -61,13 +67,20 @@ void WMOGroupRender::upload() _draw_calls.clear(); WMOCombinedDrawCall* draw_call = nullptr; std::vector _used_batches; + QSettings settings; + bool modern_features = settings.value("modern_features", false).toBool(); batch_counter = 0; for (auto& batch : _wmo_group->_batches) { - WMOMaterial& mat = _wmo_group->wmo->materials.at(batch.texture); + std::uint16_t material_to_use = batch.texture; + if (modern_features && batch.flags & 2) + material_to_use = batch.unused[5]; + + WMOMaterial& mat(_wmo_group->wmo->materials.at(material_to_use)); + bool backface_cull = !mat.flags.unculled; - bool use_tex2 = mat.shader == 6 || mat.shader == 5 || mat.shader == 3; + bool use_tex2 = mat.shader == 6 || mat.shader == 5 || mat.shader == 3 || mat.shader == 21 || mat.shader == 23; bool create_draw_call = false; if (draw_call && draw_call->backface_cull == backface_cull && batch.index_start == draw_call->index_start + draw_call->index_count) @@ -336,6 +349,9 @@ void WMOGroupRender::initRenderBatches() _render_batches.resize(_wmo_group->_batches.size()); + QSettings settings; + bool modern_features = settings.value("modern_features", false).toBool(); + std::size_t batch_counter = 0; for (auto& batch : _wmo_group->_batches) { @@ -361,7 +377,11 @@ void WMOGroupRender::initRenderBatches() flags |= WMORenderBatchFlags::eWMOBatch_HasMOCV; } - WMOMaterial const& mat (_wmo_group->wmo->materials.at (batch.texture)); + std::uint16_t material_to_use = batch.texture; + if (modern_features && batch.flags == 2) + material_to_use = batch.unused[5]; + + WMOMaterial const& mat (_wmo_group->wmo->materials.at (material_to_use)); if (mat.flags.unlit) { diff --git a/src/noggit/rendering/WorldRender.cpp b/src/noggit/rendering/WorldRender.cpp index 7ab0d55a..bd43265b 100755 --- a/src/noggit/rendering/WorldRender.cpp +++ b/src/noggit/rendering/WorldRender.cpp @@ -74,15 +74,33 @@ void WorldRender::draw (glm::mat4x4 const& model_view _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; + _terrain_params_ubo_data.draw_only_normals = minimap_render_settings->draw_only_normals; + _terrain_params_ubo_data.point_normals_up = minimap_render_settings->point_normals_up; _need_terrain_params_ubo_update = true; } + // After coming out of minimap rendering mode and draw_only_normals is still on, disable it. + if (!render_settings.minimap_render && _terrain_params_ubo_data.draw_only_normals) { + _terrain_params_ubo_data.draw_only_normals = false; + _need_terrain_params_ubo_update = true; + } + + // After coming out of minimap rendering mode and point_normals_up is still on, disable it. + if (!render_settings.minimap_render && _terrain_params_ubo_data.point_normals_up) { + _terrain_params_ubo_data.point_normals_up = false; + _need_terrain_params_ubo_update = true; + } + if (_need_terrain_params_ubo_update) updateTerrainParamsUniformBlock(); // Frustum culling _world->_n_loaded_tiles = 0; unsigned tile_counter = 0; + + QSettings settings; + bool modern_features = settings.value("modern_features", false).toBool(); + for (MapTile* tile : _world->mapIndex.loaded_tiles()) { tile->_was_rendered_last_frame = false; @@ -243,6 +261,7 @@ void WorldRender::draw (glm::mat4x4 const& model_view { OpenGL::Scoped::use_program mcnk_shader{ *_mcnk_program.get() }; + mcnk_shader.uniform("enable_mists_heightmapping", modern_features); mcnk_shader.uniform("camera", glm::vec3(camera_pos.x, camera_pos.y, camera_pos.z)); mcnk_shader.uniform("animtime", static_cast(_world->animtime)); @@ -1572,10 +1591,17 @@ void WorldRender::updateLightingUniformBlockMinimap(MinimapRenderSettings* setti glm::vec3 diffuse = settings->diffuse_color; glm::vec3 ambient = settings->ambient_color; - _lighting_ubo_data.DiffuseColor_FogStart = { diffuse, 0 }; - _lighting_ubo_data.AmbientColor_FogEnd = { ambient, 0 }; _lighting_ubo_data.FogColor_FogOn = { 0, 0, 0, 0 }; - _lighting_ubo_data.LightDir_FogRate = { _outdoor_light_stats.dayDir.x, _outdoor_light_stats.dayDir.y, _outdoor_light_stats.dayDir.z, _skies->fogRate() }; + if (settings->export_mode == MinimapGenMode::LOD_MAPTEXTURES) { + _lighting_ubo_data.DiffuseColor_FogStart = { 0.5, 0.5, 0.5, 0 }; + _lighting_ubo_data.AmbientColor_FogEnd = { 0.5, 0.5, 0.5, 0 }; + _lighting_ubo_data.LightDir_FogRate = { 0.0, -1.0, 0.0, _skies->fogRate() }; + } + else { + _lighting_ubo_data.DiffuseColor_FogStart = { diffuse, 0 }; + _lighting_ubo_data.AmbientColor_FogEnd = { ambient, 0 }; + _lighting_ubo_data.LightDir_FogRate = { _outdoor_light_stats.dayDir.x, _outdoor_light_stats.dayDir.y, _outdoor_light_stats.dayDir.z, _skies->fogRate() }; + } _lighting_ubo_data.OceanColorLight = settings->ocean_color_light; _lighting_ubo_data.OceanColorDark = settings->ocean_color_dark; _lighting_ubo_data.RiverColorLight = settings->river_color_light; @@ -1996,17 +2022,27 @@ bool WorldRender::saveMinimap(TileIndex const& tile_idx, MinimapRenderSettings* str += "/"; } - QDir dir(str + "/textures/minimap/"); + QString target_dir = QString("/textures/minimap/"); + if(settings->export_mode == MinimapGenMode::LOD_MAPTEXTURES || settings->export_mode == MinimapGenMode::LOD_MAPTEXTURES_N) + { + target_dir = QString("/textures/maptextures/"); + } + + QDir dir(str + target_dir); if (!dir.exists()) dir.mkpath("."); std::string tex_name = std::string(_world->basename + "_" + std::to_string(tile_idx.x) + "_" + std::to_string(tile_idx.z) + ".blp"); + if (settings->export_mode == MinimapGenMode::LOD_MAPTEXTURES_N) + { + tex_name = std::string(_world->basename + "_" + std::to_string(tile_idx.x) + "_" + std::to_string(tile_idx.z) + "_n.blp"); + } if (settings->file_format == ".png") { image.save(dir.filePath(std::string(_world->basename + "_" + std::to_string(tile_idx.x) + "_" + std::to_string(tile_idx.z) + ".png").c_str())); } - else if (settings->file_format == ".blp") + else if (settings->file_format == ".blp (DXT1)" || settings->file_format == ".blp (DXT5)") { QByteArray bytes; QBuffer buffer( &bytes ); @@ -2020,7 +2056,7 @@ bool WorldRender::saveMinimap(TileIndex const& tile_idx, MinimapRenderSettings* uint32_t file_size; // void* blp_image = blp.createBlpDxtInMemory(true, FORMAT_DXT5, file_size); // this mirrors blizzards : dxt1, no mipmap - void* blp_image = blp.createBlpDxtInMemory(false, FORMAT_DXT1, file_size); + void* blp_image = blp.createBlpDxtInMemory(settings->file_format == ".blp (DXT5)" ? true : false, settings->file_format == ".blp (DXT5)" ? FORMAT_DXT5 : FORMAT_DXT1, file_size); // converts the texture name to an md5 hash like blizzard, this is used to avoid duplicates textures for ocean // downside is that if the file gets updated regularly there will be a lot of duplicates in the project folder diff --git a/src/noggit/rendering/glsl/terrain_frag.glsl b/src/noggit/rendering/glsl/terrain_frag.glsl old mode 100755 new mode 100644 index d858c8c3..54159dc3 --- a/src/noggit/rendering/glsl/terrain_frag.glsl +++ b/src/noggit/rendering/glsl/terrain_frag.glsl @@ -36,6 +36,8 @@ layout (std140) uniform overlay_params int draw_groundeffectid_overlay; int draw_groundeffect_layerid_overlay; int draw_noeffectdoodad_overlay; + int draw_only_normals; + int point_normals_up; }; struct ChunkInstanceData @@ -48,6 +50,14 @@ struct ChunkInstanceData ivec4 AreaIDColor_Pad2_DrawSelection; ivec4 ChunkXZ_TileXZ; ivec4 ChunkTexAnimDir; + + // Mists Heightmapping + + ivec4 ChunkHeightTextureSamplers; + ivec4 ChunkTextureUVScale; + vec4 ChunkTextureHeightScale; + vec4 ChunkTextureHeightOffset; + 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. @@ -71,6 +81,7 @@ uniform float cursorRotation; uniform float outer_cursor_radius; uniform float inner_cursor_ratio; uniform vec4 cursor_color; +uniform bool enable_mists_heightmapping; in vec3 vary_position; in vec2 vary_texcoord; @@ -188,6 +199,71 @@ vec4 get_tex_color(vec2 tex_coord, int tex_sampler, int array_index) } +const int numChunks = 16; +const int numTiles = 64; + +vec2 getAdjustedUV(vec2 uv, int textureScale) { + vec2 worldOffset = (numChunks * instances[instanceID].ChunkXZ_TileXZ.zw) + instances[instanceID].ChunkXZ_TileXZ.xy; + + // Scale the UV coordinates. Wow Interprets texture scaling this way. + vec2 combinedUV = fract((uv + worldOffset) / ((1 << textureScale) / 8.0f)); + + return combinedUV; +} + +vec4 mists_texture_blend() +{ + vec3 alpha = texture(alphamap, vec3(vary_texcoord / 8.0, instanceID)).rgb; + + int layer_count = instances[instanceID].ChunkHoles_DrawImpass_TexLayerCount_CantPaint.b; + + alpha.r = mix(alpha.r, 0.0, float(layer_count < 2)); + alpha.g = mix(alpha.g, 0.0, float(layer_count < 3)); + alpha.b = mix(alpha.b, 0.0, float(layer_count < 4)); + + + vec2 worldScaled_vary_t0_uv = getAdjustedUV(vary_t0_uv/8.0, instances[instanceID].ChunkTextureUVScale.x); + vec2 worldScaled_vary_t1_uv = getAdjustedUV(vary_t1_uv/8.0, instances[instanceID].ChunkTextureUVScale.y); + vec2 worldScaled_vary_t2_uv = getAdjustedUV(vary_t2_uv/8.0, instances[instanceID].ChunkTextureUVScale.z); + vec2 worldScaled_vary_t3_uv = getAdjustedUV(vary_t3_uv/8.0, instances[instanceID].ChunkTextureUVScale.w); + + // Mists HeightMapping: Multi Layer Blending. + vec4 layer_weights = vec4(1.0 - clamp(dot(vec3(1.0),alpha), 0, 1), alpha); + + vec4 t0h = get_tex_color(worldScaled_vary_t0_uv, instances[instanceID].ChunkHeightTextureSamplers.x, abs(instances[instanceID].ChunkTextureArrayIDs.x)); + vec4 t1h = get_tex_color(worldScaled_vary_t1_uv, instances[instanceID].ChunkHeightTextureSamplers.y, abs(instances[instanceID].ChunkTextureArrayIDs.y)); + vec4 t2h = get_tex_color(worldScaled_vary_t2_uv, instances[instanceID].ChunkHeightTextureSamplers.z, abs(instances[instanceID].ChunkTextureArrayIDs.z)); + vec4 t3h = get_tex_color(worldScaled_vary_t3_uv, instances[instanceID].ChunkHeightTextureSamplers.w, abs(instances[instanceID].ChunkTextureArrayIDs.w)); + + vec4 layer_pct = vec4 ( layer_weights.x * ( t0h.a * instances[instanceID].ChunkTextureHeightScale.x + instances[instanceID].ChunkTextureHeightOffset.x) + , layer_weights.y * ( t1h.a * instances[instanceID].ChunkTextureHeightScale.y + instances[instanceID].ChunkTextureHeightOffset.y) + , layer_weights.z * ( t2h.a * instances[instanceID].ChunkTextureHeightScale.z + instances[instanceID].ChunkTextureHeightOffset.z) + , layer_weights.w * ( t3h.a * instances[instanceID].ChunkTextureHeightScale.w + instances[instanceID].ChunkTextureHeightOffset.w) + ); + vec4 layer_pct_max = vec4( max( max(layer_pct.x, layer_pct.y) , max(layer_pct.z, layer_pct.w) ) ); + layer_pct = layer_pct * (vec4(1.0) - clamp(layer_pct_max - layer_pct, 0, 1)); + layer_pct = layer_pct / vec4( dot(vec4(1.0),layer_pct) ); + + vec4 t0 = get_tex_color(worldScaled_vary_t0_uv, instances[instanceID].ChunkTextureSamplers.x, + abs(instances[instanceID].ChunkTextureArrayIDs.x)) * layer_pct.x; + t0.a = mix(t0.a, 0.f, int(instances[instanceID].ChunkTextureArrayIDs.x < 0)); + + vec4 t1 = get_tex_color(worldScaled_vary_t1_uv, instances[instanceID].ChunkTextureSamplers.y, + abs(instances[instanceID].ChunkTextureArrayIDs.y)) * layer_pct.y; + //vec4 t1 = get_tex_color(vary_t1_uv / 5 , instances[instanceID].ChunkTextureSamplers.y, abs(instances[instanceID].ChunkTextureArrayIDs.y)); + t1.a = mix(t1.a, 0.f, int(instances[instanceID].ChunkTextureArrayIDs.y < 0)); + + vec4 t2 = get_tex_color(worldScaled_vary_t2_uv, instances[instanceID].ChunkTextureSamplers.z, + abs(instances[instanceID].ChunkTextureArrayIDs.z)) * layer_pct.z; + t2.a = mix(t2.a, 0.f, int(instances[instanceID].ChunkTextureArrayIDs.z < 0)); + + vec4 t3 =get_tex_color(worldScaled_vary_t3_uv, instances[instanceID].ChunkTextureSamplers.w, + abs(instances[instanceID].ChunkTextureArrayIDs.w)) * layer_pct.w; + t3.a = mix(t3.a, 0.f, int(instances[instanceID].ChunkTextureArrayIDs.w < 0)); + + return vec4 (t0 + t1 + t2 + t3);//(t0 * (1.0 - (a0 + a1 + a2)) + t1 * a0 + t2 * a1 + t3 * a2); +} + vec4 texture_blend() { vec3 alpha = texture(alphamap, vec3(vary_texcoord / 8.0, instanceID)).rgb; @@ -243,6 +319,10 @@ void main() // vec3 accumlatedLight = vec3(1.0, 1.0, 1.0); vec3 normalized_normal = normalize(vary_normal); + if(point_normals_up == 1) + { + normalized_normal = vec3(0, 1, 0); + } float nDotL = clamp(dot(normalized_normal, -normalize(LightDir_FogRate.xyz)), 0.0, 1.0); // default LightDir = -0.6 vec3 skyColor = (AmbientColor_FogEnd.xyz * 1.10000002); @@ -255,7 +335,14 @@ void main() float specularFactor = max(dot(reflection, normalize(camera - vary_position)), 0.0); // blend textures - out_color = mix(vec4(1.0, 1.0, 1.0, 0.0), texture_blend(), int(instances[instanceID].ChunkHoles_DrawImpass_TexLayerCount_CantPaint.b > 0)); + if(enable_mists_heightmapping) + { + out_color = mix(vec4(1.0, 1.0, 1.0, 0.0), mists_texture_blend(), int(instances[instanceID].ChunkHoles_DrawImpass_TexLayerCount_CantPaint.b > 0)); + } + else + { + out_color = mix(vec4(1.0, 1.0, 1.0, 0.0), texture_blend(), int(instances[instanceID].ChunkHoles_DrawImpass_TexLayerCount_CantPaint.b > 0)); + } vec3 spc = out_color.a * out_color.rgb * pow(specularFactor, 8); out_color.a = 1.0; @@ -533,4 +620,9 @@ void main() out_color.rgb = mix(cursor_color.rgb, out_color.rgb, alpha);*/ } + if(draw_only_normals != 0) + { + out_color.rgb = vec3(vary_normal.z * -1, vary_normal.y, vary_normal.x * -1) * 0.5 + 0.5; + } + } diff --git a/src/noggit/rendering/glsl/terrain_vert.glsl b/src/noggit/rendering/glsl/terrain_vert.glsl index 7acb8c41..6e6daa2c 100755 --- a/src/noggit/rendering/glsl/terrain_vert.glsl +++ b/src/noggit/rendering/glsl/terrain_vert.glsl @@ -23,6 +23,14 @@ struct ChunkInstanceData ivec4 AreaIDColor_Pad2_DrawSelection; ivec4 ChunkXZ_TileXZ; ivec4 ChunkTexAnimDir; + + // Mists Heightmapping + + ivec4 ChunkHeightTextureSamplers; + ivec4 ChunkTextureUVScale; + vec4 ChunkTextureHeightScale; + vec4 ChunkTextureHeightOffset; + vec4 ChunkGroundEffectColor; ivec4 ChunkDoodadsEnabled2_ChunksLayerEnabled2; }; diff --git a/src/noggit/rendering/glsl/wmo_frag.glsl b/src/noggit/rendering/glsl/wmo_frag.glsl index 94f47046..378a63af 100755 --- a/src/noggit/rendering/glsl/wmo_frag.glsl +++ b/src/noggit/rendering/glsl/wmo_frag.glsl @@ -194,6 +194,10 @@ void main() vec3 layer2 = mix(tex.rgb, tex_2.rgb, tex_2.a); out_color = vec4(apply_lighting(mix(layer2, tex.rgb, vertex_color.a)), 1.); } + else if (shader == 21 || shader == 23) + { + out_color = vec4(apply_lighting(tex_2.rgb), 1.); + } else // default shader, used for shader 0,1,2,4 (Diffuse, Specular, Metal, Opaque) { out_color = vec4(apply_lighting(tex.rgb), 1.); diff --git a/src/noggit/scripting/script_global.cpp b/src/noggit/scripting/script_global.cpp old mode 100755 new mode 100644 index 0aaaf624..82a49ec2 --- a/src/noggit/scripting/script_global.cpp +++ b/src/noggit/scripting/script_global.cpp @@ -41,12 +41,20 @@ namespace Noggit { state->set_function("add_wmo",[global]( std::string const& filename , glm::vec3 const& pos + , float scale , glm::vec3 const& rotation) { + // note: we set both min/max random scale and the normal scale parameter, + // because noggit picks one based on random scale settings in the object tool + object_paste_params p; + p.minScale = scale; + p.maxScale = scale; global->get_view()->_world.get()->addWMO( filename , pos + , scale , math::degrees::vec3(rotation) + , &p , false); }); diff --git a/src/noggit/scripting/script_model.cpp b/src/noggit/scripting/script_model.cpp old mode 100755 new mode 100644 index 87aa0bf6..654fdfe2 --- a/src/noggit/scripting/script_model.cpp +++ b/src/noggit/scripting/script_model.cpp @@ -53,13 +53,10 @@ namespace Noggit void model::set_scale(float scale) { - if (_object->which() != eWMO) - { world()->updateTilesEntry(_object, model_update::remove); _object->scale = scale; _object->recalcExtents(); world()->updateTilesEntry(_object, model_update::add); - } } unsigned model::get_uid() @@ -101,7 +98,7 @@ namespace Noggit if (filename.ends_with(".wmo")) { _object = - world()->addWMOAndGetInstance(filename, get_pos(), math::degrees::vec3 {get_rot()}, false); + world()->addWMOAndGetInstance(filename, get_pos(), math::degrees::vec3 {get_rot()}, get_scale(), false); } else { diff --git a/src/noggit/texture_set.cpp b/src/noggit/texture_set.cpp old mode 100755 new mode 100644 index 538aac95..a20abb7c --- a/src/noggit/texture_set.cpp +++ b/src/noggit/texture_set.cpp @@ -295,6 +295,13 @@ bool TextureSet::eraseUnusedTextures() return false; } + QSettings settings; + bool cleanup_unused_textures = settings.value("cleanup_unused_textures", true).toBool(); + if (!cleanup_unused_textures) + { + return false; + } + std::set visible_tex; if (tmp_edit_values) diff --git a/src/noggit/texture_set.hpp b/src/noggit/texture_set.hpp old mode 100755 new mode 100644 index d1549700..9fb615e1 --- a/src/noggit/texture_set.hpp +++ b/src/noggit/texture_set.hpp @@ -150,6 +150,11 @@ private: std::vector textures; std::array, MAX_ALPHAMAPS> alphamaps; + + // Mists Heightmapping + std::vector heightTextures; + std::array heightMappingData; + size_t nTextures; // byte[8][8] // can store the 2bits value in a byte, but might never be higher than 3 or layer count. diff --git a/src/noggit/tools/MinimapTool.cpp b/src/noggit/tools/MinimapTool.cpp index d1600f35..91b5078b 100644 --- a/src/noggit/tools/MinimapTool.cpp +++ b/src/noggit/tools/MinimapTool.cpp @@ -182,6 +182,8 @@ namespace Noggit break; } case MinimapGenMode::MAP: + case MinimapGenMode::LOD_MAPTEXTURES: + case MinimapGenMode::LOD_MAPTEXTURES_N: { // init progress if (!_mmap_async_index) @@ -192,6 +194,26 @@ namespace Noggit if (!saving_minimap) return false; + QSettings noggitSettings; + bool modern_features = noggitSettings.value("modern_features", false).toBool(); + if (modern_features && (settings->export_mode == MinimapGenMode::LOD_MAPTEXTURES || settings->export_mode == MinimapGenMode::LOD_MAPTEXTURES_N)) { + settings->draw_m2 = false; + settings->draw_wmo = false; + settings->draw_water = false; + settings->resolution = 512; + settings->file_format = ".blp (DXT5)"; + + if (settings->export_mode == MinimapGenMode::LOD_MAPTEXTURES_N) + { + settings->draw_only_normals = true; + settings->resolution = 256; + } + else if (settings->export_mode == MinimapGenMode::LOD_MAPTEXTURES) { + // Point normals upwards for diffuse maptexture baking + settings->point_normals_up = true; + } + } + if (_mmap_async_index < 4096 && static_cast(_mmap_render_index) < progress->maximum()) { save(); diff --git a/src/noggit/tools/ObjectTool.cpp b/src/noggit/tools/ObjectTool.cpp index cf74060d..c023aee1 100644 --- a/src/noggit/tools/ObjectTool.cpp +++ b/src/noggit/tools/ObjectTool.cpp @@ -315,7 +315,7 @@ namespace Noggit // auto replace_wmo = static_cast(replacement_obj); // auto source_wmo = static_cast(old_obj); - auto new_obj = world->addWMOAndGetInstance(replace_path, source_pos, source_rot, true); + auto new_obj = world->addWMOAndGetInstance(replace_path, source_pos, source_rot, source_scale, true); new_obj->wmo->wait_until_loaded(); new_obj->wmo->waitForChildrenLoaded(); new_obj->recalcExtents(); @@ -521,7 +521,7 @@ namespace Noggit { NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, Noggit::ActionModalityControllers::eSCALE); - world->scale_selected_models(_keys * numpad_moveratio / 50.f, World::m2_scaling_type::add); + world->scale_selected_models(_keys * numpad_moveratio / 50.f, World::object_scaling_type::add); updateRotationEditor(); } if (_keyr != 0.f) @@ -543,7 +543,7 @@ namespace Noggit NOGGIT_ACTION_MGR->beginAction(mv, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, Noggit::ActionModalityControllers::eALT | Noggit::ActionModalityControllers::eMMB); - world->scale_selected_models(std::pow(2.f, _mv * 4.f), World::m2_scaling_type::mult); + world->scale_selected_models(std::pow(2.f, _mv * 4.f), World::object_scaling_type::mult); } else if (params.mod_shift_down) { @@ -688,7 +688,7 @@ namespace Noggit float min = _object_paste_params.minScale; float max = _object_paste_params.maxScale; - world->scale_selected_models(misc::randfloat(min, max), World::m2_scaling_type::set); + world->scale_selected_models(misc::randfloat(min, max), World::object_scaling_type::set); } } } diff --git a/src/noggit/ui/CurrentTexture.cpp b/src/noggit/ui/CurrentTexture.cpp index 7feeb282..1f33c6f4 100755 --- a/src/noggit/ui/CurrentTexture.cpp +++ b/src/noggit/ui/CurrentTexture.cpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace Noggit { diff --git a/src/noggit/ui/MinimapCreator.cpp b/src/noggit/ui/MinimapCreator.cpp index 0dfc4410..f8d01291 100755 --- a/src/noggit/ui/MinimapCreator.cpp +++ b/src/noggit/ui/MinimapCreator.cpp @@ -65,11 +65,24 @@ namespace Noggit auto cur_adt_btn = new QPushButton("Current ADT", generate_widget); auto sel_adts_btn = new QPushButton("Selected ADTs", generate_widget); auto all_adts_btn = new QPushButton("Map", generate_widget); + auto maptexture_btn = new QPushButton("Map Textures", generate_widget); + maptexture_btn->setVisible(false); + auto maptexture_n_btn = new QPushButton("Map Textures (Normals)", generate_widget); + maptexture_n_btn->setVisible(false); generate_layout->addRow (cur_adt_btn); generate_layout->addRow (sel_adts_btn); generate_layout->addRow (all_adts_btn); + QSettings settings; + bool modern_features = settings.value("modern_features", false).toBool(); + if (modern_features) { + generate_layout->addRow (maptexture_btn); + maptexture_btn->setVisible(true); + generate_layout->addRow(maptexture_n_btn); + maptexture_n_btn->setVisible(true); + } + // Render settings box auto render_settings_box = new QGroupBox("Render options", generate_widget); generate_layout->addRow (render_settings_box); @@ -88,9 +101,10 @@ namespace Noggit render_settings_box_layout->addRow (resolution); auto file_format = new QComboBox(this); - file_format->addItem(".blp"); + file_format->addItem(".blp (DXT1)"); + file_format->addItem(".blp (DXT5)"); file_format->addItem(".png"); - file_format->setCurrentText(".blp"); + file_format->setCurrentText(".blp (DXT1)"); render_settings_box_layout->addRow (file_format); @@ -840,6 +854,16 @@ namespace Noggit emit onSave(); }); + connect(maptexture_btn, &QPushButton::clicked, [=]() { + _render_settings.export_mode = MinimapGenMode::LOD_MAPTEXTURES; + emit onSave(); + }); + + connect(maptexture_n_btn, &QPushButton::clicked, [=]() { + _render_settings.export_mode = MinimapGenMode::LOD_MAPTEXTURES_N; + emit onSave(); + }); + } void MinimapCreator::changeRadius(float change) diff --git a/src/noggit/ui/MinimapCreator.hpp b/src/noggit/ui/MinimapCreator.hpp old mode 100755 new mode 100644 diff --git a/src/noggit/ui/ObjectEditor.cpp b/src/noggit/ui/ObjectEditor.cpp old mode 100755 new mode 100644 index b4e661a2..17b54442 --- a/src/noggit/ui/ObjectEditor.cpp +++ b/src/noggit/ui/ObjectEditor.cpp @@ -700,14 +700,16 @@ namespace Noggit } else if (obj->which() == eWMO) { + float scale(1.f); math::degrees::vec3 rotation(math::degrees(0)._, math::degrees(0)._, math::degrees(0)._); if (_copy_model_stats) { - // copy rot from original model. Dirty but working + // copy rot size from original model. Dirty but working + scale = obj->scale; rotation = obj->dir; } - auto new_obj = world->addWMOAndGetInstance(obj->instance_model()->file_key(), pos, rotation, true); + auto new_obj = world->addWMOAndGetInstance(obj->instance_model()->file_key(), pos, rotation, scale, true); new_obj->wmo->wait_until_loaded(); new_obj->wmo->waitForChildrenLoaded(); new_obj->recalcExtents(); @@ -834,6 +836,8 @@ namespace Noggit { auto original = static_cast(obj); auto clone = new WMOInstance(original->wmo->file_key().filepath(), _map_view->getRenderContext()); + + clone->scale = original->scale; clone->dir = original->dir; clone->pos = pivot ? original->pos - pivot.value() : glm::vec3(); diff --git a/src/noggit/ui/RotationEditor.cpp b/src/noggit/ui/RotationEditor.cpp index 46583e96..a702f7a3 100755 --- a/src/noggit/ui/RotationEditor.cpp +++ b/src/noggit/ui/RotationEditor.cpp @@ -199,7 +199,7 @@ namespace Noggit { NOGGIT_ACTION_MGR->beginAction(reinterpret_cast(parent), Noggit::ActionFlags::eOBJECTS_TRANSFORMED); - world->scale_selected_models(v, World::m2_scaling_type::set); + world->scale_selected_models(v, World::object_scaling_type::set); NOGGIT_ACTION_MGR->endAction(); } } @@ -214,7 +214,7 @@ namespace Noggit { NOGGIT_ACTION_MGR->beginAction(reinterpret_cast(parent), Noggit::ActionFlags::eOBJECTS_TRANSFORMED); - world->scale_selected_models(_scale->value(), World::m2_scaling_type::mult); + world->scale_selected_models(_scale->value(), World::object_scaling_type::mult); NOGGIT_ACTION_MGR->endAction(); } else // reset value @@ -268,7 +268,23 @@ namespace Noggit auto obj = std::get(selection); - _scale->setEnabled(obj->which() != eWMO); + if(obj->which() == eWMO) + { + QSettings settings; + bool modern_features = settings.value("modern_features", false).toBool(); + if(modern_features) + { + _scale->setEnabled(true); + } + else + { + _scale->setEnabled(false); + } + } + else + { + _scale->setEnabled(true); + } _position_x->setValue(obj->pos.x); _position_y->setValue(obj->pos.y); diff --git a/src/noggit/ui/ShaderTool.cpp b/src/noggit/ui/ShaderTool.cpp index a7d3aa9d..38fc2f23 100755 --- a/src/noggit/ui/ShaderTool.cpp +++ b/src/noggit/ui/ShaderTool.cpp @@ -39,7 +39,7 @@ namespace Noggit _radius_slider = new Noggit::Ui::Tools::UiCommon::ExtendedSlider (this); _radius_slider->setPrefix("Radius:"); - _radius_slider->setRange(0, 1000); + _radius_slider->setRange(0, 10000); _radius_slider->setDecimals(2); _radius_slider->setValue (15.0f); diff --git a/src/noggit/ui/TexturePicker.cpp b/src/noggit/ui/TexturePicker.cpp old mode 100755 new mode 100644 diff --git a/src/noggit/ui/TexturingGUI.cpp b/src/noggit/ui/TexturingGUI.cpp old mode 100755 new mode 100644 index ca5f775a..166fa09a --- a/src/noggit/ui/TexturingGUI.cpp +++ b/src/noggit/ui/TexturingGUI.cpp @@ -67,6 +67,10 @@ namespace Noggit std::vector tilesets; std::unordered_set tilesets_with_specular_variant; + // If modern features are enabled, set filtering to height textures (_h), otherwise specular (_s). + QSettings settings; + bool modern_features = settings.value("modern_features", false).toBool(); + for (auto const& entry_pair : Application::NoggitApplication::instance()->clientData()->listfile()->pathToFileDataIDMap()) { std::string const& filepath = entry_pair.first; @@ -75,7 +79,7 @@ namespace Noggit && filepath.find (".blp") != std::string::npos ) { - auto suffix_pos (filepath.find ("_s.blp")); + auto suffix_pos (filepath.find (modern_features ? "_h.blp" : "_s.blp")); if (suffix_pos == std::string::npos) { tilesets.emplace_back (filepath); @@ -83,7 +87,7 @@ namespace Noggit else { std::string specular (filepath); - specular.erase (suffix_pos, strlen ("_s")); + specular.erase (suffix_pos, strlen (modern_features ? "_h" : "_s")); tilesets_with_specular_variant.emplace (specular); } } @@ -107,7 +111,7 @@ namespace Noggit && entry.find("_h.blp") == std::string::npos // skip _h textures ) { - auto suffix_pos (entry.find ("_s.blp")); + auto suffix_pos (entry.find (modern_features ? "_h.blp" : "_s.blp")); if (suffix_pos == std::string::npos) { tilesets.emplace_back (entry); @@ -115,7 +119,7 @@ namespace Noggit else { std::string specular (entry); - specular.erase (suffix_pos, strlen ("_s")); + specular.erase (suffix_pos, strlen (modern_features ? "_h" : "_s")); tilesets_with_specular_variant.emplace (specular); } } @@ -138,12 +142,12 @@ namespace Noggit model->appendRow (item); } - auto specular_filter (new QSortFilterProxyModel); - specular_filter->setSourceModel (model); - specular_filter->setFilterRole (has_specular_role); + auto texture_filter (new QSortFilterProxyModel); + texture_filter->setSourceModel (model); + texture_filter->setFilterRole (has_specular_role); auto search_filter (new QSortFilterProxyModel); - search_filter->setSourceModel (specular_filter); + search_filter->setSourceModel (texture_filter); search_filter->sort (0, Qt::AscendingOrder); @@ -165,17 +169,19 @@ namespace Noggit } ); + auto texture_filter_box(new QCheckBox("only with specular texture variant")); - auto only_specular (new QCheckBox ("only with specular texture variant")); - connect ( only_specular, &QCheckBox::toggled - , [=] (bool on) - { - specular_filter->setFilterRegExp (on ? "true" : ""); - } - ); - only_specular->setChecked (false); + if (modern_features) + texture_filter_box->setText("only with height texture variant"); + connect(texture_filter_box, &QCheckBox::toggled + , [=](bool on) + { + texture_filter->setFilterRegExp(on ? "true" : ""); + } + ); + texture_filter_box->setChecked(true); auto list = new TextureList(this); list->setEditTriggers (QAbstractItemView::NoEditTriggers); @@ -214,7 +220,7 @@ namespace Noggit layout->addLayout (top_bar); top_bar->addWidget (size_slider); top_bar->addStretch(); - top_bar->addWidget (only_specular); + top_bar->addWidget (texture_filter_box); top_bar->addWidget (filter); layout->addWidget (list); diff --git a/src/noggit/ui/texturing_tool.cpp b/src/noggit/ui/texturing_tool.cpp old mode 100755 new mode 100644 index a5ad3f7d..c86439b5 --- a/src/noggit/ui/texturing_tool.cpp +++ b/src/noggit/ui/texturing_tool.cpp @@ -12,18 +12,21 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include #define _USE_MATH_DEFINES #include +#include namespace Noggit { @@ -208,8 +211,73 @@ namespace Noggit tool_layout->addWidget(quick_palette_btn); tool_layout->setAlignment(quick_palette_btn, Qt::AlignTop); + // Mists HeightMapping, only enable if modern feature setting is on + bool modern_features = settings.value("modern_features", false).toBool(); - auto geffect_tools_btn(new QPushButton(/*"Ground Effect Tools"*/ "In developement", this)); + // Define UI elements regardless of modern_features being enabled because they're used later on as well. + _heightmapping_group = new QGroupBox("Height Mapping", tool_widget); + _heightmapping_group->setVisible(modern_features); + + auto heightmapping_scale_spin = new QDoubleSpinBox(_heightmapping_group); + heightmapping_scale_spin->setVisible(modern_features); + + auto heightmapping_heightscale_spin = new QDoubleSpinBox(_heightmapping_group); + heightmapping_heightscale_spin->setVisible(modern_features); + + auto heightmapping_heightoffset_spin = new QDoubleSpinBox(_heightmapping_group); + heightmapping_heightoffset_spin->setVisible(modern_features); + + QPushButton* _heightmapping_copy_btn = new QPushButton("Copy to JSON", this); + _heightmapping_copy_btn->setVisible(modern_features); + + if (modern_features) { + + auto heightmapping_group_layout(new QFormLayout(_heightmapping_group)); + + heightmapping_scale_spin->setRange(0, 512); + heightmapping_scale_spin->setSingleStep(1); + heightmapping_scale_spin->setDecimals(0); + heightmapping_scale_spin->setValue(0); + heightmapping_group_layout->addRow("Scale:", heightmapping_scale_spin); + + heightmapping_heightscale_spin->setRange(-512, 512); + heightmapping_heightscale_spin->setSingleStep(0.1); + heightmapping_heightscale_spin->setDecimals(3); + heightmapping_heightscale_spin->setValue(0); + heightmapping_group_layout->addRow("Height Scale:", heightmapping_heightscale_spin); + + heightmapping_heightoffset_spin->setRange(-512, 512); + heightmapping_heightoffset_spin->setSingleStep(0.1); + heightmapping_heightoffset_spin->setDecimals(3); + heightmapping_heightoffset_spin->setValue(1); + heightmapping_group_layout->addRow("Height Offset:", heightmapping_heightoffset_spin); + + auto heightmapping_btngroup_layout(new QVBoxLayout(_heightmapping_group)); + auto heightmapping_buttons_widget = new QWidget(_heightmapping_group); + heightmapping_buttons_widget->setLayout(heightmapping_btngroup_layout); + + auto wrap_label = new QLabel("Note: This doesn't save to .cfg, use copy and do it manually.", _heightmapping_group); + wrap_label->setWordWrap(true); + heightmapping_group_layout->addRow(wrap_label); + + _heightmapping_apply_global_btn = new QPushButton("Apply (Global)", this); + _heightmapping_apply_global_btn->setFixedHeight(30); + heightmapping_btngroup_layout->addWidget(_heightmapping_apply_global_btn); + + _heightmapping_apply_adt_btn = new QPushButton("Apply (Current ADT)", this); + _heightmapping_apply_adt_btn->setFixedHeight(30); + heightmapping_btngroup_layout->addWidget(_heightmapping_apply_adt_btn); + + _heightmapping_copy_btn->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + _heightmapping_copy_btn->setFixedHeight(30); + heightmapping_btngroup_layout->addWidget(_heightmapping_copy_btn); + + heightmapping_group_layout->addRow(heightmapping_buttons_widget); + + tool_layout->addWidget(_heightmapping_group); + } + + auto geffect_tools_btn(new QPushButton("In development", this)); tool_layout->addWidget(geffect_tools_btn); tool_layout->setAlignment(geffect_tools_btn, Qt::AlignTop); @@ -261,6 +329,28 @@ namespace Noggit connect (anim_speed_slider, &QSlider::valueChanged, &_anim_speed_prop, &Noggit::unsigned_int_property::set); connect (anim_orientation_dial, &QDial::valueChanged, &_anim_rotation_prop, &Noggit::unsigned_int_property::set); + + if (modern_features) { + connect(heightmapping_scale_spin, qOverload(&QDoubleSpinBox::valueChanged) + , [&](double v) + { + textureHeightmappingData.uvScale = v; + } + ); + + connect(heightmapping_heightscale_spin, qOverload(&QDoubleSpinBox::valueChanged) + , [&](double v) + { + textureHeightmappingData.heightScale = v; + } + ); + connect(heightmapping_heightoffset_spin, qOverload(&QDoubleSpinBox::valueChanged) + , [&](double v) + { + textureHeightmappingData.heightOffset = v; + } + ); + } connect ( tabs, &QTabWidget::currentChanged , [this] (int index) @@ -377,7 +467,47 @@ namespace Noggit connect (_radius_slider, &Noggit::Ui::Tools::UiCommon::ExtendedSlider::valueChanged, this, &texturing_tool::updateMaskImage); connect(_image_mask_group, &Noggit::Ui::Tools::ImageMaskSelector::pixmapUpdated, this, &texturing_tool::updateMaskImage); + // Mists Heightmapping + if (modern_features) { + connect(_current_texture, &Noggit::Ui::current_texture::texture_updated + , [=]() + { + auto proj = Noggit::Project::CurrentProject::get(); + auto foundTexture = proj->ExtraMapData.TextureHeightData_Global.find(_current_texture->filename()); + if (foundTexture != proj->ExtraMapData.TextureHeightData_Global.end()) + { + heightmapping_scale_spin->setValue(foundTexture->second.uvScale); + heightmapping_heightscale_spin->setValue(foundTexture->second.heightScale); + heightmapping_heightoffset_spin->setValue(foundTexture->second.heightOffset); + } + + } + ); + + connect(_heightmapping_copy_btn, &QPushButton::pressed + , [=]() + { + std::ostringstream oss; + oss << "{\r\n \"" << _current_texture->filename() << "\": {\r\n" + << " \"Scale\": " << textureHeightmappingData.uvScale << ",\r\n" + << " \"HeightScale\": " << textureHeightmappingData.heightScale << ",\r\n" + << " \"HeightOffset\": " << textureHeightmappingData.heightOffset << "\r\n" + << " }\r\n}"; + + QClipboard* clip = QApplication::clipboard(); + clip->setText(QString::fromStdString(oss.str())); + + QMessageBox::information + (nullptr + , "Copied" + , "JSON Copied to Clipboard", + QMessageBox::Ok + ); + + } + ); + } _spray_content->hide(); update_brush_hardness(); diff --git a/src/noggit/ui/texturing_tool.hpp b/src/noggit/ui/texturing_tool.hpp old mode 100755 new mode 100644 index d28938d0..483db5a9 --- a/src/noggit/ui/texturing_tool.hpp +++ b/src/noggit/ui/texturing_tool.hpp @@ -199,6 +199,9 @@ namespace Noggit QJsonObject toJSON(); void fromJSON(QJsonObject const& json); + QPushButton* const heightmappingApplyGlobalButton() { return _heightmapping_apply_global_btn; } + QPushButton* const heightmappingApplyAdtButton() { return _heightmapping_apply_adt_btn; } + texture_heightmapping_data& getCurrentHeightMappingSetting() {return textureHeightmappingData; } signals: void texturePaletteToggled(); @@ -217,6 +220,8 @@ namespace Noggit int _brush_level; bool _show_unpaintable_chunks; + int* _heightinfo_group; + float _spray_size; float _spray_pressure; @@ -226,6 +231,7 @@ namespace Noggit BoolToggleProperty _overbright_prop; texturing_mode _texturing_mode; // use getTexturingMode() to check for ground effect mode + texture_heightmapping_data textureHeightmappingData; private: OpacitySlider* _brush_level_slider; @@ -248,6 +254,10 @@ namespace Noggit texture_swapper* _texture_switcher; + QGroupBox* _heightmapping_group; + QPushButton* _heightmapping_apply_global_btn; + QPushButton* _heightmapping_apply_adt_btn; + GroundEffectsTool* _ground_effect_tool; Noggit::Ui::Tools::ImageMaskSelector* _image_mask_group; diff --git a/src/noggit/ui/tools/LightEditor/LightEditor.cpp b/src/noggit/ui/tools/LightEditor/LightEditor.cpp old mode 100755 new mode 100644 index feb139af..60573719 --- a/src/noggit/ui/tools/LightEditor/LightEditor.cpp +++ b/src/noggit/ui/tools/LightEditor/LightEditor.cpp @@ -1,7 +1,6 @@ // This file is part of Noggit3, licensed under GNU General Public License (version 3). #include "LightEditor.hpp" -#include #include #include #include @@ -20,6 +19,7 @@ #include #include + using namespace Noggit::Ui::Tools; LightEditor::LightEditor(MapView* map_view, QWidget* parent) @@ -321,14 +321,14 @@ LightEditor::LightEditor(MapView* map_view, QWidget* parent) global_values_layout->addRow(name_layout); pos_x_spin = new QDoubleSpinBox(this); - pos_x_spin->setRange(-17066.66656 * 2, 17066.66656 * 2); // size = 17066.66656 + pos_x_spin->setRange(-17066.66656 * 2, 17066.66656 * 2); // size = �17066.66656 pos_x_spin->setValue(0); pos_x_spin->setSingleStep(50); pos_x_spin->setEnabled(false); global_values_layout->addRow("Position X:", pos_x_spin); pos_y_spin = new QDoubleSpinBox(this); - pos_y_spin->setRange(-17066.66656 * 2, 17066.66656 * 2); // size = 17066.66656 + pos_y_spin->setRange(-17066.66656 * 2, 17066.66656 * 2); // size = �17066.66656 pos_y_spin->setValue(0); pos_y_spin->setSingleStep(50); pos_y_spin->setEnabled(false); @@ -342,14 +342,14 @@ LightEditor::LightEditor(MapView* map_view, QWidget* parent) global_values_layout->addRow("Position Z:", pos_z_spin); inner_radius_spin = new QDoubleSpinBox(this); - inner_radius_spin->setRange(0, 100000); // max seen in dbc is 3871 (139363 E36 ) + inner_radius_spin->setRange(0, 100000); // max seen in dbc is 3871 (139363 �E36 ) inner_radius_spin->setValue(0); inner_radius_spin->setSingleStep(50); inner_radius_spin->setEnabled(false); global_values_layout->addRow("Inner Radius:", inner_radius_spin); outer_radius_spin = new QDoubleSpinBox(this); - outer_radius_spin->setRange(0, 100000); // max seen in dbc is 3871 (139363 E36 ) + outer_radius_spin->setRange(0, 100000); // max seen in dbc is 3871 (139363 �E36 ) outer_radius_spin->setValue(0); outer_radius_spin->setSingleStep(50); outer_radius_spin->setEnabled(false); diff --git a/src/noggit/ui/tools/LightEditor/LightEditor.hpp b/src/noggit/ui/tools/LightEditor/LightEditor.hpp old mode 100755 new mode 100644 diff --git a/src/noggit/ui/tools/NodeEditor/Nodes/World/Object/AddObjectInstance.cpp b/src/noggit/ui/tools/NodeEditor/Nodes/World/Object/AddObjectInstance.cpp old mode 100755 new mode 100644 index 7f280a1e..401f8280 --- a/src/noggit/ui/tools/NodeEditor/Nodes/World/Object/AddObjectInstance.cpp +++ b/src/noggit/ui/tools/NodeEditor/Nodes/World/Object/AddObjectInstance.cpp @@ -62,7 +62,7 @@ void AddObjectInstanceNode::compute() } else if (QString(path.c_str()).endsWith(".wmo", Qt::CaseInsensitive)) { - obj = world->addWMOAndGetInstance(path, {pos.x, pos.y, pos.z}, {math::degrees(dir.x)._, math::degrees(dir.y)._, math::degrees(dir.z)._ }, false); + obj = world->addWMOAndGetInstance(path, {pos.x, pos.y, pos.z}, {math::degrees(dir.x)._, math::degrees(dir.y)._, math::degrees(dir.z)._ }, scale, false); } else { diff --git a/src/noggit/ui/tools/NodeEditor/Nodes/World/Object/ObjectInstanceInfo.cpp b/src/noggit/ui/tools/NodeEditor/Nodes/World/Object/ObjectInstanceInfo.cpp index b8872177..1f8e225e 100755 --- a/src/noggit/ui/tools/NodeEditor/Nodes/World/Object/ObjectInstanceInfo.cpp +++ b/src/noggit/ui/tools/NodeEditor/Nodes/World/Object/ObjectInstanceInfo.cpp @@ -48,7 +48,7 @@ void ObjectInstanceInfoNode::compute() if (_out_ports[2].connected) { - _out_ports[2].out_value = std::make_shared(obj->which() == eMODEL ? obj->scale : 1.0); + _out_ports[2].out_value = std::make_shared(obj->scale); _node->onDataUpdated(2); } diff --git a/src/noggit/ui/tools/NodeEditor/Nodes/World/Object/ObjectInstanceSetScale.cpp b/src/noggit/ui/tools/NodeEditor/Nodes/World/Object/ObjectInstanceSetScale.cpp index 5f14e5b6..1ab83c09 100755 --- a/src/noggit/ui/tools/NodeEditor/Nodes/World/Object/ObjectInstanceSetScale.cpp +++ b/src/noggit/ui/tools/NodeEditor/Nodes/World/Object/ObjectInstanceSetScale.cpp @@ -39,7 +39,19 @@ void ObjectInstanceSetScaleNode::compute() return; } - obj->scale = obj->which() == eMODEL ? scale : 1.0; + if (obj->which() == eWMO) { + QSettings settings; + bool modern_features = settings.value("modern_features", false).toBool(); + if (modern_features) { + obj->scale = scale; + } + else { + obj->scale = 1.0; + } + } + else { + obj->scale = scale; + } obj->recalcExtents(); diff --git a/src/noggit/ui/tools/NodeEditor/Nodes/World/Selection/ScaleSelectedObjectInstances.cpp b/src/noggit/ui/tools/NodeEditor/Nodes/World/Selection/ScaleSelectedObjectInstances.cpp index 9749c034..d9dbc0c0 100755 --- a/src/noggit/ui/tools/NodeEditor/Nodes/World/Selection/ScaleSelectedObjectInstances.cpp +++ b/src/noggit/ui/tools/NodeEditor/Nodes/World/Selection/ScaleSelectedObjectInstances.cpp @@ -35,15 +35,15 @@ void ScaleSelectedObjectInstancesNode::compute() switch (_operation->currentIndex()) { case 0: // Set - world->scale_selected_models(delta, World::m2_scaling_type::set); + world->scale_selected_models(delta, World::object_scaling_type::set); break; case 1: // Add - world->scale_selected_models(delta, World::m2_scaling_type::add); + world->scale_selected_models(delta, World::object_scaling_type::add); break; case 2: // Multiply - world->scale_selected_models(delta, World::m2_scaling_type::mult); + world->scale_selected_models(delta, World::object_scaling_type::mult); break; } diff --git a/src/noggit/ui/tools/ViewportGizmo/ViewportGizmo.cpp b/src/noggit/ui/tools/ViewportGizmo/ViewportGizmo.cpp index e6750dd0..ff61b3c3 100755 --- a/src/noggit/ui/tools/ViewportGizmo/ViewportGizmo.cpp +++ b/src/noggit/ui/tools/ViewportGizmo/ViewportGizmo.cpp @@ -146,6 +146,9 @@ void ViewportGizmo::handleTransformGizmo(MapView* map_view NOGGIT_ACTION_MGR->beginAction(map_view, Noggit::ActionFlags::eOBJECTS_TRANSFORMED, Noggit::ActionModalityControllers::eLMB); + QSettings settings; + bool modern_features = settings.value("modern_features", false).toBool(); + if (gizmo_selection_type == MULTISELECTION) { @@ -163,8 +166,13 @@ void ViewportGizmo::handleTransformGizmo(MapView* map_view glm::vec3& pos = obj_instance->pos; math::degrees::vec3& rotation = obj_instance->dir; - float wmo_scale = 0.f; - float& scale = obj_instance->which() == eMODEL ? obj_instance->scale : wmo_scale; + float& scale = obj_instance->scale; + + // If modern features are disabled, we don't want to scale WMOs + if (obj_instance->which() == eWMO && !modern_features && _gizmo_operation == ImGuizmo::SCALE) { + scale = 1.0f; + continue; + } if (_world) _world->updateTilesEntry(selected, model_update::remove); @@ -279,8 +287,13 @@ void ViewportGizmo::handleTransformGizmo(MapView* map_view glm::vec3& pos = obj_instance->pos; math::degrees::vec3& rotation = obj_instance->dir; - float wmo_scale = 0.f; - float& scale = obj_instance->which() == eMODEL ? obj_instance->scale : wmo_scale; + float& scale = obj_instance->scale; + + // If modern features are disabled, we don't want to scale WMOs + if (obj_instance->which() == eWMO && !modern_features && _gizmo_operation == ImGuizmo::SCALE) { + scale = 1.0f; + continue; + } if (_world) _world->updateTilesEntry(selected, model_update::remove); diff --git a/src/noggit/ui/windows/settingsPanel/SettingsPanel.cpp b/src/noggit/ui/windows/settingsPanel/SettingsPanel.cpp old mode 100755 new mode 100644 index 57611cb5..d38a55fc --- a/src/noggit/ui/windows/settingsPanel/SettingsPanel.cpp +++ b/src/noggit/ui/windows/settingsPanel/SettingsPanel.cpp @@ -225,6 +225,7 @@ namespace Noggit ui->_keyboard_locale->setCurrentText(_settings->value("keyboard_locale", "QWERTY").toString()); ui->_use_mclq_liquids_export->setChecked(_settings->value("use_mclq_liquids_export", false).toBool()); ui->_theme->setCurrentText(_settings->value("theme", "Dark").toString()); + ui->_modern_features->setChecked(_settings->value("modern_features", false).toBool()); ui->assetBrowserBgCol->setColor(_settings->value("assetBrowser/background_color", QVariant::fromValue(QColor(127, 127, 127))).value()); @@ -316,6 +317,7 @@ namespace Noggit _settings->setValue("systemWindowFrame", ui->_systemWindowFrame->isChecked()); _settings->setValue("nativeMenubar", ui->_nativeMenubar->isChecked()); _settings->setValue("classicUI", ui->_classic_ui->isChecked()); + _settings->setValue("modern_features", ui->_modern_features->isChecked()); _settings->setValue("use_mclq_liquids_export", ui->_use_mclq_liquids_export->isChecked()); #ifdef USE_MYSQL_UID_STORAGE diff --git a/src/noggit/ui/windows/settingsPanel/SettingsPanel.ui b/src/noggit/ui/windows/settingsPanel/SettingsPanel.ui index ec8e48af..927f3144 100755 --- a/src/noggit/ui/windows/settingsPanel/SettingsPanel.ui +++ b/src/noggit/ui/windows/settingsPanel/SettingsPanel.ui @@ -797,6 +797,29 @@ + + + + + 200 + 0 + + + + Requires restart. This will enable modern features added in expansions after WotLK. This enables height texturing and WMO scaling. Some features may require additional tools. + + + Modern features (MoP/Legion+) + + + + + + + + + + diff --git a/src/opengl/types.hpp b/src/opengl/types.hpp index 0fa85b0d..c4c1fbfd 100755 --- a/src/opengl/types.hpp +++ b/src/opengl/types.hpp @@ -61,7 +61,9 @@ namespace OpenGL int draw_groundeffectid_overlay = false; int draw_groundeffect_layerid_overlay = false; int draw_noeffectdoodad_overlay = false; - // int padding[3]; + int draw_only_normals = false; + int point_normals_up = false; + // int padding; }; struct ChunkInstanceDataUniformBlock @@ -74,6 +76,13 @@ namespace OpenGL int AreaIDColor_Pad2_DrawSelection[4]; int ChunkXZ_TileXZ[4]; int ChunkTexAnimDir[4]; + + // Mists Heightmapping + int ChunkHeightTextureSamplers[4]; + int ChunkTextureUVScale[4]; + float ChunkTextureHeightScale[4]; + float ChunkTextureHeightOffset[4]; + float ChunkGroundEffectColor[4]; int ChunkDoodadsEnabled2_ChunksLayerEnabled2[4]; };