VOXEDIT: added FillPlane modifier

master
Martin Gerhardy 2022-05-01 21:52:05 +02:00
parent 0422bbddcd
commit 88ee7191e6
8 changed files with 111 additions and 13 deletions

View File

@ -59,7 +59,7 @@ static void fillRegion(voxel::RawVolume &in, const voxel::Voxel &voxel, const vo
const int height = region.getHeightInVoxels();
const int depth = region.getDepthInVoxels();
const int size = width * height * depth;
const glm::ivec3 mins = in.mins();
const glm::ivec3 mins = in.region().getLowerCorner();
core::DynamicArray<glm::ivec3> positions;
positions.reserve(size);
core::Buffer<bool> visitedData(size);
@ -161,30 +161,65 @@ void fillHollow(voxel::RawVolume &in, const voxel::Voxel &voxel) {
fillRegion(in, voxel, in.region());
}
void fillPlane(voxel::RawVolume &in, const voxel::Voxel &voxel, const glm::ivec3 &position, voxel::FaceNames face) {
glm::ivec3 mins(position);
glm::ivec3 maxs(position);
static void fillPlane_r(voxel::RawVolumeWrapper &in, const voxel::Region &region, const voxel::Voxel &voxel,
const voxel::Voxel &replace, const glm::ivec3 &position) {
if (!region.containsPoint(position)) {
return;
}
if (in.voxel(position).getColor() != replace.getColor()) {
return;
}
if (!in.setVoxel(position, voxel)) {
return;
}
if (region.containsPoint(position.x + 1, position.y, position.z)) {
fillPlane_r(in, region, voxel, replace, glm::ivec3(position.x + 1, position.y, position.z));
}
if (region.containsPoint(position.x - 1, position.y, position.z)) {
fillPlane_r(in, region, voxel, replace, glm::ivec3(position.x - 1, position.y, position.z));
}
if (region.containsPoint(position.x, position.y + 1, position.z)) {
fillPlane_r(in, region, voxel, replace, glm::ivec3(position.x, position.y + 1, position.z));
}
if (region.containsPoint(position.x, position.y - 1, position.z)) {
fillPlane_r(in, region, voxel, replace, glm::ivec3(position.x, position.y - 1, position.z));
}
if (region.containsPoint(position.x, position.y, position.z + 1)) {
fillPlane_r(in, region, voxel, replace, glm::ivec3(position.x, position.y, position.z + 1));
}
if (region.containsPoint(position.x, position.y, position.z - 1)) {
fillPlane_r(in, region, voxel, replace, glm::ivec3(position.x, position.y, position.z - 1));
}
}
void fillPlane(voxel::RawVolumeWrapper &in, const voxel::Voxel &voxel, const voxel::Voxel &replace, const glm::ivec3 &position,
voxel::FaceNames face) {
if (voxel.getColor() == replace.getColor()) {
return;
}
glm::ivec3 mins = in.region().getLowerCorner();
glm::ivec3 maxs = in.region().getUpperCorner();
switch (face) {
case voxel::FaceNames::PositiveX:
case voxel::FaceNames::NegativeX:
mins.x = in.region().getLowerX();
maxs.x = in.region().getUpperX();
mins.x = position.x;
maxs.x = position.x;
break;
case voxel::FaceNames::PositiveY:
case voxel::FaceNames::NegativeY:
mins.y = in.region().getLowerY();
maxs.y = in.region().getUpperY();
mins.y = position.y;
maxs.y = position.y;
break;
case voxel::FaceNames::PositiveZ:
case voxel::FaceNames::NegativeZ:
mins.z = in.region().getLowerZ();
maxs.z = in.region().getUpperZ();
mins.z = position.z;
maxs.z = position.z;
break;
case voxel::FaceNames::Max:
return;
}
const voxel::Region region(mins, maxs);
fillRegion(in, voxel, region);
fillPlane_r(in, region, voxel, replace, position);
}
} // namespace voxelutil

View File

@ -7,6 +7,10 @@
#include "voxel/Face.h"
#include "voxel/RawVolume.h"
namespace voxel {
class RawVolumeWrapper;
}
namespace voxelutil {
bool copyIntoRegion(const voxel::RawVolume &in, voxel::RawVolume &out, const voxel::Region &targetRegion);
@ -17,7 +21,7 @@ bool copy(const voxel::RawVolume &in, const voxel::Region& inRegion, voxel::RawV
* @sa voxel::isBlocked()
*/
bool isEmpty(const voxel::RawVolume &in, const voxel::Region &region);
void fillPlane(voxel::RawVolume &in, const voxel::Voxel &voxel, const glm::ivec3 &position, voxel::FaceNames face);
void fillPlane(voxel::RawVolumeWrapper &in, const voxel::Voxel &voxel, const voxel::Voxel &replace, const glm::ivec3 &position, voxel::FaceNames face);
void fillHollow(voxel::RawVolume &in, const voxel::Voxel &voxel);
}

View File

@ -4,6 +4,7 @@
#include "voxelutil/VoxelUtil.h"
#include "app/tests/AbstractTest.h"
#include "voxel/Face.h"
#include "voxel/RawVolume.h"
#include "voxel/RawVolumeWrapper.h"
#include "voxel/Region.h"
@ -58,4 +59,31 @@ TEST_F(VoxelUtilTest, testFillHollowLeak) {
EXPECT_EQ(0, v.voxel(region.getCenter()).getColor());
}
TEST_F(VoxelUtilTest, testFillPlanePositiveY) {
voxel::Region region(0, 2);
voxel::RawVolume v(region);
const voxel::Voxel fillVoxel = voxel::createVoxel(voxel::VoxelType::Generic, 2);
voxel::RawVolumeWrapper wrapper(&v);
voxelutil::fillPlane(wrapper, fillVoxel, voxel::Voxel(), glm::ivec3(1, 0, 1), voxel::FaceNames::PositiveY);
EXPECT_EQ(9, voxelutil::visitVolume(v, [&](int, int, int, const voxel::Voxel &) {}));
}
TEST_F(VoxelUtilTest, testFillPlaneNegativeX) {
voxel::Region region(-2, 0);
voxel::RawVolume v(region);
const voxel::Voxel fillVoxel = voxel::createVoxel(voxel::VoxelType::Generic, 2);
voxel::RawVolumeWrapper wrapper(&v);
voxelutil::fillPlane(wrapper, fillVoxel, voxel::Voxel(), glm::ivec3(0, -1, -1), voxel::FaceNames::NegativeX);
EXPECT_EQ(9, voxelutil::visitVolume(v, [&](int, int, int, const voxel::Voxel &) {}));
}
TEST_F(VoxelUtilTest, testFillPlanePositiveZ) {
voxel::Region region(0, 2);
voxel::RawVolume v(region);
const voxel::Voxel fillVoxel = voxel::createVoxel(voxel::VoxelType::Generic, 2);
voxel::RawVolumeWrapper wrapper(&v);
voxelutil::fillPlane(wrapper, fillVoxel, voxel::Voxel(), glm::ivec3(1, 1, 0), voxel::FaceNames::PositiveZ);
EXPECT_EQ(9, voxelutil::visitVolume(v, [&](int, int, int, const voxel::Voxel &) {}));
}
} // namespace voxelutil

View File

@ -3,6 +3,7 @@
*/
#include "ToolsPanel.h"
#include "IconsFontAwesome5.h"
#include "ui/imgui/IMGUIEx.h"
#include "ui/imgui/IconsForkAwesome.h"
#include "voxedit-util/SceneManager.h"
@ -22,6 +23,7 @@ void ToolsPanel::update(const char *title) {
core_trace_scoped(ToolsPanel);
modifierRadioButton(ICON_FA_PEN " Place", ModifierType::Place);
modifierRadioButton(ICON_FA_PEN " Single", ModifierType::Place | ModifierType::Single);
modifierRadioButton(ICON_FA_FILL_DRIP " Fill Plane", ModifierType::FillPlane);
modifierRadioButton(ICON_FA_EXPAND " Select", ModifierType::Select);
modifierRadioButton(ICON_FA_ERASER " Delete", ModifierType::Delete);
modifierRadioButton(ICON_FK_PENCIL " Pick color", ModifierType::ColorPicker);

View File

@ -212,6 +212,17 @@ void SceneManager::fillHollow() {
}
}
void SceneManager::fillPlane() {
const int nodeId = activeNode();
if (nodeId == -1) {
return;
}
voxel::RawVolume* v = volume(nodeId);
voxel::RawVolumeWrapper wrapper(v);
voxelutil::fillPlane(wrapper, _modifier.cursorVoxel(), voxel::Voxel(), _modifier.cursorPosition(), _modifier.cursorFace());
modified(nodeId, wrapper.dirtyRegion());
}
bool SceneManager::saveModels(const core::String& dir) {
bool state = false;
for (const voxelformat::SceneGraphNode & node : _sceneGraph) {
@ -1226,6 +1237,10 @@ void SceneManager::construct() {
fillHollow();
}).setHelp("Fill the inner parts of closed models");
command::Command::registerCommand("fillplane", [&] (const command::CmdArgs& args) {
fillPlane();
}).setHelp("Fill the inner parts of closed models");
command::Command::registerCommand("setreferenceposition", [&] (const command::CmdArgs& args) {
if (args.size() != 3) {
Log::info("Expected to get x, y and z coordinates");

View File

@ -203,6 +203,7 @@ protected:
*/
void moveCursor(int x, int y, int z);
void fillHollow();
void fillPlane();
void colorToNewLayer(const voxel::Voxel voxelColor);
void crop();

View File

@ -7,12 +7,14 @@
#include "core/Color.h"
#include "core/StringUtil.h"
#include "command/Command.h"
#include "voxel/RawVolumeWrapper.h"
#include "voxel/Region.h"
#include "voxel/Voxel.h"
#include "voxelgenerator/ShapeGenerator.h"
#include "../AxisUtil.h"
#include "../CustomBindingContext.h"
#include "../SceneManager.h"
#include "voxelutil/VoxelUtil.h"
namespace voxedit {
@ -343,6 +345,16 @@ bool Modifier::aabbAction(voxel::RawVolume* volume, const std::function<void(con
}
return false;
}
if (_modifierType == ModifierType::FillPlane) {
voxel::RawVolumeWrapper wrapper(volume);
voxelutil::fillPlane(wrapper, cursorVoxel(), voxel::Voxel(), cursorPosition(), cursorFace());
const voxel::Region& modifiedRegion = wrapper.dirtyRegion();
if (modifiedRegion.isValid()) {
voxel::logRegion("Dirty region", modifiedRegion);
callback(modifiedRegion, _modifierType);
}
return true;
}
const math::AABB<int> a = aabb();

View File

@ -13,6 +13,7 @@ enum class ModifierType {
Delete = (1 << 2),
Update = (1 << 3),
Select = (1 << 4),
ColorPicker = (1 << 5) | Single
ColorPicker = (1 << 5) | Single,
FillPlane = (1 << 6)
};
CORE_ENUM_BIT_OPERATIONS(ModifierType)