Extract grid UI operation planning
This commit is contained in:
@@ -235,7 +235,8 @@ add_library(pp_app_core STATIC
|
|||||||
src/app_core/document_resize.h
|
src/app_core/document_resize.h
|
||||||
src/app_core/document_route.cpp
|
src/app_core/document_route.cpp
|
||||||
src/app_core/document_sharing.h
|
src/app_core/document_sharing.h
|
||||||
src/app_core/document_session.cpp)
|
src/app_core/document_session.cpp
|
||||||
|
src/app_core/grid_ui.h)
|
||||||
target_include_directories(pp_app_core
|
target_include_directories(pp_app_core
|
||||||
PUBLIC
|
PUBLIC
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src")
|
"${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ agent or engineer to remove them without reconstructing context from chat.
|
|||||||
| DEBT-0021 | Open | Modernization | Layer rename and layer panel operation planning now consume pure `pp_app_core` through `App::dialog_layer_rename`, `App::init_sidebar` layer callbacks, `pano_cli plan-layer-rename`, and `pano_cli plan-layer-operation`, but live execution still mutates legacy `Canvas` layer state, `NodeLayer`/`NodePanelLayer`, and `ActionManager` undo entries directly | Preserve existing UI/canvas behavior while document layer commands and undo history are extracted incrementally | `pp_app_core_document_layer_tests`; `pano_cli plan-layer-rename --old-name Base --new-name Paint`; `pano_cli plan-layer-operation --kind add --layer-count 2 --index 1 --name Paint`; `ctest --preset desktop-fast --build-config Debug` | Layer command execution is owned by the document/app command boundary with legacy `Canvas`/UI nodes acting only as adapters or removed entirely |
|
| DEBT-0021 | Open | Modernization | Layer rename and layer panel operation planning now consume pure `pp_app_core` through `App::dialog_layer_rename`, `App::init_sidebar` layer callbacks, `pano_cli plan-layer-rename`, and `pano_cli plan-layer-operation`, but live execution still mutates legacy `Canvas` layer state, `NodeLayer`/`NodePanelLayer`, and `ActionManager` undo entries directly | Preserve existing UI/canvas behavior while document layer commands and undo history are extracted incrementally | `pp_app_core_document_layer_tests`; `pano_cli plan-layer-rename --old-name Base --new-name Paint`; `pano_cli plan-layer-operation --kind add --layer-count 2 --index 1 --name Paint`; `ctest --preset desktop-fast --build-config Debug` | Layer command execution is owned by the document/app command boundary with legacy `Canvas`/UI nodes acting only as adapters or removed entirely |
|
||||||
| DEBT-0022 | Open | Modernization | Animation panel frame command planning now consumes pure `pp_app_core` through `NodePanelAnimation` and `pano_cli plan-animation-operation`, and `pp_legacy_ui_core` temporarily links `pp_app_core`, but live execution still mutates legacy `Canvas`/`Layer` frame state and animation playback state directly | Preserve existing animation panel behavior while timeline/frame commands move toward the document/app command boundary | `pp_app_core_document_animation_tests`; `pano_cli plan-animation-operation --kind add --frame-count 2 --current-frame 0`; `pano_cli plan-animation-operation --kind next --total-duration 5 --current-frame 4`; `ctest --preset desktop-fast --build-config Debug` | Animation frame/timeline execution is owned by the document/app command boundary with legacy `Canvas`/`Layer`/UI nodes acting only as adapters or removed entirely |
|
| DEBT-0022 | Open | Modernization | Animation panel frame command planning now consumes pure `pp_app_core` through `NodePanelAnimation` and `pano_cli plan-animation-operation`, and `pp_legacy_ui_core` temporarily links `pp_app_core`, but live execution still mutates legacy `Canvas`/`Layer` frame state and animation playback state directly | Preserve existing animation panel behavior while timeline/frame commands move toward the document/app command boundary | `pp_app_core_document_animation_tests`; `pano_cli plan-animation-operation --kind add --frame-count 2 --current-frame 0`; `pano_cli plan-animation-operation --kind next --total-duration 5 --current-frame 4`; `ctest --preset desktop-fast --build-config Debug` | Animation frame/timeline execution is owned by the document/app command boundary with legacy `Canvas`/`Layer`/UI nodes acting only as adapters or removed entirely |
|
||||||
| DEBT-0023 | Open | Modernization | Brush/color/preset UI planning now consumes pure `pp_app_core` through `App::init_sidebar`, restored/docked floating-panel callbacks, and `pano_cli plan-brush-operation`, but live execution still mutates legacy `Brush`, calls legacy brush texture loading, and refreshes legacy quick/stroke/color widgets directly | Preserve existing brush UI behavior while brush commands move toward a brush/app command boundary and asset-managed texture selection | `pp_app_core_brush_ui_tests`; `pano_cli plan-brush-operation --kind color --r 0.25 --g 0.5 --b 0.75 --a 1`; `pano_cli plan-brush-operation --kind pattern --path data/patterns/noise.png --thumb data/patterns/thumbs/noise.png`; `ctest --preset desktop-fast --build-config Debug` | Brush color/texture/preset execution is owned by a brush/app command boundary with legacy `Brush`/UI nodes acting only as adapters or removed entirely |
|
| DEBT-0023 | Open | Modernization | Brush/color/preset UI planning now consumes pure `pp_app_core` through `App::init_sidebar`, restored/docked floating-panel callbacks, and `pano_cli plan-brush-operation`, but live execution still mutates legacy `Brush`, calls legacy brush texture loading, and refreshes legacy quick/stroke/color widgets directly | Preserve existing brush UI behavior while brush commands move toward a brush/app command boundary and asset-managed texture selection | `pp_app_core_brush_ui_tests`; `pano_cli plan-brush-operation --kind color --r 0.25 --g 0.5 --b 0.75 --a 1`; `pano_cli plan-brush-operation --kind pattern --path data/patterns/noise.png --thumb data/patterns/thumbs/noise.png`; `ctest --preset desktop-fast --build-config Debug` | Brush color/texture/preset execution is owned by a brush/app command boundary with legacy `Brush`/UI nodes acting only as adapters or removed entirely |
|
||||||
|
| DEBT-0024 | Open | Modernization | Grid/heightmap/lightmap UI planning now consumes pure `pp_app_core` through `NodePanelGrid` and `pano_cli plan-grid-operation`, but live execution still performs legacy image loading, OpenGL texture updates, nanort lightmap baking, progress UI, and `Canvas::draw_objects` commit directly | Preserve grid/lightmap behavior while moving renderable grid commands toward app/renderer/document boundaries | `pp_app_core_grid_ui_tests`; `pano_cli plan-grid-operation --kind render --float32 --texture-resolution 1024 --samples 32`; `ctest --preset desktop-fast --build-config Debug` | Grid heightmap/lightmap execution is owned by app/renderer/document services with `NodePanelGrid` acting only as UI adapter |
|
||||||
|
|
||||||
## Closed Debt
|
## Closed Debt
|
||||||
|
|
||||||
|
|||||||
@@ -499,6 +499,10 @@ before legacy `Canvas`/`Layer` frame execution continues.
|
|||||||
changes, tip/pattern/dual texture changes, preset brush replacement, and stroke
|
changes, tip/pattern/dual texture changes, preset brush replacement, and stroke
|
||||||
settings refreshes used by the live brush, quick, color, and floating panel
|
settings refreshes used by the live brush, quick, color, and floating panel
|
||||||
callbacks before legacy `Brush` mutation and resource loading continue.
|
callbacks before legacy `Brush` mutation and resource loading continue.
|
||||||
|
`pano_cli plan-grid-operation` exposes app-core planning for grid heightmap
|
||||||
|
pick/load/reload/clear, lightmap render capability/limit checks, and heightmap
|
||||||
|
commit used by the live grid panel before legacy image loading, OpenGL texture
|
||||||
|
updates, nanort lightmap baking, and `Canvas::draw_objects` execution continue.
|
||||||
`pp_platform_api` now owns a headless `PlatformServices` interface for
|
`pp_platform_api` now owns a headless `PlatformServices` interface for
|
||||||
startup storage path preparation, clipboard text, cursor visibility,
|
startup storage path preparation, clipboard text, cursor visibility,
|
||||||
virtual-keyboard visibility, UI-thread lifecycle hooks, render-context
|
virtual-keyboard visibility, UI-thread lifecycle hooks, render-context
|
||||||
@@ -1137,6 +1141,16 @@ Results:
|
|||||||
`pano_cli_plan_brush_operation_rejects_bad_color`, and
|
`pano_cli_plan_brush_operation_rejects_bad_color`, and
|
||||||
`pano_cli_plan_brush_operation_rejects_empty_texture` passed and expose live
|
`pano_cli_plan_brush_operation_rejects_empty_texture` passed and expose live
|
||||||
brush/color/preset UI planning as JSON automation.
|
brush/color/preset UI planning as JSON automation.
|
||||||
|
- `pp_app_core_grid_ui_tests` passed, covering heightmap pick/load/reload/clear
|
||||||
|
planning, lightmap capability and limit checks, missing-heightmap no-op
|
||||||
|
behavior, and commit canvas gating.
|
||||||
|
- `pano_cli_plan_grid_operation_pick_smoke`,
|
||||||
|
`pano_cli_plan_grid_operation_load_smoke`,
|
||||||
|
`pano_cli_plan_grid_operation_render_supported_smoke`,
|
||||||
|
`pano_cli_plan_grid_operation_render_unsupported_smoke`,
|
||||||
|
`pano_cli_plan_grid_operation_rejects_empty_reload`, and
|
||||||
|
`pano_cli_plan_grid_operation_rejects_bad_samples` passed and expose live
|
||||||
|
grid/heightmap/lightmap planning as JSON automation.
|
||||||
- `pp_app_core_document_sharing_tests` passed, covering saved-path gating before
|
- `pp_app_core_document_sharing_tests` passed, covering saved-path gating before
|
||||||
platform share execution.
|
platform share execution.
|
||||||
- `pano_cli_plan_share_file_unsaved_smoke` and
|
- `pano_cli_plan_share_file_unsaved_smoke` and
|
||||||
|
|||||||
145
src/app_core/grid_ui.h
Normal file
145
src/app_core/grid_ui.h
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "foundation/result.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace pp::app {
|
||||||
|
|
||||||
|
enum class GridUiOperation {
|
||||||
|
request_heightmap_pick,
|
||||||
|
load_heightmap,
|
||||||
|
clear_heightmap,
|
||||||
|
reload_heightmap,
|
||||||
|
render_lightmap,
|
||||||
|
commit_heightmap,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GridUiPlan {
|
||||||
|
GridUiOperation operation = GridUiOperation::request_heightmap_pick;
|
||||||
|
std::string path;
|
||||||
|
int texture_resolution = 0;
|
||||||
|
int sample_count = 0;
|
||||||
|
bool opens_picker = false;
|
||||||
|
bool loads_heightmap = false;
|
||||||
|
bool clears_heightmap = false;
|
||||||
|
bool renders_lightmap = false;
|
||||||
|
bool commits_heightmap = false;
|
||||||
|
bool updates_preview = false;
|
||||||
|
bool updates_ground_opacity = false;
|
||||||
|
bool updates_shading_mode = false;
|
||||||
|
bool shows_unsupported_message = false;
|
||||||
|
bool shows_progress = false;
|
||||||
|
bool mutates_grid_state = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] inline pp::foundation::Status validate_grid_texture_resolution(int texture_resolution) noexcept
|
||||||
|
{
|
||||||
|
if (texture_resolution <= 0 || texture_resolution > 16384) {
|
||||||
|
return pp::foundation::Status::out_of_range("grid texture resolution must be within 1..16384");
|
||||||
|
}
|
||||||
|
|
||||||
|
return pp::foundation::Status::success();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline pp::foundation::Status validate_grid_lightmap_samples(int sample_count) noexcept
|
||||||
|
{
|
||||||
|
if (sample_count <= 0 || sample_count > 4096) {
|
||||||
|
return pp::foundation::Status::out_of_range("grid lightmap samples must be within 1..4096");
|
||||||
|
}
|
||||||
|
|
||||||
|
return pp::foundation::Status::success();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline constexpr GridUiPlan plan_grid_heightmap_pick() noexcept
|
||||||
|
{
|
||||||
|
GridUiPlan plan;
|
||||||
|
plan.operation = GridUiOperation::request_heightmap_pick;
|
||||||
|
plan.opens_picker = true;
|
||||||
|
return plan;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline pp::foundation::Result<GridUiPlan> plan_grid_heightmap_load(std::string_view path)
|
||||||
|
{
|
||||||
|
if (path.empty()) {
|
||||||
|
return pp::foundation::Result<GridUiPlan>::failure(
|
||||||
|
pp::foundation::Status::invalid_argument("heightmap path must not be empty"));
|
||||||
|
}
|
||||||
|
|
||||||
|
GridUiPlan plan;
|
||||||
|
plan.operation = GridUiOperation::load_heightmap;
|
||||||
|
plan.path = std::string(path);
|
||||||
|
plan.loads_heightmap = true;
|
||||||
|
plan.updates_preview = true;
|
||||||
|
plan.updates_ground_opacity = true;
|
||||||
|
plan.mutates_grid_state = true;
|
||||||
|
return pp::foundation::Result<GridUiPlan>::success(std::move(plan));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline constexpr GridUiPlan plan_grid_heightmap_clear(bool has_heightmap) noexcept
|
||||||
|
{
|
||||||
|
GridUiPlan plan;
|
||||||
|
plan.operation = GridUiOperation::clear_heightmap;
|
||||||
|
plan.clears_heightmap = true;
|
||||||
|
plan.updates_preview = has_heightmap;
|
||||||
|
plan.mutates_grid_state = has_heightmap;
|
||||||
|
return plan;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline pp::foundation::Result<GridUiPlan> plan_grid_heightmap_reload(std::string_view path)
|
||||||
|
{
|
||||||
|
auto plan = plan_grid_heightmap_load(path);
|
||||||
|
if (!plan) {
|
||||||
|
return pp::foundation::Result<GridUiPlan>::failure(plan.status());
|
||||||
|
}
|
||||||
|
plan.value().operation = GridUiOperation::reload_heightmap;
|
||||||
|
plan.value().updates_ground_opacity = false;
|
||||||
|
return plan;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline pp::foundation::Result<GridUiPlan> plan_grid_lightmap_render(
|
||||||
|
bool has_heightmap,
|
||||||
|
bool supports_float32,
|
||||||
|
bool supports_float16,
|
||||||
|
int texture_resolution,
|
||||||
|
int sample_count)
|
||||||
|
{
|
||||||
|
const auto texture_status = validate_grid_texture_resolution(texture_resolution);
|
||||||
|
if (!texture_status.ok()) {
|
||||||
|
return pp::foundation::Result<GridUiPlan>::failure(texture_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto sample_status = validate_grid_lightmap_samples(sample_count);
|
||||||
|
if (!sample_status.ok()) {
|
||||||
|
return pp::foundation::Result<GridUiPlan>::failure(sample_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
GridUiPlan plan;
|
||||||
|
plan.operation = GridUiOperation::render_lightmap;
|
||||||
|
plan.texture_resolution = texture_resolution;
|
||||||
|
plan.sample_count = sample_count;
|
||||||
|
if (!supports_float32 && !supports_float16) {
|
||||||
|
plan.shows_unsupported_message = true;
|
||||||
|
return pp::foundation::Result<GridUiPlan>::success(plan);
|
||||||
|
}
|
||||||
|
|
||||||
|
plan.renders_lightmap = has_heightmap;
|
||||||
|
plan.shows_progress = has_heightmap;
|
||||||
|
plan.updates_shading_mode = has_heightmap;
|
||||||
|
plan.mutates_grid_state = has_heightmap;
|
||||||
|
return pp::foundation::Result<GridUiPlan>::success(plan);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline constexpr GridUiPlan plan_grid_heightmap_commit(bool has_canvas) noexcept
|
||||||
|
{
|
||||||
|
GridUiPlan plan;
|
||||||
|
plan.operation = GridUiOperation::commit_heightmap;
|
||||||
|
plan.commits_heightmap = has_canvas;
|
||||||
|
plan.updates_ground_opacity = has_canvas;
|
||||||
|
plan.mutates_grid_state = has_canvas;
|
||||||
|
return plan;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pp::app
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
|
#include "app_core/grid_ui.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "node_panel_grid.h"
|
#include "node_panel_grid.h"
|
||||||
#include "canvas.h"
|
#include "canvas.h"
|
||||||
@@ -77,28 +78,19 @@ void NodePanelGrid::init_controls()
|
|||||||
};
|
};
|
||||||
|
|
||||||
m_hm_load->on_click = [this](Node*) {
|
m_hm_load->on_click = [this](Node*) {
|
||||||
|
const auto plan = pp::app::plan_grid_heightmap_pick();
|
||||||
|
if (!plan.opens_picker)
|
||||||
|
return;
|
||||||
App::I->pick_image([this](std::string path) {
|
App::I->pick_image([this](std::string path) {
|
||||||
Image img;
|
load_heightmap_file(path, true);
|
||||||
if (img.load_file(path))
|
|
||||||
{
|
|
||||||
m_file_path = path;
|
|
||||||
m_hm_image = img.resize(128, 128);
|
|
||||||
m_hm_preview->tex = std::make_shared<Texture2D>();
|
|
||||||
m_hm_preview->tex->create(m_hm_image);
|
|
||||||
m_hm_preview->tex->create_mipmaps();
|
|
||||||
auto sz = m_hm_preview->tex->size();
|
|
||||||
m_hm_preview->SetAspectRatio(sz.x / sz.y);
|
|
||||||
m_hm_plane.create(1, 1, m_hm_image, get_resolution(), get_height());
|
|
||||||
m_hm_preview->SetHeight(100);
|
|
||||||
if (m_groud_opacity->get_value() == 0.f)
|
|
||||||
m_groud_opacity->set_value(1.f);
|
|
||||||
m_rt_dirty = true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
m_hm_clear->on_click = [this](Node*)
|
m_hm_clear->on_click = [this](Node*)
|
||||||
{
|
{
|
||||||
|
const auto plan = pp::app::plan_grid_heightmap_clear(static_cast<bool>(m_hm_image.data()));
|
||||||
|
if (!plan.clears_heightmap)
|
||||||
|
return;
|
||||||
m_hm_plane.create(1, 1, 100 * get_resolution());
|
m_hm_plane.create(1, 1, 100 * get_resolution());
|
||||||
m_hm_image.destroy();
|
m_hm_image.destroy();
|
||||||
m_hm_preview->tex.reset();
|
m_hm_preview->tex.reset();
|
||||||
@@ -107,24 +99,26 @@ void NodePanelGrid::init_controls()
|
|||||||
|
|
||||||
m_hm_reload->on_click = [this](Node*)
|
m_hm_reload->on_click = [this](Node*)
|
||||||
{
|
{
|
||||||
Image img;
|
load_heightmap_file(m_file_path, false);
|
||||||
if (img.load_file(m_file_path))
|
|
||||||
{
|
|
||||||
m_hm_image = img.resize(128, 128);
|
|
||||||
m_hm_preview->tex = std::make_shared<Texture2D>();
|
|
||||||
m_hm_preview->tex->create(m_hm_image);
|
|
||||||
m_hm_preview->tex->create_mipmaps();
|
|
||||||
auto sz = m_hm_preview->tex->size();
|
|
||||||
m_hm_preview->SetAspectRatio(sz.x / sz.y);
|
|
||||||
m_hm_plane.create(1, 1, m_hm_image, get_resolution(), get_height());
|
|
||||||
m_hm_preview->SetHeight(100);
|
|
||||||
m_rt_dirty = true;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
m_render->on_click = [this](Node*)
|
m_render->on_click = [this](Node*)
|
||||||
{
|
{
|
||||||
if (ShaderManager::ext_float32 || ShaderManager::ext_float16)
|
const auto plan = pp::app::plan_grid_lightmap_render(
|
||||||
|
static_cast<bool>(m_hm_image.data()),
|
||||||
|
ShaderManager::ext_float32,
|
||||||
|
ShaderManager::ext_float16,
|
||||||
|
get_texres(),
|
||||||
|
get_samples());
|
||||||
|
if (!plan)
|
||||||
|
return;
|
||||||
|
if (plan.value().shows_unsupported_message)
|
||||||
|
{
|
||||||
|
App::I->message_box("Rendering failed",
|
||||||
|
"Your hardware does not support lightmap rendering.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (plan.value().renders_lightmap)
|
||||||
{
|
{
|
||||||
std::thread([this] {
|
std::thread([this] {
|
||||||
BT_SetTerminate();
|
BT_SetTerminate();
|
||||||
@@ -133,17 +127,16 @@ void NodePanelGrid::init_controls()
|
|||||||
m_shade_mode = ShadeMode::Textured;
|
m_shade_mode = ShadeMode::Textured;
|
||||||
}).detach();
|
}).detach();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
App::I->message_box("Rendering failed",
|
|
||||||
"Your hardware does not support lightmap rendering.");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
m_commit->on_click = [this](Node*)
|
m_commit->on_click = [this](Node*)
|
||||||
{
|
{
|
||||||
|
const auto plan = pp::app::plan_grid_heightmap_commit(Canvas::I != nullptr);
|
||||||
|
if (!plan.commits_heightmap)
|
||||||
|
return;
|
||||||
Canvas::I->draw_objects([this](const glm::mat4& camera, const glm::mat4& proj, int i) {
|
Canvas::I->draw_objects([this](const glm::mat4& camera, const glm::mat4& proj, int i) {
|
||||||
draw_heightmap(proj, camera, true);
|
draw_heightmap(proj, camera, true);
|
||||||
}, Canvas::I->layer().m_frame_index, true);
|
}, Canvas::I->layer().m_frame_index, true);
|
||||||
|
if (plan.updates_ground_opacity)
|
||||||
m_groud_opacity->set_value(0);
|
m_groud_opacity->set_value(0);
|
||||||
};
|
};
|
||||||
m_hm_texres->on_select = [this](Node*, int index) {
|
m_hm_texres->on_select = [this](Node*, int index) {
|
||||||
@@ -226,6 +219,33 @@ float NodePanelGrid::get_offset() const
|
|||||||
return glm::pow(m_groud_offset->get_value() - 0.5f, 3);
|
return glm::pow(m_groud_offset->get_value() - 0.5f, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NodePanelGrid::load_heightmap_file(const std::string& path, bool raise_ground_opacity)
|
||||||
|
{
|
||||||
|
const auto plan = raise_ground_opacity
|
||||||
|
? pp::app::plan_grid_heightmap_load(path)
|
||||||
|
: pp::app::plan_grid_heightmap_reload(path);
|
||||||
|
if (!plan)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Image img;
|
||||||
|
if (!img.load_file(plan.value().path))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_file_path = plan.value().path;
|
||||||
|
m_hm_image = img.resize(128, 128);
|
||||||
|
m_hm_preview->tex = std::make_shared<Texture2D>();
|
||||||
|
m_hm_preview->tex->create(m_hm_image);
|
||||||
|
m_hm_preview->tex->create_mipmaps();
|
||||||
|
auto sz = m_hm_preview->tex->size();
|
||||||
|
m_hm_preview->SetAspectRatio(sz.x / sz.y);
|
||||||
|
m_hm_plane.create(1, 1, m_hm_image, get_resolution(), get_height());
|
||||||
|
m_hm_preview->SetHeight(100);
|
||||||
|
if (plan.value().updates_ground_opacity && m_groud_opacity->get_value() == 0.f)
|
||||||
|
m_groud_opacity->set_value(1.f);
|
||||||
|
m_rt_dirty = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void NodePanelGrid::draw_heightmap(const glm::mat4& proj, const glm::mat4& camera, bool commit) const
|
void NodePanelGrid::draw_heightmap(const glm::mat4& proj, const glm::mat4& camera, bool commit) const
|
||||||
{
|
{
|
||||||
assert(App::I->is_render_thread());
|
assert(App::I->is_render_thread());
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ public:
|
|||||||
float get_resolution() const;
|
float get_resolution() const;
|
||||||
float get_height() const;
|
float get_height() const;
|
||||||
float get_offset() const;
|
float get_offset() const;
|
||||||
|
bool load_heightmap_file(const std::string& path, bool raise_ground_opacity);
|
||||||
void draw_heightmap(const glm::mat4& proj, const glm::mat4& camera, bool commit) const;
|
void draw_heightmap(const glm::mat4& proj, const glm::mat4& camera, bool commit) const;
|
||||||
void bake_uvs();
|
void bake_uvs();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -278,6 +278,16 @@ add_test(NAME pp_app_core_brush_ui_tests COMMAND pp_app_core_brush_ui_tests)
|
|||||||
set_tests_properties(pp_app_core_brush_ui_tests PROPERTIES
|
set_tests_properties(pp_app_core_brush_ui_tests PROPERTIES
|
||||||
LABELS "app;paint;desktop-fast;fuzz")
|
LABELS "app;paint;desktop-fast;fuzz")
|
||||||
|
|
||||||
|
add_executable(pp_app_core_grid_ui_tests
|
||||||
|
app_core/grid_ui_tests.cpp)
|
||||||
|
target_link_libraries(pp_app_core_grid_ui_tests PRIVATE
|
||||||
|
pp_app_core
|
||||||
|
pp_test_harness)
|
||||||
|
|
||||||
|
add_test(NAME pp_app_core_grid_ui_tests COMMAND pp_app_core_grid_ui_tests)
|
||||||
|
set_tests_properties(pp_app_core_grid_ui_tests PROPERTIES
|
||||||
|
LABELS "app;ui;renderer;desktop-fast;fuzz")
|
||||||
|
|
||||||
add_executable(pp_app_core_document_route_tests
|
add_executable(pp_app_core_document_route_tests
|
||||||
app_core/document_route_tests.cpp)
|
app_core/document_route_tests.cpp)
|
||||||
target_link_libraries(pp_app_core_document_route_tests PRIVATE
|
target_link_libraries(pp_app_core_document_route_tests PRIVATE
|
||||||
@@ -816,6 +826,42 @@ if(TARGET pano_cli)
|
|||||||
LABELS "app;paint;integration;desktop-fast;fuzz"
|
LABELS "app;paint;integration;desktop-fast;fuzz"
|
||||||
WILL_FAIL TRUE)
|
WILL_FAIL TRUE)
|
||||||
|
|
||||||
|
add_test(NAME pano_cli_plan_grid_operation_pick_smoke
|
||||||
|
COMMAND pano_cli plan-grid-operation --kind pick)
|
||||||
|
set_tests_properties(pano_cli_plan_grid_operation_pick_smoke PROPERTIES
|
||||||
|
LABELS "app;ui;renderer;integration;desktop-fast"
|
||||||
|
PASS_REGULAR_EXPRESSION "\"command\":\"plan-grid-operation\".*\"operation\":\"request-heightmap-pick\".*\"opensPicker\":true.*\"mutatesGridState\":false")
|
||||||
|
|
||||||
|
add_test(NAME pano_cli_plan_grid_operation_load_smoke
|
||||||
|
COMMAND pano_cli plan-grid-operation --kind load --path D:/Paint/height.png)
|
||||||
|
set_tests_properties(pano_cli_plan_grid_operation_load_smoke PROPERTIES
|
||||||
|
LABELS "app;ui;renderer;integration;desktop-fast"
|
||||||
|
PASS_REGULAR_EXPRESSION "\"command\":\"plan-grid-operation\".*\"operation\":\"load-heightmap\".*\"path\":\"D:/Paint/height.png\".*\"loadsHeightmap\":true.*\"updatesPreview\":true.*\"updatesGroundOpacity\":true")
|
||||||
|
|
||||||
|
add_test(NAME pano_cli_plan_grid_operation_render_supported_smoke
|
||||||
|
COMMAND pano_cli plan-grid-operation --kind render --float32 --texture-resolution 1024 --samples 32)
|
||||||
|
set_tests_properties(pano_cli_plan_grid_operation_render_supported_smoke PROPERTIES
|
||||||
|
LABELS "app;ui;renderer;integration;desktop-fast"
|
||||||
|
PASS_REGULAR_EXPRESSION "\"command\":\"plan-grid-operation\".*\"operation\":\"render-lightmap\".*\"textureResolution\":1024.*\"sampleCount\":32.*\"rendersLightmap\":true.*\"updatesShadingMode\":true.*\"showsProgress\":true")
|
||||||
|
|
||||||
|
add_test(NAME pano_cli_plan_grid_operation_render_unsupported_smoke
|
||||||
|
COMMAND pano_cli plan-grid-operation --kind render)
|
||||||
|
set_tests_properties(pano_cli_plan_grid_operation_render_unsupported_smoke PROPERTIES
|
||||||
|
LABELS "app;ui;renderer;integration;desktop-fast;fuzz"
|
||||||
|
PASS_REGULAR_EXPRESSION "\"command\":\"plan-grid-operation\".*\"operation\":\"render-lightmap\".*\"rendersLightmap\":false.*\"showsUnsupportedMessage\":true")
|
||||||
|
|
||||||
|
add_test(NAME pano_cli_plan_grid_operation_rejects_empty_reload
|
||||||
|
COMMAND pano_cli plan-grid-operation --kind reload)
|
||||||
|
set_tests_properties(pano_cli_plan_grid_operation_rejects_empty_reload PROPERTIES
|
||||||
|
LABELS "app;ui;renderer;integration;desktop-fast;fuzz"
|
||||||
|
WILL_FAIL TRUE)
|
||||||
|
|
||||||
|
add_test(NAME pano_cli_plan_grid_operation_rejects_bad_samples
|
||||||
|
COMMAND pano_cli plan-grid-operation --kind render --float32 --samples 0)
|
||||||
|
set_tests_properties(pano_cli_plan_grid_operation_rejects_bad_samples PROPERTIES
|
||||||
|
LABELS "app;ui;renderer;integration;desktop-fast;fuzz"
|
||||||
|
WILL_FAIL TRUE)
|
||||||
|
|
||||||
add_test(NAME pano_cli_plan_share_file_unsaved_smoke
|
add_test(NAME pano_cli_plan_share_file_unsaved_smoke
|
||||||
COMMAND pano_cli plan-share-file)
|
COMMAND pano_cli plan-share-file)
|
||||||
set_tests_properties(pano_cli_plan_share_file_unsaved_smoke PROPERTIES
|
set_tests_properties(pano_cli_plan_share_file_unsaved_smoke PROPERTIES
|
||||||
|
|||||||
99
tests/app_core/grid_ui_tests.cpp
Normal file
99
tests/app_core/grid_ui_tests.cpp
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#include "app_core/grid_ui.h"
|
||||||
|
#include "test_harness.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void heightmap_load_reload_and_clear_plan_state(pp::tests::Harness& harness)
|
||||||
|
{
|
||||||
|
const auto pick = pp::app::plan_grid_heightmap_pick();
|
||||||
|
PP_EXPECT(harness, pick.operation == pp::app::GridUiOperation::request_heightmap_pick);
|
||||||
|
PP_EXPECT(harness, pick.opens_picker);
|
||||||
|
PP_EXPECT(harness, !pick.mutates_grid_state);
|
||||||
|
|
||||||
|
const auto load = pp::app::plan_grid_heightmap_load("D:/Paint/height.png");
|
||||||
|
PP_EXPECT(harness, load);
|
||||||
|
if (load) {
|
||||||
|
PP_EXPECT(harness, load.value().operation == pp::app::GridUiOperation::load_heightmap);
|
||||||
|
PP_EXPECT(harness, load.value().path == "D:/Paint/height.png");
|
||||||
|
PP_EXPECT(harness, load.value().loads_heightmap);
|
||||||
|
PP_EXPECT(harness, load.value().updates_preview);
|
||||||
|
PP_EXPECT(harness, load.value().updates_ground_opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto reload = pp::app::plan_grid_heightmap_reload("D:/Paint/height.png");
|
||||||
|
PP_EXPECT(harness, reload);
|
||||||
|
if (reload) {
|
||||||
|
PP_EXPECT(harness, reload.value().operation == pp::app::GridUiOperation::reload_heightmap);
|
||||||
|
PP_EXPECT(harness, reload.value().loads_heightmap);
|
||||||
|
PP_EXPECT(harness, !reload.value().updates_ground_opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto clear_existing = pp::app::plan_grid_heightmap_clear(true);
|
||||||
|
PP_EXPECT(harness, clear_existing.clears_heightmap);
|
||||||
|
PP_EXPECT(harness, clear_existing.updates_preview);
|
||||||
|
PP_EXPECT(harness, clear_existing.mutates_grid_state);
|
||||||
|
|
||||||
|
const auto clear_empty = pp::app::plan_grid_heightmap_clear(false);
|
||||||
|
PP_EXPECT(harness, clear_empty.clears_heightmap);
|
||||||
|
PP_EXPECT(harness, !clear_empty.updates_preview);
|
||||||
|
PP_EXPECT(harness, !clear_empty.mutates_grid_state);
|
||||||
|
|
||||||
|
PP_EXPECT(harness, !pp::app::plan_grid_heightmap_load(""));
|
||||||
|
PP_EXPECT(harness, !pp::app::plan_grid_heightmap_reload(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
void lightmap_render_validates_capabilities_and_limits(pp::tests::Harness& harness)
|
||||||
|
{
|
||||||
|
const auto supported = pp::app::plan_grid_lightmap_render(true, true, false, 1024, 32);
|
||||||
|
PP_EXPECT(harness, supported);
|
||||||
|
if (supported) {
|
||||||
|
PP_EXPECT(harness, supported.value().operation == pp::app::GridUiOperation::render_lightmap);
|
||||||
|
PP_EXPECT(harness, supported.value().renders_lightmap);
|
||||||
|
PP_EXPECT(harness, supported.value().shows_progress);
|
||||||
|
PP_EXPECT(harness, supported.value().updates_shading_mode);
|
||||||
|
PP_EXPECT(harness, supported.value().texture_resolution == 1024);
|
||||||
|
PP_EXPECT(harness, supported.value().sample_count == 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto missing_heightmap = pp::app::plan_grid_lightmap_render(false, true, false, 1024, 32);
|
||||||
|
PP_EXPECT(harness, missing_heightmap);
|
||||||
|
if (missing_heightmap) {
|
||||||
|
PP_EXPECT(harness, !missing_heightmap.value().renders_lightmap);
|
||||||
|
PP_EXPECT(harness, !missing_heightmap.value().shows_unsupported_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto unsupported = pp::app::plan_grid_lightmap_render(true, false, false, 1024, 32);
|
||||||
|
PP_EXPECT(harness, unsupported);
|
||||||
|
if (unsupported) {
|
||||||
|
PP_EXPECT(harness, unsupported.value().shows_unsupported_message);
|
||||||
|
PP_EXPECT(harness, !unsupported.value().renders_lightmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
PP_EXPECT(harness, !pp::app::plan_grid_lightmap_render(true, true, false, 0, 32));
|
||||||
|
PP_EXPECT(harness, !pp::app::plan_grid_lightmap_render(true, true, false, 1024, 0));
|
||||||
|
PP_EXPECT(harness, !pp::app::plan_grid_lightmap_render(true, true, false, 20000, 32));
|
||||||
|
PP_EXPECT(harness, !pp::app::plan_grid_lightmap_render(true, true, false, 1024, 4097));
|
||||||
|
}
|
||||||
|
|
||||||
|
void commit_plan_requires_canvas(pp::tests::Harness& harness)
|
||||||
|
{
|
||||||
|
const auto live = pp::app::plan_grid_heightmap_commit(true);
|
||||||
|
PP_EXPECT(harness, live.operation == pp::app::GridUiOperation::commit_heightmap);
|
||||||
|
PP_EXPECT(harness, live.commits_heightmap);
|
||||||
|
PP_EXPECT(harness, live.updates_ground_opacity);
|
||||||
|
|
||||||
|
const auto headless = pp::app::plan_grid_heightmap_commit(false);
|
||||||
|
PP_EXPECT(harness, !headless.commits_heightmap);
|
||||||
|
PP_EXPECT(harness, !headless.mutates_grid_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
pp::tests::Harness harness;
|
||||||
|
harness.run("heightmap load reload and clear plan state", heightmap_load_reload_and_clear_plan_state);
|
||||||
|
harness.run("lightmap render validates capabilities and limits", lightmap_render_validates_capabilities_and_limits);
|
||||||
|
harness.run("commit plan requires canvas", commit_plan_requires_canvas);
|
||||||
|
return harness.finish();
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "app_core/document_route.h"
|
#include "app_core/document_route.h"
|
||||||
#include "app_core/document_sharing.h"
|
#include "app_core/document_sharing.h"
|
||||||
#include "app_core/document_session.h"
|
#include "app_core/document_session.h"
|
||||||
|
#include "app_core/grid_ui.h"
|
||||||
#include "assets/image_format.h"
|
#include "assets/image_format.h"
|
||||||
#include "assets/image_metadata.h"
|
#include "assets/image_metadata.h"
|
||||||
#include "assets/image_pixels.h"
|
#include "assets/image_pixels.h"
|
||||||
@@ -263,6 +264,17 @@ struct PlanBrushOperationArgs {
|
|||||||
bool has_brush = true;
|
bool has_brush = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PlanGridOperationArgs {
|
||||||
|
std::string kind = "pick";
|
||||||
|
std::string path;
|
||||||
|
bool has_heightmap = true;
|
||||||
|
bool has_canvas = true;
|
||||||
|
bool supports_float32 = false;
|
||||||
|
bool supports_float16 = false;
|
||||||
|
int texture_resolution = 1024;
|
||||||
|
int sample_count = 32;
|
||||||
|
};
|
||||||
|
|
||||||
struct SimulateAppSessionArgs {
|
struct SimulateAppSessionArgs {
|
||||||
bool has_canvas = true;
|
bool has_canvas = true;
|
||||||
bool new_document = false;
|
bool new_document = false;
|
||||||
@@ -592,6 +604,26 @@ const char* brush_ui_operation_name(pp::app::BrushUiOperation operation) noexcep
|
|||||||
return "stroke-settings-changed";
|
return "stroke-settings-changed";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* grid_ui_operation_name(pp::app::GridUiOperation operation) noexcept
|
||||||
|
{
|
||||||
|
switch (operation) {
|
||||||
|
case pp::app::GridUiOperation::request_heightmap_pick:
|
||||||
|
return "request-heightmap-pick";
|
||||||
|
case pp::app::GridUiOperation::load_heightmap:
|
||||||
|
return "load-heightmap";
|
||||||
|
case pp::app::GridUiOperation::clear_heightmap:
|
||||||
|
return "clear-heightmap";
|
||||||
|
case pp::app::GridUiOperation::reload_heightmap:
|
||||||
|
return "reload-heightmap";
|
||||||
|
case pp::app::GridUiOperation::render_lightmap:
|
||||||
|
return "render-lightmap";
|
||||||
|
case pp::app::GridUiOperation::commit_heightmap:
|
||||||
|
return "commit-heightmap";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "request-heightmap-pick";
|
||||||
|
}
|
||||||
|
|
||||||
const char* document_file_write_decision_name(pp::app::DocumentFileWriteDecision decision) noexcept
|
const char* document_file_write_decision_name(pp::app::DocumentFileWriteDecision decision) noexcept
|
||||||
{
|
{
|
||||||
switch (decision) {
|
switch (decision) {
|
||||||
@@ -847,6 +879,7 @@ void print_help()
|
|||||||
<< " plan-layer-operation --kind add|duplicate|select|reorder|remove|opacity|visibility|alpha-lock|blend-mode|highlight [--layer-count N] [--index N] [--from-index N] [--to-index N] [--source-index N] [--name NAME] [--opacity N] [--blend-mode N] [--enabled]\n"
|
<< " plan-layer-operation --kind add|duplicate|select|reorder|remove|opacity|visibility|alpha-lock|blend-mode|highlight [--layer-count N] [--index N] [--from-index N] [--to-index N] [--source-index N] [--name NAME] [--opacity N] [--blend-mode N] [--enabled]\n"
|
||||||
<< " plan-animation-operation --kind add|duplicate|remove|duration|move|goto|next|prev|onion [--frame-count N] [--total-duration N] [--current-frame N] [--selected-frame N] [--current-duration N] [--delta N] [--offset N] [--onion-size N]\n"
|
<< " plan-animation-operation --kind add|duplicate|remove|duration|move|goto|next|prev|onion [--frame-count N] [--total-duration N] [--current-frame N] [--selected-frame N] [--current-duration N] [--delta N] [--offset N] [--onion-size N]\n"
|
||||||
<< " plan-brush-operation --kind color|tip|pattern|dual|preset|settings [--path FILE] [--thumb FILE] [--r N] [--g N] [--b N] [--a N] [--no-brush]\n"
|
<< " plan-brush-operation --kind color|tip|pattern|dual|preset|settings [--path FILE] [--thumb FILE] [--r N] [--g N] [--b N] [--a N] [--no-brush]\n"
|
||||||
|
<< " plan-grid-operation --kind pick|load|reload|clear|render|commit [--path FILE] [--no-heightmap] [--no-canvas] [--float32] [--float16] [--texture-resolution N] [--samples N]\n"
|
||||||
<< " plan-share-file [--path FILE]\n"
|
<< " plan-share-file [--path FILE]\n"
|
||||||
<< " plan-picked-path [--path FILE]\n"
|
<< " plan-picked-path [--path FILE]\n"
|
||||||
<< " plan-display-file [--path FILE]\n"
|
<< " plan-display-file [--path FILE]\n"
|
||||||
@@ -2885,6 +2918,127 @@ int plan_brush_operation(int argc, char** argv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pp::foundation::Status parse_plan_grid_operation_args(
|
||||||
|
int argc,
|
||||||
|
char** argv,
|
||||||
|
PlanGridOperationArgs& args)
|
||||||
|
{
|
||||||
|
for (int i = 2; i < argc; ++i) {
|
||||||
|
const std::string_view key(argv[i]);
|
||||||
|
if (key == "--kind" || key == "--path") {
|
||||||
|
if (i + 1 >= argc) {
|
||||||
|
return pp::foundation::Status::invalid_argument("missing value for option");
|
||||||
|
}
|
||||||
|
if (key == "--kind") {
|
||||||
|
args.kind = argv[++i];
|
||||||
|
} else {
|
||||||
|
args.path = argv[++i];
|
||||||
|
}
|
||||||
|
} else if (key == "--texture-resolution" || key == "--samples") {
|
||||||
|
if (i + 1 >= argc) {
|
||||||
|
return pp::foundation::Status::invalid_argument("missing value for option");
|
||||||
|
}
|
||||||
|
const auto value = parse_i32_arg(argv[++i]);
|
||||||
|
if (!value) {
|
||||||
|
return value.status();
|
||||||
|
}
|
||||||
|
if (key == "--texture-resolution") {
|
||||||
|
args.texture_resolution = value.value();
|
||||||
|
} else {
|
||||||
|
args.sample_count = value.value();
|
||||||
|
}
|
||||||
|
} else if (key == "--no-heightmap") {
|
||||||
|
args.has_heightmap = false;
|
||||||
|
} else if (key == "--no-canvas") {
|
||||||
|
args.has_canvas = false;
|
||||||
|
} else if (key == "--float32") {
|
||||||
|
args.supports_float32 = true;
|
||||||
|
} else if (key == "--float16") {
|
||||||
|
args.supports_float16 = true;
|
||||||
|
} else {
|
||||||
|
return pp::foundation::Status::invalid_argument("unknown option");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pp::foundation::Status::success();
|
||||||
|
}
|
||||||
|
|
||||||
|
pp::foundation::Result<pp::app::GridUiPlan> make_grid_operation_plan(const PlanGridOperationArgs& args)
|
||||||
|
{
|
||||||
|
if (args.kind == "pick") {
|
||||||
|
return pp::foundation::Result<pp::app::GridUiPlan>::success(pp::app::plan_grid_heightmap_pick());
|
||||||
|
}
|
||||||
|
if (args.kind == "load") {
|
||||||
|
return pp::app::plan_grid_heightmap_load(args.path);
|
||||||
|
}
|
||||||
|
if (args.kind == "reload") {
|
||||||
|
return pp::app::plan_grid_heightmap_reload(args.path);
|
||||||
|
}
|
||||||
|
if (args.kind == "clear") {
|
||||||
|
return pp::foundation::Result<pp::app::GridUiPlan>::success(
|
||||||
|
pp::app::plan_grid_heightmap_clear(args.has_heightmap));
|
||||||
|
}
|
||||||
|
if (args.kind == "render") {
|
||||||
|
return pp::app::plan_grid_lightmap_render(
|
||||||
|
args.has_heightmap,
|
||||||
|
args.supports_float32,
|
||||||
|
args.supports_float16,
|
||||||
|
args.texture_resolution,
|
||||||
|
args.sample_count);
|
||||||
|
}
|
||||||
|
if (args.kind == "commit") {
|
||||||
|
return pp::foundation::Result<pp::app::GridUiPlan>::success(
|
||||||
|
pp::app::plan_grid_heightmap_commit(args.has_canvas));
|
||||||
|
}
|
||||||
|
|
||||||
|
return pp::foundation::Result<pp::app::GridUiPlan>::failure(
|
||||||
|
pp::foundation::Status::invalid_argument("unknown grid operation kind"));
|
||||||
|
}
|
||||||
|
|
||||||
|
int plan_grid_operation(int argc, char** argv)
|
||||||
|
{
|
||||||
|
PlanGridOperationArgs args;
|
||||||
|
const auto status = parse_plan_grid_operation_args(argc, argv, args);
|
||||||
|
if (!status.ok()) {
|
||||||
|
print_error("plan-grid-operation", status.message);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto plan = make_grid_operation_plan(args);
|
||||||
|
if (!plan) {
|
||||||
|
print_error("plan-grid-operation", plan.status().message);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& value = plan.value();
|
||||||
|
std::cout << "{\"ok\":true,\"command\":\"plan-grid-operation\""
|
||||||
|
<< ",\"state\":{\"kind\":\"" << json_escape(args.kind)
|
||||||
|
<< "\",\"path\":\"" << json_escape(args.path)
|
||||||
|
<< "\",\"hasHeightmap\":" << json_bool(args.has_heightmap)
|
||||||
|
<< ",\"hasCanvas\":" << json_bool(args.has_canvas)
|
||||||
|
<< ",\"float32\":" << json_bool(args.supports_float32)
|
||||||
|
<< ",\"float16\":" << json_bool(args.supports_float16)
|
||||||
|
<< ",\"textureResolution\":" << args.texture_resolution
|
||||||
|
<< ",\"samples\":" << args.sample_count
|
||||||
|
<< "},\"plan\":{\"operation\":\"" << grid_ui_operation_name(value.operation)
|
||||||
|
<< "\",\"path\":\"" << json_escape(value.path)
|
||||||
|
<< "\",\"textureResolution\":" << value.texture_resolution
|
||||||
|
<< ",\"sampleCount\":" << value.sample_count
|
||||||
|
<< ",\"opensPicker\":" << json_bool(value.opens_picker)
|
||||||
|
<< ",\"loadsHeightmap\":" << json_bool(value.loads_heightmap)
|
||||||
|
<< ",\"clearsHeightmap\":" << json_bool(value.clears_heightmap)
|
||||||
|
<< ",\"rendersLightmap\":" << json_bool(value.renders_lightmap)
|
||||||
|
<< ",\"commitsHeightmap\":" << json_bool(value.commits_heightmap)
|
||||||
|
<< ",\"updatesPreview\":" << json_bool(value.updates_preview)
|
||||||
|
<< ",\"updatesGroundOpacity\":" << json_bool(value.updates_ground_opacity)
|
||||||
|
<< ",\"updatesShadingMode\":" << json_bool(value.updates_shading_mode)
|
||||||
|
<< ",\"showsUnsupportedMessage\":" << json_bool(value.shows_unsupported_message)
|
||||||
|
<< ",\"showsProgress\":" << json_bool(value.shows_progress)
|
||||||
|
<< ",\"mutatesGridState\":" << json_bool(value.mutates_grid_state)
|
||||||
|
<< "}}\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
pp::foundation::Status parse_plan_share_file_args(
|
pp::foundation::Status parse_plan_share_file_args(
|
||||||
int argc,
|
int argc,
|
||||||
char** argv,
|
char** argv,
|
||||||
@@ -5305,6 +5459,10 @@ int main(int argc, char** argv)
|
|||||||
return plan_brush_operation(argc, argv);
|
return plan_brush_operation(argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (command == "plan-grid-operation") {
|
||||||
|
return plan_grid_operation(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
if (command == "plan-share-file") {
|
if (command == "plan-share-file") {
|
||||||
return plan_share_file(argc, argv);
|
return plan_share_file(argc, argv);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user