Curves: Add initial undo system

This adds an `UndoType` for the `Curves` object, for edit mode.
For now, this will only store the `CurvesGeometry` at every step.
Other properties such as the `selection_domain` or the `surface` object
will have to be dealt with in subsequent commits.

Differential Revision: https://developer.blender.org/D16979
This commit is contained in:
Falk David 2023-01-20 16:32:25 +01:00
parent c07fdad03d
commit d650162ecd
6 changed files with 168 additions and 6 deletions

View File

@ -12,6 +12,7 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/clog
../../../../intern/guardedalloc
../../bmesh
@ -24,6 +25,7 @@ set(SRC
intern/curves_data.cc
intern/curves_ops.cc
intern/curves_selection.cc
intern/curves_undo.cc
)
set(LIB

View File

@ -60,7 +60,7 @@
namespace blender::ed::curves {
static bool object_has_editable_curves(const Main &bmain, const Object &object)
bool object_has_editable_curves(const Main &bmain, const Object &object)
{
if (object.type != OB_CURVES) {
return false;
@ -95,7 +95,10 @@ VectorSet<Curves *> get_unique_editable_curves(const bContext &C)
return unique_curves;
}
static bool curves_poll_impl(bContext *C, const bool check_editable, const bool check_surface)
static bool curves_poll_impl(bContext *C,
const bool check_editable,
const bool check_surface,
const bool check_edit_mode)
{
Object *object = CTX_data_active_object(C);
if (object == nullptr || object->type != OB_CURVES) {
@ -113,27 +116,37 @@ static bool curves_poll_impl(bContext *C, const bool check_editable, const bool
return false;
}
}
if (check_edit_mode) {
if ((object->mode & OB_MODE_EDIT) == 0) {
return false;
}
}
return true;
}
bool editable_curves_in_edit_mode_poll(bContext *C)
{
return curves_poll_impl(C, true, false, true);
}
bool editable_curves_with_surface_poll(bContext *C)
{
return curves_poll_impl(C, true, true);
return curves_poll_impl(C, true, true, false);
}
bool curves_with_surface_poll(bContext *C)
{
return curves_poll_impl(C, false, true);
return curves_poll_impl(C, false, true, false);
}
bool editable_curves_poll(bContext *C)
{
return curves_poll_impl(C, false, false);
return curves_poll_impl(C, false, false, false);
}
bool curves_poll(bContext *C)
{
return curves_poll_impl(C, false, false);
return curves_poll_impl(C, false, false, false);
}
using bke::CurvesGeometry;

View File

@ -0,0 +1,141 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edcurves
*/
#include "BKE_context.h"
#include "BKE_curves.hh"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_undo_system.h"
#include "CLG_log.h"
#include "DEG_depsgraph.h"
#include "ED_curves.h"
#include "ED_undo.h"
#include "MEM_guardedalloc.h"
#include "WM_api.h"
#include "WM_types.h"
static CLG_LogRef LOG = {"ed.undo.curves"};
namespace blender::ed::curves::undo {
/* -------------------------------------------------------------------- */
/** \name Implements ED Undo System
*
* \note This is similar for all edit-mode types.
* \{ */
struct StepObject {
UndoRefID_Object obedit_ref = {};
bke::CurvesGeometry geometry = {};
};
struct CurvesUndoStep {
UndoStep step;
Array<StepObject> objects;
};
static bool step_encode(bContext *C, Main *bmain, UndoStep *us_p)
{
CurvesUndoStep *us = reinterpret_cast<CurvesUndoStep *>(us_p);
const Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
uint objects_num = 0;
Object **objects = ED_undo_editmode_objects_from_view_layer(scene, view_layer, &objects_num);
new (&us->objects) Array<StepObject>(objects_num);
threading::parallel_for(us->objects.index_range(), 8, [&](const IndexRange range) {
for (const int i : range) {
Object *ob = objects[i];
const Curves &curves_id = *static_cast<Curves *>(ob->data);
StepObject &object = us->objects[i];
object.obedit_ref.ptr = ob;
object.geometry = bke::CurvesGeometry::wrap(curves_id.geometry);
}
});
MEM_SAFE_FREE(objects);
bmain->is_memfile_undo_flush_needed = true;
return true;
}
static void step_decode(
bContext *C, Main *bmain, UndoStep *us_p, const eUndoStepDir /*dir*/, bool /*is_final*/)
{
CurvesUndoStep *us = reinterpret_cast<CurvesUndoStep *>(us_p);
ED_undo_object_editmode_restore_helper(C,
&us->objects.first().obedit_ref.ptr,
us->objects.size(),
sizeof(decltype(us->objects)::value_type));
BLI_assert(BKE_object_is_in_editmode(us->objects.first().obedit_ref.ptr));
for (const StepObject &object : us->objects) {
Curves &curves_id = *static_cast<Curves *>(object.obedit_ref.ptr->data);
/* Overwrite the curves geometry. */
bke::CurvesGeometry::wrap(curves_id.geometry) = object.geometry;
DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
}
ED_undo_object_set_active_or_warn(CTX_data_scene(C),
CTX_data_view_layer(C),
us->objects.first().obedit_ref.ptr,
us_p->name,
&LOG);
bmain->is_memfile_undo_flush_needed = true;
WM_event_add_notifier(C, NC_GEOM | ND_DATA, nullptr);
}
static void step_free(UndoStep *us_p)
{
CurvesUndoStep *us = reinterpret_cast<CurvesUndoStep *>(us_p);
us->objects.~Array();
}
static void foreach_ID_ref(UndoStep *us_p,
UndoTypeForEachIDRefFn foreach_ID_ref_fn,
void *user_data)
{
CurvesUndoStep *us = reinterpret_cast<CurvesUndoStep *>(us_p);
for (const StepObject &object : us->objects) {
foreach_ID_ref_fn(user_data, ((UndoRefID *)&object.obedit_ref));
}
}
/** \} */
} // namespace blender::ed::curves::undo
void ED_curves_undosys_type(UndoType *ut)
{
using namespace blender::ed;
ut->name = "Edit Curves";
ut->poll = curves::editable_curves_in_edit_mode_poll;
ut->step_encode = curves::undo::step_encode;
ut->step_decode = curves::undo::step_decode;
ut->step_free = curves::undo::step_free;
ut->step_foreach_ID_ref = curves::undo::foreach_ID_ref;
ut->flags = UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE;
ut->step_size = sizeof(curves::undo::CurvesUndoStep);
}

View File

@ -18,6 +18,7 @@ extern "C" {
* \{ */
void ED_operatortypes_curves(void);
void ED_curves_undosys_type(struct UndoType *ut);
/**
* Return an owning pointer to an array of point normals the same size as the number of control
@ -43,6 +44,7 @@ float (*ED_curves_point_normals_array_create(const struct Curves *curves_id))[3]
namespace blender::ed::curves {
bool object_has_editable_curves(const Main &bmain, const Object &object);
bke::CurvesGeometry primitive_random_sphere(int curves_size, int points_per_curve);
VectorSet<Curves *> get_unique_editable_curves(const bContext &C);
void ensure_surface_deformation_node_exists(bContext &C, Object &curves_ob);
@ -52,6 +54,7 @@ void ensure_surface_deformation_node_exists(bContext &C, Object &curves_ob);
* \{ */
bool editable_curves_with_surface_poll(bContext *C);
bool editable_curves_in_edit_mode_poll(bContext *C);
bool curves_with_surface_poll(bContext *C);
bool editable_curves_poll(bContext *C);
bool curves_poll(bContext *C);

View File

@ -29,6 +29,7 @@ set(LIB
bf_blenkernel
bf_blenlib
bf_editor_curve
bf_editor_curves
bf_editor_lattice
bf_editor_mesh
bf_editor_metaball

View File

@ -10,6 +10,7 @@
#include "ED_armature.h"
#include "ED_curve.h"
#include "ED_curves.h"
#include "ED_lattice.h"
#include "ED_mball.h"
#include "ED_mesh.h"
@ -32,6 +33,7 @@ void ED_undosys_type_init(void)
BKE_undosys_type_append(ED_lattice_undosys_type);
BKE_undosys_type_append(ED_mball_undosys_type);
BKE_undosys_type_append(ED_mesh_undosys_type);
BKE_undosys_type_append(ED_curves_undosys_type);
/* Paint Modes */
BKE_UNDOSYS_TYPE_IMAGE = BKE_undosys_type_append(ED_image_undosys_type);