Add brush stroke control boundary
This commit is contained in:
@@ -28,6 +28,83 @@ enum class BrushTextureListOperation {
|
||||
move_texture,
|
||||
};
|
||||
|
||||
enum class BrushStrokeControlOperation {
|
||||
set_float,
|
||||
set_bool,
|
||||
set_blend_mode,
|
||||
reset_tip_aspect,
|
||||
reset_default_brush,
|
||||
};
|
||||
|
||||
enum class BrushStrokeFloatSetting {
|
||||
tip_size,
|
||||
tip_spacing,
|
||||
tip_flow,
|
||||
tip_opacity,
|
||||
tip_angle,
|
||||
tip_angle_smooth,
|
||||
tip_mix,
|
||||
tip_wet,
|
||||
tip_noise,
|
||||
tip_hue,
|
||||
tip_saturation,
|
||||
tip_value,
|
||||
jitter_scale,
|
||||
jitter_angle,
|
||||
jitter_scatter,
|
||||
jitter_flow,
|
||||
jitter_opacity,
|
||||
jitter_hue,
|
||||
jitter_saturation,
|
||||
jitter_value,
|
||||
jitter_aspect,
|
||||
dual_size,
|
||||
dual_spacing,
|
||||
dual_scatter,
|
||||
tip_aspect,
|
||||
dual_opacity,
|
||||
dual_flow,
|
||||
dual_rotate,
|
||||
pattern_scale,
|
||||
pattern_brightness,
|
||||
pattern_contrast,
|
||||
pattern_depth,
|
||||
};
|
||||
|
||||
enum class BrushStrokeBoolSetting {
|
||||
tip_angle_init,
|
||||
tip_angle_follow,
|
||||
tip_flow_pressure,
|
||||
tip_opacity_pressure,
|
||||
tip_size_pressure,
|
||||
jitter_scatter_both_axis,
|
||||
jitter_aspect_both_axis,
|
||||
jitter_hsv_each_sample,
|
||||
tip_invert,
|
||||
tip_flip_x,
|
||||
tip_flip_y,
|
||||
pattern_enabled,
|
||||
dual_enabled,
|
||||
dual_scatter_both_axis,
|
||||
dual_invert,
|
||||
dual_flip_x,
|
||||
dual_flip_y,
|
||||
dual_random_flip,
|
||||
tip_random_flip_x,
|
||||
tip_random_flip_y,
|
||||
pattern_each_sample,
|
||||
pattern_invert,
|
||||
pattern_flip_x,
|
||||
pattern_flip_y,
|
||||
pattern_random_offset,
|
||||
};
|
||||
|
||||
enum class BrushStrokeBlendSetting {
|
||||
tip,
|
||||
dual,
|
||||
pattern,
|
||||
};
|
||||
|
||||
struct BrushUiPlan {
|
||||
BrushUiOperation operation = BrushUiOperation::stroke_settings_changed;
|
||||
BrushUiTextureSlot texture_slot = BrushUiTextureSlot::tip;
|
||||
@@ -62,6 +139,20 @@ struct BrushTextureListPlan {
|
||||
bool no_op = false;
|
||||
};
|
||||
|
||||
struct BrushStrokeControlPlan {
|
||||
BrushStrokeControlOperation operation = BrushStrokeControlOperation::set_float;
|
||||
BrushStrokeFloatSetting float_setting = BrushStrokeFloatSetting::tip_size;
|
||||
BrushStrokeBoolSetting bool_setting = BrushStrokeBoolSetting::tip_angle_init;
|
||||
BrushStrokeBlendSetting blend_setting = BrushStrokeBlendSetting::tip;
|
||||
float float_value = 0.0F;
|
||||
bool bool_value = false;
|
||||
int blend_mode = 0;
|
||||
bool mutates_brush = false;
|
||||
bool updates_controls = false;
|
||||
bool refreshes_preview = false;
|
||||
bool notifies_stroke_change = false;
|
||||
};
|
||||
|
||||
class BrushUiServices {
|
||||
public:
|
||||
virtual ~BrushUiServices() = default;
|
||||
@@ -88,6 +179,20 @@ public:
|
||||
virtual void save_texture_list() = 0;
|
||||
};
|
||||
|
||||
class BrushStrokeControlServices {
|
||||
public:
|
||||
virtual ~BrushStrokeControlServices() = default;
|
||||
|
||||
virtual void set_float_setting(BrushStrokeFloatSetting setting, float value) = 0;
|
||||
virtual void set_bool_setting(BrushStrokeBoolSetting setting, bool value) = 0;
|
||||
virtual void set_blend_mode(BrushStrokeBlendSetting setting, int blend_mode) = 0;
|
||||
virtual void reset_tip_aspect(float value) = 0;
|
||||
virtual void reset_default_brush() = 0;
|
||||
virtual void update_stroke_controls() = 0;
|
||||
virtual void refresh_stroke_preview() = 0;
|
||||
virtual void notify_stroke_changed() = 0;
|
||||
};
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Result<std::string_view> brush_texture_source_stem(
|
||||
std::string_view source_path) noexcept
|
||||
{
|
||||
@@ -116,6 +221,24 @@ public:
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Status validate_brush_stroke_float(float value) noexcept
|
||||
{
|
||||
if (!std::isfinite(value)) {
|
||||
return pp::foundation::Status::invalid_argument("brush stroke float setting must be finite");
|
||||
}
|
||||
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Status validate_brush_stroke_blend_mode(int blend_mode) noexcept
|
||||
{
|
||||
if (blend_mode < 0 || blend_mode > 63) {
|
||||
return pp::foundation::Status::out_of_range("brush stroke blend mode must be within 0..63");
|
||||
}
|
||||
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Result<BrushUiPlan> plan_brush_ui_color(
|
||||
float r,
|
||||
float g,
|
||||
@@ -189,6 +312,81 @@ public:
|
||||
return plan;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Result<BrushStrokeControlPlan> plan_brush_stroke_float_setting(
|
||||
BrushStrokeFloatSetting setting,
|
||||
float value)
|
||||
{
|
||||
const auto status = validate_brush_stroke_float(value);
|
||||
if (!status.ok()) {
|
||||
return pp::foundation::Result<BrushStrokeControlPlan>::failure(status);
|
||||
}
|
||||
|
||||
BrushStrokeControlPlan plan;
|
||||
plan.operation = BrushStrokeControlOperation::set_float;
|
||||
plan.float_setting = setting;
|
||||
plan.float_value = value;
|
||||
plan.mutates_brush = true;
|
||||
plan.refreshes_preview = true;
|
||||
plan.notifies_stroke_change = true;
|
||||
return pp::foundation::Result<BrushStrokeControlPlan>::success(plan);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr BrushStrokeControlPlan plan_brush_stroke_bool_setting(
|
||||
BrushStrokeBoolSetting setting,
|
||||
bool value) noexcept
|
||||
{
|
||||
BrushStrokeControlPlan plan;
|
||||
plan.operation = BrushStrokeControlOperation::set_bool;
|
||||
plan.bool_setting = setting;
|
||||
plan.bool_value = value;
|
||||
plan.mutates_brush = true;
|
||||
plan.refreshes_preview = true;
|
||||
plan.notifies_stroke_change = true;
|
||||
return plan;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Result<BrushStrokeControlPlan> plan_brush_stroke_blend_mode(
|
||||
BrushStrokeBlendSetting setting,
|
||||
int blend_mode)
|
||||
{
|
||||
const auto status = validate_brush_stroke_blend_mode(blend_mode);
|
||||
if (!status.ok()) {
|
||||
return pp::foundation::Result<BrushStrokeControlPlan>::failure(status);
|
||||
}
|
||||
|
||||
BrushStrokeControlPlan plan;
|
||||
plan.operation = BrushStrokeControlOperation::set_blend_mode;
|
||||
plan.blend_setting = setting;
|
||||
plan.blend_mode = blend_mode;
|
||||
plan.mutates_brush = true;
|
||||
plan.refreshes_preview = true;
|
||||
plan.notifies_stroke_change = true;
|
||||
return pp::foundation::Result<BrushStrokeControlPlan>::success(plan);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr BrushStrokeControlPlan plan_brush_tip_aspect_reset(float value = 0.5F) noexcept
|
||||
{
|
||||
BrushStrokeControlPlan plan;
|
||||
plan.operation = BrushStrokeControlOperation::reset_tip_aspect;
|
||||
plan.float_setting = BrushStrokeFloatSetting::tip_aspect;
|
||||
plan.float_value = value;
|
||||
plan.mutates_brush = true;
|
||||
plan.refreshes_preview = true;
|
||||
plan.notifies_stroke_change = true;
|
||||
return plan;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr BrushStrokeControlPlan plan_brush_default_settings_reset() noexcept
|
||||
{
|
||||
BrushStrokeControlPlan plan;
|
||||
plan.operation = BrushStrokeControlOperation::reset_default_brush;
|
||||
plan.mutates_brush = true;
|
||||
plan.updates_controls = true;
|
||||
plan.refreshes_preview = true;
|
||||
plan.notifies_stroke_change = true;
|
||||
return plan;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Result<BrushTextureListPlan> plan_brush_texture_list_add(
|
||||
std::string_view directory_name,
|
||||
std::string_view data_path,
|
||||
@@ -315,6 +513,63 @@ public:
|
||||
return pp::foundation::Status::invalid_argument("unknown brush UI operation");
|
||||
}
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Status execute_brush_stroke_control_plan(
|
||||
const BrushStrokeControlPlan& plan,
|
||||
BrushStrokeControlServices& services)
|
||||
{
|
||||
switch (plan.operation) {
|
||||
case BrushStrokeControlOperation::set_float:
|
||||
{
|
||||
const auto status = validate_brush_stroke_float(plan.float_value);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
services.set_float_setting(plan.float_setting, plan.float_value);
|
||||
break;
|
||||
}
|
||||
|
||||
case BrushStrokeControlOperation::set_bool:
|
||||
services.set_bool_setting(plan.bool_setting, plan.bool_value);
|
||||
break;
|
||||
|
||||
case BrushStrokeControlOperation::set_blend_mode:
|
||||
{
|
||||
const auto status = validate_brush_stroke_blend_mode(plan.blend_mode);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
services.set_blend_mode(plan.blend_setting, plan.blend_mode);
|
||||
break;
|
||||
}
|
||||
|
||||
case BrushStrokeControlOperation::reset_tip_aspect:
|
||||
{
|
||||
const auto status = validate_brush_stroke_float(plan.float_value);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
services.reset_tip_aspect(plan.float_value);
|
||||
break;
|
||||
}
|
||||
|
||||
case BrushStrokeControlOperation::reset_default_brush:
|
||||
services.reset_default_brush();
|
||||
break;
|
||||
}
|
||||
|
||||
if (plan.updates_controls) {
|
||||
services.update_stroke_controls();
|
||||
}
|
||||
if (plan.refreshes_preview) {
|
||||
services.refresh_stroke_preview();
|
||||
}
|
||||
if (plan.notifies_stroke_change) {
|
||||
services.notify_stroke_changed();
|
||||
}
|
||||
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Status execute_brush_texture_list_plan(
|
||||
const BrushTextureListPlan& plan,
|
||||
BrushTextureListServices& services)
|
||||
|
||||
Reference in New Issue
Block a user