403 lines
14 KiB
C++
403 lines
14 KiB
C++
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup RNA
|
|
*/
|
|
|
|
#include "DNA_curves_types.h"
|
|
|
|
#include "RNA_define.hh"
|
|
|
|
#include "RNA_enum_types.hh"
|
|
|
|
#include "rna_internal.hh" /* own include */
|
|
|
|
#ifdef RNA_RUNTIME
|
|
|
|
# include "BKE_curves.hh"
|
|
# include "BKE_geometry_compare.hh"
|
|
# include "BKE_report.hh"
|
|
|
|
# include "BLI_index_mask.hh"
|
|
# include "BLI_set.hh"
|
|
|
|
# include "ED_curves.hh"
|
|
|
|
# include "DEG_depsgraph.hh"
|
|
|
|
# include "WM_api.hh"
|
|
|
|
# include "rna_curves_utils.hh"
|
|
|
|
/* Common `CurvesGeometry` API functions. */
|
|
|
|
using blender::IndexMask;
|
|
using blender::IndexMaskMemory;
|
|
using blender::IndexRange;
|
|
using blender::Span;
|
|
|
|
bool rna_CurvesGeometry_add_curves(blender::bke::CurvesGeometry &curves,
|
|
ReportList *reports,
|
|
const int *sizes_ptr,
|
|
const int sizes_num)
|
|
{
|
|
using namespace blender;
|
|
if (std::any_of(sizes_ptr, sizes_ptr + sizes_num, [](const int size) { return size < 1; })) {
|
|
BKE_report(reports, RPT_ERROR, "Curve sizes must be greater than zero");
|
|
return false;
|
|
}
|
|
|
|
ed::curves::add_curves(curves, {sizes_ptr, sizes_num});
|
|
curves.tag_topology_changed();
|
|
return true;
|
|
}
|
|
|
|
static std::optional<IndexMask> rna_indices_to_mask(const IndexRange universe,
|
|
const int *indices_ptr,
|
|
const int indices_num,
|
|
ReportList &reports,
|
|
IndexMaskMemory &memory)
|
|
{
|
|
if (!indices_ptr) {
|
|
return IndexMask(universe);
|
|
}
|
|
const Span<int> indices(indices_ptr, indices_num);
|
|
if (std::any_of(indices.begin(), indices.end(), [&](const int index) {
|
|
return !universe.contains(index);
|
|
}))
|
|
{
|
|
BKE_report(&reports, RPT_ERROR, "Indices must be in range");
|
|
return std::nullopt;
|
|
}
|
|
if (!std::is_sorted(indices.begin(), indices.end())) {
|
|
BKE_report(&reports, RPT_ERROR, "Indices must be sorted in ascending order");
|
|
return std::nullopt;
|
|
}
|
|
if (std::adjacent_find(indices.begin(), indices.end(), std::greater_equal<>()) != indices.end())
|
|
{
|
|
BKE_report(&reports, RPT_ERROR, "Indices can't have duplicates");
|
|
return std::nullopt;
|
|
}
|
|
return IndexMask::from_indices(indices, memory);
|
|
}
|
|
|
|
bool rna_CurvesGeometry_remove_curves(blender::bke::CurvesGeometry &curves,
|
|
ReportList *reports,
|
|
const int *indices_ptr,
|
|
const int indices_num)
|
|
{
|
|
using namespace blender;
|
|
IndexMaskMemory memory;
|
|
const std::optional<IndexMask> curves_to_delete = rna_indices_to_mask(
|
|
curves.curves_range(), indices_ptr, indices_num, *reports, memory);
|
|
if (!curves_to_delete) {
|
|
return false;
|
|
}
|
|
curves.remove_curves(*curves_to_delete, {});
|
|
return true;
|
|
}
|
|
|
|
bool rna_CurvesGeometry_resize_curves(blender::bke::CurvesGeometry &curves,
|
|
ReportList *reports,
|
|
const int *sizes_ptr,
|
|
const int sizes_num,
|
|
const int *indices_ptr,
|
|
const int indices_num)
|
|
{
|
|
using namespace blender;
|
|
const Span<int> new_sizes(sizes_ptr, sizes_num);
|
|
if (std::any_of(new_sizes.begin(), new_sizes.end(), [](const int size) { return size < 1; })) {
|
|
BKE_report(reports, RPT_ERROR, "Sizes must be greater than zero");
|
|
return false;
|
|
}
|
|
IndexMaskMemory memory;
|
|
const std::optional<IndexMask> curves_to_resize = rna_indices_to_mask(
|
|
curves.curves_range(), indices_ptr, indices_num, *reports, memory);
|
|
if (!curves_to_resize) {
|
|
return false;
|
|
}
|
|
if (curves_to_resize->size() != sizes_num) {
|
|
BKE_report(reports, RPT_ERROR, "Length of sizes must be the same as the selection size");
|
|
return false;
|
|
}
|
|
ed::curves::resize_curves(curves, *curves_to_resize, {sizes_ptr, sizes_num});
|
|
return true;
|
|
}
|
|
|
|
bool rna_CurvesGeometry_reorder_curves(blender::bke::CurvesGeometry &curves,
|
|
ReportList *reports,
|
|
const int *reorder_indices_ptr,
|
|
const int reorder_indices_num)
|
|
{
|
|
using namespace blender;
|
|
const Span<int> new_to_old_indices_map(reorder_indices_ptr, reorder_indices_num);
|
|
if (curves.curves_num() != reorder_indices_num) {
|
|
BKE_report(
|
|
reports, RPT_ERROR, "Length of reorder indices must be the same as the number of curves");
|
|
return false;
|
|
}
|
|
if (std::any_of(new_to_old_indices_map.begin(),
|
|
new_to_old_indices_map.end(),
|
|
[&](const int index) { return !curves.curves_range().contains(index); }))
|
|
{
|
|
BKE_report(reports, RPT_ERROR, "Reorder indices must be valid");
|
|
return false;
|
|
}
|
|
if (Set(new_to_old_indices_map).size() != reorder_indices_num) {
|
|
BKE_report(reports, RPT_ERROR, "Reorder indices must not have duplicates");
|
|
return false;
|
|
}
|
|
ed::curves::reorder_curves(curves, new_to_old_indices_map);
|
|
return true;
|
|
}
|
|
|
|
bool rna_CurvesGeometry_set_types(blender::bke::CurvesGeometry &curves,
|
|
ReportList *reports,
|
|
const int type,
|
|
const int *indices_ptr,
|
|
const int indices_num)
|
|
{
|
|
IndexMaskMemory memory;
|
|
const std::optional<IndexMask> selection = rna_indices_to_mask(
|
|
curves.curves_range(), indices_ptr, indices_num, *reports, memory);
|
|
if (!selection) {
|
|
return false;
|
|
}
|
|
curves.fill_curve_types(*selection, CurveType(type));
|
|
return true;
|
|
}
|
|
|
|
/* Curves API functions. */
|
|
|
|
static void rna_Curves_add_curves(Curves *curves_id,
|
|
ReportList *reports,
|
|
const int *sizes,
|
|
const int sizes_num)
|
|
{
|
|
using namespace blender;
|
|
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
|
|
if (!rna_CurvesGeometry_add_curves(curves, reports, sizes, sizes_num)) {
|
|
return;
|
|
}
|
|
|
|
/* Avoid updates for importers creating curves. */
|
|
if (curves_id->id.us > 0) {
|
|
DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
|
|
WM_main_add_notifier(NC_GEOM | ND_DATA, curves_id);
|
|
}
|
|
}
|
|
|
|
static void rna_Curves_remove_curves(Curves *curves_id,
|
|
ReportList *reports,
|
|
const int *indices_ptr,
|
|
const int indices_num)
|
|
{
|
|
using namespace blender;
|
|
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
|
|
if (!rna_CurvesGeometry_remove_curves(curves, reports, indices_ptr, indices_num)) {
|
|
return;
|
|
}
|
|
|
|
/* Avoid updates for importers creating curves. */
|
|
if (curves_id->id.us > 0) {
|
|
DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
|
|
WM_main_add_notifier(NC_GEOM | ND_DATA, curves_id);
|
|
}
|
|
}
|
|
|
|
static void rna_Curves_resize_curves(Curves *curves_id,
|
|
ReportList *reports,
|
|
const int *sizes_ptr,
|
|
const int sizes_num,
|
|
const int *indices_ptr,
|
|
const int indices_num)
|
|
{
|
|
using namespace blender;
|
|
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
|
|
if (!rna_CurvesGeometry_resize_curves(
|
|
curves, reports, sizes_ptr, sizes_num, indices_ptr, indices_num))
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* Avoid updates for importers creating curves. */
|
|
if (curves_id->id.us > 0) {
|
|
DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
|
|
WM_main_add_notifier(NC_GEOM | ND_DATA, curves_id);
|
|
}
|
|
}
|
|
|
|
static void rna_Curves_reorder_curves(Curves *curves_id,
|
|
ReportList *reports,
|
|
const int *reorder_indices_ptr,
|
|
const int reorder_indices_num)
|
|
{
|
|
using namespace blender;
|
|
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
|
|
if (!rna_CurvesGeometry_reorder_curves(
|
|
curves, reports, reorder_indices_ptr, reorder_indices_num))
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* Avoid updates for importers creating curves. */
|
|
if (curves_id->id.us > 0) {
|
|
DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
|
|
WM_main_add_notifier(NC_GEOM | ND_DATA, curves_id);
|
|
}
|
|
}
|
|
|
|
static void rna_Curves_set_types(Curves *curves_id,
|
|
ReportList *reports,
|
|
const int type,
|
|
const int *indices_ptr,
|
|
const int indices_num)
|
|
{
|
|
using namespace blender;
|
|
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
|
|
if (!rna_CurvesGeometry_set_types(curves, reports, type, indices_ptr, indices_num)) {
|
|
return;
|
|
}
|
|
/* Avoid updates for importers creating curves. */
|
|
if (curves_id->id.us > 0) {
|
|
DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
|
|
WM_main_add_notifier(NC_GEOM | ND_DATA, curves_id);
|
|
}
|
|
}
|
|
|
|
static const char *rna_Curves_unit_test_compare(Curves *curves1, Curves *curves2, float threshold)
|
|
{
|
|
using namespace blender::bke::compare_geometry;
|
|
|
|
const std::optional<GeoMismatch> mismatch = compare_curves(
|
|
curves1->geometry.wrap(), curves2->geometry.wrap(), threshold);
|
|
|
|
if (!mismatch) {
|
|
return "Same";
|
|
}
|
|
|
|
return mismatch_to_string(mismatch.value());
|
|
}
|
|
|
|
#else
|
|
|
|
void RNA_api_curves(StructRNA *srna)
|
|
{
|
|
FunctionRNA *func;
|
|
PropertyRNA *parm;
|
|
|
|
func = RNA_def_function(srna, "add_curves", "rna_Curves_add_curves");
|
|
RNA_def_function_flag(func, FUNC_USE_REPORTS);
|
|
parm = RNA_def_int_array(func,
|
|
"sizes",
|
|
1,
|
|
nullptr,
|
|
0,
|
|
INT_MAX,
|
|
"Sizes",
|
|
"The number of points in each curve",
|
|
1,
|
|
10000);
|
|
RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_REQUIRED);
|
|
|
|
func = RNA_def_function(srna, "remove_curves", "rna_Curves_remove_curves");
|
|
RNA_def_function_ui_description(func,
|
|
"Remove all curves. If indices are provided, remove only the "
|
|
"curves with the given indices.");
|
|
RNA_def_function_flag(func, FUNC_USE_REPORTS);
|
|
parm = RNA_def_int_array(func,
|
|
"indices",
|
|
1,
|
|
nullptr,
|
|
0,
|
|
INT_MAX,
|
|
"Indices",
|
|
"The indices of the curves to remove",
|
|
0,
|
|
10000);
|
|
RNA_def_parameter_flags(parm, PROP_DYNAMIC, ParameterFlag(0));
|
|
|
|
func = RNA_def_function(srna, "resize_curves", "rna_Curves_resize_curves");
|
|
RNA_def_function_ui_description(
|
|
func,
|
|
"Resize all existing curves. If indices are provided, resize only the curves with the given "
|
|
"indices. If the new size for a curve is smaller, the curve is trimmed. If "
|
|
"the new size for a curve is larger, the new end values are default initialized.");
|
|
RNA_def_function_flag(func, FUNC_USE_REPORTS);
|
|
parm = RNA_def_int_array(func,
|
|
"sizes",
|
|
1,
|
|
nullptr,
|
|
1,
|
|
INT_MAX,
|
|
"Sizes",
|
|
"The number of points in each curve",
|
|
1,
|
|
10000);
|
|
RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_REQUIRED);
|
|
parm = RNA_def_int_array(func,
|
|
"indices",
|
|
1,
|
|
nullptr,
|
|
0,
|
|
INT_MAX,
|
|
"Indices",
|
|
"The indices of the curves to resize",
|
|
0,
|
|
10000);
|
|
RNA_def_parameter_flags(parm, PROP_DYNAMIC, ParameterFlag(0));
|
|
|
|
func = RNA_def_function(srna, "reorder_curves", "rna_Curves_reorder_curves");
|
|
RNA_def_function_ui_description(func, "Reorder the curves by the new indices.");
|
|
RNA_def_function_flag(func, FUNC_USE_REPORTS);
|
|
parm = RNA_def_int_array(func,
|
|
"new_indices",
|
|
1,
|
|
nullptr,
|
|
0,
|
|
INT_MAX,
|
|
"New indices",
|
|
"The new index for each of the curves",
|
|
0,
|
|
10000);
|
|
RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_REQUIRED);
|
|
|
|
func = RNA_def_function(srna, "set_types", "rna_Curves_set_types");
|
|
RNA_def_function_ui_description(func,
|
|
"Set the curve type. If indices are provided, set only the "
|
|
"types with the given curve indices.");
|
|
RNA_def_function_flag(func, FUNC_USE_REPORTS);
|
|
RNA_def_enum(func, "type", rna_enum_curves_type_items, CURVE_TYPE_CATMULL_ROM, "Type", "");
|
|
parm = RNA_def_int_array(func,
|
|
"indices",
|
|
1,
|
|
nullptr,
|
|
0,
|
|
INT_MAX,
|
|
"Indices",
|
|
"The indices of the curves to resize",
|
|
0,
|
|
INT_MAX);
|
|
RNA_def_parameter_flags(parm, PROP_DYNAMIC, ParameterFlag(0));
|
|
|
|
func = RNA_def_function(srna, "unit_test_compare", "rna_Curves_unit_test_compare");
|
|
RNA_def_pointer(func, "curves", "Curves", "", "Curves to compare to");
|
|
RNA_def_float_factor(func,
|
|
"threshold",
|
|
FLT_EPSILON * 60,
|
|
0.0f,
|
|
FLT_MAX,
|
|
"Threshold",
|
|
"Comparison tolerance threshold",
|
|
0.0f,
|
|
FLT_MAX);
|
|
/* return value */
|
|
parm = RNA_def_string(
|
|
func, "result", "nothing", 64, "Return value", "String description of result of comparison");
|
|
RNA_def_function_return(func, parm);
|
|
}
|
|
|
|
#endif
|