Files
WickedEngine/Editor/VoxelGridWindow.cpp
T

299 lines
11 KiB
C++

#include "stdafx.h"
#include "VoxelGridWindow.h"
using namespace wi::ecs;
using namespace wi::scene;
void VoxelGridWindow::Create(EditorComponent* _editor)
{
editor = _editor;
wi::gui::Window::Create(ICON_VOXELGRID " VoxelGrid", wi::gui::Window::WindowControls::COLLAPSE | wi::gui::Window::WindowControls::CLOSE);
SetSize(XMFLOAT2(520, 480));
closeButton.SetTooltip("Delete VoxelGrid");
OnClose([=](wi::gui::EventArgs args) {
wi::Archive& archive = editor->AdvanceHistory();
archive << EditorComponent::HISTORYOP_COMPONENT_DATA;
editor->RecordEntity(archive, entity);
editor->GetCurrentScene().voxel_grids.Remove(entity);
editor->RecordEntity(archive, entity);
editor->componentsWnd.RefreshEntityTree();
});
float x = 80;
float y = 0;
float hei = 18;
float wid = 200;
float step = hei + 4;
infoLabel.Create("");
infoLabel.SetSize(XMFLOAT2(100, 150));
AddWidget(&infoLabel);
dimXInput.Create("DimX");
dimXInput.SetSize(XMFLOAT2(100, hei));
dimXInput.SetDescription("Dimension X: ");
dimXInput.OnInputAccepted([=](wi::gui::EventArgs args) {
Scene& scene = editor->GetCurrentScene();
wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity);
if (voxelgrid == nullptr)
return;
voxelgrid->init(uint32_t(std::max(1, args.iValue)), voxelgrid->resolution.y, voxelgrid->resolution.z);
});
AddWidget(&dimXInput);
dimYInput.Create("DimY");
dimYInput.SetSize(XMFLOAT2(100, hei));
dimYInput.SetDescription("Y: ");
dimYInput.OnInputAccepted([=](wi::gui::EventArgs args) {
Scene& scene = editor->GetCurrentScene();
wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity);
if (voxelgrid == nullptr)
return;
voxelgrid->init(voxelgrid->resolution.x, uint32_t(std::max(1, args.iValue)), voxelgrid->resolution.z);
});
AddWidget(&dimYInput);
dimZInput.Create("DimZ");
dimZInput.SetSize(XMFLOAT2(100, hei));
dimZInput.SetDescription("Z: ");
dimZInput.OnInputAccepted([=](wi::gui::EventArgs args) {
Scene& scene = editor->GetCurrentScene();
wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity);
if (voxelgrid == nullptr)
return;
voxelgrid->init(voxelgrid->resolution.x, voxelgrid->resolution.y, uint32_t(std::max(1, args.iValue)));
});
AddWidget(&dimZInput);
clearButton.Create("Clear voxels " ICON_CLEARVOXELS);
clearButton.SetSize(XMFLOAT2(100, hei));
clearButton.OnClick([=](wi::gui::EventArgs args) {
Scene& scene = editor->GetCurrentScene();
wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity);
if (voxelgrid == nullptr)
return;
voxelgrid->cleardata();
});
AddWidget(&clearButton);
voxelizeObjectsButton.Create("Voxelize objects " ICON_VOXELIZE);
voxelizeObjectsButton.SetTooltip("Generate navigation grid including all meshes.");
voxelizeObjectsButton.SetSize(XMFLOAT2(100, hei));
voxelizeObjectsButton.OnClick([=](wi::gui::EventArgs args) {
Scene& scene = editor->GetCurrentScene();
wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity);
if (voxelgrid == nullptr)
return;
scene.VoxelizeScene(*voxelgrid, subtractCheckBox.GetCheck(), wi::enums::FILTER_OBJECT_ALL);
});
AddWidget(&voxelizeObjectsButton);
voxelizeNavigationButton.Create("Voxelize navigation " ICON_VOXELIZE);
voxelizeNavigationButton.SetTooltip("Generate navigation grid including all navmeshes (object tagged as navmesh).");
voxelizeNavigationButton.SetSize(XMFLOAT2(100, hei));
voxelizeNavigationButton.OnClick([=](wi::gui::EventArgs args) {
Scene& scene = editor->GetCurrentScene();
wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity);
if (voxelgrid == nullptr)
return;
scene.VoxelizeScene(*voxelgrid, subtractCheckBox.GetCheck(), wi::enums::FILTER_NAVIGATION_MESH);
});
AddWidget(&voxelizeNavigationButton);
voxelizeCollidersButton.Create("Voxelize CPU colliders " ICON_VOXELIZE);
voxelizeCollidersButton.SetTooltip("Generate navigation grid including all CPU colliders.");
voxelizeCollidersButton.SetSize(XMFLOAT2(100, hei));
voxelizeCollidersButton.OnClick([=](wi::gui::EventArgs args) {
Scene& scene = editor->GetCurrentScene();
wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity);
if (voxelgrid == nullptr)
return;
scene.VoxelizeScene(*voxelgrid, subtractCheckBox.GetCheck(), wi::enums::FILTER_COLLIDER);
});
AddWidget(&voxelizeCollidersButton);
floodfillButton.Create("Flood fill " ICON_VOXELFILL);
floodfillButton.SetTooltip("Fill enclosed empty voxel areas to solid.\nThis can take long if there are large enclosed empty areas.");
floodfillButton.SetSize(XMFLOAT2(100, hei));
floodfillButton.OnClick([=](wi::gui::EventArgs args) {
Scene& scene = editor->GetCurrentScene();
wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity);
if (voxelgrid == nullptr)
return;
wi::Timer tim;
voxelgrid->flood_fill();
char text[256] = {};
snprintf(text, arraysize(text), "Flood filling took %.2f seconds.", tim.elapsed_seconds());
wi::backlog::post(text);
});
AddWidget(&floodfillButton);
fitToSceneButton.Create("Fit bounds to scene " ICON_VOXELBOUNDS);
fitToSceneButton.SetTooltip("Fit the bounds of the voxel grid onto the whole scene.");
fitToSceneButton.SetSize(XMFLOAT2(100, hei));
fitToSceneButton.OnClick([=](wi::gui::EventArgs args) {
Scene& scene = editor->GetCurrentScene();
if (scene.bounds.getArea() < 0)
return;
wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity);
if (voxelgrid == nullptr)
return;
voxelgrid->from_aabb(scene.bounds);
TransformComponent* transform = scene.transforms.GetComponent(entity);
if (transform != nullptr)
{
// feed back to transform component if it exists:
transform->translation_local = voxelgrid->center;
transform->scale_local = voxelgrid->voxelSize;
transform->SetDirty();
}
});
AddWidget(&fitToSceneButton);
generateMeshButton.Create("Generate Mesh " ICON_MESH);
generateMeshButton.SetTooltip("Generate a mesh from the voxels.");
generateMeshButton.SetSize(XMFLOAT2(100, hei));
generateMeshButton.OnClick([=](wi::gui::EventArgs args) {
Scene& scene = editor->GetCurrentScene();
wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity);
if (voxelgrid == nullptr)
return;
wi::vector<uint32_t> indices;
wi::vector<XMFLOAT3> vertices;
voxelgrid->create_mesh(indices, vertices, false);
if (vertices.empty())
{
wi::backlog::post("VoxelGrid.create_mesh() : no voxels were found, so mesh creation is aborted.", wi::backlog::LogLevel::Warning);
return;
}
scene.Entity_CreateMeshFromData("voxelgrid_to_mesh", indices.size(), indices.data(), vertices.size(), vertices.data());
});
AddWidget(&generateMeshButton);
generateSimplifiedMeshButton.Create("Generate Simplified Mesh " ICON_MESH);
generateSimplifiedMeshButton.SetTooltip("Generate a simplified mesh from the voxels.");
generateSimplifiedMeshButton.SetSize(XMFLOAT2(100, hei));
generateSimplifiedMeshButton.OnClick([=](wi::gui::EventArgs args) {
Scene& scene = editor->GetCurrentScene();
wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity);
if (voxelgrid == nullptr)
return;
wi::vector<uint32_t> indices;
wi::vector<XMFLOAT3> vertices;
voxelgrid->create_mesh(indices, vertices, true);
if (vertices.empty())
{
wi::backlog::post("VoxelGrid.create_mesh() : no voxels were found, so mesh creation is aborted.", wi::backlog::LogLevel::Warning);
return;
}
scene.Entity_CreateMeshFromData("voxelgrid_to_mesh", indices.size(), indices.data(), vertices.size(), vertices.data());
});
AddWidget(&generateSimplifiedMeshButton);
subtractCheckBox.Create("Subtraction mode: ");
subtractCheckBox.SetTooltip("If enabled, voxelization will be subtractive, so it will remove voxels instead of add.");
subtractCheckBox.SetSize(XMFLOAT2(hei, hei));
AddWidget(&subtractCheckBox);
debugAllCheckBox.Create("Debug draw all: ");
debugAllCheckBox.SetTooltip("Draw all voxel grids, whether they are selected or not.");
debugAllCheckBox.SetSize(XMFLOAT2(hei, hei));
AddWidget(&debugAllCheckBox);
SetMinimized(true);
SetVisible(false);
}
void VoxelGridWindow::SetEntity(Entity entity)
{
bool changed = this->entity != entity;
this->entity = entity;
Scene& scene = editor->GetCurrentScene();
wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity);
if (voxelgrid != nullptr)
{
std::string infotext = "Voxel grid can be used for navigation. By voxelizing the scene into the grid, path finding can be used on the resulting voxel grid.";
infotext += "\n\nMemory usage: ";
infotext += wi::helper::GetMemorySizeText(voxelgrid->get_memory_size());
infoLabel.SetText(infotext);
dimXInput.SetValue((int)voxelgrid->resolution.x);
dimYInput.SetValue((int)voxelgrid->resolution.y);
dimZInput.SetValue((int)voxelgrid->resolution.z);
}
}
void VoxelGridWindow::ResizeLayout()
{
wi::gui::Window::ResizeLayout();
const float padding = 4;
const float width = GetWidgetAreaSize().x;
float y = padding;
float jump = 20;
const float margin_left = 90;
const float margin_right = 40;
auto add = [&](wi::gui::Widget& widget) {
if (!widget.IsVisible())
return;
widget.SetPos(XMFLOAT2(margin_left, y));
widget.SetSize(XMFLOAT2(width - margin_left - margin_right, widget.GetScale().y));
y += widget.GetSize().y;
y += padding;
};
auto add_right = [&](wi::gui::Widget& widget) {
if (!widget.IsVisible())
return;
const float margin_right = padding;
widget.SetPos(XMFLOAT2(width - margin_right - widget.GetSize().x, y));
y += widget.GetSize().y;
y += padding;
};
auto add_fullwidth = [&](wi::gui::Widget& widget) {
if (!widget.IsVisible())
return;
const float margin_left = padding;
const float margin_right = padding;
widget.SetPos(XMFLOAT2(margin_left, y));
widget.SetSize(XMFLOAT2(width - margin_left - margin_right, widget.GetScale().y));
y += widget.GetSize().y;
y += padding;
};
add_fullwidth(infoLabel);
const float padding2 = 20;
const float l = 95;
const float r = width;
float w = ((r - l) - padding2 * 2) / 3.0f;
dimXInput.SetSize(XMFLOAT2(w, dimXInput.GetSize().y));
dimYInput.SetSize(XMFLOAT2(w, dimYInput.GetSize().y));
dimZInput.SetSize(XMFLOAT2(w, dimZInput.GetSize().y));
dimXInput.SetPos(XMFLOAT2(margin_left, y));
dimYInput.SetPos(XMFLOAT2(dimXInput.GetPos().x + w + padding2, y));
dimZInput.SetPos(XMFLOAT2(dimYInput.GetPos().x + w + padding2, y));
y += dimZInput.GetSize().y;
y += padding;
add_fullwidth(clearButton);
add_fullwidth(voxelizeObjectsButton);
add_fullwidth(voxelizeCollidersButton);
add_fullwidth(voxelizeNavigationButton);
add_fullwidth(floodfillButton);
add_fullwidth(fitToSceneButton);
add_fullwidth(generateMeshButton);
add_fullwidth(generateSimplifiedMeshButton);
add_right(subtractCheckBox);
add_right(debugAllCheckBox);
}