462 lines
18 KiB
C++
462 lines
18 KiB
C++
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
|
|
|
#pragma once
|
|
|
|
#include <math/frustum.hpp>
|
|
#include <math/trig.hpp>
|
|
#include <noggit/rendering/CursorRender.hpp>
|
|
#include <noggit/Misc.h>
|
|
#include <noggit/Model.h> // ModelManager
|
|
#include <noggit/Selection.h>
|
|
#include <noggit/Sky.h> // Skies, OutdoorLighting, OutdoorLightStats
|
|
#include <noggit/WMO.h> // WMOManager
|
|
#include <noggit/map_horizon.h>
|
|
#include <noggit/map_index.hpp>
|
|
#include <noggit/TileIndex.hpp>
|
|
#include <noggit/tool_enums.hpp>
|
|
#include <noggit/world_tile_update_queue.hpp>
|
|
#include <noggit/world_model_instances_storage.hpp>
|
|
#include <noggit/ui/MinimapCreator.hpp>
|
|
#include <noggit/ContextObject.hpp>
|
|
#include <noggit/rendering/Primitives.hpp>
|
|
#include <opengl/shader.fwd.hpp>
|
|
#include <opengl/types.hpp>
|
|
#include <noggit/rendering/LiquidTextureManager.hpp>
|
|
#include <optional>
|
|
#include <QtCore/QSettings>
|
|
#include <map>
|
|
#include <string>
|
|
#include <unordered_set>
|
|
#include <vector>
|
|
#include <array>
|
|
#include <noggit/project/ApplicationProject.h>
|
|
#include <noggit/rendering/WorldRender.hpp>
|
|
#include <QProgressDialog>
|
|
|
|
namespace Noggit
|
|
{
|
|
struct object_paste_params;
|
|
struct VertexSelectionCache;
|
|
|
|
namespace Rendering
|
|
{
|
|
class WorldRender;
|
|
}
|
|
}
|
|
|
|
class Brush;
|
|
class MapTile;
|
|
class QPixmap;
|
|
|
|
static const float detail_size = 8.0f;
|
|
|
|
using StripType = uint16_t;
|
|
|
|
|
|
class World
|
|
{
|
|
friend class Noggit::Rendering::WorldRender;
|
|
|
|
protected:
|
|
std::unordered_set<unsigned int> selected_uids; // fast lookup
|
|
std::vector<selection_type> _current_selection;
|
|
// std::unordered_map<std::string, std::vector<ModelInstance*>> _models_by_filename;
|
|
Noggit::world_model_instances_storage _model_instance_storage;
|
|
Noggit::world_tile_update_queue _tile_update_queue;
|
|
public:
|
|
std::vector<selection_group> _selection_groups;
|
|
|
|
MapIndex mapIndex;
|
|
Noggit::map_horizon horizon;
|
|
|
|
// Temporary variables for loading a WMO, if we have a global WMO.
|
|
std::string mWmoFilename;
|
|
ENTRY_MODF mWmoEntry;
|
|
|
|
unsigned int getMapID() const;
|
|
|
|
// Time of the day.
|
|
float animtime;
|
|
float time;
|
|
|
|
//! \brief Name of this map.
|
|
std::string basename;
|
|
|
|
explicit World(const std::string& name, int map_id, Noggit::NoggitRenderContext context, bool create_empty = false);
|
|
|
|
void LoadSavedSelectionGroups();
|
|
|
|
void saveSelectionGroups();
|
|
|
|
void setBasename(const std::string& name);
|
|
|
|
SceneObject* getObjectInstance(std::uint32_t uid);
|
|
|
|
void update_models_emitters(float dt);
|
|
|
|
unsigned int getAreaID (glm::vec3 const&);
|
|
void setAreaID(glm::vec3 const& pos, int id, bool adt, float radius = -1.0f);
|
|
|
|
Noggit::NoggitRenderContext getRenderContext() { return _context; };
|
|
|
|
selection_result intersect (glm::mat4x4 const& model_view
|
|
, math::ray const&
|
|
, bool only_map
|
|
, bool do_objects
|
|
, bool draw_terrain
|
|
, bool draw_wmo
|
|
, bool draw_models
|
|
, bool draw_hidden_models
|
|
, bool draw_wmo_exterior
|
|
, bool animate
|
|
);
|
|
|
|
MapChunk* getChunkAt(glm::vec3 const& pos);
|
|
|
|
bool isInIndoorWmoGroup(std::array<glm::vec3, 2> obj_bounds, glm::mat4x4 obj_transform);
|
|
|
|
protected:
|
|
// Information about the currently selected model / WMO / triangle.
|
|
int _selected_model_count = 0;
|
|
std::optional<glm::vec3> _multi_select_pivot;
|
|
public:
|
|
|
|
Noggit::Rendering::WorldRender* renderer() { return &_renderer; }
|
|
|
|
void update_selection_pivot();
|
|
std::optional<glm::vec3> const& multi_select_pivot() const { return _multi_select_pivot; }
|
|
|
|
// Selection related methods.
|
|
bool is_selected(selection_type selection);
|
|
bool is_selected(std::uint32_t uid) const;
|
|
std::vector<selection_type> const& current_selection() const { return _current_selection; }
|
|
std::vector<selected_object_type> const get_selected_objects() const;
|
|
std::optional<selection_type> get_last_selected_model() const;
|
|
bool has_selection() const { return !_current_selection.empty(); }
|
|
bool has_multiple_model_selected() const { return _selected_model_count > 1; }
|
|
int get_selected_model_count() const { return _selected_model_count; }
|
|
// Unused in Red, models are now iterated by adt because of the occlusion check
|
|
// std::unordered_map<std::string, std::vector<ModelInstance*>> get_models_by_filename() const& { return _models_by_filename; }
|
|
void set_current_selection(selection_type entry);
|
|
bool add_to_selection(selection_type entry, bool skip_group = false, bool update_pivot = true);
|
|
void remove_from_selection(selection_type entry, bool skip_group = false, bool update_pivot = true);
|
|
void remove_from_selection(std::uint32_t uid, bool skip_group = false, bool update_pivot = true);
|
|
void reset_selection();
|
|
void delete_selected_models();
|
|
glm::vec3 get_ground_height(glm::vec3 pos);
|
|
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 object_scaling_type
|
|
{
|
|
set,
|
|
add,
|
|
mult
|
|
};
|
|
|
|
void snap_selected_models_to_the_ground();
|
|
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)
|
|
{
|
|
move_selected_models(delta.x, delta.y, delta.z);
|
|
}
|
|
void set_selected_models_pos(float x, float y, float z, bool change_height = true)
|
|
{
|
|
return set_selected_models_pos({x,y,z}, change_height);
|
|
}
|
|
void set_selected_models_pos(glm::vec3 const& pos, bool change_height = true);
|
|
void set_model_pos(selection_type entry, glm::vec3 const& pos, bool change_height = true);
|
|
void rotate_selected_models(math::degrees rx, math::degrees ry, math::degrees rz, bool use_pivot);
|
|
void rotate_selected_models_randomly(float minX, float maxX, float minY, float maxY, float minZ, float maxZ);
|
|
void set_selected_models_rotation(math::degrees rx, math::degrees ry, math::degrees rz);
|
|
|
|
void update_selected_model_groups();
|
|
|
|
// Checks the normal of the terrain on model origin and rotates to that spot.
|
|
void rotate_selected_models_to_ground_normal(bool smoothNormals);
|
|
void rotate_model_to_ground_normal(SceneObject* obj, bool smoothNormals);
|
|
|
|
bool GetVertex(float x, float z, glm::vec3 *V) const;
|
|
|
|
// check if the cursor is under map or in an unloaded tile
|
|
bool isUnderMap(glm::vec3 const& pos) const;
|
|
|
|
template<typename Fun>
|
|
bool for_all_chunks_in_range ( glm::vec3 const& pos
|
|
, float radius
|
|
, Fun&& /* MapChunk* -> bool changed */
|
|
);
|
|
template<typename Fun, typename Post>
|
|
bool for_all_chunks_in_range ( glm::vec3 const& pos
|
|
, float radius
|
|
, Fun&& /* MapChunk* -> bool changed */
|
|
, Post&& /* MapChunk* -> void; called for all changed chunks */
|
|
);
|
|
|
|
template<typename Fun>
|
|
bool for_all_chunks_in_rect ( glm::vec3 const& pos
|
|
, float radius
|
|
, Fun&& /* MapChunk* -> bool changed */
|
|
);
|
|
|
|
template<typename Fun, typename Post>
|
|
bool for_all_chunks_in_rect (glm::vec3 const& pos
|
|
, float radius
|
|
, Fun&& /* MapChunk* -> bool changed */
|
|
, Post&& /* MapChunk* -> void; called for all changed chunks */
|
|
);
|
|
|
|
template<typename Fun>
|
|
void for_all_chunks_on_tile (glm::vec3 const& pos, Fun&&);
|
|
|
|
template<typename Fun>
|
|
void for_all_chunks_on_tile(MapTile* tile, Fun&& fun);
|
|
|
|
template<typename Fun>
|
|
void for_chunk_at(glm::vec3 const& pos, Fun&& fun);
|
|
template<typename Fun>
|
|
auto for_maybe_chunk_at (glm::vec3 const& pos, Fun&& fun) -> std::optional<decltype (fun (nullptr))>;
|
|
|
|
template<typename Fun>
|
|
void for_tile_at(const TileIndex& pos, Fun&&);
|
|
|
|
template<typename Fun>
|
|
void for_tile_at_force(const TileIndex& pos, Fun&&);
|
|
|
|
void changeObjectsWithTerrain(glm::vec3 const& pos, float change, float radius, int BrushType, float inner_radius, bool iter_wmos_ = true, bool iter_m2s = true);
|
|
void changeTerrain(glm::vec3 const& pos, float change, float radius, int BrushType, float inner_radius);
|
|
std::vector<selected_object_type> getObjectsInRange(glm::vec3 const& pos, float radius, bool ignore_height = true, bool iter_wmos_ = true, bool iter_m2s = true);
|
|
void changeShader(glm::vec3 const& pos, glm::vec4 const& color, float change, float radius, bool editMode);
|
|
void stampShader(glm::vec3 const& pos, glm::vec4 const& color, float change, float radius, bool editMode, QImage* img, bool paint, bool use_image_colors);
|
|
glm::vec3 pickShaderColor(glm::vec3 const& pos);
|
|
void flattenTerrain(glm::vec3 const& pos, float remain, float radius, int BrushType, flatten_mode const& mode, const glm::vec3& origin, math::degrees angle, math::degrees orientation);
|
|
std::vector<std::pair<SceneObject*, float>> getObjectsGroundDistance(glm::vec3 const& pos, float radius, bool iter_wmos_, bool iter_m2s);
|
|
void blurTerrain(glm::vec3 const& pos, float remain, float radius, int BrushType, flatten_mode const& mode);
|
|
bool paintTexture(glm::vec3 const& pos, Brush *brush, float strength, float pressure, scoped_blp_texture_reference texture);
|
|
bool stampTexture(glm::vec3 const& pos, Brush *brush, float strength, float pressure, scoped_blp_texture_reference texture, QImage* img, bool paint);
|
|
bool sprayTexture(glm::vec3 const& pos, Brush *brush, float strength, float pressure, float spraySize, float sprayPressure, scoped_blp_texture_reference texture);
|
|
bool replaceTexture(glm::vec3 const& pos, float radius, scoped_blp_texture_reference const& old_texture, scoped_blp_texture_reference new_texture, bool entire_chunk = false, bool entire_tile = false);
|
|
|
|
void eraseTextures(glm::vec3 const& pos);
|
|
void overwriteTextureAtCurrentChunk(glm::vec3 const& pos, scoped_blp_texture_reference const& oldTexture, scoped_blp_texture_reference newTexture);
|
|
void paintGroundEffectExclusion(glm::vec3 const& pos, float radius, bool exclusion);
|
|
void setBaseTexture(glm::vec3 const& pos);
|
|
void clear_shadows(glm::vec3 const& pos);
|
|
void clearTextures(glm::vec3 const& pos);
|
|
void swapTexture(glm::vec3 const& pos, scoped_blp_texture_reference tex);
|
|
void swapTextureGlobal(scoped_blp_texture_reference tex);
|
|
void removeTexture(glm::vec3 const& pos, scoped_blp_texture_reference tex);
|
|
void removeTexDuplicateOnADT(glm::vec3 const& pos);
|
|
void change_texture_flag(glm::vec3 const& pos, scoped_blp_texture_reference const& tex, std::size_t flag, bool add);
|
|
|
|
void setHole(glm::vec3 const& pos, float radius, bool big, bool hole);
|
|
void setHoleADT(glm::vec3 const& pos, bool hole);
|
|
|
|
void exportADTAlphamap(glm::vec3 const& pos);
|
|
void exportADTNormalmap(glm::vec3 const& pos);
|
|
void exportADTAlphamap(glm::vec3 const& pos, std::string const& filename);
|
|
void exportADTHeightmap(glm::vec3 const& pos, float min_height, float max_height);
|
|
void exportADTVertexColorMap(glm::vec3 const& pos);
|
|
void exportAllADTsAlphamap();
|
|
void exportAllADTsAlphamap(std::string const& filename);
|
|
void exportAllADTsHeightmap();
|
|
void exportAllADTsVertexColorMap();
|
|
|
|
void importADTAlphamap(glm::vec3 const& pos, QImage const& image, unsigned layer, bool cleanup);
|
|
void importADTAlphamap(glm::vec3 const& pos, bool cleanup);
|
|
void importADTHeightmap(glm::vec3 const& pos, QImage const& image, float min_height, float max_height, unsigned mode, bool tiledEdges);
|
|
void importADTHeightmap(glm::vec3 const& pos, float min_height, float max_height, unsigned mode, bool tiledEdges);
|
|
void importADTWatermap(glm::vec3 const& pos, QImage const& image, float min_height, float max_height, unsigned mode, bool tiledEdges);
|
|
void importADTVertexColorMap(glm::vec3 const& pos, int mode, bool tiledEdges);
|
|
void importADTVertexColorMap(glm::vec3 const& pos, QImage const& image, int mode, bool tiledEdges);
|
|
|
|
void importAllADTsAlphamaps(QProgressDialog* progress_dialog);
|
|
void importAllADTsHeightmaps(QProgressDialog* progress_dialog, float min_height, float max_height, unsigned mode, bool tiledEdges);
|
|
void importAllADTVertexColorMaps(unsigned mode, bool tiledEdges);
|
|
|
|
void ensureAllTilesetsADT(glm::vec3 const& pos);
|
|
void ensureAllTilesetsAllADTs();
|
|
|
|
void notifyTileRendererOnSelectedTextureChange();
|
|
|
|
void addM2 ( BlizzardArchive::Listfile::FileKey const& file_key
|
|
, glm::vec3 newPos
|
|
, float scale, math::degrees::vec3 rotation
|
|
, Noggit::object_paste_params*
|
|
, bool action
|
|
);
|
|
void addWMO ( BlizzardArchive::Listfile::FileKey const& file_key
|
|
, glm::vec3 newPos
|
|
, float scale, math::degrees::vec3 rotation
|
|
, Noggit::object_paste_params*
|
|
, bool action
|
|
);
|
|
|
|
ModelInstance* addM2AndGetInstance ( BlizzardArchive::Listfile::FileKey const& file_key
|
|
, glm::vec3 newPos
|
|
, float scale, math::degrees::vec3 rotation
|
|
, Noggit::object_paste_params*
|
|
, bool ignore_params
|
|
, bool action
|
|
);
|
|
|
|
WMOInstance* addWMOAndGetInstance ( BlizzardArchive::Listfile::FileKey const& file_key
|
|
, glm::vec3 newPos
|
|
, math::degrees::vec3 rotation
|
|
, float scale
|
|
, bool action
|
|
);
|
|
|
|
auto stamp(glm::vec3 const& pos, float dt, QImage const* img, float radiusOuter
|
|
, float radiusInner, int BrushType, bool sculpt) -> void;
|
|
|
|
// add a m2 instance to the world (needs to be positioned already), return the uid
|
|
std::uint32_t add_model_instance(ModelInstance model_instance, bool from_reloading, bool action);
|
|
// add a wmo instance to the world (needs to be positioned already), return the uid
|
|
std::uint32_t add_wmo_instance(WMOInstance wmo_instance, bool from_reloading, bool action);
|
|
|
|
std::optional<selection_type> get_model(std::uint32_t uid);
|
|
void remove_models_if_needed(std::vector<uint32_t> const& uids);
|
|
|
|
void reload_tile(TileIndex const& tile);
|
|
|
|
void updateTilesEntry(selection_type const& entry, model_update type);
|
|
void updateTilesEntry(SceneObject* entry, model_update type);
|
|
void updateTilesWMO(WMOInstance* wmo, model_update type);
|
|
void updateTilesModel(ModelInstance* m2, model_update type);
|
|
void wait_for_all_tile_updates();
|
|
|
|
void deleteModelInstance(int uid, bool action);
|
|
void deleteWMOInstance(int uid, bool action);
|
|
void deleteInstance(int uid, bool action);
|
|
|
|
bool uid_duplicates_found() const;
|
|
void delete_duplicate_model_and_wmo_instances();
|
|
// used after the uid fix all
|
|
void unload_every_model_and_wmo_instance();
|
|
|
|
static bool IsEditableWorld(BlizzardDatabaseLib::Structures::BlizzardDatabaseRow& record);
|
|
|
|
static bool IsWMOWorld(BlizzardDatabaseLib::Structures::BlizzardDatabaseRow& record);
|
|
|
|
void clearHeight(glm::vec3 const& pos);
|
|
void clearAllModelsOnADT(TileIndex const& tile, bool action);
|
|
|
|
// liquids
|
|
void paintLiquid( glm::vec3 const& pos
|
|
, float radius
|
|
, int liquid_id
|
|
, bool add
|
|
, math::radians const& angle
|
|
, math::radians const& orientation
|
|
, bool lock
|
|
, glm::vec3 const& origin
|
|
, bool override_height
|
|
, bool override_liquid_id
|
|
, float opacity_factor
|
|
);
|
|
void CropWaterADT(const TileIndex& pos);
|
|
void setWaterType(const TileIndex& pos, int type, int layer);
|
|
int getWaterType(const TileIndex& tile, int layer) const;
|
|
void autoGenWaterTrans(const TileIndex&, float factor);
|
|
|
|
|
|
void fixAllGaps();
|
|
|
|
void CleanupEmptyTexturesChunks();
|
|
void convert_alphamap(QProgressDialog* progress_dialog, bool to_big_alpha);
|
|
|
|
bool deselectVertices(glm::vec3 const& pos, float radius);
|
|
void selectVertices(glm::vec3 const& pos, float radius);
|
|
void moveVertices(float h);
|
|
void orientVertices ( glm::vec3 const& ref_pos
|
|
, math::degrees vertex_angle
|
|
, math::degrees vertex_orientation
|
|
);
|
|
void flattenVertices (float height);
|
|
|
|
void updateSelectedVertices();
|
|
void updateVertexCenter();
|
|
void clearVertexSelection();
|
|
|
|
void deleteObjects(std::vector<selected_object_type> const& types, bool action);
|
|
|
|
float getMaxTileHeight(const TileIndex& tile);
|
|
|
|
glm::vec3 const& vertexCenter();
|
|
|
|
void recalc_norms (MapChunk*) const;
|
|
|
|
Noggit::VertexSelectionCache getVertexSelectionCache();
|
|
void setVertexSelectionCache(Noggit::VertexSelectionCache& cache);
|
|
|
|
bool need_model_updates = false;
|
|
|
|
void loadAllTiles(glm::vec3& camera_pos);
|
|
unsigned getNumLoadedTiles() const { return _n_loaded_tiles; };
|
|
unsigned getNumRenderedTiles() const { return _n_rendered_tiles; };
|
|
unsigned getNumRenderedObjects() const { return _n_rendered_objects; };
|
|
|
|
void select_objects_in_area(
|
|
const std::array<glm::vec2, 2>& selection_box,
|
|
bool reset_selection,
|
|
const glm::mat4x4& view,
|
|
const glm::mat4x4& projection,
|
|
int viewport_width,
|
|
int viewport_height,
|
|
float user_depth,
|
|
const glm::vec3& camera_position
|
|
);
|
|
|
|
|
|
void add_object_group_from_selection();
|
|
// void remove_selection_group(selection_group* group);
|
|
|
|
void clear_selection_groups();
|
|
|
|
private:
|
|
bool is_point_occluded_by_terrain(const glm::vec3& point
|
|
, const glm::mat4x4& view
|
|
, const glm::mat4& VPmatrix
|
|
, float viewport_width
|
|
, float viewport_height
|
|
, const glm::vec3& camera_position
|
|
, float distance_override = 0.0f);
|
|
|
|
public:
|
|
bool paste_model_random_rotation = false;
|
|
bool paste_model_random_tilt = false;
|
|
bool paste_model_random_size = false;
|
|
|
|
protected:
|
|
// void update_models_by_filename();
|
|
|
|
std::unordered_set<MapChunk*>& vertexBorderChunks();
|
|
|
|
std::unordered_set<MapTile*> _vertex_tiles;
|
|
std::unordered_set<MapChunk*> _vertex_chunks;
|
|
std::unordered_set<MapChunk*> _vertex_border_chunks;
|
|
std::unordered_set<glm::vec3*> _vertices_selected;
|
|
glm::vec3 _vertex_center;
|
|
bool _vertex_center_updated = false;
|
|
bool _vertex_border_updated = false;
|
|
|
|
QSettings* _settings;
|
|
|
|
Noggit::NoggitRenderContext _context;
|
|
|
|
std::array<std::pair<std::pair<int, int>, MapTile*>, 64 * 64 > _loaded_tiles_buffer;
|
|
|
|
Noggit::Rendering::WorldRender _renderer;
|
|
|
|
// Debug metrics
|
|
unsigned _n_loaded_tiles = 0;
|
|
unsigned _n_rendered_tiles = 0;;
|
|
|
|
// unsigned _n_loaded_objects; // done from instance storage size currently
|
|
unsigned _n_rendered_objects = 0;
|
|
|
|
};
|