Blender V4.3
grease_pencil_interpolate.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BKE_colortools.hh"
6#include "BKE_context.hh"
7#include "BKE_curves.hh"
9#include "BKE_material.h"
10#include "BKE_paint.hh"
11
12#include "BLI_array_utils.hh"
13#include "BLI_easing.h"
14#include "BLI_index_mask.hh"
16#include "BLI_math_geom.h"
17#include "BLI_math_rotation.h"
18#include "BLI_math_rotation.hh"
19#include "BLI_math_vector.hh"
20#include "BLI_offset_indices.hh"
21#include "BLI_task.hh"
22
23#include "BLT_translation.hh"
24
25#include "DEG_depsgraph.hh"
26
28
29#include "ED_curves.hh"
30#include "ED_grease_pencil.hh"
31#include "ED_numinput.hh"
32#include "ED_screen.hh"
33
35#include "GEO_smooth_curves.hh"
36
37#include "MEM_guardedalloc.h"
38
39#include "RNA_access.hh"
40#include "RNA_define.hh"
41#include "RNA_enum_types.hh"
42#include "RNA_prototypes.hh"
43
44#include "UI_interface.hh"
45#include "UI_resources.hh"
46
47#include <climits>
48
50
53
54/* -------------------------------------------------------------------- */
58/* Modes for the interpolation tool. */
61 Linear,
64 /* Easing Equations. */
65 Back,
66 Bounce,
68 Cubic,
69 Elastic,
72 Quartic,
73 Quintic,
74 Sine,
75};
76
82 /* Interpolation. */
84 N_("Standard transitions between keyframes")),
85 {int(InterpolationType::Linear),
86 "LINEAR",
87 ICON_IPO_LINEAR,
88 "Linear",
89 "Straight-line interpolation between A and B (i.e. no ease in/out)"},
90 {int(InterpolationType::CurveMap),
91 "CUSTOM",
92 ICON_IPO_BEZIER,
93 "Custom",
94 "Custom interpolation defined using a curve map"},
95
96 /* Easing. */
98 N_("Predefined inertial transitions, useful for motion graphics "
99 "(from least to most \"dramatic\")")),
100 {int(InterpolationType::Sine),
101 "SINE",
102 ICON_IPO_SINE,
103 "Sinusoidal",
104 "Sinusoidal easing (weakest, almost linear but with a slight curvature)"},
105 {int(InterpolationType::Quadratic), "QUAD", ICON_IPO_QUAD, "Quadratic", "Quadratic easing"},
106 {int(InterpolationType::Cubic), "CUBIC", ICON_IPO_CUBIC, "Cubic", "Cubic easing"},
107 {int(InterpolationType::Quartic), "QUART", ICON_IPO_QUART, "Quartic", "Quartic easing"},
108 {int(InterpolationType::Quintic), "QUINT", ICON_IPO_QUINT, "Quintic", "Quintic easing"},
109 {int(InterpolationType::Exponential),
110 "EXPO",
111 ICON_IPO_EXPO,
112 "Exponential",
113 "Exponential easing (dramatic)"},
114 {int(InterpolationType::Circular),
115 "CIRC",
116 ICON_IPO_CIRC,
117 "Circular",
118 "Circular easing (strongest and most dynamic)"},
119
121 N_("Simple physics-inspired easing effects")),
122 {int(InterpolationType::Back),
123 "BACK",
124 ICON_IPO_BACK,
125 "Back",
126 "Cubic easing with overshoot and settle"},
127 {int(InterpolationType::Bounce),
128 "BOUNCE",
129 ICON_IPO_BOUNCE,
130 "Bounce",
131 "Exponentially decaying parabolic bounce, like when objects collide"},
132 {int(InterpolationType::Elastic),
133 "ELASTIC",
134 ICON_IPO_ELASTIC,
135 "Elastic",
136 "Exponentially decaying sine wave, like an elastic band"},
137
138 {0, nullptr, 0, nullptr, nullptr},
139};
140
142 {int(InterpolateFlipMode::None), "NONE", 0, "No Flip", ""},
143 {int(InterpolateFlipMode::Flip), "FLIP", 0, "Flip", ""},
144 {int(InterpolateFlipMode::FlipAuto), "AUTO", 0, "Automatic", ""},
145 {0, nullptr, 0, nullptr, nullptr},
146};
147
149 {int(InterpolateLayerMode::Active), "ACTIVE", 0, "Active", ""},
150 {int(InterpolateLayerMode::All), "ALL", 0, "All Layers", ""},
151 {0, nullptr, 0, nullptr, nullptr},
152};
153
154constexpr float interpolate_factor_min = -1.0f;
155constexpr float interpolate_factor_max = 2.0f;
156
157/* Pair of curves in a layer that get interpolated. */
164
166 struct LayerData {
167 /* Curve pairs to interpolate from this layer. */
169
170 /* Geometry of the target frame before interpolation for restoring on cancel. */
171 std::optional<bke::CurvesGeometry> orig_curves;
172 };
173
174 /* Layers to include. */
177 /* Exclude breakdown keyframes when finding intervals. */
179
180 /* Interpolation factor bias controlled by the user. */
181 float shift;
182 /* Interpolation base factor for the active layer. */
184 InterpolateFlipMode flipmode;
187
191
192 static InterpolateOpData *from_operator(const bContext &C, const wmOperator &op);
193};
194
195using FramesMapKeyIntervalT = std::pair<int, int>;
196
197static std::optional<FramesMapKeyIntervalT> find_frames_interval(
198 const bke::greasepencil::Layer &layer, const int frame_number, const bool exclude_breakdowns)
199{
202 using SortedKeysIterator = Layer::SortedKeysIterator;
203
204 const Span<FramesMapKeyT> sorted_keys = layer.sorted_keys();
205 SortedKeysIterator prev_key_it = layer.sorted_keys_iterator_at(frame_number);
206 if (!prev_key_it) {
207 return std::nullopt;
208 }
209 SortedKeysIterator next_key_it = std::next(prev_key_it);
210
211 /* Skip over invalid keyframes on either side. */
212 auto is_valid_keyframe = [&](const FramesMapKeyT key) {
213 const GreasePencilFrame *frame = layer.frame_at(key);
214 if (!frame || frame->is_end()) {
215 return false;
216 }
217 if (exclude_breakdowns && frame->type == BEZT_KEYTYPE_BREAKDOWN) {
218 return false;
219 }
220 return true;
221 };
222
223 for (; next_key_it != sorted_keys.end(); ++next_key_it) {
224 if (is_valid_keyframe(*next_key_it)) {
225 break;
226 }
227 }
228 for (; prev_key_it != sorted_keys.begin(); --prev_key_it) {
229 if (is_valid_keyframe(*prev_key_it)) {
230 break;
231 }
232 }
233 if (next_key_it == sorted_keys.end() || !is_valid_keyframe(*prev_key_it)) {
234 return std::nullopt;
235 }
236
237 return std::make_pair(*prev_key_it, *next_key_it);
238}
239
240/* Build index lists for curve interpolation using index. */
241static bool find_curve_mapping_from_index(const GreasePencil &grease_pencil,
242 const bke::greasepencil::Layer &layer,
243 const int current_frame,
244 const bool exclude_breakdowns,
245 const bool only_selected,
246 InterpolationPairs &pairs)
247{
249
250 const std::optional<FramesMapKeyIntervalT> interval = find_frames_interval(
251 layer, current_frame, exclude_breakdowns);
252 if (!interval) {
253 return false;
254 }
255
256 BLI_assert(layer.has_drawing_at(interval->first));
257 BLI_assert(layer.has_drawing_at(interval->second));
258 const Drawing &from_drawing = *grease_pencil.get_drawing_at(layer, interval->first);
259 const Drawing &to_drawing = *grease_pencil.get_drawing_at(layer, interval->second);
260
261 IndexMaskMemory memory;
262 IndexMask from_selection, to_selection;
263 if (only_selected && ed::curves::has_anything_selected(from_drawing.strokes()) &&
265 {
266 from_selection = ed::curves::retrieve_selected_curves(from_drawing.strokes(), memory);
267 to_selection = ed::curves::retrieve_selected_curves(to_drawing.strokes(), memory);
268 }
269 else {
270 from_selection = from_drawing.strokes().curves_range();
271 to_selection = to_drawing.strokes().curves_range();
272 }
273
274 const int pairs_num = std::min(from_selection.size(), to_selection.size());
275
276 const int old_pairs_num = pairs.from_frames.size();
277 pairs.from_frames.append_n_times(interval->first, pairs_num);
278 pairs.to_frames.append_n_times(interval->second, pairs_num);
279 pairs.from_curves.resize(old_pairs_num + pairs_num);
280 pairs.to_curves.resize(old_pairs_num + pairs_num);
281
282 /* Write source indices into the pair data. The drawing with fewer curves will discard some based
283 * on index. */
284 from_selection.slice(0, pairs_num)
285 .to_indices(pairs.from_curves.as_mutable_span().slice(old_pairs_num, pairs_num));
286 to_selection.slice(0, pairs_num)
287 .to_indices(pairs.to_curves.as_mutable_span().slice(old_pairs_num, pairs_num));
288
289 return true;
290}
291
293{
296
297 const Scene &scene = *CTX_data_scene(&C);
298 const int current_frame = scene.r.cfra;
299 const Object &object = *CTX_data_active_object(&C);
300 const GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
301
302 BLI_assert(grease_pencil.has_active_layer());
303 const Layer &active_layer = *grease_pencil.get_active_layer();
304
305 InterpolateOpData *data = MEM_new<InterpolateOpData>(__func__);
306
307 if (RNA_struct_find_property(op.ptr, "shift") != nullptr) {
308 data->shift = RNA_float_get(op.ptr, "shift");
309 }
310 data->exclude_breakdowns = RNA_boolean_get(op.ptr, "exclude_breakdowns");
311 data->flipmode = InterpolateFlipMode(RNA_enum_get(op.ptr, "flip"));
312 data->smooth_factor = RNA_float_get(op.ptr, "smooth_factor");
313 data->smooth_steps = RNA_int_get(op.ptr, "smooth_steps");
314 data->active_layer_index = *grease_pencil.get_layer_index(active_layer);
315 const bool use_selection = RNA_boolean_get(op.ptr, "use_selection");
316
317 const auto layer_mode = InterpolateLayerMode(RNA_enum_get(op.ptr, "layers"));
318 switch (layer_mode) {
319 case InterpolateLayerMode::Active:
320 data->layer_mask = IndexRange::from_single(data->active_layer_index);
321 break;
322 case InterpolateLayerMode::All:
323 data->layer_mask = IndexMask::from_predicate(
324 grease_pencil.layers().index_range(),
325 GrainSize(1024),
326 data->layer_mask_memory,
327 [&](const int layer_index) { return grease_pencil.layer(layer_index).is_editable(); });
328 break;
329 }
330
331 bool found_mapping = false;
332 data->layer_data.reinitialize(grease_pencil.layers().size());
333 data->layer_mask.foreach_index([&](const int layer_index) {
334 const Layer &layer = grease_pencil.layer(layer_index);
335 InterpolateOpData::LayerData &layer_data = data->layer_data[layer_index];
336
337 /* Pair from/to curves by index. */
338 const bool has_curve_mapping = find_curve_mapping_from_index(grease_pencil,
339 layer,
340 current_frame,
341 data->exclude_breakdowns,
342 use_selection,
343 layer_data.curve_pairs);
344 found_mapping = found_mapping || has_curve_mapping;
345 });
346
347 /* No mapping between frames was found. */
348 if (!found_mapping) {
349 MEM_delete(data);
350 return nullptr;
351 }
352
353 const std::optional<FramesMapKeyIntervalT> active_layer_interval = find_frames_interval(
354 active_layer, current_frame, data->exclude_breakdowns);
355 data->init_factor = active_layer_interval ?
356 float(current_frame - active_layer_interval->first) /
357 (active_layer_interval->second - active_layer_interval->first + 1) :
358 0.5f;
359
360 return data;
361}
362
363static bool compute_auto_flip(const Span<float3> from_positions, const Span<float3> to_positions)
364{
365 if (from_positions.size() < 2 || to_positions.size() < 2) {
366 return false;
367 }
368
369 constexpr float min_angle = DEG2RADF(15);
370
371 const float3 &from_first = from_positions.first();
372 const float3 &from_last = from_positions.last();
373 const float3 &to_first = to_positions.first();
374 const float3 &to_last = to_positions.last();
375
376 /* If lines intersect at a sharp angle check distances. */
377 if (isect_seg_seg_v2(from_first, to_first, from_last, to_last) == ISECT_LINE_LINE_CROSS) {
378 if (math::angle_between(math::normalize(to_first - from_first),
379 math::normalize(to_last - from_last))
380 .radian() < min_angle)
381 {
382 if (math::distance_squared(from_first, to_first) >=
383 math::distance_squared(from_last, to_first))
384 {
385 return math::distance_squared(from_last, to_first) >=
386 math::distance_squared(from_last, to_last);
387 }
388
389 return math::distance_squared(from_first, to_first) <
390 math::distance_squared(from_first, to_last);
391 }
392
393 return true;
394 }
395
396 return math::dot(from_last - from_first, to_last - to_first) < 0.0f;
397}
398
400 const bke::greasepencil::Layer &layer,
401 const InterpolationPairs &curve_pairs,
402 const float mix_factor,
403 const InterpolateFlipMode flip_mode)
404{
406
407 const int dst_curve_num = curve_pairs.from_curves.size();
408 BLI_assert(curve_pairs.to_curves.size() == dst_curve_num);
409 BLI_assert(curve_pairs.from_frames.size() == dst_curve_num);
410 BLI_assert(curve_pairs.to_frames.size() == dst_curve_num);
411
412 /* Sort pairs by unique to/from frame combinations.
413 * Curves for each frame pair are then interpolated together.
414 * Map entries are indices into the original curve_pairs array,
415 * so the order of strokes can be maintained. */
416 Array<int> sorted_pairs(dst_curve_num);
418 std::sort(sorted_pairs.begin(), sorted_pairs.end(), [&](const int a, const int b) {
419 const int from_frame_a = curve_pairs.from_frames[a];
420 const int to_frame_a = curve_pairs.to_frames[a];
421 const int from_frame_b = curve_pairs.from_frames[b];
422 const int to_frame_b = curve_pairs.to_frames[b];
423 return from_frame_a < from_frame_b ||
424 (from_frame_a == from_frame_b && to_frame_a < to_frame_b);
425 });
426
427 /* Find ranges of sorted pairs with the same from/to frame intervals. */
428 Vector<int> pair_offsets;
429 const OffsetIndices curves_by_pair = [&]() {
430 int prev_from_frame = INT_MIN;
431 int prev_to_frame = INT_MIN;
432 int current_count = 0;
433 for (const int sorted_index : IndexRange(dst_curve_num)) {
434 const int pair_index = sorted_pairs[sorted_index];
435 const int from_frame = curve_pairs.from_frames[pair_index];
436 const int to_frame = curve_pairs.to_frames[pair_index];
437 if (from_frame != prev_from_frame || to_frame != prev_to_frame) {
438 /* New pair. */
439 if (current_count > 0) {
440 pair_offsets.append(current_count);
441 }
442 current_count = 0;
443 }
444 ++current_count;
445 }
446 if (current_count > 0) {
447 pair_offsets.append(current_count);
448 }
449
450 /* Last entry for overall size. */
451 if (pair_offsets.is_empty()) {
452 return OffsetIndices<int>{};
453 }
454
455 pair_offsets.append(0);
457 }();
458
459 /* Compute curve length and flip mode for each pair. */
460 Array<int> dst_curve_offsets(curves_by_pair.size() + 1, 0);
461 Array<bool> dst_curve_flip(curves_by_pair.size(), false);
462 const OffsetIndices<int> dst_points_by_curve = [&]() {
463 /* Last entry for overall size. */
464 if (curves_by_pair.is_empty()) {
465 return OffsetIndices<int>{};
466 }
467
468 for (const int pair_range_i : curves_by_pair.index_range()) {
469 const IndexRange pair_range = curves_by_pair[pair_range_i];
470 BLI_assert(!pair_range.is_empty());
471
472 const int first_pair_index = sorted_pairs[pair_range.first()];
473 const int from_frame = curve_pairs.from_frames[first_pair_index];
474 const int to_frame = curve_pairs.to_frames[first_pair_index];
475 const Drawing *from_drawing = grease_pencil.get_drawing_at(layer, from_frame);
476 const Drawing *to_drawing = grease_pencil.get_drawing_at(layer, to_frame);
477 if (!from_drawing || !to_drawing) {
478 continue;
479 }
480 const OffsetIndices from_points_by_curve = from_drawing->strokes().points_by_curve();
481 const OffsetIndices to_points_by_curve = to_drawing->strokes().points_by_curve();
482 const Span<float3> from_positions = from_drawing->strokes().positions();
483 const Span<float3> to_positions = to_drawing->strokes().positions();
484
485 for (const int sorted_index : pair_range) {
486 const int pair_index = sorted_pairs[sorted_index];
487 const int from_curve = curve_pairs.from_curves[pair_index];
488 const int to_curve = curve_pairs.to_curves[pair_index];
489 const IndexRange from_points = from_points_by_curve[from_curve];
490 const IndexRange to_points = to_points_by_curve[to_curve];
491
492 dst_curve_offsets[pair_index] = std::max(from_points.size(), to_points.size());
493 switch (flip_mode) {
494 case InterpolateFlipMode::None:
495 dst_curve_flip[pair_index] = false;
496 break;
497 case InterpolateFlipMode::Flip:
498 dst_curve_flip[pair_index] = true;
499 break;
500 case InterpolateFlipMode::FlipAuto: {
501 dst_curve_flip[pair_index] = compute_auto_flip(from_positions.slice(from_points),
502 to_positions.slice(to_points));
503 break;
504 }
505 }
506 }
507 }
508 return offset_indices::accumulate_counts_to_offsets(dst_curve_offsets);
509 }();
510 const int dst_point_num = dst_points_by_curve.total_size();
511
512 bke::CurvesGeometry dst_curves(dst_point_num, dst_curve_num);
513 /* Offsets are empty when there are no curves. */
514 if (dst_curve_num > 0) {
515 dst_curves.offsets_for_write().copy_from(dst_curve_offsets);
516 }
517
518 /* Sorted map arrays that can be passed to the interpolation function directly.
519 * These index maps have the same order as the sorted indices, so slices of indices can be used
520 * for interpolating all curves of a frame pair at once. */
521 Array<int> sorted_from_curve_indices(dst_curve_num);
522 Array<int> sorted_to_curve_indices(dst_curve_num);
523
524 for (const int pair_range_i : curves_by_pair.index_range()) {
525 const IndexRange pair_range = curves_by_pair[pair_range_i];
526 const int first_pair_index = sorted_pairs[pair_range.first()];
527 const int from_frame = curve_pairs.from_frames[first_pair_index];
528 const int to_frame = curve_pairs.to_frames[first_pair_index];
529 const Drawing *from_drawing = grease_pencil.get_drawing_at(layer, from_frame);
530 const Drawing *to_drawing = grease_pencil.get_drawing_at(layer, to_frame);
531 if (!from_drawing || !to_drawing) {
532 continue;
533 }
534 const IndexRange from_curves = from_drawing->strokes().curves_range();
535 const IndexRange to_curves = to_drawing->strokes().curves_range();
536
537 IndexMaskMemory selection_memory;
538 /* Subset of target curves that are filled by this frame pair. Selection is built from pair
539 * indices, which correspond to dst curve indices. */
540 const IndexMask dst_curve_mask = IndexMask::from_indices(
541 sorted_pairs.as_span().slice(pair_range), selection_memory);
542 MutableSpan<int> pair_from_indices = sorted_from_curve_indices.as_mutable_span().slice(
543 pair_range);
544 MutableSpan<int> pair_to_indices = sorted_to_curve_indices.as_mutable_span().slice(pair_range);
545 for (const int i : pair_range) {
546 const int pair_index = sorted_pairs[i];
547 sorted_from_curve_indices[i] = std::clamp(
548 curve_pairs.from_curves[pair_index], 0, int(from_curves.last()));
549 sorted_to_curve_indices[i] = std::clamp(
550 curve_pairs.to_curves[pair_index], 0, int(to_curves.last()));
551 }
553 to_drawing->strokes(),
554 pair_from_indices,
555 pair_to_indices,
556 dst_curve_mask,
557 dst_curve_flip,
558 mix_factor,
559 dst_curves);
560 }
561
562 return dst_curves;
563}
564
567/* -------------------------------------------------------------------- */
572 const InterpolateOpData &opdata)
573{
574 Scene &scene = *CTX_data_scene(&C);
575 ScrArea &area = *CTX_wm_area(&C);
576
577 const StringRef msg = IFACE_("GPencil Interpolation: ");
578
579 std::string status;
580 if (hasNumInput(&opdata.numeric_input)) {
581 char str_ofs[NUM_STR_REP_LEN];
582 outputNumInput(&const_cast<NumInput &>(opdata.numeric_input), str_ofs, &scene.unit);
583 status = msg + std::string(str_ofs);
584 }
585 else {
586 status = msg + std::to_string(int((opdata.init_factor + opdata.shift) * 100.0f)) + " %";
587 }
588
589 ED_area_status_text(&area, status.c_str());
591 &C, IFACE_("ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/MOVE to adjust factor"));
592}
593
594/* Utility function to get a drawing at the exact frame number. */
597 const int frame_number)
598{
600
601 const std::optional<int> start_frame = layer.start_frame_at(frame_number);
602 if (start_frame && *start_frame == frame_number) {
603 return grease_pencil.get_editable_drawing_at(layer, frame_number);
604 }
605 return nullptr;
606}
607
609 GreasePencil &grease_pencil,
612 const int frame_number)
613{
615
616 static constexpr eBezTriple_KeyframeType keyframe_type = BEZT_KEYTYPE_BREAKDOWN;
617
618 if (Drawing *drawing = get_drawing_at_exact_frame(grease_pencil, layer, frame_number)) {
619 layer_data.orig_curves = drawing->strokes();
620 return drawing;
621 }
622 return grease_pencil.insert_frame(layer, frame_number, 0, keyframe_type);
623}
624
626{
629
630 const auto &opdata = *static_cast<InterpolateOpData *>(op.customdata);
631 const Scene &scene = *CTX_data_scene(&C);
632 const int current_frame = scene.r.cfra;
633 Object &object = *CTX_data_active_object(&C);
634 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
635 const auto flip_mode = InterpolateFlipMode(RNA_enum_get(op.ptr, "flip"));
636
637 opdata.layer_mask.foreach_index([&](const int layer_index) {
638 Layer &layer = grease_pencil.layer(layer_index);
639 const InterpolateOpData::LayerData &layer_data = opdata.layer_data[layer_index];
640
641 /* Drawings must be created on operator invoke. */
642 Drawing *dst_drawing = get_drawing_at_exact_frame(grease_pencil, layer, current_frame);
643 if (dst_drawing == nullptr) {
644 return;
645 }
646
647 const float mix_factor = opdata.init_factor + opdata.shift;
649 grease_pencil, layer, layer_data.curve_pairs, mix_factor, flip_mode);
650
651 if (opdata.smooth_factor > 0.0f && opdata.smooth_steps > 0) {
652 MutableSpan<float3> positions = interpolated_curves.positions_for_write();
654 interpolated_curves.curves_range(),
655 interpolated_curves.points_by_curve(),
656 VArray<bool>::ForSingle(true, interpolated_curves.points_num()),
657 interpolated_curves.cyclic(),
658 opdata.smooth_steps,
659 opdata.smooth_factor,
660 false,
661 true,
662 positions);
663 interpolated_curves.tag_positions_changed();
664 }
665
666 dst_drawing->strokes_for_write() = std::move(interpolated_curves);
667 dst_drawing->tag_topology_changed();
668 });
669
671
674}
675
676/* Restore timeline changes when canceled. */
678{
681
682 if (op.customdata == nullptr) {
683 return;
684 }
685
686 const auto &opdata = *static_cast<InterpolateOpData *>(op.customdata);
687 const Scene &scene = *CTX_data_scene(&C);
688 const int current_frame = scene.r.cfra;
689 Object &object = *CTX_data_active_object(&C);
690 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
691
692 opdata.layer_mask.foreach_index([&](const int layer_index) {
693 Layer &layer = grease_pencil.layer(layer_index);
694 const InterpolateOpData::LayerData &layer_data = opdata.layer_data[layer_index];
695
696 if (layer_data.orig_curves) {
697 /* Keyframe existed before the operator, restore geometry. */
698 Drawing *drawing = grease_pencil.get_editable_drawing_at(layer, current_frame);
699 if (drawing) {
700 drawing->strokes_for_write() = *layer_data.orig_curves;
701 drawing->tag_topology_changed();
704 }
705 }
706 else {
707 /* Frame was empty, remove the added drawing. */
708 grease_pencil.remove_frames(layer, {current_frame});
711 }
712 });
713}
714
716{
718
720 if (op.customdata == nullptr) {
721 return false;
722 }
723 InterpolateOpData &data = *static_cast<InterpolateOpData *>(op.customdata);
724
725 const Scene &scene = *CTX_data_scene(&C);
726 const int current_frame = scene.r.cfra;
727 Object &object = *CTX_data_active_object(&C);
728 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
729
730 /* Create target frames. */
731 data.layer_mask.foreach_index([&](const int layer_index) {
732 Layer &layer = grease_pencil.layer(layer_index);
733 InterpolateOpData::LayerData &layer_data = data.layer_data[layer_index];
734
735 ensure_drawing_at_exact_frame(grease_pencil, layer, layer_data, current_frame);
736 });
737
738 return true;
739}
740
741/* Exit and free memory. */
743{
744 ScrArea &area = *CTX_wm_area(&C);
745
746 if (op.customdata == nullptr) {
747 return;
748 }
749
750 ED_area_status_text(&area, nullptr);
751 ED_workspace_status_text(&C, nullptr);
752
753 MEM_delete(static_cast<InterpolateOpData *>(op.customdata));
754 op.customdata = nullptr;
755}
756
758{
760 return false;
761 }
763 if (!ts || !ts->gp_paint) {
764 return false;
765 }
766 /* Only 3D view */
767 ScrArea *area = CTX_wm_area(C);
768 if (area && area->spacetype != SPACE_VIEW3D) {
769 return false;
770 }
771
772 return true;
773}
774
775/* Invoke handler: Initialize the operator */
776static int grease_pencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
777{
778 wmWindow &win = *CTX_wm_window(C);
779
780 if (!grease_pencil_interpolate_init(*C, *op)) {
782 return OPERATOR_CANCELLED;
783 }
784 InterpolateOpData &opdata = *static_cast<InterpolateOpData *>(op->customdata);
785
786 /* Set cursor to indicate modal operator. */
788
790
792
794
796}
797
799 Cancel = 1,
800 Confirm,
801 Increase,
802 Decrease,
803};
804
805/* Modal handler: Events handling during interactive part */
807{
808 wmWindow &win = *CTX_wm_window(C);
809 const ARegion &region = *CTX_wm_region(C);
810 ScrArea &area = *CTX_wm_area(C);
811 InterpolateOpData &opdata = *static_cast<InterpolateOpData *>(op->customdata);
812 const bool has_numinput = hasNumInput(&opdata.numeric_input);
813
814 switch (event->type) {
815 case EVT_MODAL_MAP: {
816 switch (InterpolateToolModalEvent(event->val)) {
818 ED_area_status_text(&area, nullptr);
819 ED_workspace_status_text(C, nullptr);
821
824 return OPERATOR_CANCELLED;
826 ED_area_status_text(&area, nullptr);
827 ED_workspace_status_text(C, nullptr);
829
830 /* Write current factor to properties for the next execution. */
831 RNA_float_set(op->ptr, "shift", opdata.shift);
832
834 return OPERATOR_FINISHED;
836 opdata.shift = std::clamp(opdata.init_factor + opdata.shift + 0.01f,
839 opdata.init_factor;
841 break;
843 opdata.shift = std::clamp(opdata.init_factor + opdata.shift - 0.01f,
846 opdata.init_factor;
848 break;
849 }
850 break;
851 }
852 case MOUSEMOVE:
853 /* Only handle mouse-move if not doing numeric-input. */
854 if (!has_numinput) {
855 const float mouse_pos = event->mval[0];
856 const float factor = std::clamp(
857 mouse_pos / region.winx, interpolate_factor_min, interpolate_factor_max);
858 opdata.shift = factor - opdata.init_factor;
859
861 }
862 break;
863 default: {
864 if ((event->val == KM_PRESS) && handleNumInput(C, &opdata.numeric_input, event)) {
865 float value = (opdata.init_factor + opdata.shift) * 100.0f;
866 applyNumInput(&opdata.numeric_input, &value);
867 opdata.shift = std::clamp(value * 0.01f, interpolate_factor_min, interpolate_factor_max) -
868 opdata.init_factor;
869
871 break;
872 }
873 /* Unhandled event, allow to pass through. */
875 }
876 }
877
879}
880
886
888{
889 ot->name = "Grease Pencil Interpolation";
890 ot->idname = "GREASE_PENCIL_OT_interpolate";
891 ot->description = "Interpolate grease pencil strokes between frames";
892
897
899
901 ot->srna,
902 "shift",
903 0.0f,
904 -1.0f,
905 1.0f,
906 "Shift",
907 "Bias factor for which frame has more influence on the interpolated strokes",
908 -0.9f,
909 0.9f);
910
912 "layers",
914 0,
915 "Layer",
916 "Layers included in the interpolation");
917
919 "exclude_breakdowns",
920 false,
921 "Exclude Breakdowns",
922 "Exclude existing Breakdowns keyframes as interpolation extremes");
923
925 "use_selection",
926 false,
927 "Use Selection",
928 "Use only selected strokes for interpolating");
929
931 "flip",
933 int(InterpolateFlipMode::FlipAuto),
934 "Flip Mode",
935 "Invert destination stroke to match start and end with source stroke");
936
938 "smooth_steps",
939 1,
940 1,
941 3,
942 "Iterations",
943 "Number of times to smooth newly created strokes",
944 1,
945 3);
946
948 "smooth_factor",
949 0.0f,
950 0.0f,
951 2.0f,
952 "Smooth",
953 "Amount of smoothing to apply to interpolated strokes, to reduce jitter/noise",
954 0.0f,
955 2.0f);
956}
957
960/* -------------------------------------------------------------------- */
964/* Helper: Perform easing equation calculations for GP interpolation operator. */
966 const InterpolationType type,
967 const float back_easing,
968 const float amplitude,
969 const float period,
970 const CurveMapping &custom_ipo,
971 const float time)
972{
973 constexpr float begin = 0.0f;
974 constexpr float change = 1.0f;
975 constexpr float duration = 1.0f;
976
977 switch (type) {
978 case InterpolationType::Linear:
979 return time;
980
981 case InterpolationType::CurveMap:
982 return BKE_curvemapping_evaluateF(&custom_ipo, 0, time);
983
984 case InterpolationType::Back:
985 switch (easing) {
986 case BEZT_IPO_EASE_IN:
987 return BLI_easing_back_ease_in(time, begin, change, duration, back_easing);
989 return BLI_easing_back_ease_out(time, begin, change, duration, back_easing);
991 return BLI_easing_back_ease_in_out(time, begin, change, duration, back_easing);
992
993 default:
994 return BLI_easing_back_ease_out(time, begin, change, duration, back_easing);
995 }
996 break;
997
998 case InterpolationType::Bounce:
999 switch (easing) {
1000 case BEZT_IPO_EASE_IN:
1001 return BLI_easing_bounce_ease_in(time, begin, change, duration);
1002 case BEZT_IPO_EASE_OUT:
1003 return BLI_easing_bounce_ease_out(time, begin, change, duration);
1005 return BLI_easing_bounce_ease_in_out(time, begin, change, duration);
1006
1007 default:
1008 return BLI_easing_bounce_ease_out(time, begin, change, duration);
1009 }
1010 break;
1011
1012 case InterpolationType::Circular:
1013 switch (easing) {
1014 case BEZT_IPO_EASE_IN:
1015 return BLI_easing_circ_ease_in(time, begin, change, duration);
1016 case BEZT_IPO_EASE_OUT:
1017 return BLI_easing_circ_ease_out(time, begin, change, duration);
1019 return BLI_easing_circ_ease_in_out(time, begin, change, duration);
1020
1021 default:
1022 return BLI_easing_circ_ease_in(time, begin, change, duration);
1023 }
1024 break;
1025
1026 case InterpolationType::Cubic:
1027 switch (easing) {
1028 case BEZT_IPO_EASE_IN:
1029 return BLI_easing_cubic_ease_in(time, begin, change, duration);
1030 case BEZT_IPO_EASE_OUT:
1031 return BLI_easing_cubic_ease_out(time, begin, change, duration);
1033 return BLI_easing_cubic_ease_in_out(time, begin, change, duration);
1034
1035 default:
1036 return BLI_easing_cubic_ease_in(time, begin, change, duration);
1037 }
1038 break;
1039
1040 case InterpolationType::Elastic:
1041 switch (easing) {
1042 case BEZT_IPO_EASE_IN:
1043 return BLI_easing_elastic_ease_in(time, begin, change, duration, amplitude, period);
1044 case BEZT_IPO_EASE_OUT:
1045 return BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
1047 return BLI_easing_elastic_ease_in_out(time, begin, change, duration, amplitude, period);
1048
1049 default:
1050 return BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
1051 }
1052 break;
1053
1054 case InterpolationType::Exponential:
1055 switch (easing) {
1056 case BEZT_IPO_EASE_IN:
1057 return BLI_easing_expo_ease_in(time, begin, change, duration);
1058 case BEZT_IPO_EASE_OUT:
1059 return BLI_easing_expo_ease_out(time, begin, change, duration);
1061 return BLI_easing_expo_ease_in_out(time, begin, change, duration);
1062
1063 default:
1064 return BLI_easing_expo_ease_in(time, begin, change, duration);
1065 }
1066 break;
1067
1068 case InterpolationType::Quadratic:
1069 switch (easing) {
1070 case BEZT_IPO_EASE_IN:
1071 return BLI_easing_quad_ease_in(time, begin, change, duration);
1072 case BEZT_IPO_EASE_OUT:
1073 return BLI_easing_quad_ease_out(time, begin, change, duration);
1075 return BLI_easing_quad_ease_in_out(time, begin, change, duration);
1076
1077 default:
1078 return BLI_easing_quad_ease_in(time, begin, change, duration);
1079 }
1080 break;
1081
1082 case InterpolationType::Quartic:
1083 switch (easing) {
1084 case BEZT_IPO_EASE_IN:
1085 return BLI_easing_quart_ease_in(time, begin, change, duration);
1086 case BEZT_IPO_EASE_OUT:
1087 return BLI_easing_quart_ease_out(time, begin, change, duration);
1089 return BLI_easing_quart_ease_in_out(time, begin, change, duration);
1090
1091 default:
1092 return BLI_easing_quart_ease_in(time, begin, change, duration);
1093 }
1094 break;
1095
1096 case InterpolationType::Quintic:
1097 switch (easing) {
1098 case BEZT_IPO_EASE_IN:
1099 return BLI_easing_quint_ease_in(time, begin, change, duration);
1100 case BEZT_IPO_EASE_OUT:
1101 return BLI_easing_quint_ease_out(time, begin, change, duration);
1103 return BLI_easing_quint_ease_in_out(time, begin, change, duration);
1104
1105 default:
1106 return BLI_easing_quint_ease_in(time, begin, change, duration);
1107 }
1108 break;
1109
1110 case InterpolationType::Sine:
1111 switch (easing) {
1112 case BEZT_IPO_EASE_IN:
1113 return BLI_easing_sine_ease_in(time, begin, change, duration);
1114 case BEZT_IPO_EASE_OUT:
1115 return BLI_easing_sine_ease_out(time, begin, change, duration);
1117 return BLI_easing_sine_ease_in_out(time, begin, change, duration);
1118
1119 default:
1120 return BLI_easing_sine_ease_in(time, begin, change, duration);
1121 }
1122 break;
1123
1124 default:
1126 break;
1127 }
1128
1129 return time;
1130}
1131
1133{
1136
1138 if (op->customdata == nullptr) {
1139 return OPERATOR_FINISHED;
1140 }
1141 InterpolateOpData &opdata = *static_cast<InterpolateOpData *>(op->customdata);
1142
1143 const Scene &scene = *CTX_data_scene(C);
1144 const int current_frame = scene.r.cfra;
1145 Object &object = *CTX_data_active_object(C);
1146 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
1148 const InterpolationType type = InterpolationType(RNA_enum_get(op->ptr, "type"));
1149 const eBezTriple_Easing easing = eBezTriple_Easing(RNA_enum_get(op->ptr, "easing"));
1150 const float back_easing = RNA_float_get(op->ptr, "back");
1151 const float amplitude = RNA_float_get(op->ptr, "amplitude");
1152 const float period = RNA_float_get(op->ptr, "period");
1153 const int step = RNA_int_get(op->ptr, "step");
1154
1155 GP_Interpolate_Settings &ipo_settings = ts.gp_interpolate;
1156 if (ipo_settings.custom_ipo == nullptr) {
1157 ipo_settings.custom_ipo = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
1158 }
1159 BKE_curvemapping_init(ipo_settings.custom_ipo);
1160
1161 opdata.layer_mask.foreach_index([&](const int layer_index) {
1162 Layer &layer = grease_pencil.layer(layer_index);
1163 InterpolateOpData::LayerData &layer_data = opdata.layer_data[layer_index];
1164
1165 std::optional<FramesMapKeyIntervalT> interval = find_frames_interval(
1166 layer, current_frame, opdata.exclude_breakdowns);
1167 if (!interval) {
1168 return;
1169 }
1170
1171 const int frame_range_size = interval->second - interval->first + 1;
1172
1173 /* First and last frame are ignored. */
1174 for (int cframe = interval->first + step; cframe < interval->second; cframe += step) {
1175 ensure_drawing_at_exact_frame(grease_pencil, layer, layer_data, cframe);
1176 Drawing *dst_drawing = get_drawing_at_exact_frame(grease_pencil, layer, cframe);
1177 if (dst_drawing == nullptr) {
1178 return;
1179 }
1180
1181 const float base_factor = float(cframe - interval->first) /
1182 std::max(frame_range_size - 1, 1);
1183 const float mix_factor = grease_pencil_interpolate_sequence_easing_calc(
1184 easing, type, back_easing, amplitude, period, *ipo_settings.custom_ipo, base_factor);
1185
1186 bke::CurvesGeometry interpolated_curves = interpolate_between_curves(
1187 grease_pencil, layer, layer_data.curve_pairs, mix_factor, opdata.flipmode);
1188
1189 if (opdata.smooth_factor > 0.0f && opdata.smooth_steps > 0) {
1190 MutableSpan<float3> positions = interpolated_curves.positions_for_write();
1192 interpolated_curves.curves_range(),
1193 interpolated_curves.points_by_curve(),
1194 VArray<bool>::ForSingle(true, interpolated_curves.points_num()),
1195 interpolated_curves.cyclic(),
1196 opdata.smooth_steps,
1197 opdata.smooth_factor,
1198 false,
1199 true,
1200 positions);
1201 interpolated_curves.tag_positions_changed();
1202 }
1203
1204 dst_drawing->strokes_for_write() = std::move(interpolated_curves);
1205 dst_drawing->tag_topology_changed();
1206 }
1207 });
1208
1209 /* Notifiers */
1212
1213 MEM_delete(static_cast<InterpolateOpData *>(op->customdata));
1214 op->customdata = nullptr;
1215
1216 return OPERATOR_FINISHED;
1217}
1218
1220{
1221 uiLayout *layout = op->layout;
1222 uiLayout *col, *row;
1223
1224 const InterpolationType type = InterpolationType(RNA_enum_get(op->ptr, "type"));
1225
1226 uiLayoutSetPropSep(layout, true);
1227 uiLayoutSetPropDecorate(layout, false);
1228 row = uiLayoutRow(layout, true);
1229 uiItemR(row, op->ptr, "step", UI_ITEM_NONE, nullptr, ICON_NONE);
1230
1231 row = uiLayoutRow(layout, true);
1232 uiItemR(row, op->ptr, "layers", UI_ITEM_NONE, nullptr, ICON_NONE);
1233
1235 row = uiLayoutRow(layout, true);
1236 uiItemR(row, op->ptr, "interpolate_selected_only", UI_ITEM_NONE, nullptr, ICON_NONE);
1237 }
1238
1239 row = uiLayoutRow(layout, true);
1240 uiItemR(row, op->ptr, "exclude_breakdowns", UI_ITEM_NONE, nullptr, ICON_NONE);
1241
1242 row = uiLayoutRow(layout, true);
1243 uiItemR(row, op->ptr, "flip", UI_ITEM_NONE, nullptr, ICON_NONE);
1244
1245 col = uiLayoutColumn(layout, true);
1246 uiItemR(col, op->ptr, "smooth_factor", UI_ITEM_NONE, nullptr, ICON_NONE);
1247 uiItemR(col, op->ptr, "smooth_steps", UI_ITEM_NONE, nullptr, ICON_NONE);
1248
1249 row = uiLayoutRow(layout, true);
1250 uiItemR(row, op->ptr, "type", UI_ITEM_NONE, nullptr, ICON_NONE);
1251
1252 if (type == InterpolationType::CurveMap) {
1253 /* Get an RNA pointer to ToolSettings to give to the custom curve. */
1254 Scene *scene = CTX_data_scene(C);
1255 ToolSettings *ts = scene->toolsettings;
1256 PointerRNA gpsettings_ptr = RNA_pointer_create(
1257 &scene->id, &RNA_GPencilInterpolateSettings, &ts->gp_interpolate);
1259 layout, &gpsettings_ptr, "interpolation_curve", 0, false, true, true, false);
1260 }
1261 else if (type != InterpolationType::Linear) {
1262 row = uiLayoutRow(layout, false);
1263 uiItemR(row, op->ptr, "easing", UI_ITEM_NONE, nullptr, ICON_NONE);
1264 if (type == InterpolationType::Back) {
1265 row = uiLayoutRow(layout, false);
1266 uiItemR(row, op->ptr, "back", UI_ITEM_NONE, nullptr, ICON_NONE);
1267 }
1268 else if (type == InterpolationType::Elastic) {
1269 row = uiLayoutRow(layout, false);
1270 uiItemR(row, op->ptr, "amplitude", UI_ITEM_NONE, nullptr, ICON_NONE);
1271 row = uiLayoutRow(layout, false);
1272 uiItemR(row, op->ptr, "period", UI_ITEM_NONE, nullptr, ICON_NONE);
1273 }
1274 }
1275}
1276
1278{
1279 PropertyRNA *prop;
1280
1281 ot->name = "Interpolate Sequence";
1282 ot->idname = "GREASE_PENCIL_OT_interpolate_sequence";
1284 ot->description = "Generate 'in-betweens' to smoothly interpolate between Grease Pencil frames";
1285
1289
1291 "step",
1292 1,
1293 1,
1294 MAXFRAME,
1295 "Step",
1296 "Number of frames between generated interpolated frames",
1297 1,
1298 MAXFRAME);
1299
1301 "layers",
1303 0,
1304 "Layer",
1305 "Layers included in the interpolation");
1306
1308 "exclude_breakdowns",
1309 false,
1310 "Exclude Breakdowns",
1311 "Exclude existing Breakdowns keyframes as interpolation extremes");
1312
1314 "flip",
1316 int(InterpolateFlipMode::FlipAuto),
1317 "Flip Mode",
1318 "Invert destination stroke to match start and end with source stroke");
1319
1321 "smooth_steps",
1322 1,
1323 1,
1324 3,
1325 "Iterations",
1326 "Number of times to smooth newly created strokes",
1327 1,
1328 3);
1329
1331 "smooth_factor",
1332 0.0f,
1333 0.0f,
1334 2.0f,
1335 "Smooth",
1336 "Amount of smoothing to apply to interpolated strokes, to reduce jitter/noise",
1337 0.0f,
1338 2.0f);
1339
1340 prop = RNA_def_enum(ot->srna,
1341 "type",
1343 0,
1344 "Type",
1345 "Interpolation method to use the next time 'Interpolate Sequence' is run");
1347
1348 prop = RNA_def_enum(
1349 ot->srna,
1350 "easing",
1353 "Easing",
1354 "Which ends of the segment between the preceding and following grease pencil frames "
1355 "easing interpolation is applied to");
1357
1359 "back",
1360 1.702f,
1361 0.0f,
1362 FLT_MAX,
1363 "Back",
1364 "Amount of overshoot for 'back' easing",
1365 0.0f,
1366 FLT_MAX);
1367
1369 "amplitude",
1370 0.15f,
1371 0.0f,
1372 FLT_MAX,
1373 "Amplitude",
1374 "Amount to boost elastic bounces for 'elastic' easing",
1375 0.0f,
1376 FLT_MAX);
1377
1379 "period",
1380 0.15f,
1381 -FLT_MAX,
1382 FLT_MAX,
1383 "Period",
1384 "Time between bounces for elastic easing",
1385 -FLT_MAX,
1386 FLT_MAX);
1387
1389}
1390
1393} // namespace blender::ed::sculpt_paint::greasepencil
1394
1395/* -------------------------------------------------------------------- */
1400{
1402 WM_operatortype_append(GREASE_PENCIL_OT_interpolate);
1403 WM_operatortype_append(GREASE_PENCIL_OT_interpolate_sequence);
1404}
1405
1407{
1409 static const EnumPropertyItem modal_items[] = {
1410 {int(InterpolateToolModalEvent::Cancel), "CANCEL", 0, "Cancel", ""},
1411 {int(InterpolateToolModalEvent::Confirm), "CONFIRM", 0, "Confirm", ""},
1412 {int(InterpolateToolModalEvent::Increase), "INCREASE", 0, "Increase", ""},
1413 {int(InterpolateToolModalEvent::Decrease), "DECREASE", 0, "Decrease", ""},
1414 {0, nullptr, 0, nullptr, nullptr},
1415 };
1416
1417 wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Interpolate Tool Modal Map");
1418
1419 /* This function is called for each space-type, only needs to add map once. */
1420 if (keymap && keymap->modal_items) {
1421 return;
1422 }
1423
1424 keymap = WM_modalkeymap_ensure(keyconf, "Interpolate Tool Modal Map", modal_items);
1425
1426 WM_modalkeymap_assign(keymap, "GREASE_PENCIL_OT_interpolate");
1427}
1428
float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value)
void BKE_curvemapping_init(CurveMapping *cumap)
CurveMapping * BKE_curvemapping_add(int tot, float minx, float miny, float maxx, float maxy)
Definition colortools.cc:90
@ CTX_MODE_EDIT_GPENCIL_LEGACY
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
ToolSettings * CTX_data_tool_settings(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
enum eContextObjectMode CTX_data_mode_enum(const bContext *C)
Low-level operations for curves.
Low-level operations for grease pencil.
General operations, lookup, etc. for materials.
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
float BLI_easing_sine_ease_in(float time, float begin, float change, float duration)
Definition easing.c:348
float BLI_easing_back_ease_out(float time, float begin, float change, float duration, float overshoot)
Definition easing.c:25
float BLI_easing_bounce_ease_in_out(float time, float begin, float change, float duration)
Definition easing.c:66
float BLI_easing_quint_ease_out(float time, float begin, float change, float duration)
Definition easing.c:334
float BLI_easing_quart_ease_in_out(float time, float begin, float change, float duration)
Definition easing.c:320
float BLI_easing_circ_ease_in_out(float time, float begin, float change, float duration)
Definition easing.c:87
float BLI_easing_quart_ease_out(float time, float begin, float change, float duration)
Definition easing.c:314
float BLI_easing_bounce_ease_in(float time, float begin, float change, float duration)
Definition easing.c:61
float BLI_easing_circ_ease_in(float time, float begin, float change, float duration)
Definition easing.c:75
float BLI_easing_expo_ease_in(float time, float begin, float change, float duration)
Definition easing.c:255
float BLI_easing_expo_ease_out(float time, float begin, float change, float duration)
Definition easing.c:263
float BLI_easing_elastic_ease_in(float time, float begin, float change, float duration, float amplitude, float period)
Definition easing.c:146
float BLI_easing_quad_ease_in_out(float time, float begin, float change, float duration)
Definition easing.c:299
float BLI_easing_elastic_ease_out(float time, float begin, float change, float duration, float amplitude, float period)
Definition easing.c:179
float BLI_easing_cubic_ease_in(float time, float begin, float change, float duration)
Definition easing.c:96
float BLI_easing_elastic_ease_in_out(float time, float begin, float change, float duration, float amplitude, float period)
Definition easing.c:211
float BLI_easing_quint_ease_in(float time, float begin, float change, float duration)
Definition easing.c:329
float BLI_easing_sine_ease_out(float time, float begin, float change, float duration)
Definition easing.c:353
float BLI_easing_bounce_ease_out(float time, float begin, float change, float duration)
Definition easing.c:43
float BLI_easing_quad_ease_in(float time, float begin, float change, float duration)
Definition easing.c:287
float BLI_easing_quad_ease_out(float time, float begin, float change, float duration)
Definition easing.c:293
float BLI_easing_circ_ease_out(float time, float begin, float change, float duration)
Definition easing.c:81
float BLI_easing_cubic_ease_out(float time, float begin, float change, float duration)
Definition easing.c:102
float BLI_easing_back_ease_in(float time, float begin, float change, float duration, float overshoot)
Definition easing.c:18
float BLI_easing_quint_ease_in_out(float time, float begin, float change, float duration)
Definition easing.c:339
float BLI_easing_expo_ease_in_out(float time, float begin, float change, float duration)
Definition easing.c:271
float BLI_easing_quart_ease_in(float time, float begin, float change, float duration)
Definition easing.c:308
float BLI_easing_back_ease_in_out(float time, float begin, float change, float duration, float overshoot)
Definition easing.c:32
float BLI_easing_cubic_ease_in_out(float time, float begin, float change, float duration)
Definition easing.c:108
float BLI_easing_sine_ease_in_out(float time, float begin, float change, float duration)
Definition easing.c:358
int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
#define ISECT_LINE_LINE_CROSS
#define DEG2RADF(_deg)
#define CTX_N_(context, msgid)
#define BLT_I18NCONTEXT_ID_GPENCIL
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1021
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
@ BEZT_IPO_LIN
eBezTriple_Easing
@ BEZT_IPO_EASE_OUT
@ BEZT_IPO_EASE_IN
@ BEZT_IPO_EASE_IN_OUT
eBezTriple_KeyframeType
@ BEZT_KEYTYPE_BREAKDOWN
#define MAXFRAME
@ SPACE_VIEW3D
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void ED_interpolatetool_modal_keymap(wmKeyConfig *keyconf)
void ED_operatortypes_grease_pencil_interpolate()
#define NUM_STR_REP_LEN
void outputNumInput(NumInput *n, char *str, const UnitSettings *unit_settings)
Definition numinput.cc:88
bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
Definition numinput.cc:312
bool applyNumInput(NumInput *n, float *vec)
Definition numinput.cc:190
bool hasNumInput(const NumInput *n)
Definition numinput.cc:171
void ED_area_status_text(ScrArea *area, const char *str)
Definition area.cc:803
void ED_workspace_status_text(bContext *C, const char *str)
Definition area.cc:966
Read Guarded memory(de)allocation.
#define RNA_ENUM_ITEM_HEADING(name, description)
Definition RNA_types.hh:522
void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propname, int type, bool levels, bool brush, bool neg_slope, bool tone)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ OPTYPE_BLOCKING
Definition WM_types.hh:164
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define ND_DATA
Definition WM_types.hh:475
@ KM_PRESS
Definition WM_types.hh:284
#define NA_EDITED
Definition WM_types.hh:550
#define NC_GPENCIL
Definition WM_types.hh:366
Span< T > as_span() const
Definition BLI_array.hh:232
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:237
const T * end() const
Definition BLI_array.hh:314
const T * begin() const
Definition BLI_array.hh:310
constexpr int64_t first() const
constexpr int64_t last(const int64_t n=0) const
constexpr int64_t size() const
constexpr bool is_empty() const
static constexpr IndexRange from_single(const int64_t index)
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:574
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:726
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr const T & first() const
Definition BLI_span.hh:316
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr const T & last(const int64_t n=0) const
Definition BLI_span.hh:326
constexpr const T * end() const
Definition BLI_span.hh:225
constexpr const T * begin() const
Definition BLI_span.hh:221
int64_t size() const
void append(const T &value)
bool is_empty() const
void resize(const int64_t new_size)
MutableSpan< T > as_mutable_span()
void append_n_times(const T &value, const int64_t n)
MutableSpan< float3 > positions_for_write()
OffsetIndices< int > points_by_curve() const
IndexRange curves_range() const
Span< float3 > positions() const
MutableSpan< int > offsets_for_write()
VArray< bool > cyclic() const
bke::CurvesGeometry & strokes_for_write()
const bke::CurvesGeometry & strokes() const
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
void to_indices(MutableSpan< T > r_indices) const
IndexMask slice(IndexRange range) const
static IndexMask from_indices(Span< T > indices, IndexMaskMemory &memory)
void foreach_index(Fn &&fn) const
local_group_size(16, 16) .push_constant(Type b
double time
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
uint col
void fill_index_range(MutableSpan< T > span, const T start=0)
static bool has_anything_selected(const Span< Curves * > curves_ids)
IndexMask retrieve_selected_curves(const bke::CurvesGeometry &curves, IndexMaskMemory &memory)
bool active_grease_pencil_poll(bContext *C)
static float grease_pencil_interpolate_sequence_easing_calc(const eBezTriple_Easing easing, const InterpolationType type, const float back_easing, const float amplitude, const float period, const CurveMapping &custom_ipo, const float time)
static void grease_pencil_interpolate_exit(bContext &C, wmOperator &op)
static bool find_curve_mapping_from_index(const GreasePencil &grease_pencil, const bke::greasepencil::Layer &layer, const int current_frame, const bool exclude_breakdowns, const bool only_selected, InterpolationPairs &pairs)
static int grease_pencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent *event)
static bke::CurvesGeometry interpolate_between_curves(const GreasePencil &grease_pencil, const bke::greasepencil::Layer &layer, const InterpolationPairs &curve_pairs, const float mix_factor, const InterpolateFlipMode flip_mode)
static void grease_pencil_interpolate_cancel(bContext *C, wmOperator *op)
static void grease_pencil_interpolate_status_indicators(bContext &C, const InterpolateOpData &opdata)
static const EnumPropertyItem grease_pencil_interpolate_layer_items[]
static bool grease_pencil_interpolate_init(const bContext &C, wmOperator &op)
static int grease_pencil_interpolate_sequence_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem grease_pencil_interpolate_flip_mode_items[]
static bool compute_auto_flip(const Span< float3 > from_positions, const Span< float3 > to_positions)
static int grease_pencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent *)
static const EnumPropertyItem grease_pencil_interpolation_type_items[]
static void grease_pencil_interpolate_sequence_ui(bContext *C, wmOperator *op)
static bke::greasepencil::Drawing * get_drawing_at_exact_frame(GreasePencil &grease_pencil, bke::greasepencil::Layer &layer, const int frame_number)
static void grease_pencil_interpolate_update(bContext &C, const wmOperator &op)
static void GREASE_PENCIL_OT_interpolate_sequence(wmOperatorType *ot)
static std::optional< FramesMapKeyIntervalT > find_frames_interval(const bke::greasepencil::Layer &layer, const int frame_number, const bool exclude_breakdowns)
static void grease_pencil_interpolate_restore(bContext &C, wmOperator &op)
static void GREASE_PENCIL_OT_interpolate(wmOperatorType *ot)
static bke::greasepencil::Drawing * ensure_drawing_at_exact_frame(GreasePencil &grease_pencil, bke::greasepencil::Layer &layer, InterpolateOpData::LayerData &layer_data, const int frame_number)
void interpolate_curves(const bke::CurvesGeometry &from_curves, const bke::CurvesGeometry &to_curves, Span< int > from_curve_indices, Span< int > to_curve_indices, const IndexMask &dst_curve_mask, Span< bool > dst_curve_flip_direction, const float mix_factor, bke::CurvesGeometry &dst_curves)
void smooth_curve_attribute(const IndexMask &curves_to_smooth, const OffsetIndices< int > points_by_curve, const VArray< bool > &point_selection, const VArray< bool > &cyclic, int iterations, float influence, bool smooth_ends, bool keep_shape, GMutableSpan attribute_data)
AngleRadianBase< T > angle_between(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
OffsetIndices< int > accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=0)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
int RNA_int_get(PointerRNA *ptr, const char *name)
float RNA_float_get(PointerRNA *ptr, const char *name)
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_float_factor(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
const EnumPropertyItem rna_enum_beztriple_interpolation_easing_items[]
#define FLT_MAX
Definition stdcycles.h:14
signed char int8_t
Definition stdint.h:75
struct CurveMapping * custom_ipo
struct GP_Interpolate_Settings gp_interpolate
static InterpolateOpData * from_operator(const bContext &C, const wmOperator &op)
short val
Definition WM_types.hh:724
short type
Definition WM_types.hh:722
const void * modal_items
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * translation_context
Definition WM_types.hh:994
const char * description
Definition WM_types.hh:996
void(* ui)(bContext *C, wmOperator *op)
Definition WM_types.hh:1053
StructRNA * srna
Definition WM_types.hh:1080
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
struct uiLayout * layout
struct PointerRNA * ptr
#define N_(msgid)
void WM_cursor_modal_set(wmWindow *win, int val)
void WM_cursor_modal_restore(wmWindow *win)
@ WM_CURSOR_EW_SCROLL
Definition wm_cursors.hh:53
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ EVT_MODAL_MAP
@ MOUSEMOVE
wmOperatorType * ot
Definition wm_files.cc:4125
wmKeyMap * WM_modalkeymap_ensure(wmKeyConfig *keyconf, const char *idname, const EnumPropertyItem *items)
Definition wm_keymap.cc:933
void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
wmKeyMap * WM_modalkeymap_find(wmKeyConfig *keyconf, const char *idname)
Definition wm_keymap.cc:960
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))