Implement early drafts of the Stamp Tool and contribute various small fixes.

This commit is contained in:
p620
2020-10-30 11:40:38 +03:00
parent 2d3c96bcd3
commit f5fad0d448
13 changed files with 395 additions and 10 deletions

View File

@@ -6,6 +6,7 @@ uniform sampler2D tex0;
uniform sampler2D tex1;
uniform sampler2D tex2;
uniform sampler2D tex3;
//uniform sampler2D stampBrush;
uniform vec2 tex_anim_0;
uniform vec2 tex_anim_1;
uniform vec2 tex_anim_2;

View File

@@ -19,6 +19,8 @@
#include <algorithm>
#include <iostream>
#include <map>
#include <QPixmap>
#include <QImage>
MapChunk::MapChunk(MapTile *maintile, MPQFile *f, bool bigAlpha, tile_mode mode)
: _mode(mode)
@@ -977,6 +979,28 @@ bool MapChunk::blurTerrain ( math::vector_3d const& pos
return changed;
}
auto MapChunk::stamp(math::vector_3d const& pos, float dt, bool doAdd, QImage const& img, float radiusOuter
, float radiusInner, float rotation) -> void
{
bool changed{false};
for(int i{}; i < mapbufsize; ++i)
{
/*if(std::abs(misc::dist(mVertices[i].x, mVertices[i].z, pos.x, pos.z) / radiusOuter) > 1.f)
continue;*/
if(std::abs(pos.x - mVertices[i].x) > radiusOuter || std::abs(pos.z - mVertices[i].z) > radiusOuter)
continue;
math::vector_3d const diff{mVertices[i] - pos};
mVertices[i].y += (doAdd ? .5f : -.5f) * ((img.pixel(std::floor(diff.x + radiusOuter)
, std::floor(diff.z + radiusOuter)) & 0xFF) / 255.f);
changed = true;
}
if(changed)
updateVerticesData();
}
void MapChunk::eraseTextures()
{

View File

@@ -27,6 +27,7 @@ namespace math
class Brush;
class ChunkWater;
class sExtendableArray;
class QPixmap;
using StripType = uint16_t;
static const int mapbufsize = 9 * 9 + 8 * 8; // chunk size
@@ -156,6 +157,8 @@ public:
, std::function<boost::optional<float> (float, float)> height
);
auto stamp(math::vector_3d const& pos, float dt, bool doAdd, QImage const& pixmap, float radiusOuter
, float radiusInner, float rotation) -> void;
void selectVertex(math::vector_3d const& pos, float radius, std::set<math::vector_3d*>& vertices);
void fixVertices(std::set<math::vector_3d*>& selected);
// for the vertex tool

View File

@@ -37,6 +37,7 @@
#include <noggit/ui/texture_palette_small.hpp>
#include <noggit/ui/MinimapCreator.hpp>
#include <opengl/scoped.hpp>
#include <noggit/Red/StampMode/Ui/Model/Item.hpp>
#include "revision.h"
@@ -63,6 +64,7 @@
#include <regex>
#include <string>
#include <vector>
#include <filesystem>
static const float XSENS = 15.0f;
@@ -130,6 +132,9 @@ void MapView::setToolPropertyWidgetVisibility(editing_mode mode)
case editing_mode::minimap:
_minimap_tool_dock->setVisible(!ui_hidden);
break;
case editing_mode::stamp:
_dockStamp.setVisible(!ui_hidden);
break;
}
@@ -237,22 +242,22 @@ void MapView::createGUI()
_flatten_blur_dock->setWidget(flattenTool);
_tool_properties_docks.insert(_flatten_blur_dock);
_texturing_dock = new QDockWidget("Texturing", this);
_texturing_dock = new QDockWidget("Texture Painter", this);
texturingTool = new noggit::ui::texturing_tool(&_camera.position, _world.get(), &_show_texture_palette_small_window, _texturing_dock);
_texturing_dock->setWidget(texturingTool);
_tool_properties_docks.insert(_texturing_dock);
_hole_tool_dock = new QDockWidget("Holes", this);
_hole_tool_dock = new QDockWidget("Hole Cutter", this);
holeTool = new noggit::ui::hole_tool(_hole_tool_dock);
_hole_tool_dock->setWidget(holeTool);
_tool_properties_docks.insert(_hole_tool_dock);
_areaid_editor_dock = new QDockWidget("Area ID", this);
_areaid_editor_dock = new QDockWidget("Area Designator", this);
ZoneIDBrowser = new noggit::ui::zone_id_browser(_areaid_editor_dock);
_areaid_editor_dock->setWidget(ZoneIDBrowser);
_tool_properties_docks.insert(_areaid_editor_dock);
_water_editor_dock = new QDockWidget("Water", this);
_water_editor_dock = new QDockWidget("Water Editor", this);
guiWater = new noggit::ui::water(&_displayed_water_layer, &_display_all_water_layers, _water_editor_dock);
_water_editor_dock->setWidget(guiWater);
_tool_properties_docks.insert(_water_editor_dock);
@@ -278,18 +283,18 @@ void MapView::createGUI()
}
);
_vertex_shading_dock = new QDockWidget("Vertex Shading", this);
_vertex_shading_dock = new QDockWidget("Vertex Painter", this);
shaderTool = new noggit::ui::shader_tool(shader_color, _vertex_shading_dock);
_vertex_shading_dock->setWidget(shaderTool);
_tool_properties_docks.insert(_vertex_shading_dock);
_minimap_tool_dock = new QDockWidget("Minimap Creator", this);
_minimap_tool_dock = new QDockWidget("Minimap Editor", this);
_minimap_tool_dock->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
minimapTool = new noggit::ui::MinimapCreator(this, _world.get(), _minimap_tool_dock);
_minimap_tool_dock->setWidget(minimapTool);
_tool_properties_docks.insert(_minimap_tool_dock);
_object_editor_dock = new QDockWidget("Object", this);
_object_editor_dock = new QDockWidget("Object Editor", this);
objectEditor = new noggit::ui::object_editor(this
, _world.get()
, &_move_model_to_cursor_position
@@ -1355,12 +1360,18 @@ MapView::MapView( math::degrees camera_yaw0
, _minimap (new noggit::ui::minimap_widget (nullptr))
, _minimap_dock (new QDockWidget ("Minimap", this))
, _texture_palette_dock(new QDockWidget(this))
, _dockStamp{"Stamp Tool", this}
, _modeStampTool{&_showStampPalette, this}
, _modeStampPaletteMain{this}
{
_main_window->setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
_main_window->setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
_main_window->setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
_main_window->setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
if(QString pathProject{_settings->value("project/path").toString()}; !(pathProject.endsWith('\\') || pathProject.endsWith('/')))
_settings->setValue("project/path", pathProject.append('/'));
_main_window->statusBar()->addWidget (_status_position);
connect ( this
, &QObject::destroyed
@@ -1456,6 +1467,10 @@ MapView::MapView( math::degrees camera_yaw0
_startup_time.start();
_update_every_event_loop.start (0);
connect (&_update_every_event_loop, &QTimer::timeout, [this] { update(); });
_tool_properties_docks.insert(&_dockStamp);
_dockStamp.setWidget(&_modeStampTool);
connect(&_showStampPalette, &noggit::bool_toggle_property::changed, &_modeStampPaletteMain, &QWidget::show);
connect(&_modeStampPaletteMain, &noggit::Red::StampMode::Ui::PaletteMain::itemSelected, &_modeStampTool, &noggit::Red::StampMode::Ui::Tool::setPixmap);
}
void MapView::tabletEvent(QTabletEvent* event)
@@ -1465,6 +1480,20 @@ void MapView::tabletEvent(QTabletEvent* event)
}
auto MapView::populateImageModel(QStandardItemModel* model) const -> void
{
using namespace noggit::Red::StampMode::Ui::Model;
namespace fs = std::filesystem;
for(auto& image : fs::directory_iterator{_settings->value("project/path").toString().toStdString() + "Images/"})
if(!image.is_directory())
{
auto item{new Item{image.path().string().c_str()}};
item->setText(image.path().filename().c_str());
model->appendRow(item);
}
}
void MapView::move_camera_with_auto_height (math::vector_3d const& pos)
{
makeCurrent();
@@ -1546,7 +1575,7 @@ void MapView::initializeGL()
, "UID Warning"
, "Some models were missing or couldn't be loaded. "
"This will lead to culling (visibility) errors in game\n"
"It is recommanded to fix those models (listed in the log file) and run the uid fix all again."
"It is recommended to fix those models (listed in the log file) and run the uid fix all again."
, QMessageBox::Ok
);
}
@@ -2067,6 +2096,14 @@ void MapView::tick (float dt)
}
}
break;
case editing_mode::stamp:
if(!underMap)
{
if(_mod_shift_down)
_modeStampTool.stamp(_world.get(), _cursor_pos, dt, true);
else if(_mod_ctrl_down)
_modeStampTool.stamp(_world.get(), _cursor_pos, dt, false);
}
}
}
}
@@ -2564,6 +2601,10 @@ void MapView::draw_map()
case editing_mode::minimap:
radius = minimapTool->brushRadius();
break;
case editing_mode::stamp:
radius = _modeStampTool.getOuterRadius();
inner_radius = _modeStampTool.getInnerRadius() / radius;
break;
}
//! \note Select terrain below mouse, if no item selected or the item is map.

View File

@@ -13,6 +13,8 @@
#include <noggit/ui/MinimapCreator.hpp>
#include <noggit/ui/uid_fix_window.hpp>
#include <noggit/unsigned_int_property.hpp>
#include <noggit/Red/StampMode/Ui/Tool.hpp>
#include <noggit/Red/StampMode/Ui/PaletteMain.hpp>
#include <boost/optional.hpp>
@@ -26,6 +28,7 @@
#include <forward_list>
#include <map>
#include <unordered_map>
#include <unordered_set>
@@ -201,6 +204,7 @@ public:
void change_selected_wmo_doodadset(int set);
void saveMinimap(MinimapRenderSettings* settings);
void initMinimapSave() { saving_minimap = true; };
auto populateImageModel(QStandardItemModel* model) const -> void;
noggit::camera* getCamera() { return &_camera; };
void set_editing_mode (editing_mode);
@@ -282,6 +286,7 @@ private:
noggit::bool_toggle_property _show_keybindings_window = {false};
noggit::bool_toggle_property _show_texture_palette_window = {false};
noggit::bool_toggle_property _show_texture_palette_small_window = {false};
noggit::bool_toggle_property _showStampPalette{false};
noggit::ui::minimap_widget* _minimap;
QDockWidget* _minimap_dock;
@@ -318,4 +323,8 @@ private:
QDockWidget* _hole_tool_dock;
noggit::ui::MinimapCreator* minimapTool;
QDockWidget* _minimap_tool_dock;
QDockWidget _dockStamp;
noggit::Red::StampMode::Ui::Tool _modeStampTool;
noggit::Red::StampMode::Ui::PaletteMain _modeStampPaletteMain;
std::unordered_map<std::string, QPixmap> _images;
};

View File

@@ -0,0 +1,17 @@
#include "Item.hpp"
using namespace noggit::Red::StampMode::Ui::Model;
Item::Item(QString const& filepath)
: _pixmap{filepath} { }
auto Item::data(int role) const -> QVariant
{
if(role == Qt::DecorationRole)
return QIcon{_pixmap};
if(role == Qt::UserRole)
return qVariantFromValue(&_pixmap);
return QStandardItem::data(role);
}

View File

@@ -0,0 +1,25 @@
#ifndef NOGGIT_SRC_NOGGIT_RED_STAMPMODE_UI_MODEL_ITEM_HPP
#define NOGGIT_SRC_NOGGIT_RED_STAMPMODE_UI_MODEL_ITEM_HPP
#include <QStandardItem>
#include <QPixmap>
#include <QVariant>
class QString;
Q_DECLARE_METATYPE(QPixmap const*);
namespace noggit::Red::StampMode::Ui::Model
{
class Item : public QStandardItem
{
public:
explicit
Item(QString const& filepath);
auto data(int role) const -> QVariant override;
private:
QPixmap _pixmap;
};
}
#endif//NOGGIT_SRC_NOGGIT_RED_STAMPMODE_UI_MODEL_ITEM_HPP

View File

@@ -0,0 +1,39 @@
#include "PaletteMain.hpp"
#include <QIcon>
#include <QString>
#include <QMenu>
#include <QListView>
#include <QContextMenuEvent>
#include <noggit/MapView.h>
using namespace noggit::Red::StampMode::Ui;
PaletteMain::PaletteMain(MapView* parent)
: QWidget{parent, Qt::Window}, _layout{this}, _model{}, _view{this}
{
setWindowTitle("Stamp Palette");
setWindowIcon(QIcon{":/icon"});
setMinimumWidth(640);
setMinimumHeight(480);
setWindowFlag(Qt::WindowStaysOnTopHint);
setLayout(&_layout);
parent->populateImageModel(&_model);
_view.setEditTriggers(QAbstractItemView::NoEditTriggers);
_view.setViewMode(QListView::IconMode);
_view.setMovement(QListView::Static);
_view.setResizeMode(QListView::Adjust);
_view.setUniformItemSizes(true);
_view.setIconSize({128, 128});
_view.setWrapping(true);
_view.setModel(&_model);
connect(&_view, &QAbstractItemView::clicked, [this](QModelIndex const& index) -> void { emit itemSelected(index.data(Qt::UserRole).value<QPixmap const*>()); });
_layout.addWidget(&_view);
}
auto PaletteMain::contextMenuEvent(QContextMenuEvent* event) -> void
{
QMenu menu{this};
menu.addAction("Add");
menu.exec(event->globalPos());
}

View File

@@ -0,0 +1,35 @@
#ifndef NOGGIT_SRC_NOGGIT_RED_STAMPMODE_UI_PALETTEMAIN_HPP
#define NOGGIT_SRC_NOGGIT_RED_STAMPMODE_UI_PALETTEMAIN_HPP
#include <QWidget>
#include <QGridLayout>
#include <QListView>
#include <QStandardItemModel>
#include "Model/Item.hpp"
class QContextMenuEvent;
class MapView;
namespace noggit::Red::StampMode::Ui
{
class PaletteMain : public QWidget
{
Q_OBJECT
public:
explicit
PaletteMain(MapView* parent);
auto contextMenuEvent(QContextMenuEvent* event) -> void override;
signals:
void itemSelected(QPixmap const* pixmap) const;
private:
QGridLayout _layout;
QStandardItemModel _model;
QListView _view;
};
}
#endif//NOGGIT_SRC_NOGGIT_RED_STAMPMODE_UI_PALETTEMAIN_HPP

View File

@@ -0,0 +1,119 @@
#include "Tool.hpp"
#include <noggit/World.h>
#include <noggit/bool_toggle_property.hpp>
#include <QSignalBlocker>
using namespace noggit::Red::StampMode::Ui;
auto Tool::setPixmap(QPixmap const* pixmap) -> void
{
_curPixmap = pixmap;
_label.setPixmap(pixmap->scaled(128, 128));
}
Tool::Tool(bool_toggle_property* showPalette, QWidget* parent)
: QWidget{parent}, _radiusOuter{25.f}, _radiusInner{10.f}, _layout{this}, _label{this}
, _btnPalette{"Open Palette", this}, _sliderRadiusOuter{Qt::Orientation::Horizontal, this}
, _spinboxRadiusOuter{this}, _sliderRadiusInner{Qt::Orientation::Horizontal, this}
, _spinboxRadiusInner{this}, _dialRotation{this}, _curPixmap{nullptr}
{
_layout.addRow(&_label);
_layout.addRow(&_btnPalette);
_layout.setAlignment(&_label, Qt::AlignHCenter);
_layout.setAlignment(&_btnPalette, Qt::AlignHCenter);
_sliderRadiusOuter.setRange(.1f, 1000.f);
_sliderRadiusOuter.setValue(_radiusOuter);
_spinboxRadiusOuter.setRange(.1f, 1000.f);
_spinboxRadiusOuter.setDecimals(1);
_spinboxRadiusOuter.setValue(_radiusOuter);
_sliderRadiusInner.setRange(.1f, 1000.f);
_sliderRadiusInner.setValue(_radiusInner);
_spinboxRadiusInner.setRange(.1f, 1000.f);
_spinboxRadiusInner.setDecimals(1);
_spinboxRadiusInner.setValue(_radiusInner);
_dialRotation.setRange(0, 360);
_dialRotation.setWrapping(true);
_dialRotation.setSingleStep(10);
_layout.addRow("Outer Radius:", &_spinboxRadiusOuter);
_layout.addRow(&_sliderRadiusOuter);
_layout.addRow("Inner Radius:", &_spinboxRadiusInner);
_layout.addRow(&_sliderRadiusInner);
_layout.addRow(&_dialRotation);
connect(&_btnPalette, &QPushButton::pressed, [showPalette](void) -> void { showPalette->toggle(); });
connect(&_sliderRadiusOuter, &QSlider::valueChanged, [this](int val) -> void
{
if(val < _radiusInner)
{
QSignalBlocker blocker{&_sliderRadiusOuter};
_sliderRadiusOuter.setValue(_radiusInner);
return;
}
_radiusOuter = val;
QSignalBlocker blocker{&_spinboxRadiusOuter};
_spinboxRadiusOuter.setValue(_radiusOuter);
});
connect(&_spinboxRadiusOuter, qOverload<double>(&QDoubleSpinBox::valueChanged), [this](double val) -> void
{
if(val < _radiusInner)
{
QSignalBlocker blocker{&_spinboxRadiusOuter};
_spinboxRadiusOuter.setValue(_radiusInner);
return;
}
_radiusOuter = val;
QSignalBlocker blocker{&_sliderRadiusOuter};
_sliderRadiusOuter.setValue(_radiusOuter);
});
connect(&_sliderRadiusInner, &QSlider::valueChanged, [this](int val) -> void
{
if(val > _radiusOuter)
{
QSignalBlocker blocker{&_sliderRadiusInner};
_sliderRadiusInner.setValue(_radiusOuter);
return;
}
_radiusInner = val;
QSignalBlocker blocker{&_spinboxRadiusInner};
_spinboxRadiusInner.setValue(_radiusInner);
});
connect(&_spinboxRadiusInner, qOverload<double>(&QDoubleSpinBox::valueChanged), [this](double val) -> void
{
if(val > _radiusOuter)
{
QSignalBlocker blocker{&_spinboxRadiusInner};
_spinboxRadiusInner.setValue(_radiusOuter);
return;
}
_radiusInner = val;
QSignalBlocker blocker{&_sliderRadiusInner};
_sliderRadiusInner.setValue(val);
});
connect(&_dialRotation, &QDial::valueChanged, [this](int val) -> void{ _rotation = val; });
}
auto Tool::getOuterRadius(void) const -> float
{
return _radiusOuter;
}
auto Tool::getInnerRadius(void) const -> float
{
return _radiusInner;
}
auto Tool::getRotation(void) const -> float
{
return _rotation;
}
auto Tool::stamp(World* world, math::vector_3d const& pos, float dt, bool doAdd) const -> void
{
if(!_curPixmap)
return;
world->stamp(pos, dt, doAdd, _curPixmap, _radiusOuter, _radiusInner, _rotation);
}

View File

@@ -0,0 +1,55 @@
#ifndef NOGGIT_SRC_NOGGIT_RED_STAMPMODE_UI_TOOL_HPP
#define NOGGIT_SRC_NOGGIT_RED_STAMPMODE_UI_TOOL_HPP
#include <QWidget>
#include <QLabel>
#include <QFormLayout>
#include <QPushButton>
#include <QSlider>
#include <QDial>
#include <QDoubleSpinBox>
class QPixmap;
class World;
namespace math
{
class vector_3d;
}
namespace noggit
{
struct bool_toggle_property;
namespace Red::StampMode::Ui
{
class Tool : public QWidget
{
Q_OBJECT
public:
explicit
Tool(bool_toggle_property* showPalette, QWidget* parent = nullptr);
auto stamp(World* world, math::vector_3d const& pos, float dt, bool doAdd) const -> void;
auto getOuterRadius(void) const -> float;
auto getInnerRadius(void) const -> float;
auto getRotation(void) const -> float;
public slots:
void setPixmap(QPixmap const* pixmap);
private:
float _radiusOuter;
float _radiusInner;
float _rotation;
QFormLayout _layout;
QLabel _label;
QPushButton _btnPalette;
QPixmap const* _curPixmap;
QSlider _sliderRadiusOuter;
QDoubleSpinBox _spinboxRadiusOuter;
QSlider _sliderRadiusInner;
QDoubleSpinBox _spinboxRadiusInner;
QDial _dialRotation;
};
}
}
#endif//NOGGIT_SRC_NOGGIT_RED_STAMPMODE_UI_TOOL_HPP

View File

@@ -33,6 +33,8 @@
#include <QDir>
#include <QBuffer>
#include <QByteArray>
#include <QPixmap>
#include <QImage>
#include <algorithm>
#include <cassert>
@@ -915,6 +917,7 @@ void World::draw ( math::matrix_4x4 const& model_view
mcnk_shader.uniform("tex1", 2);
mcnk_shader.uniform("tex2", 3);
mcnk_shader.uniform("tex3", 4);
//mcnk_shader.uniform("stampBrush", 5);
mcnk_shader.uniform("draw_shadows", 1);
mcnk_shader.uniform("shadow_map", 5);
@@ -1547,6 +1550,17 @@ math::vector_3d World::pickShaderColor(math::vector_3d const& pos)
return color;
}
auto World::stamp(math::vector_3d const& pos, float dt, bool doAdd, QPixmap const* pixmap, float radiusOuter
, float radiusInner, float rotation) -> void
{
QMatrix matrix;
matrix.rotate(rotation);
int const k{static_cast<int>(std::floor(radiusOuter)) * 2};
QImage const img{pixmap->transformed(matrix).scaled(k, k).toImage()};
for_all_chunks_in_range(pos, radiusOuter, [=](MapChunk* chunk) -> bool { chunk->stamp(pos, dt, doAdd, img
, radiusOuter, radiusInner, rotation); return true; }, [this](MapChunk* chunk) -> void { recalc_norms(chunk); });
}
void World::changeTerrain(math::vector_3d const& pos, float change, float radius, int BrushType, float inner_radius)
{
for_all_chunks_in_range
@@ -2159,10 +2173,10 @@ bool World::saveMinimap(tile_index const& tile_idx, MinimapRenderSettings* setti
, settings);
// Clearing alpha from image
gl.colorMask(FALSE, FALSE, FALSE, TRUE);
gl.colorMask(false, false, false, true);
gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
gl.colorMask(TRUE, TRUE, TRUE, TRUE);
gl.colorMask(true, true, true, true);
QImage image = pixel_buffer.toImage();

View File

@@ -36,6 +36,7 @@ namespace noggit
class Brush;
class MapTile;
class QPixmap;
static const float detail_size = 8.0f;
static const float highresdistance = 384.0f;
@@ -249,6 +250,8 @@ public:
, math::vector_3d newPos
, math::vector_3d rotation
);
auto stamp(math::vector_3d const& pos, float dt, bool doAdd, QPixmap const* pixmap, float radiusOuter
, float radiusInner, float rotation) -> 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);