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"
8#include "BKE_deform.hh"
10#include "BKE_material.h"
11#include "BKE_paint.hh"
12
13#include "BLI_array_utils.hh"
14#include "BLI_easing.h"
15#include "BLI_index_mask.hh"
17#include "BLI_math_geom.h"
18#include "BLI_math_rotation.h"
19#include "BLI_math_rotation.hh"
20#include "BLI_math_vector.hh"
21#include "BLI_offset_indices.hh"
22#include "BLI_task.hh"
23
24#include "BLT_translation.hh"
25
26#include "DEG_depsgraph.hh"
27
29
30#include "ED_curves.hh"
31#include "ED_grease_pencil.hh"
32#include "ED_numinput.hh"
33#include "ED_screen.hh"
34
36#include "GEO_smooth_curves.hh"
37
38#include "MEM_guardedalloc.h"
39
40#include "RNA_access.hh"
41#include "RNA_define.hh"
42#include "RNA_enum_types.hh"
43#include "RNA_prototypes.hh"
44
45#include "UI_interface.hh"
46#include "UI_resources.hh"
47
48#include <climits>
49
51
54
55/* -------------------------------------------------------------------- */
58
59/* Modes for the interpolation tool. */
77
83 /* Interpolation. */
85 N_("Standard transitions between keyframes")),
86 {int(InterpolationType::Linear),
87 "LINEAR",
88 ICON_IPO_LINEAR,
89 "Linear",
90 "Straight-line interpolation between A and B (i.e. no ease in/out)"},
91 {int(InterpolationType::CurveMap),
92 "CUSTOM",
93 ICON_IPO_BEZIER,
94 "Custom",
95 "Custom interpolation defined using a curve map"},
96
97 /* Easing. */
99 N_("Predefined inertial transitions, useful for motion graphics "
100 "(from least to most \"dramatic\")")),
101 {int(InterpolationType::Sine),
102 "SINE",
103 ICON_IPO_SINE,
104 "Sinusoidal",
105 "Sinusoidal easing (weakest, almost linear but with a slight curvature)"},
106 {int(InterpolationType::Quadratic), "QUAD", ICON_IPO_QUAD, "Quadratic", "Quadratic easing"},
107 {int(InterpolationType::Cubic), "CUBIC", ICON_IPO_CUBIC, "Cubic", "Cubic easing"},
108 {int(InterpolationType::Quartic), "QUART", ICON_IPO_QUART, "Quartic", "Quartic easing"},
109 {int(InterpolationType::Quintic), "QUINT", ICON_IPO_QUINT, "Quintic", "Quintic easing"},
110 {int(InterpolationType::Exponential),
111 "EXPO",
112 ICON_IPO_EXPO,
113 "Exponential",
114 "Exponential easing (dramatic)"},
115 {int(InterpolationType::Circular),
116 "CIRC",
117 ICON_IPO_CIRC,
118 "Circular",
119 "Circular easing (strongest and most dynamic)"},
120
122 N_("Simple physics-inspired easing effects")),
123 {int(InterpolationType::Back),
124 "BACK",
125 ICON_IPO_BACK,
126 "Back",
127 "Cubic easing with overshoot and settle"},
128 {int(InterpolationType::Bounce),
129 "BOUNCE",
130 ICON_IPO_BOUNCE,
131 "Bounce",
132 "Exponentially decaying parabolic bounce, like when objects collide"},
133 {int(InterpolationType::Elastic),
134 "ELASTIC",
135 ICON_IPO_ELASTIC,
136 "Elastic",
137 "Exponentially decaying sine wave, like an elastic band"},
138
139 {0, nullptr, 0, nullptr, nullptr},
140};
141
143 {int(InterpolateFlipMode::None), "NONE", 0, "No Flip", ""},
144 {int(InterpolateFlipMode::Flip), "FLIP", 0, "Flip", ""},
145 {int(InterpolateFlipMode::FlipAuto), "AUTO", 0, "Automatic", ""},
146 {0, nullptr, 0, nullptr, nullptr},
147};
148
150 {int(InterpolateLayerMode::Active), "ACTIVE", 0, "Active", ""},
151 {int(InterpolateLayerMode::All), "ALL", 0, "All Layers", ""},
152 {0, nullptr, 0, nullptr, nullptr},
153};
154
155constexpr float interpolate_factor_min = -1.0f;
156constexpr float interpolate_factor_max = 2.0f;
157
158/* Pair of curves in a layer that get interpolated. */
165
167 struct LayerData {
168 /* Curve pairs to interpolate from this layer. */
170
171 /* Geometry of the target frame before interpolation for restoring on cancel. */
172 std::optional<bke::CurvesGeometry> orig_curves;
173 };
174
175 /* Layers to include. */
178 /* Exclude breakdown keyframes when finding intervals. */
180
181 /* Interpolation factor bias controlled by the user. */
182 float shift;
183 /* Interpolation base factor for the active layer. */
188
192
193 static InterpolateOpData *from_operator(const bContext &C, const wmOperator &op);
194};
195
196using FramesMapKeyIntervalT = std::pair<int, int>;
197
198static std::optional<FramesMapKeyIntervalT> find_frames_interval(
199 const bke::greasepencil::Layer &layer, const int frame_number, const bool exclude_breakdowns)
200{
203 using SortedKeysIterator = Layer::SortedKeysIterator;
204
205 const Span<FramesMapKeyT> sorted_keys = layer.sorted_keys();
206 SortedKeysIterator prev_key_it = layer.sorted_keys_iterator_at(frame_number);
207 if (!prev_key_it) {
208 return std::nullopt;
209 }
210 SortedKeysIterator next_key_it = std::next(prev_key_it);
211
212 /* Skip over invalid keyframes on either side. */
213 auto is_valid_keyframe = [&](const FramesMapKeyT key) {
214 const GreasePencilFrame *frame = layer.frame_at(key);
215 if (!frame || frame->is_end()) {
216 return false;
217 }
218 if (exclude_breakdowns && frame->type == BEZT_KEYTYPE_BREAKDOWN) {
219 return false;
220 }
221 return true;
222 };
223
224 for (; next_key_it != sorted_keys.end(); ++next_key_it) {
225 if (is_valid_keyframe(*next_key_it)) {
226 break;
227 }
228 }
229 for (; prev_key_it != sorted_keys.begin(); --prev_key_it) {
230 if (is_valid_keyframe(*prev_key_it)) {
231 break;
232 }
233 }
234 if (next_key_it == sorted_keys.end() || !is_valid_keyframe(*prev_key_it)) {
235 return std::nullopt;
236 }
237
238 return std::make_pair(*prev_key_it, *next_key_it);
239}
240
241/* Build index lists for curve interpolation using index. */
242static bool find_curve_mapping_from_index(const GreasePencil &grease_pencil,
243 const bke::greasepencil::Layer &layer,
244 const int current_frame,
245 const bool exclude_breakdowns,
246 const bool only_selected,
247 InterpolationPairs &pairs)
248{
250
251 const std::optional<FramesMapKeyIntervalT> interval = find_frames_interval(
252 layer, current_frame, exclude_breakdowns);
253 if (!interval) {
254 return false;
255 }
256
257 BLI_assert(layer.has_drawing_at(interval->first));
258 BLI_assert(layer.has_drawing_at(interval->second));
259 const Drawing &from_drawing = *grease_pencil.get_drawing_at(layer, interval->first);
260 const Drawing &to_drawing = *grease_pencil.get_drawing_at(layer, interval->second);
261
262 IndexMaskMemory memory;
263 IndexMask from_selection, to_selection;
264 if (only_selected && ed::curves::has_anything_selected(from_drawing.strokes()) &&
266 {
267 from_selection = ed::curves::retrieve_selected_curves(from_drawing.strokes(), memory);
268 to_selection = ed::curves::retrieve_selected_curves(to_drawing.strokes(), memory);
269 }
270 else {
271 from_selection = from_drawing.strokes().curves_range();
272 to_selection = to_drawing.strokes().curves_range();
273 }
274
275 const int pairs_num = std::min(from_selection.size(), to_selection.size());
276
277 const int old_pairs_num = pairs.from_frames.size();
278 pairs.from_frames.append_n_times(interval->first, pairs_num);
279 pairs.to_frames.append_n_times(interval->second, pairs_num);
280 pairs.from_curves.resize(old_pairs_num + pairs_num);
281 pairs.to_curves.resize(old_pairs_num + pairs_num);
282
283 /* Write source indices into the pair data. The drawing with fewer curves will discard some based
284 * on index. */
285 from_selection.slice(0, pairs_num)
286 .to_indices(pairs.from_curves.as_mutable_span().slice(old_pairs_num, pairs_num));
287 to_selection.slice(0, pairs_num)
288 .to_indices(pairs.to_curves.as_mutable_span().slice(old_pairs_num, pairs_num));
289
290 return true;
291}
292
294{
297
298 const Scene &scene = *CTX_data_scene(&C);
299 const int current_frame = scene.r.cfra;
300 const Object &object = *CTX_data_active_object(&C);
301 const GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
302
303 BLI_assert(grease_pencil.has_active_layer());
304 const Layer &active_layer = *grease_pencil.get_active_layer();
305
306 InterpolateOpData *data = MEM_new<InterpolateOpData>(__func__);
307
308 if (RNA_struct_find_property(op.ptr, "shift") != nullptr) {
309 data->shift = RNA_float_get(op.ptr, "shift");
310 }
311 data->exclude_breakdowns = RNA_boolean_get(op.ptr, "exclude_breakdowns");
312 data->flipmode = InterpolateFlipMode(RNA_enum_get(op.ptr, "flip"));
313 data->smooth_factor = RNA_float_get(op.ptr, "smooth_factor");
314 data->smooth_steps = RNA_int_get(op.ptr, "smooth_steps");
315 data->active_layer_index = *grease_pencil.get_layer_index(active_layer);
316 const bool use_selection = RNA_boolean_get(op.ptr, "use_selection");
317
318 const auto layer_mode = InterpolateLayerMode(RNA_enum_get(op.ptr, "layers"));
319 switch (layer_mode) {
320 case InterpolateLayerMode::Active:
321 data->layer_mask = IndexRange::from_single(data->active_layer_index);
322 break;
323 case InterpolateLayerMode::All:
324 data->layer_mask = IndexMask::from_predicate(
325 grease_pencil.layers().index_range(),
326 GrainSize(1024),
327 data->layer_mask_memory,
328 [&](const int layer_index) { return grease_pencil.layer(layer_index).is_editable(); });
329 break;
330 }
331
332 bool found_mapping = false;
333 data->layer_data.reinitialize(grease_pencil.layers().size());
334 data->layer_mask.foreach_index([&](const int layer_index) {
335 const Layer &layer = grease_pencil.layer(layer_index);
336 InterpolateOpData::LayerData &layer_data = data->layer_data[layer_index];
337
338 /* Pair from/to curves by index. */
339 const bool has_curve_mapping = find_curve_mapping_from_index(grease_pencil,
340 layer,
341 current_frame,
342 data->exclude_breakdowns,
343 use_selection,
344 layer_data.curve_pairs);
345 found_mapping = found_mapping || has_curve_mapping;
346 });
347
348 /* No mapping between frames was found. */
349 if (!found_mapping) {
350 MEM_delete(data);
351 return nullptr;
352 }
353
354 const std::optional<FramesMapKeyIntervalT> active_layer_interval = find_frames_interval(
355 active_layer, current_frame, data->exclude_breakdowns);
356 data->init_factor = active_layer_interval ?
357 float(current_frame - active_layer_interval->first) /
358 (active_layer_interval->second - active_layer_interval->first + 1) :
359 0.5f;
360
361 return data;
362}
363
364static bool compute_auto_flip(const Span<float3> from_positions, const Span<float3> to_positions)
365{
366 if (from_positions.size() < 2 || to_positions.size() < 2) {
367 return false;
368 }
369
370 constexpr float min_angle = DEG2RADF(15);
371
372 const float3 &from_first = from_positions.first();
373 const float3 &from_last = from_positions.last();
374 const float3 &to_first = to_positions.first();
375 const float3 &to_last = to_positions.last();
376
377 /* If lines intersect at a sharp angle check distances. */
378 if (isect_seg_seg_v2(from_first, to_first, from_last, to_last) == ISECT_LINE_LINE_CROSS) {
379 if (math::angle_between(math::normalize(to_first - from_first),
380 math::normalize(to_last - from_last))
381 .radian() < min_angle)
382 {
383 if (math::distance_squared(from_first, to_first) >=
384 math::distance_squared(from_last, to_first))
385 {
386 return math::distance_squared(from_last, to_first) >=
387 math::distance_squared(from_last, to_last);
388 }
389
390 return math::distance_squared(from_first, to_first) <
391 math::distance_squared(from_first, to_last);
392 }
393
394 return true;
395 }
396
397 return math::dot(from_last - from_first, to_last - to_first) < 0.0f;
398}
399
401 const bke::greasepencil::Layer &layer,
402 const InterpolationPairs &curve_pairs,
403 const float mix_factor,
404 const InterpolateFlipMode flip_mode)
405{
407
408 const int dst_curve_num = curve_pairs.from_curves.size();
409 BLI_assert(curve_pairs.to_curves.size() == dst_curve_num);
410 BLI_assert(curve_pairs.from_frames.size() == dst_curve_num);
411 BLI_assert(curve_pairs.to_frames.size() == dst_curve_num);
412
413 /* Sort pairs by unique to/from frame combinations.
414 * Curves for each frame pair are then interpolated together.
415 * Map entries are indices into the original curve_pairs array,
416 * so the order of strokes can be maintained. */
417 Array<int> sorted_pairs(dst_curve_num);
419 std::sort(sorted_pairs.begin(), sorted_pairs.end(), [&](const int a, const int b) {
420 const int from_frame_a = curve_pairs.from_frames[a];
421 const int to_frame_a = curve_pairs.to_frames[a];
422 const int from_frame_b = curve_pairs.from_frames[b];
423 const int to_frame_b = curve_pairs.to_frames[b];
424 return from_frame_a < from_frame_b ||
425 (from_frame_a == from_frame_b && to_frame_a < to_frame_b);
426 });
427
428 /* Find ranges of sorted pairs with the same from/to frame intervals. */
429 Vector<int> pair_offsets;
430 const OffsetIndices curves_by_pair = [&]() {
431 int prev_from_frame = INT_MIN;
432 int prev_to_frame = INT_MIN;
433 int current_count = 0;
434 for (const int sorted_index : IndexRange(dst_curve_num)) {
435 const int pair_index = sorted_pairs[sorted_index];
436 const int from_frame = curve_pairs.from_frames[pair_index];
437 const int to_frame = curve_pairs.to_frames[pair_index];
438 if (from_frame != prev_from_frame || to_frame != prev_to_frame) {
439 /* New pair. */
440 if (current_count > 0) {
441 pair_offsets.append(current_count);
442 }
443 current_count = 0;
444 }
445 ++current_count;
446 }
447 if (current_count > 0) {
448 pair_offsets.append(current_count);
449 }
450
451 /* Last entry for overall size. */
452 if (pair_offsets.is_empty()) {
453 return OffsetIndices<int>{};
454 }
455
456 pair_offsets.append(0);
458 }();
459
460 /* Compute curve length and flip mode for each pair. */
461 Array<int> dst_curve_offsets(curves_by_pair.size() + 1, 0);
462 Array<bool> dst_curve_flip(curves_by_pair.size(), false);
463 const OffsetIndices<int> dst_points_by_curve = [&]() {
464 /* Last entry for overall size. */
465 if (curves_by_pair.is_empty()) {
466 return OffsetIndices<int>{};
467 }
468
469 for (const int pair_range_i : curves_by_pair.index_range()) {
470 const IndexRange pair_range = curves_by_pair[pair_range_i];
471 BLI_assert(!pair_range.is_empty());
472
473 const int first_pair_index = sorted_pairs[pair_range.first()];
474 const int from_frame = curve_pairs.from_frames[first_pair_index];
475 const int to_frame = curve_pairs.to_frames[first_pair_index];
476 const Drawing *from_drawing = grease_pencil.get_drawing_at(layer, from_frame);
477 const Drawing *to_drawing = grease_pencil.get_drawing_at(layer, to_frame);
478 if (!from_drawing || !to_drawing) {
479 continue;
480 }
481 const OffsetIndices from_points_by_curve = from_drawing->strokes().points_by_curve();
482 const OffsetIndices to_points_by_curve = to_drawing->strokes().points_by_curve();
483 const Span<float3> from_positions = from_drawing->strokes().positions();
484 const Span<float3> to_positions = to_drawing->strokes().positions();
485
486 for (const int sorted_index : pair_range) {
487 const int pair_index = sorted_pairs[sorted_index];
488 const int from_curve = curve_pairs.from_curves[pair_index];
489 const int to_curve = curve_pairs.to_curves[pair_index];
490 const IndexRange from_points = from_points_by_curve[from_curve];
491 const IndexRange to_points = to_points_by_curve[to_curve];
492
493 dst_curve_offsets[pair_index] = std::max(from_points.size(), to_points.size());
494 switch (flip_mode) {
495 case InterpolateFlipMode::None:
496 dst_curve_flip[pair_index] = false;
497 break;
498 case InterpolateFlipMode::Flip:
499 dst_curve_flip[pair_index] = true;
500 break;
501 case InterpolateFlipMode::FlipAuto: {
502 dst_curve_flip[pair_index] = compute_auto_flip(from_positions.slice(from_points),
503 to_positions.slice(to_points));
504 break;
505 }
506 }
507 }
508 }
509 return offset_indices::accumulate_counts_to_offsets(dst_curve_offsets);
510 }();
511 const int dst_point_num = dst_points_by_curve.total_size();
512
513 bke::CurvesGeometry dst_curves(dst_point_num, dst_curve_num);
514 /* Offsets are empty when there are no curves. */
515 if (dst_curve_num > 0) {
516 dst_curves.offsets_for_write().copy_from(dst_curve_offsets);
517 }
518
519 /* Copy vertex group names since we still have other parts of the code depends on vertex group
520 * names to be available. */
522
523 /* Sorted map arrays that can be passed to the interpolation function directly.
524 * These index maps have the same order as the sorted indices, so slices of indices can be used
525 * for interpolating all curves of a frame pair at once. */
526 Array<int> sorted_from_curve_indices(dst_curve_num);
527 Array<int> sorted_to_curve_indices(dst_curve_num);
528
529 for (const int pair_range_i : curves_by_pair.index_range()) {
530 const IndexRange pair_range = curves_by_pair[pair_range_i];
531 const int first_pair_index = sorted_pairs[pair_range.first()];
532 const int from_frame = curve_pairs.from_frames[first_pair_index];
533 const int to_frame = curve_pairs.to_frames[first_pair_index];
534 const Drawing *from_drawing = grease_pencil.get_drawing_at(layer, from_frame);
535 const Drawing *to_drawing = grease_pencil.get_drawing_at(layer, to_frame);
536 if (!from_drawing || !to_drawing) {
537 continue;
538 }
539 const IndexRange from_curves = from_drawing->strokes().curves_range();
540 const IndexRange to_curves = to_drawing->strokes().curves_range();
541
542 IndexMaskMemory selection_memory;
543 /* Subset of target curves that are filled by this frame pair. Selection is built from pair
544 * indices, which correspond to dst curve indices. */
545 const IndexMask dst_curve_mask = IndexMask::from_indices(
546 sorted_pairs.as_span().slice(pair_range), selection_memory);
547 MutableSpan<int> pair_from_indices = sorted_from_curve_indices.as_mutable_span().slice(
548 pair_range);
549 MutableSpan<int> pair_to_indices = sorted_to_curve_indices.as_mutable_span().slice(pair_range);
550 for (const int i : pair_range) {
551 const int pair_index = sorted_pairs[i];
552 sorted_from_curve_indices[i] = std::clamp(
553 curve_pairs.from_curves[pair_index], 0, int(from_curves.last()));
554 sorted_to_curve_indices[i] = std::clamp(
555 curve_pairs.to_curves[pair_index], 0, int(to_curves.last()));
556 }
558 to_drawing->strokes(),
559 pair_from_indices,
560 pair_to_indices,
561 dst_curve_mask,
562 dst_curve_flip,
563 mix_factor,
564 dst_curves);
565 }
566
567 return dst_curves;
568}
569
571
572/* -------------------------------------------------------------------- */
575
577 const InterpolateOpData &opdata)
578{
579 Scene &scene = *CTX_data_scene(&C);
580 ScrArea &area = *CTX_wm_area(&C);
581
582 const StringRef msg = IFACE_("GPencil Interpolation: ");
583
584 std::string status;
585 if (hasNumInput(&opdata.numeric_input)) {
586 char str_ofs[NUM_STR_REP_LEN];
587 outputNumInput(&const_cast<NumInput &>(opdata.numeric_input), str_ofs, &scene.unit);
588 status = msg + std::string(str_ofs);
589 }
590 else {
591 status = msg + std::to_string(int((opdata.init_factor + opdata.shift) * 100.0f)) + " %";
592 }
593
594 ED_area_status_text(&area, status.c_str());
596 &C, IFACE_("ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/MOVE to adjust factor"));
597}
598
599/* Utility function to get a drawing at the exact frame number. */
602 const int frame_number)
603{
605
606 const std::optional<int> start_frame = layer.start_frame_at(frame_number);
607 if (start_frame && *start_frame == frame_number) {
608 return grease_pencil.get_editable_drawing_at(layer, frame_number);
609 }
610 return nullptr;
611}
612
614 GreasePencil &grease_pencil,
617 const int frame_number)
618{
620
621 static constexpr eBezTriple_KeyframeType keyframe_type = BEZT_KEYTYPE_BREAKDOWN;
622
623 if (Drawing *drawing = get_drawing_at_exact_frame(grease_pencil, layer, frame_number)) {
624 layer_data.orig_curves = drawing->strokes();
625 return drawing;
626 }
627 return grease_pencil.insert_frame(layer, frame_number, 0, keyframe_type);
628}
629
631{
634
635 const auto &opdata = *static_cast<InterpolateOpData *>(op.customdata);
636 const Scene &scene = *CTX_data_scene(&C);
637 const int current_frame = scene.r.cfra;
638 Object &object = *CTX_data_active_object(&C);
639 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
640 const auto flip_mode = InterpolateFlipMode(RNA_enum_get(op.ptr, "flip"));
641
642 opdata.layer_mask.foreach_index([&](const int layer_index) {
643 Layer &layer = grease_pencil.layer(layer_index);
644 const InterpolateOpData::LayerData &layer_data = opdata.layer_data[layer_index];
645
646 /* Drawings must be created on operator invoke. */
647 Drawing *dst_drawing = get_drawing_at_exact_frame(grease_pencil, layer, current_frame);
648 if (dst_drawing == nullptr) {
649 return;
650 }
651
652 const float mix_factor = opdata.init_factor + opdata.shift;
654 grease_pencil, layer, layer_data.curve_pairs, mix_factor, flip_mode);
655
656 if (opdata.smooth_factor > 0.0f && opdata.smooth_steps > 0) {
657 MutableSpan<float3> positions = interpolated_curves.positions_for_write();
659 interpolated_curves.curves_range(),
660 interpolated_curves.points_by_curve(),
661 VArray<bool>::ForSingle(true, interpolated_curves.points_num()),
662 interpolated_curves.cyclic(),
663 opdata.smooth_steps,
664 opdata.smooth_factor,
665 false,
666 true,
667 positions);
668 interpolated_curves.tag_positions_changed();
669 }
670
671 dst_drawing->strokes_for_write() = std::move(interpolated_curves);
672 dst_drawing->tag_topology_changed();
673 });
674
676
679}
680
681/* Restore timeline changes when canceled. */
683{
686
687 if (op.customdata == nullptr) {
688 return;
689 }
690
691 const auto &opdata = *static_cast<InterpolateOpData *>(op.customdata);
692 const Scene &scene = *CTX_data_scene(&C);
693 const int current_frame = scene.r.cfra;
694 Object &object = *CTX_data_active_object(&C);
695 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
696
697 opdata.layer_mask.foreach_index([&](const int layer_index) {
698 Layer &layer = grease_pencil.layer(layer_index);
699 const InterpolateOpData::LayerData &layer_data = opdata.layer_data[layer_index];
700
701 if (layer_data.orig_curves) {
702 /* Keyframe existed before the operator, restore geometry. */
703 Drawing *drawing = grease_pencil.get_editable_drawing_at(layer, current_frame);
704 if (drawing) {
705 drawing->strokes_for_write() = *layer_data.orig_curves;
706 drawing->tag_topology_changed();
709 }
710 }
711 else {
712 /* Frame was empty, remove the added drawing. */
713 grease_pencil.remove_frames(layer, {current_frame});
716 }
717 });
718}
719
721{
723
725 if (op.customdata == nullptr) {
726 return false;
727 }
728 InterpolateOpData &data = *static_cast<InterpolateOpData *>(op.customdata);
729
730 const Scene &scene = *CTX_data_scene(&C);
731 const int current_frame = scene.r.cfra;
732 Object &object = *CTX_data_active_object(&C);
733 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
734
735 /* Create target frames. */
736 data.layer_mask.foreach_index([&](const int layer_index) {
737 Layer &layer = grease_pencil.layer(layer_index);
738 InterpolateOpData::LayerData &layer_data = data.layer_data[layer_index];
739
740 ensure_drawing_at_exact_frame(grease_pencil, layer, layer_data, current_frame);
741 });
742
743 return true;
744}
745
746/* Exit and free memory. */
748{
749 ScrArea &area = *CTX_wm_area(&C);
750
751 if (op.customdata == nullptr) {
752 return;
753 }
754
755 ED_area_status_text(&area, nullptr);
756 ED_workspace_status_text(&C, nullptr);
757
758 MEM_delete(static_cast<InterpolateOpData *>(op.customdata));
759 op.customdata = nullptr;
760}
761
763{
765 return false;
766 }
768 if (!ts || !ts->gp_paint) {
769 return false;
770 }
771 /* Only 3D view */
772 ScrArea *area = CTX_wm_area(C);
773 if (area && area->spacetype != SPACE_VIEW3D) {
774 return false;
775 }
776
777 return true;
778}
779
780/* Invoke handler: Initialize the operator */
782{
783 wmWindow &win = *CTX_wm_window(C);
784
785 if (!grease_pencil_interpolate_init(*C, *op)) {
787 return OPERATOR_CANCELLED;
788 }
789 InterpolateOpData &opdata = *static_cast<InterpolateOpData *>(op->customdata);
790
791 /* Set cursor to indicate modal operator. */
793
795
797
799
801}
802
809
810/* Modal handler: Events handling during interactive part */
812{
813 wmWindow &win = *CTX_wm_window(C);
814 const ARegion &region = *CTX_wm_region(C);
815 ScrArea &area = *CTX_wm_area(C);
816 InterpolateOpData &opdata = *static_cast<InterpolateOpData *>(op->customdata);
817 const bool has_numinput = hasNumInput(&opdata.numeric_input);
818
819 switch (event->type) {
820 case EVT_MODAL_MAP: {
821 switch (InterpolateToolModalEvent(event->val)) {
823 ED_area_status_text(&area, nullptr);
824 ED_workspace_status_text(C, nullptr);
826
829 return OPERATOR_CANCELLED;
831 ED_area_status_text(&area, nullptr);
832 ED_workspace_status_text(C, nullptr);
834
835 /* Write current factor to properties for the next execution. */
836 RNA_float_set(op->ptr, "shift", opdata.shift);
837
839 return OPERATOR_FINISHED;
841 opdata.shift = std::clamp(opdata.init_factor + opdata.shift + 0.01f,
844 opdata.init_factor;
846 break;
848 opdata.shift = std::clamp(opdata.init_factor + opdata.shift - 0.01f,
851 opdata.init_factor;
853 break;
854 }
855 break;
856 }
857 case MOUSEMOVE:
858 /* Only handle mouse-move if not doing numeric-input. */
859 if (!has_numinput) {
860 const float mouse_pos = event->mval[0];
861 const float factor = std::clamp(
863 opdata.shift = factor - opdata.init_factor;
864
866 }
867 break;
868 default: {
869 if ((event->val == KM_PRESS) && handleNumInput(C, &opdata.numeric_input, event)) {
870 float value = (opdata.init_factor + opdata.shift) * 100.0f;
871 applyNumInput(&opdata.numeric_input, &value);
872 opdata.shift = std::clamp(value * 0.01f, interpolate_factor_min, interpolate_factor_max) -
873 opdata.init_factor;
874
876 break;
877 }
878 /* Unhandled event, allow to pass through. */
880 }
881 }
882
884}
885
891
893{
894 ot->name = "Grease Pencil Interpolation";
895 ot->idname = "GREASE_PENCIL_OT_interpolate";
896 ot->description = "Interpolate grease pencil strokes between frames";
897
902
904
906 ot->srna,
907 "shift",
908 0.0f,
909 -1.0f,
910 1.0f,
911 "Shift",
912 "Bias factor for which frame has more influence on the interpolated strokes",
913 -0.9f,
914 0.9f);
915
916 RNA_def_enum(ot->srna,
917 "layers",
919 0,
920 "Layer",
921 "Layers included in the interpolation");
922
923 RNA_def_boolean(ot->srna,
924 "exclude_breakdowns",
925 false,
926 "Exclude Breakdowns",
927 "Exclude existing Breakdowns keyframes as interpolation extremes");
928
929 RNA_def_boolean(ot->srna,
930 "use_selection",
931 false,
932 "Use Selection",
933 "Use only selected strokes for interpolating");
934
935 RNA_def_enum(ot->srna,
936 "flip",
938 int(InterpolateFlipMode::FlipAuto),
939 "Flip Mode",
940 "Invert destination stroke to match start and end with source stroke");
941
942 RNA_def_int(ot->srna,
943 "smooth_steps",
944 1,
945 1,
946 3,
947 "Iterations",
948 "Number of times to smooth newly created strokes",
949 1,
950 3);
951
952 RNA_def_float(ot->srna,
953 "smooth_factor",
954 0.0f,
955 0.0f,
956 2.0f,
957 "Smooth",
958 "Amount of smoothing to apply to interpolated strokes, to reduce jitter/noise",
959 0.0f,
960 2.0f);
961}
962
964
965/* -------------------------------------------------------------------- */
968
969/* Helper: Perform easing equation calculations for GP interpolation operator. */
971 const InterpolationType type,
972 const float back_easing,
973 const float amplitude,
974 const float period,
975 const CurveMapping &custom_ipo,
976 const float time)
977{
978 constexpr float begin = 0.0f;
979 constexpr float change = 1.0f;
980 constexpr float duration = 1.0f;
981
982 switch (type) {
983 case InterpolationType::Linear:
984 return time;
985
986 case InterpolationType::CurveMap:
987 return BKE_curvemapping_evaluateF(&custom_ipo, 0, time);
988
989 case InterpolationType::Back:
990 switch (easing) {
991 case BEZT_IPO_EASE_IN:
992 return BLI_easing_back_ease_in(time, begin, change, duration, back_easing);
994 return BLI_easing_back_ease_out(time, begin, change, duration, back_easing);
996 return BLI_easing_back_ease_in_out(time, begin, change, duration, back_easing);
997
998 default:
999 return BLI_easing_back_ease_out(time, begin, change, duration, back_easing);
1000 }
1001 break;
1002
1003 case InterpolationType::Bounce:
1004 switch (easing) {
1005 case BEZT_IPO_EASE_IN:
1006 return BLI_easing_bounce_ease_in(time, begin, change, duration);
1007 case BEZT_IPO_EASE_OUT:
1008 return BLI_easing_bounce_ease_out(time, begin, change, duration);
1010 return BLI_easing_bounce_ease_in_out(time, begin, change, duration);
1011
1012 default:
1013 return BLI_easing_bounce_ease_out(time, begin, change, duration);
1014 }
1015 break;
1016
1017 case InterpolationType::Circular:
1018 switch (easing) {
1019 case BEZT_IPO_EASE_IN:
1020 return BLI_easing_circ_ease_in(time, begin, change, duration);
1021 case BEZT_IPO_EASE_OUT:
1022 return BLI_easing_circ_ease_out(time, begin, change, duration);
1024 return BLI_easing_circ_ease_in_out(time, begin, change, duration);
1025
1026 default:
1027 return BLI_easing_circ_ease_in(time, begin, change, duration);
1028 }
1029 break;
1030
1031 case InterpolationType::Cubic:
1032 switch (easing) {
1033 case BEZT_IPO_EASE_IN:
1034 return BLI_easing_cubic_ease_in(time, begin, change, duration);
1035 case BEZT_IPO_EASE_OUT:
1036 return BLI_easing_cubic_ease_out(time, begin, change, duration);
1038 return BLI_easing_cubic_ease_in_out(time, begin, change, duration);
1039
1040 default:
1041 return BLI_easing_cubic_ease_in(time, begin, change, duration);
1042 }
1043 break;
1044
1045 case InterpolationType::Elastic:
1046 switch (easing) {
1047 case BEZT_IPO_EASE_IN:
1048 return BLI_easing_elastic_ease_in(time, begin, change, duration, amplitude, period);
1049 case BEZT_IPO_EASE_OUT:
1050 return BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
1052 return BLI_easing_elastic_ease_in_out(time, begin, change, duration, amplitude, period);
1053
1054 default:
1055 return BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
1056 }
1057 break;
1058
1059 case InterpolationType::Exponential:
1060 switch (easing) {
1061 case BEZT_IPO_EASE_IN:
1062 return BLI_easing_expo_ease_in(time, begin, change, duration);
1063 case BEZT_IPO_EASE_OUT:
1064 return BLI_easing_expo_ease_out(time, begin, change, duration);
1066 return BLI_easing_expo_ease_in_out(time, begin, change, duration);
1067
1068 default:
1069 return BLI_easing_expo_ease_in(time, begin, change, duration);
1070 }
1071 break;
1072
1073 case InterpolationType::Quadratic:
1074 switch (easing) {
1075 case BEZT_IPO_EASE_IN:
1076 return BLI_easing_quad_ease_in(time, begin, change, duration);
1077 case BEZT_IPO_EASE_OUT:
1078 return BLI_easing_quad_ease_out(time, begin, change, duration);
1080 return BLI_easing_quad_ease_in_out(time, begin, change, duration);
1081
1082 default:
1083 return BLI_easing_quad_ease_in(time, begin, change, duration);
1084 }
1085 break;
1086
1087 case InterpolationType::Quartic:
1088 switch (easing) {
1089 case BEZT_IPO_EASE_IN:
1090 return BLI_easing_quart_ease_in(time, begin, change, duration);
1091 case BEZT_IPO_EASE_OUT:
1092 return BLI_easing_quart_ease_out(time, begin, change, duration);
1094 return BLI_easing_quart_ease_in_out(time, begin, change, duration);
1095
1096 default:
1097 return BLI_easing_quart_ease_in(time, begin, change, duration);
1098 }
1099 break;
1100
1101 case InterpolationType::Quintic:
1102 switch (easing) {
1103 case BEZT_IPO_EASE_IN:
1104 return BLI_easing_quint_ease_in(time, begin, change, duration);
1105 case BEZT_IPO_EASE_OUT:
1106 return BLI_easing_quint_ease_out(time, begin, change, duration);
1108 return BLI_easing_quint_ease_in_out(time, begin, change, duration);
1109
1110 default:
1111 return BLI_easing_quint_ease_in(time, begin, change, duration);
1112 }
1113 break;
1114
1115 case InterpolationType::Sine:
1116 switch (easing) {
1117 case BEZT_IPO_EASE_IN:
1118 return BLI_easing_sine_ease_in(time, begin, change, duration);
1119 case BEZT_IPO_EASE_OUT:
1120 return BLI_easing_sine_ease_out(time, begin, change, duration);
1122 return BLI_easing_sine_ease_in_out(time, begin, change, duration);
1123
1124 default:
1125 return BLI_easing_sine_ease_in(time, begin, change, duration);
1126 }
1127 break;
1128
1129 default:
1131 break;
1132 }
1133
1134 return time;
1135}
1136
1138{
1141
1143 if (op->customdata == nullptr) {
1144 return OPERATOR_FINISHED;
1145 }
1146 InterpolateOpData &opdata = *static_cast<InterpolateOpData *>(op->customdata);
1147
1148 const Scene &scene = *CTX_data_scene(C);
1149 const int current_frame = scene.r.cfra;
1150 Object &object = *CTX_data_active_object(C);
1151 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
1153 const InterpolationType type = InterpolationType(RNA_enum_get(op->ptr, "type"));
1154 const eBezTriple_Easing easing = eBezTriple_Easing(RNA_enum_get(op->ptr, "easing"));
1155 const float back_easing = RNA_float_get(op->ptr, "back");
1156 const float amplitude = RNA_float_get(op->ptr, "amplitude");
1157 const float period = RNA_float_get(op->ptr, "period");
1158 const int step = RNA_int_get(op->ptr, "step");
1159
1160 GP_Interpolate_Settings &ipo_settings = ts.gp_interpolate;
1161 if (ipo_settings.custom_ipo == nullptr) {
1162 ipo_settings.custom_ipo = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
1163 }
1164 BKE_curvemapping_init(ipo_settings.custom_ipo);
1165
1166 opdata.layer_mask.foreach_index([&](const int layer_index) {
1167 Layer &layer = grease_pencil.layer(layer_index);
1168 InterpolateOpData::LayerData &layer_data = opdata.layer_data[layer_index];
1169
1170 std::optional<FramesMapKeyIntervalT> interval = find_frames_interval(
1171 layer, current_frame, opdata.exclude_breakdowns);
1172 if (!interval) {
1173 return;
1174 }
1175
1176 const int frame_range_size = interval->second - interval->first + 1;
1177
1178 /* First and last frame are ignored. */
1179 for (int cframe = interval->first + step; cframe < interval->second; cframe += step) {
1180 ensure_drawing_at_exact_frame(grease_pencil, layer, layer_data, cframe);
1181 Drawing *dst_drawing = get_drawing_at_exact_frame(grease_pencil, layer, cframe);
1182 if (dst_drawing == nullptr) {
1183 return;
1184 }
1185
1186 const float base_factor = float(cframe - interval->first) /
1187 std::max(frame_range_size - 1, 1);
1188 const float mix_factor = grease_pencil_interpolate_sequence_easing_calc(
1189 easing, type, back_easing, amplitude, period, *ipo_settings.custom_ipo, base_factor);
1190
1191 bke::CurvesGeometry interpolated_curves = interpolate_between_curves(
1192 grease_pencil, layer, layer_data.curve_pairs, mix_factor, opdata.flipmode);
1193
1194 if (opdata.smooth_factor > 0.0f && opdata.smooth_steps > 0) {
1195 MutableSpan<float3> positions = interpolated_curves.positions_for_write();
1197 interpolated_curves.curves_range(),
1198 interpolated_curves.points_by_curve(),
1199 VArray<bool>::ForSingle(true, interpolated_curves.points_num()),
1200 interpolated_curves.cyclic(),
1201 opdata.smooth_steps,
1202 opdata.smooth_factor,
1203 false,
1204 true,
1205 positions);
1206 interpolated_curves.tag_positions_changed();
1207 }
1208
1209 dst_drawing->strokes_for_write() = std::move(interpolated_curves);
1210 dst_drawing->tag_topology_changed();
1211 }
1212 });
1213
1214 /* Notifiers */
1217
1218 MEM_delete(static_cast<InterpolateOpData *>(op->customdata));
1219 op->customdata = nullptr;
1220
1221 return OPERATOR_FINISHED;
1222}
1223
1225{
1226 uiLayout *layout = op->layout;
1227 uiLayout *col, *row;
1228
1229 const InterpolationType type = InterpolationType(RNA_enum_get(op->ptr, "type"));
1230
1231 uiLayoutSetPropSep(layout, true);
1232 uiLayoutSetPropDecorate(layout, false);
1233 row = uiLayoutRow(layout, true);
1234 uiItemR(row, op->ptr, "step", UI_ITEM_NONE, nullptr, ICON_NONE);
1235
1236 row = uiLayoutRow(layout, true);
1237 uiItemR(row, op->ptr, "layers", UI_ITEM_NONE, nullptr, ICON_NONE);
1238
1240 row = uiLayoutRow(layout, true);
1241 uiItemR(row, op->ptr, "interpolate_selected_only", UI_ITEM_NONE, nullptr, ICON_NONE);
1242 }
1243
1244 row = uiLayoutRow(layout, true);
1245 uiItemR(row, op->ptr, "exclude_breakdowns", UI_ITEM_NONE, nullptr, ICON_NONE);
1246
1247 row = uiLayoutRow(layout, true);
1248 uiItemR(row, op->ptr, "flip", UI_ITEM_NONE, nullptr, ICON_NONE);
1249
1250 col = uiLayoutColumn(layout, true);
1251 uiItemR(col, op->ptr, "smooth_factor", UI_ITEM_NONE, nullptr, ICON_NONE);
1252 uiItemR(col, op->ptr, "smooth_steps", UI_ITEM_NONE, nullptr, ICON_NONE);
1253
1254 row = uiLayoutRow(layout, true);
1255 uiItemR(row, op->ptr, "type", UI_ITEM_NONE, nullptr, ICON_NONE);
1256
1257 if (type == InterpolationType::CurveMap) {
1258 /* Get an RNA pointer to ToolSettings to give to the custom curve. */
1259 Scene *scene = CTX_data_scene(C);
1260 ToolSettings *ts = scene->toolsettings;
1261 PointerRNA gpsettings_ptr = RNA_pointer_create(
1262 &scene->id, &RNA_GPencilInterpolateSettings, &ts->gp_interpolate);
1264 layout, &gpsettings_ptr, "interpolation_curve", 0, false, true, true, false);
1265 }
1266 else if (type != InterpolationType::Linear) {
1267 row = uiLayoutRow(layout, false);
1268 uiItemR(row, op->ptr, "easing", UI_ITEM_NONE, nullptr, ICON_NONE);
1269 if (type == InterpolationType::Back) {
1270 row = uiLayoutRow(layout, false);
1271 uiItemR(row, op->ptr, "back", UI_ITEM_NONE, nullptr, ICON_NONE);
1272 }
1273 else if (type == InterpolationType::Elastic) {
1274 row = uiLayoutRow(layout, false);
1275 uiItemR(row, op->ptr, "amplitude", UI_ITEM_NONE, nullptr, ICON_NONE);
1276 row = uiLayoutRow(layout, false);
1277 uiItemR(row, op->ptr, "period", UI_ITEM_NONE, nullptr, ICON_NONE);
1278 }
1279 }
1280}
1281
1283{
1284 PropertyRNA *prop;
1285
1286 ot->name = "Interpolate Sequence";
1287 ot->idname = "GREASE_PENCIL_OT_interpolate_sequence";
1288 ot->translation_context = BLT_I18NCONTEXT_ID_GPENCIL;
1289 ot->description = "Generate 'in-betweens' to smoothly interpolate between Grease Pencil frames";
1290
1294
1295 RNA_def_int(ot->srna,
1296 "step",
1297 1,
1298 1,
1299 MAXFRAME,
1300 "Step",
1301 "Number of frames between generated interpolated frames",
1302 1,
1303 MAXFRAME);
1304
1305 RNA_def_enum(ot->srna,
1306 "layers",
1308 0,
1309 "Layer",
1310 "Layers included in the interpolation");
1311
1312 RNA_def_boolean(ot->srna,
1313 "exclude_breakdowns",
1314 false,
1315 "Exclude Breakdowns",
1316 "Exclude existing Breakdowns keyframes as interpolation extremes");
1317
1318 RNA_def_enum(ot->srna,
1319 "flip",
1321 int(InterpolateFlipMode::FlipAuto),
1322 "Flip Mode",
1323 "Invert destination stroke to match start and end with source stroke");
1324
1325 RNA_def_int(ot->srna,
1326 "smooth_steps",
1327 1,
1328 1,
1329 3,
1330 "Iterations",
1331 "Number of times to smooth newly created strokes",
1332 1,
1333 3);
1334
1335 RNA_def_float(ot->srna,
1336 "smooth_factor",
1337 0.0f,
1338 0.0f,
1339 2.0f,
1340 "Smooth",
1341 "Amount of smoothing to apply to interpolated strokes, to reduce jitter/noise",
1342 0.0f,
1343 2.0f);
1344
1345 prop = RNA_def_enum(ot->srna,
1346 "type",
1348 0,
1349 "Type",
1350 "Interpolation method to use the next time 'Interpolate Sequence' is run");
1352
1353 prop = RNA_def_enum(
1354 ot->srna,
1355 "easing",
1358 "Easing",
1359 "Which ends of the segment between the preceding and following grease pencil frames "
1360 "easing interpolation is applied to");
1362
1363 RNA_def_float(ot->srna,
1364 "back",
1365 1.702f,
1366 0.0f,
1367 FLT_MAX,
1368 "Back",
1369 "Amount of overshoot for 'back' easing",
1370 0.0f,
1371 FLT_MAX);
1372
1373 RNA_def_float(ot->srna,
1374 "amplitude",
1375 0.15f,
1376 0.0f,
1377 FLT_MAX,
1378 "Amplitude",
1379 "Amount to boost elastic bounces for 'elastic' easing",
1380 0.0f,
1381 FLT_MAX);
1382
1383 RNA_def_float(ot->srna,
1384 "period",
1385 0.15f,
1386 -FLT_MAX,
1387 FLT_MAX,
1388 "Period",
1389 "Time between bounces for elastic easing",
1390 -FLT_MAX,
1391 FLT_MAX);
1392
1393 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1394}
1395
1397
1398} // namespace blender::ed::sculpt_paint::greasepencil
1399
1400/* -------------------------------------------------------------------- */
1403
1410
1412{
1414 static const EnumPropertyItem modal_items[] = {
1415 {int(InterpolateToolModalEvent::Cancel), "CANCEL", 0, "Cancel", ""},
1416 {int(InterpolateToolModalEvent::Confirm), "CONFIRM", 0, "Confirm", ""},
1417 {int(InterpolateToolModalEvent::Increase), "INCREASE", 0, "Increase", ""},
1418 {int(InterpolateToolModalEvent::Decrease), "DECREASE", 0, "Decrease", ""},
1419 {0, nullptr, 0, nullptr, nullptr},
1420 };
1421
1422 wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Interpolate Tool Modal Map");
1423
1424 /* This function is called for each space-type, only needs to add map once. */
1425 if (keymap && keymap->modal_items) {
1426 return;
1427 }
1428
1429 keymap = WM_modalkeymap_ensure(keyconf, "Interpolate Tool Modal Map", modal_items);
1430
1431 WM_modalkeymap_assign(keymap, "GREASE_PENCIL_OT_interpolate");
1432}
1433
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.
support for deformation groups and hooks.
void BKE_defgroup_copy_list(ListBase *outbase, const ListBase *inbase)
Definition deform.cc:76
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
#define C
Definition RandGen.cpp:29
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)
#define ND_DATA
Definition WM_types.hh:475
@ OPTYPE_BLOCKING
Definition WM_types.hh:164
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define NA_EDITED
Definition WM_types.hh:550
#define NC_GPENCIL
Definition WM_types.hh:366
@ KM_PRESS
Definition WM_types.hh:284
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
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
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
static IndexMask from_indices(Span< T > indices, IndexMaskMemory &memory)
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)
const int * SortedKeysIterator
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
static VArray ForSingle(T value, const int64_t size)
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
SortedKeysIterator sorted_keys_iterator_at(int frame_number) const
const GreasePencilFrame * frame_at(const int frame_number) const
bool has_drawing_at(const int frame_number) const
std::optional< int > start_frame_at(int frame_number) const
Span< FramesMapKeyT > sorted_keys() const
void to_indices(MutableSpan< T > r_indices) const
IndexMask slice(IndexRange range) const
void foreach_index(Fn &&fn) const
local_group_size(16, 16) .push_constant(Type b
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)
VecBase< float, 3 > float3
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
ListBase vertex_group_names
struct CurveMapping * custom_ipo
struct ToolSettings * toolsettings
struct RenderData r
struct UnitSettings unit
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
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 *))