Modern features (height texturing, WMO scaling, maptexture generation)

This commit is contained in:
Martin Benjamins
2024-11-01 02:48:08 +00:00
committed by T1ti
parent df5374d443
commit d93dbc55ad
51 changed files with 928 additions and 130 deletions

View File

@@ -3,6 +3,7 @@
#include <glm/mat4x4.hpp>
#include <optional>
#include <cmath>
#include <iostream>
namespace math
{

4
src/noggit/Action.cpp Executable file → Normal file
View File

@@ -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);

2
src/noggit/MapChunk.cpp Executable file → Normal file
View File

@@ -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 don<EFBFBD>t 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;

View File

@@ -121,7 +121,7 @@ struct ENTRY_MODF
uint16_t flags;
uint16_t doodadSet;
uint16_t nameSet;
uint16_t unknown;
uint16_t scale;
};
struct MapChunkHeader {

25
src/noggit/MapTile.cpp Executable file → Normal file
View File

@@ -13,6 +13,7 @@
#include <noggit/texture_set.hpp>
#include <noggit/ui/TexturingGUI.h>
#include <noggit/application/NoggitApplication.hpp>
#include <noggit/project/CurrentProject.hpp>
#include <ClientFile.hpp>
#include <opengl/scoped.hpp>
#include <opengl/shader.hpp>
@@ -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())
@@ -1865,5 +1886,3 @@ void MapTile::recalcCombinedExtents()
_combined_extents_dirty = false;
}

4
src/noggit/MapTile.h Executable file → Normal file
View File

@@ -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<glm::vec3, 2> _extents;
std::array<glm::vec3, 2> _object_instance_extents;
std::array<glm::vec3, 2> _combined_extents;

20
src/noggit/MapView.cpp Executable file → Normal file
View File

@@ -103,6 +103,7 @@
#include <QFileDialog>
#include <QProgressDialog>
#include <QClipboard>
#include <QProcess>
#include <algorithm>
#include <cmath>
@@ -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<WMOInstance*>(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

View File

@@ -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<bool, 4096> selected_tiles = {false};
std::vector<char> selected_tiles = std::vector<char>( size_t{4096}, false, {} );
std::vector<char> selected_tiles = std::vector<char>(size_t{ 4096 }, false, {});
// Filtering
QListWidget* m2_model_filter_include = nullptr;

View File

@@ -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<blp_texture>(height_filename,_context);
heightMap->finishLoading();
}
}
}
BlizzardArchive::ClientFile f(

20
src/noggit/TextureManager.h Executable file → Normal file
View File

@@ -13,6 +13,7 @@
#include <QtGui/QOffscreenSurface>
#include <QtGui/QOpenGLFramebufferObjectFormat>
#include <QPainter>
#include <QtGui/QPixmap>
#include <optional>
#include <map>
@@ -23,6 +24,19 @@
#include <tuple>
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 <class T1, class T2, class T3, class T4>
@@ -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<int, std::vector<uint32_t>> _data;
@@ -91,6 +109,8 @@ private:
std::optional<GLint> _compression_format;
int _array_index = -1;
GLuint _texture_array = 0;
std::unique_ptr<blp_texture> heightMap;
};
struct TexArrayParams

View File

@@ -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)

View File

@@ -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;

View File

@@ -13,11 +13,13 @@
#include <sstream>
#include <QtCore/QSettings>
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<float>(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)
{

View File

@@ -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);

77
src/noggit/World.cpp Executable file → Normal file
View File

@@ -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,8 +788,42 @@ void World::scale_selected_models(float v, m2_scaling_type type)
auto obj = std::get<selected_object_type>(entry);
if (obj->which() != eMODEL)
{
// If we are not using modern features, we don't want to scale WMOs
if(!modern_features)
continue;
WMOInstance* wi = static_cast<WMOInstance*>(obj);
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<ModelInstance*>(obj);
NOGGIT_CUR_ACTION->registerObjectTransformed(mi);
@@ -794,13 +832,13 @@ void World::scale_selected_models(float v, m2_scaling_type type)
switch (type)
{
case World::m2_scaling_type::set:
case World::object_scaling_type::set:
scale = v;
break;
case World::m2_scaling_type::add:
case World::object_scaling_type::add:
scale += v;
break;
case World::m2_scaling_type::mult:
case World::object_scaling_type::mult:
scale *= v;
break;
}
@@ -817,6 +855,7 @@ void World::scale_selected_models(float v, m2_scaling_type type)
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();

8
src/noggit/World.h Executable file → Normal file
View File

@@ -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
);

View File

@@ -0,0 +1,93 @@
#include "ApplicationProject.h"
#include <noggit/World.h>
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;
}
};

View File

@@ -9,6 +9,9 @@
#include <blizzard-database-library/include/BlizzardDatabase.h>
#include <noggit/application/Configuration/NoggitApplicationConfiguration.hpp>
#include <noggit/ui/windows/downloadFileDialog/DownloadFileDialog.h>
#include <noggit/TextureManager.h>
#include <external/tsl/robin_map.h>
#include <noggit/World.h>
#include <noggit/Log.h>
#include <QJsonDocument>
#include <QMessageBox>
@@ -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<int,
tsl::robin_map< int, tsl::robin_map<int , tsl::robin_map<std::string, texture_heightmapping_data> >>> 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<NoggitProjectTexturePalette> TexturePalettes;
std::vector<NoggitProjectSelectionGroups> ObjectSelectionGroups;
NoggitExtraMapData ExtraMapData;
NoggitProject()
{
PinnedMaps = std::vector<NoggitProjectPinnedMap>();
@@ -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<NoggitProject>(project.value());
}
void loadExtraData(NoggitProject& project);
};
}

View File

@@ -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();

View File

@@ -5,6 +5,7 @@
#include <noggit/MapChunk.h>
#include <noggit/ui/TexturingGUI.h>
#include <external/tracy/Tracy.hpp>
#include <QtCore/QSettings>
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();
@@ -573,6 +599,34 @@ 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;

View File

@@ -3,6 +3,7 @@
#include "WMOGroupRender.hpp"
#include <noggit/WMO.h>
#include <noggit/Log.h> // LogDebug
#include <QtCore/QSettings>
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<WMORenderBatch*> _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)
{

View File

@@ -74,6 +74,20 @@ 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;
}
@@ -83,6 +97,10 @@ void WorldRender::draw (glm::mat4x4 const& model_view
// 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<int>(_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.FogColor_FogOn = { 0, 0, 0, 0 };
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.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() };
}
_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

92
src/noggit/rendering/glsl/terrain_frag.glsl Executable file → Normal file
View File

@@ -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
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;
}
}

View File

@@ -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;
};

View File

@@ -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.);

8
src/noggit/scripting/script_global.cpp Executable file → Normal file
View File

@@ -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);
});

5
src/noggit/scripting/script_model.cpp Executable file → Normal file
View File

@@ -52,15 +52,12 @@ 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
{

7
src/noggit/texture_set.cpp Executable file → Normal file
View File

@@ -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<int> visible_tex;
if (tmp_edit_values)

5
src/noggit/texture_set.hpp Executable file → Normal file
View File

@@ -150,6 +150,11 @@ private:
std::vector<scoped_blp_texture_reference> textures;
std::array<std::unique_ptr<Alphamap>, MAX_ALPHAMAPS> alphamaps;
// Mists Heightmapping
std::vector<scoped_blp_texture_reference> heightTextures;
std::array<texture_heightmapping_data, 4> 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.

View File

@@ -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<int>(_mmap_render_index) < progress->maximum())
{
save();

View File

@@ -315,7 +315,7 @@ namespace Noggit
// auto replace_wmo = static_cast<WMOInstance*>(replacement_obj);
// auto source_wmo = static_cast<WMOInstance*>(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);
}
}
}

View File

@@ -12,6 +12,7 @@
#include <QtGui/QDrag>
#include <QtGui/QPainter>
#include <QMimeData>
#include <QPainter>
namespace Noggit
{

View File

@@ -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)

0
src/noggit/ui/MinimapCreator.hpp Executable file → Normal file
View File

8
src/noggit/ui/ObjectEditor.cpp Executable file → Normal file
View File

@@ -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<WMOInstance*>(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();

View File

@@ -199,7 +199,7 @@ namespace Noggit
{
NOGGIT_ACTION_MGR->beginAction(reinterpret_cast<MapView*>(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<MapView*>(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<selected_object_type>(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);

View File

@@ -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);

0
src/noggit/ui/TexturePicker.cpp Executable file → Normal file
View File

36
src/noggit/ui/TexturingGUI.cpp Executable file → Normal file
View File

@@ -67,6 +67,10 @@ namespace Noggit
std::vector<std::string> tilesets;
std::unordered_set<std::string> 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)
if (modern_features)
texture_filter_box->setText("only with height texture variant");
connect(texture_filter_box, &QCheckBox::toggled
, [=](bool on)
{
specular_filter->setFilterRegExp (on ? "true" : "");
texture_filter->setFilterRegExp(on ? "true" : "");
}
);
only_specular->setChecked (false);
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);

132
src/noggit/ui/texturing_tool.cpp Executable file → Normal file
View File

@@ -12,18 +12,21 @@
#include <noggit/ui/texture_swapper.hpp>
#include <noggit/DBC.h>
#include <util/qt/overload.hpp>
#include <noggit/TextureManager.h>
#include <noggit/ui/tools/AssetBrowser/Ui/AssetBrowser.hpp>
#include <QtWidgets/QFormLayout>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QTabWidget>
#include <noggit/ui/tools/UiCommon/ExtendedSlider.hpp>
#include <QClipboard>
#include <noggit/ui/tools/UiCommon/expanderwidget.h>
#include <noggit/ui/WeightListWidgetItem.hpp>
#include <noggit/ui/FontAwesome.hpp>
#define _USE_MATH_DEFINES
#include <math.h>
#include <noggit/project/CurrentProject.hpp>
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);
@@ -262,6 +330,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<double>(&QDoubleSpinBox::valueChanged)
, [&](double v)
{
textureHeightmappingData.uvScale = v;
}
);
connect(heightmapping_heightscale_spin, qOverload<double>(&QDoubleSpinBox::valueChanged)
, [&](double v)
{
textureHeightmappingData.heightScale = v;
}
);
connect(heightmapping_heightoffset_spin, qOverload<double>(&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();

10
src/noggit/ui/texturing_tool.hpp Executable file → Normal file
View File

@@ -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;

10
src/noggit/ui/tools/LightEditor/LightEditor.cpp Executable file → Normal file
View File

@@ -1,7 +1,6 @@
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
#include "LightEditor.hpp"
#include <noggit/DBC.h>
#include <noggit/World.h>
#include <noggit/MapView.h>
#include <noggit/ui/FontAwesome.hpp>
@@ -20,6 +19,7 @@
#include <QTextStream>
#include <QStringList>
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 = <20>17066.66656
pos_x_spin->setRange(-17066.66656 * 2, 17066.66656 * 2); // size = <20>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 = <20>17066.66656
pos_y_spin->setRange(-17066.66656 * 2, 17066.66656 * 2); // size = <20>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 <20>E36 )
inner_radius_spin->setRange(0, 100000); // max seen in dbc is 3871 (139363 <20>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 <20>E36 )
outer_radius_spin->setRange(0, 100000); // max seen in dbc is 3871 (139363 <20>E36 )
outer_radius_spin->setValue(0);
outer_radius_spin->setSingleStep(50);
outer_radius_spin->setEnabled(false);

0
src/noggit/ui/tools/LightEditor/LightEditor.hpp Executable file → Normal file
View File

View File

@@ -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
{

View File

@@ -48,7 +48,7 @@ void ObjectInstanceInfoNode::compute()
if (_out_ports[2].connected)
{
_out_ports[2].out_value = std::make_shared<DecimalData>(obj->which() == eMODEL ? obj->scale : 1.0);
_out_ports[2].out_value = std::make_shared<DecimalData>(obj->scale);
_node->onDataUpdated(2);
}

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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);

2
src/noggit/ui/windows/settingsPanel/SettingsPanel.cpp Executable file → Normal file
View File

@@ -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<QColor>());
@@ -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

View File

@@ -797,6 +797,29 @@
</item>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_44">
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>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.</string>
</property>
<property name="text">
<string>Modern features (MoP/Legion+)</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="_modern_features">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_12">
<property name="minimumSize">

View File

@@ -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];
};