Blender V5.0
grease_pencil_convert_legacy.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <optional>
10
11#include <fmt/format.h>
12
13#include "BKE_action.hh"
14#include "BKE_anim_data.hh"
15#include "BKE_attribute.hh"
17#include "BKE_colortools.hh"
18#include "BKE_curves.hh"
19#include "BKE_deform.hh"
20#include "BKE_fcurve.hh"
22#include "BKE_grease_pencil.hh"
24#include "BKE_idprop.hh"
25#include "BKE_lib_id.hh"
26#include "BKE_lib_remap.hh"
27#include "BKE_main.hh"
28#include "BKE_material.hh"
29#include "BKE_modifier.hh"
30#include "BKE_node.hh"
32#include "BKE_object.hh"
33#include "BKE_screen.hh"
34
35#include "BLO_readfile.hh"
36
37#include "BLI_color.hh"
38#include "BLI_function_ref.hh"
39#include "BLI_listbase.h"
40#include "BLI_map.hh"
41#include "BLI_math_matrix.h"
42#include "BLI_math_matrix.hh"
44#include "BLI_string.h"
45#include "BLI_string_utf8.h"
46#include "BLI_vector.hh"
47
48#include "BLT_translation.hh"
49
50#include "DNA_anim_types.h"
51#include "DNA_brush_types.h"
55#include "DNA_meshdata_types.h"
56#include "DNA_modifier_types.h"
57#include "DNA_screen_types.h"
58#include "DNA_space_types.h"
59
60#include "DEG_depsgraph.hh"
62
63#include "ANIM_action.hh"
65
67
84
85/* -------------------------------------------------------------------- */
91
92using FCurveConvertCB = void(FCurve &fcurve);
93
120
140 ConversionData &conversion_data;
141
142 ID &id_src;
143 ID &id_dst;
144 AnimData *animdata_src;
145 AnimData *animdata_dst;
146
148 const bool is_transfer_between_ids;
154 const bool skip_nla;
155
164 const Array<AnimDataFCurveConvertor> fcurve_convertors;
165
166 public:
171 std::string root_path_src;
172 std::string root_path_dst;
173
174 private:
181 blender::Vector<FCurve *> fcurves_from_src_main_action = {};
182 blender::Vector<FCurve *> fcurves_from_src_tmp_action = {};
183 blender::Vector<FCurve *> fcurves_from_src_drivers = {};
188 bool has_changes = false;
189
190 public:
193 ID &id_src,
194 const Array<AnimDataFCurveConvertor> fcurve_convertors = {})
195 : conversion_data(conversion_data),
196 id_src(id_src),
197 id_dst(id_src),
198 animdata_src(BKE_animdata_from_id(&id_src)),
199 animdata_dst(BKE_animdata_from_id(&id_dst)),
200 is_transfer_between_ids(false),
201 skip_nla(false),
202 fcurve_convertors(fcurve_convertors)
203 {
204 }
205
207 ID &id_dst,
208 ID &id_src,
209 const Array<AnimDataFCurveConvertor> fcurve_convertors = {})
210 : conversion_data(conversion_data),
211 id_src(id_src),
212 id_dst(id_dst),
213 animdata_src(BKE_animdata_from_id(&id_src)),
214 animdata_dst(BKE_animdata_from_id(&id_dst)),
215 is_transfer_between_ids(true),
216 skip_nla(true),
217 fcurve_convertors(fcurve_convertors)
218 {
219 }
221
222 private:
223 using FCurveCallback = bool(bAction *owner_action, FCurve &fcurve);
224 using ActionCallback = bool(bAction &action);
225
228 bool is_valid() const
229 {
230 return this->animdata_src != nullptr;
231 }
232
233 /* Basic common check to decide whether a legacy fcurve should be processed or not. */
234 bool legacy_fcurves_is_valid_for_root_path(FCurve &fcurve, StringRefNull legacy_root_path) const
235 {
236 if (!fcurve.rna_path) {
237 return false;
238 }
239 StringRefNull rna_path = fcurve.rna_path;
240 if (!rna_path.startswith(legacy_root_path)) {
241 return false;
242 }
243 return true;
244 }
245
250 bool animation_fcurve_is_valid(bAction *owner_action, FCurve &fcurve) const
251 {
252 if (!this->is_valid()) {
253 return false;
254 }
255 /* Only take into account drivers (nullptr `action_owner`), and Actions directly assigned
256 * to the animdata, not the NLA ones. */
257 if (owner_action &&
258 !ELEM(owner_action, this->animdata_src->action, this->animdata_src->tmpact))
259 {
260 return false;
261 }
262 if (!legacy_fcurves_is_valid_for_root_path(fcurve, this->root_path_src)) {
263 return false;
264 }
265 return true;
266 }
267
268 /* Iterator over all FCurves in a given animation data. */
269
270 bool fcurve_foreach_in_action(bAction *owner_action,
271 blender::FunctionRef<FCurveCallback> callback) const
272 {
273 bool is_changed = false;
274 animrig::foreach_fcurve_in_action(owner_action->wrap(), [&](FCurve &fcurve) {
275 const bool local_is_changed = callback(owner_action, fcurve);
276 is_changed = is_changed || local_is_changed;
277 });
278
279 return is_changed;
280 }
281
282 bool fcurve_foreach_in_listbase(ListBase &fcurves,
283 blender::FunctionRef<FCurveCallback> callback) const
284 {
285 bool is_changed = false;
286 LISTBASE_FOREACH (FCurve *, fcurve, &fcurves) {
287 const bool local_is_changed = callback(nullptr, *fcurve);
288 is_changed = is_changed || local_is_changed;
289 }
290 return is_changed;
291 }
292
293 bool nla_strip_fcurve_foreach(NlaStrip &nla_strip,
294 blender::FunctionRef<FCurveCallback> callback) const
295 {
296 bool is_changed = false;
297 if (nla_strip.act) {
298 if (this->fcurve_foreach_in_action(nla_strip.act, callback)) {
300 is_changed = true;
301 }
302 }
303 LISTBASE_FOREACH (NlaStrip *, nla_strip_children, &nla_strip.strips) {
304 const bool local_is_changed = this->nla_strip_fcurve_foreach(*nla_strip_children, callback);
305 is_changed = is_changed || local_is_changed;
306 }
307 return is_changed;
308 }
309
310 bool animdata_fcurve_foreach(AnimData &anim_data,
311 blender::FunctionRef<FCurveCallback> callback) const
312 {
313 bool is_changed = false;
314 if (anim_data.action) {
315 if (this->fcurve_foreach_in_action(anim_data.action, callback)) {
317 is_changed = true;
318 }
319 }
320 if (anim_data.tmpact) {
321 if (this->fcurve_foreach_in_action(anim_data.tmpact, callback)) {
323 is_changed = true;
324 }
325 }
326
327 {
328 const bool local_is_changed = this->fcurve_foreach_in_listbase(anim_data.drivers, callback);
329 is_changed = is_changed || local_is_changed;
330 }
331
332 /* NOTE: New layered actions system can be ignored here, it did not exist together with GPv2.
333 */
334
335 if (this->skip_nla) {
336 return is_changed;
337 }
338
339 LISTBASE_FOREACH (NlaTrack *, nla_track, &anim_data.nla_tracks) {
340 LISTBASE_FOREACH (NlaStrip *, nla_strip, &nla_track->strips) {
341 const bool local_is_changed = this->nla_strip_fcurve_foreach(*nla_strip, callback);
342 is_changed = is_changed || local_is_changed;
343 }
344 }
345 return is_changed;
346 }
347
348 bool action_process(bAction &action, blender::FunctionRef<ActionCallback> callback) const
349 {
350 if (callback(action)) {
352 return true;
353 }
354 return false;
355 }
356
357 bool nla_strip_action_foreach(NlaStrip &nla_strip,
358 blender::FunctionRef<ActionCallback> callback) const
359 {
360 bool is_changed = false;
361 if (nla_strip.act) {
362 is_changed = action_process(*nla_strip.act, callback);
363 }
364 LISTBASE_FOREACH (NlaStrip *, nla_strip_children, &nla_strip.strips) {
365 is_changed = is_changed || this->nla_strip_action_foreach(*nla_strip_children, callback);
366 }
367 return is_changed;
368 }
369
370 bool animdata_action_foreach(AnimData &anim_data,
371 blender::FunctionRef<ActionCallback> callback) const
372 {
373 bool is_changed = false;
374
375 if (anim_data.action) {
376 is_changed = is_changed || action_process(*anim_data.action, callback);
377 }
378 if (anim_data.tmpact) {
379 is_changed = is_changed || action_process(*anim_data.tmpact, callback);
380 }
381
382 /* NOTE: New layered actions system can be ignored here, it did not exist together with GPv2.
383 */
384
385 if (this->skip_nla) {
386 return is_changed;
387 }
388
389 LISTBASE_FOREACH (NlaTrack *, nla_track, &anim_data.nla_tracks) {
390 LISTBASE_FOREACH (NlaStrip *, nla_strip, &nla_track->strips) {
391 is_changed = is_changed || this->nla_strip_action_foreach(*nla_strip, callback);
392 }
393 }
394 return is_changed;
395 }
396
397 public:
403 {
404 if (!this->is_valid()) {
405 return false;
406 }
407
408 if (GS(id_src.name) != GS(id_dst.name)) {
409 return true;
410 }
411
412 bool has_animation = false;
413 auto animation_detection_cb = [&](bAction *owner_action, FCurve &fcurve) -> bool {
414 /* Early out if we already know that the target data is animated. */
415 if (has_animation) {
416 return false;
417 }
418 if (!this->animation_fcurve_is_valid(owner_action, fcurve)) {
419 return false;
420 }
421 if (this->fcurve_convertors.is_empty()) {
422 has_animation = true;
423 return false;
424 }
425 StringRefNull rna_path = fcurve.rna_path;
426 for (const AnimDataFCurveConvertor &fcurve_convertor : this->fcurve_convertors) {
427 const std::string rna_path_src = fmt::format(
428 "{}{}", this->root_path_src, fcurve_convertor.relative_rna_path_src);
429 if (rna_path == rna_path_src) {
430 has_animation = true;
431 return false;
432 }
433 }
434 return false;
435 };
436
437 this->animdata_fcurve_foreach(*this->animdata_src, animation_detection_cb);
438 return has_animation;
439 }
440
448 {
449 if (!this->is_valid()) {
450 return;
451 }
452
453 auto fcurve_convert_cb = [&](const AnimDataFCurveConvertor *fcurve_convertor,
454 bAction *owner_action,
455 FCurve &fcurve,
456 const std::string &rna_path_dst) {
457 MEM_freeN(fcurve.rna_path);
458 fcurve.rna_path = BLI_strdupn(rna_path_dst.c_str(), rna_path_dst.size());
459 if (fcurve_convertor && fcurve_convertor->convert_cb) {
460 fcurve_convertor->convert_cb(fcurve);
461 }
462 this->has_changes = true;
463
464 if (!this->is_transfer_between_ids) {
465 return;
466 }
467 if (owner_action) {
468 if (owner_action == this->animdata_src->action) {
469 this->fcurves_from_src_main_action.append(&fcurve);
470 }
471 else if (owner_action == this->animdata_src->tmpact) {
472 this->fcurves_from_src_tmp_action.append(&fcurve);
473 }
474 }
475 else { /* Driver */
476 this->fcurves_from_src_drivers.append(&fcurve);
477 }
478 };
479
480 /* Update all FCurves which RNA path starts with the #root_path_src. */
481 if (this->fcurve_convertors.is_empty()) {
482 auto fcurve_root_path_convert_cb = [&](bAction *owner_action, FCurve &fcurve) -> bool {
483 if (!legacy_fcurves_is_valid_for_root_path(fcurve, this->root_path_src)) {
484 return false;
485 }
486 StringRefNull rna_path = fcurve.rna_path;
487 const std::string rna_path_dst = fmt::format(
488 "{}{}", this->root_path_dst, rna_path.substr(int64_t(this->root_path_src.size())));
489 fcurve_convert_cb(nullptr, owner_action, fcurve, rna_path_dst);
490 return true;
491 };
492
493 this->animdata_fcurve_foreach(*(this->animdata_src), fcurve_root_path_convert_cb);
494 return;
495 }
496
497 /* Update all FCurves which RNA path starts with the #root_path_src, and remains of the path
498 * matches one of the entries in #fcurve_convertors. */
499 auto fcurve_full_path_convert_cb = [&](bAction *owner_action, FCurve &fcurve) -> bool {
500 if (!animation_fcurve_is_valid(owner_action, fcurve)) {
501 return false;
502 }
503 StringRefNull rna_path = fcurve.rna_path;
504 for (const AnimDataFCurveConvertor &fcurve_convertor : this->fcurve_convertors) {
505 const std::string rna_path_src = fmt::format(
506 "{}{}", this->root_path_src, fcurve_convertor.relative_rna_path_src);
507 if (rna_path == rna_path_src) {
508 const std::string rna_path_dst = fmt::format(
509 "{}{}", this->root_path_dst, fcurve_convertor.relative_rna_path_dst);
510 fcurve_convert_cb(&fcurve_convertor, owner_action, fcurve, rna_path_dst);
511 return true;
512 }
513 }
514 return false;
515 };
516
517 this->animdata_fcurve_foreach(*(this->animdata_src), fcurve_full_path_convert_cb);
518 }
519
531 {
532 if (!this->is_valid()) {
533 return;
534 }
535
536 /* Ensure existing actions moved to a different ID type keep a 'valid' `idroot` value. Not
537 * essential, but 'nice to have'. */
538 if (GS(this->id_src.name) != GS(this->id_dst.name)) {
539 if (!this->animdata_dst) {
540 this->animdata_dst = BKE_animdata_ensure_id(&this->id_dst);
541 }
542 auto actions_idroot_ensure = [&](bAction &action) -> bool {
543 BKE_animdata_action_ensure_idroot(&this->id_dst, &action);
544 return true;
545 };
546 this->animdata_action_foreach(*this->animdata_dst, actions_idroot_ensure);
547 }
548
549 if (&id_src == &id_dst) {
550 if (this->has_changes) {
552 DEG_relations_tag_update(&this->conversion_data.bmain);
553 }
554 return;
555 }
556
557 if (this->fcurves_from_src_main_action.is_empty() &&
558 this->fcurves_from_src_tmp_action.is_empty() && this->fcurves_from_src_drivers.is_empty())
559 {
560 return;
561 }
562 if (!this->animdata_dst) {
563 this->animdata_dst = BKE_animdata_ensure_id(&this->id_dst);
564 }
565
566 auto fcurves_move = [&](bAction *action_dst,
567 const animrig::slot_handle_t slot_handle_dst,
568 bAction *action_src,
569 const Span<FCurve *> fcurves) {
570 for (FCurve *fcurve : fcurves) {
572 action_dst->wrap(), slot_handle_dst, action_src->wrap(), *fcurve);
573 }
574 };
575
576 auto fcurves_move_between_listbases =
577 [&](ListBase &fcurves_dst, ListBase &fcurves_src, const Span<FCurve *> fcurves) {
578 for (FCurve *fcurve : fcurves) {
579 BLI_assert(BLI_findindex(&fcurves_src, fcurve) >= 0);
580 BLI_remlink(&fcurves_src, fcurve);
581 BLI_addtail(&fcurves_dst, fcurve);
582 }
583 };
584
585 if (!this->fcurves_from_src_main_action.is_empty()) {
586 if (!this->animdata_dst->action) {
587 /* Create a new action. */
589 this->conversion_data.bmain,
590 this->animdata_src->action ? this->animdata_src->action->id.name + 2 : nullptr);
591 action.slot_add_for_id(this->id_dst);
592
593 const bool ok = animrig::assign_action(&action, {this->id_dst, *this->animdata_dst});
594 BLI_assert_msg(ok, "Expecting action assignment to work when converting Grease Pencil");
596 }
597 fcurves_move(this->animdata_dst->action,
598 this->animdata_dst->slot_handle,
599 this->animdata_src->action,
600 this->fcurves_from_src_main_action);
601 this->fcurves_from_src_main_action.clear();
602 }
603 if (!this->fcurves_from_src_tmp_action.is_empty()) {
604 if (!this->animdata_dst->tmpact) {
605 /* Create a new tmpact. */
607 this->conversion_data.bmain,
608 this->animdata_src->tmpact ? this->animdata_src->tmpact->id.name + 2 : nullptr);
609 tmpact.slot_add_for_id(this->id_dst);
610
611 const bool ok = animrig::assign_tmpaction(&tmpact, {this->id_dst, *this->animdata_dst});
612 BLI_assert_msg(ok, "Expecting tmpact assignment to work when converting Grease Pencil");
614 }
615 fcurves_move(this->animdata_dst->tmpact,
616 this->animdata_dst->tmp_slot_handle,
617 this->animdata_src->tmpact,
618 this->fcurves_from_src_tmp_action);
619 this->fcurves_from_src_tmp_action.clear();
620 }
621 if (!this->fcurves_from_src_drivers.is_empty()) {
622 fcurves_move_between_listbases(this->animdata_dst->drivers,
623 this->animdata_src->drivers,
624 this->fcurves_from_src_drivers);
625 this->fcurves_from_src_drivers.clear();
626 }
627
630 DEG_relations_tag_update(&this->conversion_data.bmain);
631 }
632};
633
635
642static void find_used_vertex_groups(const bGPDframe &gpf,
643 const ListBase &vertex_group_names,
644 const int num_vertex_groups,
645 ListBase &r_vertex_group_names,
646 Array<int> &r_indices)
647{
648 Array<int> is_group_used(num_vertex_groups, false);
649 LISTBASE_FOREACH (bGPDstroke *, gps, &gpf.strokes) {
650 if (!gps->dvert) {
651 continue;
652 }
653 Span<MDeformVert> dverts = {gps->dvert, gps->totpoints};
654 for (const MDeformVert &dvert : dverts) {
655 for (const MDeformWeight &weight : Span<MDeformWeight>{dvert.dw, dvert.totweight}) {
656 if (weight.def_nr >= num_vertex_groups) {
657 /* Ignore invalid deform weight group indices. */
658 continue;
659 }
660 is_group_used[weight.def_nr] = true;
661 }
662 }
663 }
664 BLI_listbase_clear(&r_vertex_group_names);
665 r_indices.reinitialize(num_vertex_groups);
666 int new_group_i = 0;
667 int old_group_i;
668 LISTBASE_FOREACH_INDEX (const bDeformGroup *, def_group, &vertex_group_names, old_group_i) {
669 if (!is_group_used[old_group_i]) {
670 r_indices[old_group_i] = -1;
671 continue;
672 }
673 r_indices[old_group_i] = new_group_i++;
674
675 bDeformGroup *def_group_copy = static_cast<bDeformGroup *>(MEM_dupallocN(def_group));
676 BLI_addtail(&r_vertex_group_names, def_group_copy);
677 }
678}
679
680/*
681 * This takes the legacy UV transforms and returns the stroke-space to texture-space matrix.
682 */
684 const float uv_rotation,
685 const float2 uv_scale)
686{
687 using namespace blender;
688
689 /* Bounding box data. */
690 const float2 minv = float2(-1.0f, -1.0f);
691 const float2 maxv = float2(1.0f, 1.0f);
692 /* Center of rotation. */
693 const float2 center = float2(0.5f, 0.5f);
694
695 const float2 uv_scale_inv = math::safe_rcp(uv_scale);
696 const float2 diagonal = maxv - minv;
697 const float sin_rotation = sin(uv_rotation);
698 const float cos_rotation = cos(uv_rotation);
699 const float2x2 rotation = float2x2(float2(cos_rotation, sin_rotation),
700 float2(-sin_rotation, cos_rotation));
701
702 float3x2 texture_matrix = float3x2::identity();
703
704 /* Apply bounding box re-scaling. */
705 texture_matrix[2] -= minv;
706 texture_matrix = math::from_scale<float2x2>(1.0f / diagonal) * texture_matrix;
707
708 /* Apply translation. */
709 texture_matrix[2] += uv_translation;
710
711 /* Apply rotation. */
712 texture_matrix[2] -= center;
713 texture_matrix = rotation * texture_matrix;
714 texture_matrix[2] += center;
715
716 /* Apply scale. */
717 texture_matrix = math::from_scale<float2x2>(uv_scale_inv) * texture_matrix;
718
719 return texture_matrix;
720}
721
722/*
723 * This gets the legacy layer-space to stroke-space matrix.
724 */
726{
727 using namespace blender;
728 using namespace blender::math;
729
730 const bGPDspoint *points = gps->points;
731 const int totpoints = gps->totpoints;
732
733 if (totpoints < 2) {
734 return float4x2::identity();
735 }
736
737 const bGPDspoint *point0 = &points[0];
738 const bGPDspoint *point1 = &points[1];
739 const bGPDspoint *point3 = &points[int(totpoints * 0.75f)];
740
741 const float3 pt0 = float3(point0->x, point0->y, point0->z);
742 const float3 pt1 = float3(point1->x, point1->y, point1->z);
743 const float3 pt3 = float3(point3->x, point3->y, point3->z);
744
745 /* Local X axis (p0 -> p1) */
746 const float3 local_x = normalize(pt1 - pt0);
747
748 /* Point vector at 3/4 */
749 const float3 local_3 = (totpoints == 2) ? (pt3 * 0.001f) - pt0 : pt3 - pt0;
750
751 /* Vector orthogonal to polygon plane. */
752 const float3 normal = cross(local_x, local_3);
753
754 /* Local Y axis (cross to normal/x axis). */
755 const float3 local_y = normalize(cross(normal, local_x));
756
757 /* Get local space using first point as origin. */
758 const float4x2 mat = transpose(
759 float2x4(float4(local_x, -dot(pt0, local_x)), float4(local_y, -dot(pt0, local_y))));
760
761 return mat;
762}
763
765{
766 const float3x2 texture_matrix = get_legacy_stroke_to_texture_matrix(
767 float2(gps->uv_translation), gps->uv_rotation, float2(gps->uv_scale));
768
769 const float4x2 strokemat = get_legacy_layer_to_stroke_matrix(gps);
770 float4x3 strokemat4x3 = float4x3(strokemat);
771 /*
772 * We need the diagonal of ones to start from the bottom right instead top left to properly apply
773 * the two matrices.
774 *
775 * i.e.
776 * # # # # # # # #
777 * We need # # # # Instead of # # # #
778 * 0 0 0 1 0 0 1 0
779 *
780 */
781 strokemat4x3[2][2] = 0.0f;
782 strokemat4x3[3][2] = 1.0f;
783
784 return texture_matrix * strokemat4x3;
785}
786
788 const ListBase &vertex_group_names)
789{
790 /* Create a new empty drawing. */
791 Drawing drawing;
792
793 /* Get the number of points, number of strokes and the offsets for each stroke. */
794 Vector<int> offsets;
795 Vector<int8_t> curve_types;
796 offsets.append(0);
797 int num_strokes = 0;
798 int num_points = 0;
799 bool has_bezier_stroke = false;
800 LISTBASE_FOREACH (bGPDstroke *, gps, &gpf.strokes) {
801 /* Check for a valid edit curve. This is only the case when the `editcurve` exists and wasn't
802 * tagged for a stroke update. This tag indicates that the stroke points have changed,
803 * invalidating the edit curve. */
804 if (gps->editcurve != nullptr && (gps->editcurve->flag & GP_CURVE_NEEDS_STROKE_UPDATE) == 0) {
805 if (gps->editcurve->tot_curve_points == 0) {
806 continue;
807 }
808 has_bezier_stroke = true;
809 num_points += gps->editcurve->tot_curve_points;
810 curve_types.append(CURVE_TYPE_BEZIER);
811 }
812 else {
813 if (gps->totpoints == 0) {
814 continue;
815 }
816 num_points += gps->totpoints;
817 curve_types.append(CURVE_TYPE_POLY);
818 }
819 num_strokes++;
820 offsets.append(num_points);
821 }
822
823 /* Return if the legacy frame contains no strokes (or zero points). */
824 if (num_strokes == 0) {
825 return drawing;
826 }
827
828 /* Resize the CurvesGeometry. */
830 curves.resize(num_points, num_strokes);
831 curves.offsets_for_write().copy_from(offsets);
832
833 OffsetIndices<int> points_by_curve = curves.points_by_curve();
834 MutableAttributeAccessor attributes = curves.attributes_for_write();
835
836 if (!has_bezier_stroke) {
837 /* All strokes are poly curves. */
838 curves.fill_curve_types(CURVE_TYPE_POLY);
839 }
840 else {
841 curves.curve_types_for_write().copy_from(curve_types);
842 curves.update_curve_types();
843 }
844
845 /* Find used vertex groups in this drawing. */
846 ListBase stroke_vertex_group_names;
847 Array<int> stroke_def_nr_map;
848 const int num_vertex_groups = BLI_listbase_count(&vertex_group_names);
850 gpf, vertex_group_names, num_vertex_groups, stroke_vertex_group_names, stroke_def_nr_map);
851 BLI_assert(BLI_listbase_is_empty(&curves.vertex_group_names));
852 curves.vertex_group_names = stroke_vertex_group_names;
853 const bool use_dverts = !BLI_listbase_is_empty(&curves.vertex_group_names);
854
855 /* Copy vertex weights and map the vertex group indices. */
856 auto copy_dvert = [&](const MDeformVert &src_dvert, MDeformVert &dst_dvert) {
857 dst_dvert = src_dvert;
858 dst_dvert.dw = static_cast<MDeformWeight *>(MEM_dupallocN(src_dvert.dw));
859 const MutableSpan<MDeformWeight> vertex_weights = {dst_dvert.dw, dst_dvert.totweight};
860 for (MDeformWeight &weight : vertex_weights) {
861 if (weight.def_nr >= num_vertex_groups) {
862 /* Ignore invalid deform weight group indices. */
863 continue;
864 }
865 /* Map def_nr to the reduced vertex group list. */
866 weight.def_nr = stroke_def_nr_map[weight.def_nr];
867 }
868 };
869
870 /* Point Attributes. */
871 MutableSpan<float3> positions = curves.positions_for_write();
872 MutableSpan<float3> handle_positions_left = has_bezier_stroke ?
873 curves.handle_positions_left_for_write() :
875 MutableSpan<float3> handle_positions_right = has_bezier_stroke ?
876 curves.handle_positions_right_for_write() :
878 MutableSpan<float> radii = drawing.radii_for_write();
879 MutableSpan<float> opacities = drawing.opacities_for_write();
880 /* Note: Since we *know* the drawing are created from scratch, we assume that the following
881 * `lookup_or_add_for_write_span` calls always return valid writers. */
882 SpanAttributeWriter<float> delta_times = attributes.lookup_or_add_for_write_span<float>(
883 "delta_time", AttrDomain::Point);
884 SpanAttributeWriter<float> rotations = attributes.lookup_or_add_for_write_span<float>(
885 "rotation", AttrDomain::Point);
887 SpanAttributeWriter<bool> selection = attributes.lookup_or_add_for_write_span<bool>(
888 ".selection", AttrDomain::Point);
889 MutableSpan<MDeformVert> dverts = use_dverts ? curves.wrap().deform_verts_for_write() :
891
892 /* Curve Attributes. */
893 SpanAttributeWriter<bool> stroke_cyclic = attributes.lookup_or_add_for_write_span<bool>(
894 "cyclic", AttrDomain::Curve);
895 SpanAttributeWriter<float> stroke_init_times = attributes.lookup_or_add_for_write_span<float>(
896 "init_time", AttrDomain::Curve);
897 SpanAttributeWriter<int8_t> stroke_start_caps = attributes.lookup_or_add_for_write_span<int8_t>(
898 "start_cap", AttrDomain::Curve);
899 SpanAttributeWriter<int8_t> stroke_end_caps = attributes.lookup_or_add_for_write_span<int8_t>(
900 "end_cap", AttrDomain::Curve);
901 SpanAttributeWriter<float> stroke_softness = attributes.lookup_or_add_for_write_span<float>(
902 "softness", AttrDomain::Curve);
903 SpanAttributeWriter<float> stroke_point_aspect_ratios =
904 attributes.lookup_or_add_for_write_span<float>("aspect_ratio", AttrDomain::Curve);
905 MutableSpan<ColorGeometry4f> stroke_fill_colors = drawing.fill_colors_for_write();
906 SpanAttributeWriter<int> stroke_materials = attributes.lookup_or_add_for_write_span<int>(
907 "material_index", AttrDomain::Curve);
908
909 Array<float4x2> legacy_texture_matrices(num_strokes);
910
911 int stroke_i = 0;
912 LISTBASE_FOREACH (bGPDstroke *, gps, &gpf.strokes) {
913 /* In GPv2 strokes with 0 points could technically be represented. In `CurvesGeometry` this is
914 * not the case and would be a bug. So we explicitly make sure to skip over strokes with no
915 * points. */
916 if (gps->totpoints == 0 ||
917 (gps->editcurve != nullptr && gps->editcurve->tot_curve_points == 0))
918 {
919 continue;
920 }
921
922 stroke_cyclic.span[stroke_i] = (gps->flag & GP_STROKE_CYCLIC) != 0;
923 /* Truncating time in ms to uint32 then we don't lose precision in lower bits. */
924 const uint32_t clamped_init_time = uint32_t(
925 std::clamp(gps->inittime * 1e3, 0.0, double(std::numeric_limits<uint32_t>::max())));
926 stroke_init_times.span[stroke_i] = float(clamped_init_time) / float(1e3);
927 stroke_start_caps.span[stroke_i] = int8_t(gps->caps[0]);
928 stroke_end_caps.span[stroke_i] = int8_t(gps->caps[1]);
929 stroke_softness.span[stroke_i] = 1.0f - gps->hardness;
930 stroke_point_aspect_ratios.span[stroke_i] = gps->aspect_ratio[0] /
931 max_ff(gps->aspect_ratio[1], 1e-8);
932 stroke_fill_colors[stroke_i] = ColorGeometry4f(gps->vert_color_fill);
933 stroke_materials.span[stroke_i] = gps->mat_nr;
934
935 const IndexRange points = points_by_curve[stroke_i];
936
937 const float stroke_thickness = float(gps->thickness) * LEGACY_RADIUS_CONVERSION_FACTOR;
938 MutableSpan<float3> dst_positions = positions.slice(points);
939 MutableSpan<float3> dst_handle_positions_left = has_bezier_stroke ?
940 handle_positions_left.slice(points) :
942 MutableSpan<float3> dst_handle_positions_right = has_bezier_stroke ?
943 handle_positions_right.slice(points) :
945 MutableSpan<float> dst_radii = radii.slice(points);
946 MutableSpan<float> dst_opacities = opacities.slice(points);
947 MutableSpan<float> dst_deltatimes = delta_times.span.slice(points);
948 MutableSpan<float> dst_rotations = rotations.span.slice(points);
949 MutableSpan<ColorGeometry4f> dst_vertex_colors = vertex_colors.slice(points);
950 MutableSpan<bool> dst_selection = selection.span.slice(points);
951 MutableSpan<MDeformVert> dst_dverts = use_dverts ? dverts.slice(points) :
953
954 if (curve_types[stroke_i] == CURVE_TYPE_POLY) {
955 BLI_assert(points.size() == gps->totpoints);
956 const Span<bGPDspoint> src_points{gps->points, gps->totpoints};
957 threading::parallel_for(src_points.index_range(), 4096, [&](const IndexRange range) {
958 for (const int point_i : range) {
959 const bGPDspoint &pt = src_points[point_i];
960 dst_positions[point_i] = float3(pt.x, pt.y, pt.z);
961 dst_radii[point_i] = stroke_thickness * pt.pressure;
962 dst_opacities[point_i] = pt.strength;
963 dst_deltatimes[point_i] = pt.time;
964 dst_rotations[point_i] = pt.uv_rot;
965 dst_vertex_colors[point_i] = ColorGeometry4f(pt.vert_color);
966 dst_selection[point_i] = (pt.flag & GP_SPOINT_SELECT) != 0;
967 if (use_dverts && gps->dvert) {
968 copy_dvert(gps->dvert[point_i], dst_dverts[point_i]);
969 }
970 }
971 });
972 }
973 else if (curve_types[stroke_i] == CURVE_TYPE_BEZIER) {
974 BLI_assert(gps->editcurve != nullptr);
975 BLI_assert(points.size() == gps->editcurve->tot_curve_points);
976 Span<bGPDcurve_point> src_curve_points{gps->editcurve->curve_points,
977 gps->editcurve->tot_curve_points};
978
979 threading::parallel_for(src_curve_points.index_range(), 4096, [&](const IndexRange range) {
980 for (const int point_i : range) {
981 const bGPDcurve_point &cpt = src_curve_points[point_i];
982 dst_positions[point_i] = float3(cpt.bezt.vec[1]);
983 dst_handle_positions_left[point_i] = float3(cpt.bezt.vec[0]);
984 dst_handle_positions_right[point_i] = float3(cpt.bezt.vec[2]);
985 dst_radii[point_i] = stroke_thickness * cpt.pressure;
986 dst_opacities[point_i] = cpt.strength;
987 dst_rotations[point_i] = cpt.uv_rot;
988 dst_vertex_colors[point_i] = ColorGeometry4f(cpt.vert_color);
989 dst_selection[point_i] = (cpt.flag & GP_CURVE_POINT_SELECT) != 0;
990 if (use_dverts && gps->dvert) {
991 copy_dvert(gps->dvert[point_i], dst_dverts[point_i]);
992 }
993 }
994 });
995 }
996 else {
997 /* Unknown curve type. */
999 }
1000
1001 const float4x2 legacy_texture_matrix = get_legacy_texture_matrix(gps);
1002 legacy_texture_matrices[stroke_i] = legacy_texture_matrix;
1003
1004 stroke_i++;
1005 }
1006
1007 /* Ensure that the normals are up to date. */
1008 curves.tag_normals_changed();
1009 drawing.set_texture_matrices(legacy_texture_matrices.as_span(), curves.curves_range());
1010
1011 delta_times.finish();
1012 rotations.finish();
1013 selection.finish();
1014
1015 stroke_cyclic.finish();
1016 stroke_init_times.finish();
1017 stroke_start_caps.finish();
1018 stroke_end_caps.finish();
1019 stroke_softness.finish();
1020 stroke_point_aspect_ratios.finish();
1021 stroke_materials.finish();
1022
1023 return drawing;
1024}
1025
1027 GreasePencil &grease_pencil,
1028 bGPdata &gpd)
1029{
1030 using namespace blender::bke::greasepencil;
1031
1032 if (gpd.flag & ID_FLAG_FAKEUSER) {
1033 id_fake_user_set(&grease_pencil.id);
1034 }
1035
1036 BLI_assert(!grease_pencil.id.properties);
1037 if (gpd.id.properties) {
1038 grease_pencil.id.properties = IDP_CopyProperty(gpd.id.properties);
1039 grease_pencil.id.system_properties = IDP_CopyProperty(gpd.id.properties);
1040 }
1041
1044 grease_pencil.flag, (gpd.flag & GP_DATA_EXPAND) != 0, GREASE_PENCIL_ANIM_CHANNEL_EXPANDED);
1045 SET_FLAG_FROM_TEST(grease_pencil.flag,
1046 (gpd.flag & GP_DATA_AUTOLOCK_LAYERS) != 0,
1050
1051 int layer_idx = 0;
1052 LISTBASE_FOREACH_INDEX (bGPDlayer *, gpl, &gpd.layers, layer_idx) {
1053 /* Create a new layer. */
1054 Layer &new_layer = grease_pencil.add_layer(StringRefNull(gpl->info, STRNLEN(gpl->info)));
1055
1056 /* Flags. */
1057 new_layer.set_visible((gpl->flag & GP_LAYER_HIDE) == 0);
1058 new_layer.set_locked((gpl->flag & GP_LAYER_LOCKED) != 0);
1059 new_layer.set_selected((gpl->flag & GP_LAYER_SELECT) != 0);
1061 new_layer.base.flag, (gpl->flag & GP_LAYER_FRAMELOCK) != 0, GP_LAYER_TREE_NODE_MUTE);
1062 SET_FLAG_FROM_TEST(new_layer.base.flag,
1063 (gpl->flag & GP_LAYER_USE_LIGHTS) != 0,
1065 SET_FLAG_FROM_TEST(new_layer.base.flag,
1066 (gpl->onion_flag & GP_LAYER_ONIONSKIN) == 0,
1069 new_layer.base.flag, (gpl->flag & GP_LAYER_USE_MASK) == 0, GP_LAYER_TREE_NODE_HIDE_MASKS);
1070
1071 /* Copy Dope-sheet channel color. */
1072 copy_v3_v3(new_layer.base.color, gpl->color);
1073 new_layer.blend_mode = int8_t(gpl->blend_mode);
1074
1075 new_layer.parent = gpl->parent;
1076 new_layer.set_parent_bone_name(gpl->parsubstr);
1077 /* GPv2 parent inverse matrix is only valid when parent is set. */
1078 if (gpl->parent) {
1079 copy_m4_m4(new_layer.parentinv, gpl->inverse);
1080 }
1081
1082 copy_v3_v3(new_layer.translation, gpl->location);
1083 copy_v3_v3(new_layer.rotation, gpl->rotation);
1084 copy_v3_v3(new_layer.scale, gpl->scale);
1085
1086 new_layer.set_view_layer_name(gpl->viewlayername);
1087 SET_FLAG_FROM_TEST(new_layer.base.flag,
1088 (gpl->flag & GP_LAYER_DISABLE_MASKS_IN_VIEWLAYER) != 0,
1090
1091 /* Convert the layer masks. */
1092 LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &gpl->mask_layers) {
1093 LayerMask *new_mask = MEM_new<LayerMask>(__func__, mask->name);
1094 new_mask->flag = mask->flag;
1095 BLI_addtail(&new_layer.masks, new_mask);
1096 }
1097 new_layer.opacity = gpl->opacity;
1098
1099 LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
1100 Drawing *dst_drawing = grease_pencil.insert_frame(
1101 new_layer, gpf->framenum, 0, eBezTriple_KeyframeType(gpf->key_type));
1102 if (dst_drawing == nullptr) {
1103 /* Might fail because GPv2 technically allowed overlapping keyframes on the same frame
1104 * (very unlikely to occur in real world files). In GPv3, keyframes always have to be on
1105 * different frames. In this case we can't create a keyframe and have to skip it. */
1106 continue;
1107 }
1108 /* Convert the frame to a drawing. */
1110
1111 /* This frame was just inserted above, so it should always exist. */
1112 GreasePencilFrame &new_frame = *new_layer.frame_at(gpf->framenum);
1113 SET_FLAG_FROM_TEST(new_frame.flag, (gpf->flag & GP_FRAME_SELECT), GP_FRAME_SELECTED);
1114 }
1115
1116 if ((gpl->flag & GP_LAYER_ACTIVE) != 0) {
1117 grease_pencil.set_active_layer(&new_layer);
1118 }
1119 }
1120
1121 /* Second loop, to write to layer attributes after all layers were created. */
1122 MutableAttributeAccessor layer_attributes = grease_pencil.attributes_for_write();
1123 /* NOTE: Layer Adjustments like the tint and the radius offsets are deliberately ignored here!
1124 * These are converted to modifiers at the bottom of the stack to keep visual compatibility with
1125 * GPv2. */
1126 SpanAttributeWriter<int> layer_passes = layer_attributes.lookup_or_add_for_write_span<int>(
1127 "pass_index", bke::AttrDomain::Layer);
1128
1129 layer_idx = 0;
1130 LISTBASE_FOREACH_INDEX (bGPDlayer *, gpl, &gpd.layers, layer_idx) {
1131 layer_passes.span[layer_idx] = int(gpl->pass_index);
1132 }
1133
1134 layer_passes.finish();
1135
1136 /* Copy vertex group names and settings. */
1139
1140 /* Convert the onion skinning settings. */
1142 settings.opacity = gpd.onion_factor;
1143 settings.mode = gpd.onion_mode;
1144 SET_FLAG_FROM_TEST(settings.flag,
1145 ((gpd.onion_flag & GP_ONION_GHOST_PREVCOL) != 0 &&
1146 (gpd.onion_flag & GP_ONION_GHOST_NEXTCOL) != 0),
1152 /* Convert keytype filter to a bit flag. */
1153 if (gpd.onion_keytype == -1) {
1155 }
1156 else {
1157 settings.filter = (1 << gpd.onion_keytype);
1158 }
1159 settings.num_frames_before = gpd.gstep;
1160 settings.num_frames_after = gpd.gstep_next;
1161 copy_v3_v3(settings.color_before, gpd.gcolor_prev);
1162 copy_v3_v3(settings.color_after, gpd.gcolor_next);
1163
1164 BKE_id_materials_copy(&conversion_data.bmain, &gpd.id, &grease_pencil.id);
1165
1166 /* Copy animation data from legacy GP data.
1167 *
1168 * Note that currently, Actions IDs are not duplicated. They may be needed ultimately, but for
1169 * the time being, assuming invalid fcurves/drivers are fine here. */
1170 if (AnimData *gpd_animdata = BKE_animdata_from_id(&gpd.id)) {
1171 grease_pencil.adt = BKE_animdata_copy_in_lib(
1172 &conversion_data.bmain, gpd.id.lib, gpd_animdata, LIB_ID_COPY_DEFAULT);
1173
1174 /* Some property was renamed between legacy GP layers and new GreasePencil ones. */
1175 AnimDataConvertor animdata_gpdata_transfer(
1176 conversion_data, grease_pencil.id, gpd.id, {{".location", ".translation"}});
1177 for (const Layer *layer_iter : grease_pencil.layers()) {
1178 /* Data comes from versioned GPv2 layers, which have a fixed max length. */
1179 char layer_name_esc[sizeof((bGPDlayer{}).info) * 2];
1180 BLI_str_escape(layer_name_esc, layer_iter->name().c_str(), sizeof(layer_name_esc));
1181 std::string layer_root_path = fmt::format("layers[\"{}\"]", layer_name_esc);
1182 animdata_gpdata_transfer.root_path_dst = layer_root_path;
1183 animdata_gpdata_transfer.root_path_src = layer_root_path;
1184 animdata_gpdata_transfer.fcurves_convert();
1185 }
1186 animdata_gpdata_transfer.fcurves_convert_finalize();
1187 }
1188}
1189
1190constexpr const char *OFFSET_RADIUS_NODETREE_NAME = "Offset Radius GPv3 Conversion";
1192{
1193 using namespace blender;
1194 /* NOTE: DO NOT translate this ID name, it is used to find a potentially already existing
1195 * node-tree. */
1197 &conversion_data.bmain, library, OFFSET_RADIUS_NODETREE_NAME, "GeometryNodeTree");
1198
1199 if (!group->geometry_node_asset_traits) {
1201 }
1203
1204 group->tree_interface.add_socket(
1205 DATA_("Geometry"), "", "NodeSocketGeometry", NODE_INTERFACE_SOCKET_INPUT, nullptr);
1206 group->tree_interface.add_socket(
1207 DATA_("Geometry"), "", "NodeSocketGeometry", NODE_INTERFACE_SOCKET_OUTPUT, nullptr);
1208
1209 bNodeTreeInterfaceSocket *radius_offset = group->tree_interface.add_socket(
1210 DATA_("Offset"), "", "NodeSocketFloat", NODE_INTERFACE_SOCKET_INPUT, nullptr);
1211 auto &radius_offset_data = *static_cast<bNodeSocketValueFloat *>(radius_offset->socket_data);
1212 radius_offset_data.subtype = PROP_DISTANCE;
1213 radius_offset_data.min = -FLT_MAX;
1214 radius_offset_data.max = FLT_MAX;
1215
1216 group->tree_interface.add_socket(
1217 DATA_("Layer"), "", "NodeSocketString", NODE_INTERFACE_SOCKET_INPUT, nullptr);
1218
1219 bNode *group_output = bke::node_add_node(nullptr, *group, "NodeGroupOutput");
1220 group_output->location[0] = 800;
1221 group_output->location[1] = 160;
1222 bNode *group_input = bke::node_add_node(nullptr, *group, "NodeGroupInput");
1223 group_input->location[0] = 0;
1224 group_input->location[1] = 160;
1225
1226 bNode *set_curve_radius = bke::node_add_node(nullptr, *group, "GeometryNodeSetCurveRadius");
1227 set_curve_radius->location[0] = 600;
1228 set_curve_radius->location[1] = 160;
1229 bNode *named_layer_selection = bke::node_add_node(
1230 nullptr, *group, "GeometryNodeInputNamedLayerSelection");
1231 named_layer_selection->location[0] = 200;
1232 named_layer_selection->location[1] = 100;
1233 bNode *input_radius = bke::node_add_node(nullptr, *group, "GeometryNodeInputRadius");
1234 input_radius->location[0] = 0;
1235 input_radius->location[1] = 0;
1236
1237 bNode *add = bke::node_add_node(nullptr, *group, "ShaderNodeMath");
1238 add->custom1 = NODE_MATH_ADD;
1239 add->location[0] = 200;
1240 add->location[1] = 0;
1241
1242 bNode *clamp_radius = bke::node_add_node(nullptr, *group, "ShaderNodeClamp");
1243 clamp_radius->location[0] = 400;
1244 clamp_radius->location[1] = 0;
1245 bNodeSocket *sock_max = bke::node_find_socket(*clamp_radius, SOCK_IN, "Max");
1246 static_cast<bNodeSocketValueFloat *>(sock_max->default_value)->value = FLT_MAX;
1247
1248 bke::node_add_link(*group,
1249 *group_input,
1250 *bke::node_find_socket(*group_input, SOCK_OUT, "Socket_0"),
1251 *set_curve_radius,
1252 *bke::node_find_socket(*set_curve_radius, SOCK_IN, "Curve"));
1253 bke::node_add_link(*group,
1254 *set_curve_radius,
1255 *bke::node_find_socket(*set_curve_radius, SOCK_OUT, "Curve"),
1256 *group_output,
1257 *bke::node_find_socket(*group_output, SOCK_IN, "Socket_1"));
1258
1259 bke::node_add_link(*group,
1260 *group_input,
1261 *bke::node_find_socket(*group_input, SOCK_OUT, "Socket_3"),
1262 *named_layer_selection,
1263 *bke::node_find_socket(*named_layer_selection, SOCK_IN, "Name"));
1264 bke::node_add_link(*group,
1265 *named_layer_selection,
1266 *bke::node_find_socket(*named_layer_selection, SOCK_OUT, "Selection"),
1267 *set_curve_radius,
1268 *bke::node_find_socket(*set_curve_radius, SOCK_IN, "Selection"));
1269
1270 bke::node_add_link(*group,
1271 *group_input,
1272 *bke::node_find_socket(*group_input, SOCK_OUT, "Socket_2"),
1273 *add,
1274 *bke::node_find_socket(*add, SOCK_IN, "Value"));
1275 bke::node_add_link(*group,
1276 *input_radius,
1277 *bke::node_find_socket(*input_radius, SOCK_OUT, "Radius"),
1278 *add,
1279 *bke::node_find_socket(*add, SOCK_IN, "Value_001"));
1280 bke::node_add_link(*group,
1281 *add,
1282 *bke::node_find_socket(*add, SOCK_OUT, "Value"),
1283 *clamp_radius,
1284 *bke::node_find_socket(*clamp_radius, SOCK_IN, "Value"));
1285 bke::node_add_link(*group,
1286 *clamp_radius,
1287 *bke::node_find_socket(*clamp_radius, SOCK_OUT, "Result"),
1288 *set_curve_radius,
1289 *bke::node_find_socket(*set_curve_radius, SOCK_IN, "Radius"));
1290
1291 LISTBASE_FOREACH (bNode *, node, &group->nodes) {
1292 bke::node_set_selected(*node, false);
1293 }
1294
1295 return group;
1296}
1297
1299 bGPdata &src_object_data,
1300 Object &dst_object)
1301{
1302 AnimDataConvertor animdata_thickness_transfer(
1303 conversion_data, dst_object.id, src_object_data.id, {{"pixel_factor", ".thickness_factor"}});
1304 animdata_thickness_transfer.root_path_src = "";
1305
1306 const float thickness_factor = src_object_data.pixfactor;
1307 const bool has_thickness_factor_animation =
1308 animdata_thickness_transfer.source_has_animation_to_convert();
1309 const bool has_thickness_factor = thickness_factor != 1.0f || has_thickness_factor_animation;
1310
1311 if (!has_thickness_factor) {
1312 return;
1313 }
1314
1316 GreasePencilThickModifierData *tmd = reinterpret_cast<GreasePencilThickModifierData *>(md);
1317
1318 tmd->thickness_fac = thickness_factor;
1319
1320 STRNCPY_UTF8(md->name, DATA_("Thickness"));
1321 BKE_modifier_unique_name(&dst_object.modifiers, md);
1322
1323 BLI_addtail(&dst_object.modifiers, md);
1324 BKE_modifiers_persistent_uid_init(dst_object, *md);
1325
1326 if (has_thickness_factor_animation) {
1327 char modifier_name_esc[MAX_NAME * 2];
1328 BLI_str_escape(modifier_name_esc, md->name, sizeof(modifier_name_esc));
1329 animdata_thickness_transfer.root_path_dst = fmt::format("modifiers[\"{}\"]",
1330 modifier_name_esc);
1331
1332 animdata_thickness_transfer.fcurves_convert();
1333 }
1334
1335 animdata_thickness_transfer.fcurves_convert_finalize();
1336}
1337
1339{
1340 if (fcurve.bezt) {
1341 for (uint i = 0; i < fcurve.totvert; i++) {
1342 BezTriple &bezier_triple = fcurve.bezt[i];
1343 bezier_triple.vec[0][1] *= LEGACY_RADIUS_CONVERSION_FACTOR;
1344 bezier_triple.vec[1][1] *= LEGACY_RADIUS_CONVERSION_FACTOR;
1345 bezier_triple.vec[2][1] *= LEGACY_RADIUS_CONVERSION_FACTOR;
1346 }
1347 }
1348 if (fcurve.fpt) {
1349 for (uint i = 0; i < fcurve.totvert; i++) {
1350 FPoint &fpoint = fcurve.fpt[i];
1352 }
1353 }
1354 fcurve.flag &= ~FCURVE_INT_VALUES;
1356}
1357
1359 Object &object)
1360{
1361 if (BKE_animdata_from_id(&object.id) == nullptr) {
1362 return;
1363 }
1364
1365 /* NOTE: At this point, the animation was already transferred to the destination object. Now we
1366 * just need to convert the fcurve data to be in the right space. */
1367 AnimDataConvertor animdata_convert_thickness(
1368 conversion_data,
1369 object.id,
1370 object.id,
1371 {{".thickness", ".thickness", fcurve_convert_thickness_cb}});
1372
1373 LISTBASE_FOREACH (ModifierData *, tmd, &object.modifiers) {
1375 continue;
1376 }
1377
1378 char modifier_name[MAX_NAME * 2];
1379 BLI_str_escape(modifier_name, tmd->name, sizeof(modifier_name));
1380 animdata_convert_thickness.root_path_src = fmt::format("modifiers[\"{}\"]", modifier_name);
1381 animdata_convert_thickness.root_path_dst = fmt::format("modifiers[\"{}\"]", modifier_name);
1382
1383 if (!animdata_convert_thickness.source_has_animation_to_convert()) {
1384 continue;
1385 }
1386 animdata_convert_thickness.fcurves_convert();
1387 }
1388
1389 animdata_convert_thickness.fcurves_convert_finalize();
1390 DEG_relations_tag_update(&conversion_data.bmain);
1391}
1392
1394 bGPdata &src_object_data,
1395 Object &dst_object)
1396{
1397 /* Handling of animation here is a bit complex, since paths needs to be updated, but also
1398 * FCurves need to be transferred from legacy GPData animation to Object animation. */
1399 AnimDataConvertor animdata_tint_transfer(
1400 conversion_data,
1401 dst_object.id,
1402 src_object_data.id,
1403 {{".tint_color", ".color"}, {".tint_factor", ".factor"}});
1404
1405 AnimDataConvertor animdata_thickness_transfer(
1406 conversion_data,
1407 dst_object.id,
1408 src_object_data.id,
1409 {{".line_change", "[\"Socket_2\"]", fcurve_convert_thickness_cb}});
1410
1411 /* Replace layer adjustments with modifiers. */
1412 LISTBASE_FOREACH (bGPDlayer *, gpl, &src_object_data.layers) {
1413 const float3 tint_color = float3(gpl->tintcolor);
1414 const float tint_factor = gpl->tintcolor[3];
1415 const int thickness_px = gpl->line_change;
1416
1417 char layer_name_esc[sizeof(gpl->info) * 2];
1418 BLI_str_escape(layer_name_esc, gpl->info, sizeof(layer_name_esc));
1419 animdata_tint_transfer.root_path_src = fmt::format("layers[\"{}\"]", layer_name_esc);
1420 animdata_thickness_transfer.root_path_src = fmt::format("layers[\"{}\"]", layer_name_esc);
1421
1422 const bool has_tint_adjustment_animation =
1423 animdata_tint_transfer.source_has_animation_to_convert();
1424 const bool has_thickness_adjustment_animation =
1425 animdata_thickness_transfer.source_has_animation_to_convert();
1426
1427 /* If tint or thickness are animated, relevant modifiers also need to be created. */
1428 const bool has_tint_adjustment = tint_factor > 0.0f || has_tint_adjustment_animation;
1429 const bool has_thickness_adjustment = thickness_px != 0 || has_thickness_adjustment_animation;
1430
1431 /* Tint adjustment. */
1432 if (has_tint_adjustment) {
1434 GreasePencilTintModifierData *tmd = reinterpret_cast<GreasePencilTintModifierData *>(md);
1435
1436 copy_v3_v3(tmd->color, tint_color);
1437 tmd->factor = tint_factor;
1438 STRNCPY_UTF8(tmd->influence.layer_name, gpl->info);
1439
1440 char modifier_name[MAX_NAME];
1441 SNPRINTF_UTF8(modifier_name, "Tint %s", gpl->info);
1443 BKE_modifier_unique_name(&dst_object.modifiers, md);
1444
1445 BLI_addtail(&dst_object.modifiers, md);
1446 BKE_modifiers_persistent_uid_init(dst_object, *md);
1447
1448 if (has_tint_adjustment_animation) {
1449 char modifier_name_esc[MAX_NAME * 2];
1450 BLI_str_escape(modifier_name_esc, md->name, sizeof(modifier_name_esc));
1451 animdata_tint_transfer.root_path_dst = fmt::format("modifiers[\"{}\"]", modifier_name_esc);
1452
1453 animdata_tint_transfer.fcurves_convert();
1454 }
1455 }
1456 /* Thickness adjustment. */
1457 if (has_thickness_adjustment) {
1458 /* Convert the "pixel" offset value into a radius value.
1459 * GPv2 used a conversion of 1 "px" = 0.001. */
1460 /* NOTE: this offset may be negative. */
1461 const float uniform_object_scale = math::average(float3(dst_object.scale));
1462 const float radius_offset = math::safe_divide(
1463 float(thickness_px) * LEGACY_RADIUS_CONVERSION_FACTOR, uniform_object_scale);
1464
1465 const auto offset_radius_ntree_ensure = [&](Library *owner_library) {
1466 if (bNodeTree **ntree = conversion_data.offset_radius_ntree_by_library.lookup_ptr(
1467 owner_library))
1468 {
1469 /* Node tree has already been found/created for this versioning call. */
1470 return *ntree;
1471 }
1472 /* Try to find an existing group added by previous versioning to avoid adding duplicates.
1473 */
1474 LISTBASE_FOREACH (bNodeTree *, ntree_iter, &conversion_data.bmain.nodetrees) {
1475 if (ntree_iter->id.lib != owner_library) {
1476 continue;
1477 }
1478 if (STREQ(ntree_iter->id.name + 2, OFFSET_RADIUS_NODETREE_NAME)) {
1479 conversion_data.offset_radius_ntree_by_library.add_new(owner_library, ntree_iter);
1480 return ntree_iter;
1481 }
1482 }
1483 bNodeTree *new_ntree = offset_radius_node_tree_add(conversion_data, owner_library);
1484 /* Remove the default user. The count is tracked manually when assigning to modifiers. */
1485 id_us_min(&new_ntree->id);
1486 conversion_data.offset_radius_ntree_by_library.add_new(owner_library, new_ntree);
1487 BKE_ntree_update_after_single_tree_change(conversion_data.bmain, *new_ntree);
1488 return new_ntree;
1489 };
1490 bNodeTree *offset_radius_node_tree = offset_radius_ntree_ensure(dst_object.id.lib);
1491
1492 auto *md = reinterpret_cast<NodesModifierData *>(BKE_modifier_new(eModifierType_Nodes));
1493
1494 char modifier_name[MAX_NAME];
1495 SNPRINTF_UTF8(modifier_name, "Thickness %s", gpl->info);
1496 STRNCPY_UTF8(md->modifier.name, modifier_name);
1497 BKE_modifier_unique_name(&dst_object.modifiers, &md->modifier);
1498 md->node_group = offset_radius_node_tree;
1499
1500 BLI_addtail(&dst_object.modifiers, md);
1501 BKE_modifiers_persistent_uid_init(dst_object, md->modifier);
1502
1503 md->settings.properties = bke::idprop::create_group("Nodes Modifier Settings").release();
1504 IDProperty *radius_offset_prop =
1505 bke::idprop::create(DATA_("Socket_2"), radius_offset).release();
1506 auto *ui_data = reinterpret_cast<IDPropertyUIDataFloat *>(
1507 IDP_ui_data_ensure(radius_offset_prop));
1508 ui_data->soft_min = 0.0;
1509 ui_data->base.rna_subtype = PROP_TRANSLATION;
1510 IDP_AddToGroup(md->settings.properties, radius_offset_prop);
1511 IDP_AddToGroup(md->settings.properties,
1512 bke::idprop::create(DATA_("Socket_3"), gpl->info).release());
1513
1514 if (has_thickness_adjustment_animation) {
1515 char modifier_name_esc[MAX_NAME * 2];
1516 BLI_str_escape(modifier_name_esc, md->modifier.name, sizeof(modifier_name_esc));
1517 animdata_thickness_transfer.root_path_dst = fmt::format("modifiers[\"{}\"]",
1518 modifier_name_esc);
1519
1520 animdata_thickness_transfer.fcurves_convert();
1521 }
1522 }
1523 }
1524
1525 animdata_tint_transfer.fcurves_convert_finalize();
1526 animdata_thickness_transfer.fcurves_convert_finalize();
1527
1528 DEG_relations_tag_update(&conversion_data.bmain);
1529}
1530
1532 Object &object,
1533 const ModifierType type,
1534 GpencilModifierData &legacy_md)
1535{
1536 /* TODO: Copy of most of #ed::object::modifier_add, this should be a BKE_modifiers function
1537 * actually. */
1538 const ModifierTypeInfo *mti = BKE_modifier_get_info(type);
1539
1540 ModifierData &new_md = *BKE_modifier_new(type);
1541
1543 ModifierData *md;
1544 for (md = static_cast<ModifierData *>(object.modifiers.first);
1546 md = md->next)
1547 {
1548 ;
1549 }
1550 BLI_insertlinkbefore(&object.modifiers, md, &new_md);
1551 }
1552 else {
1553 BLI_addtail(&object.modifiers, &new_md);
1554 }
1555
1556 /* Generate new persistent UID and best possible unique name. */
1557 BKE_modifiers_persistent_uid_init(object, new_md);
1558 if (legacy_md.name[0]) {
1559 STRNCPY_UTF8(new_md.name, legacy_md.name);
1560 }
1561 BKE_modifier_unique_name(&object.modifiers, &new_md);
1562
1563 /* Handle common modifier data. */
1564 new_md.mode = legacy_md.mode;
1566
1567 /* Attempt to copy UI state (panels) as best as possible. */
1568 new_md.ui_expand_flag = legacy_md.ui_expand_flag;
1569
1570 /* Convert animation data if needed. */
1571 if (BKE_animdata_from_id(&object.id)) {
1572 AnimDataConvertor anim_convertor(conversion_data, object.id);
1573
1574 char legacy_name_esc[MAX_NAME * 2];
1575 BLI_str_escape(legacy_name_esc, legacy_md.name, sizeof(legacy_name_esc));
1576 anim_convertor.root_path_src = fmt::format("grease_pencil_modifiers[\"{}\"]", legacy_name_esc);
1577
1578 char new_name_esc[MAX_NAME * 2];
1579 BLI_str_escape(new_name_esc, new_md.name, sizeof(new_name_esc));
1580 anim_convertor.root_path_dst = fmt::format("modifiers[\"{}\"]", new_name_esc);
1581
1582 anim_convertor.fcurves_convert();
1583 anim_convertor.fcurves_convert_finalize();
1584 }
1585
1586 return new_md;
1587}
1588
1590 StringRef layername,
1591 const int layer_pass,
1592 const bool invert_layer,
1593 const bool invert_layer_pass,
1594 Material **material,
1595 const int material_pass,
1596 const bool invert_material,
1597 const bool invert_material_pass,
1598 StringRef vertex_group_name,
1599 const bool invert_vertex_group,
1600 CurveMapping **custom_curve,
1601 const bool use_custom_curve)
1602{
1603 influence.flag = 0;
1604
1605 layername.copy_utf8_truncated(influence.layer_name);
1606 if (invert_layer) {
1608 }
1609 influence.layer_pass = layer_pass;
1610 if (layer_pass > 0) {
1612 }
1613 if (invert_layer_pass) {
1615 }
1616
1617 if (material) {
1618 influence.material = *material;
1619 *material = nullptr;
1620 }
1621 if (invert_material) {
1623 }
1624 influence.material_pass = material_pass;
1625 if (material_pass > 0) {
1627 }
1628 if (invert_material_pass) {
1630 }
1631
1632 vertex_group_name.copy_utf8_truncated(influence.vertex_group_name);
1633 if (invert_vertex_group) {
1635 }
1636
1637 if (custom_curve) {
1638 if (influence.custom_curve) {
1640 }
1641 influence.custom_curve = *custom_curve;
1642 *custom_curve = nullptr;
1643 }
1644 if (use_custom_curve) {
1646 }
1647}
1648
1650 Object &object,
1651 GpencilModifierData &legacy_md)
1652{
1654 conversion_data, object, eModifierType_GreasePencilArmature, legacy_md);
1655 auto &md_armature = reinterpret_cast<GreasePencilArmatureModifierData &>(md);
1656 auto &legacy_md_armature = reinterpret_cast<ArmatureGpencilModifierData &>(legacy_md);
1657
1658 md_armature.object = legacy_md_armature.object;
1659 legacy_md_armature.object = nullptr;
1660 md_armature.deformflag = legacy_md_armature.deformflag;
1661
1662 legacy_object_modifier_influence(md_armature.influence,
1663 "",
1664 0,
1665 false,
1666 false,
1667 nullptr,
1668 0,
1669 false,
1670 false,
1671 legacy_md_armature.vgname,
1672 legacy_md_armature.deformflag & ARM_DEF_INVERT_VGROUP,
1673 nullptr,
1674 false);
1675}
1676
1678 Object &object,
1679 GpencilModifierData &legacy_md)
1680{
1682 conversion_data, object, eModifierType_GreasePencilArray, legacy_md);
1683 auto &md_array = reinterpret_cast<GreasePencilArrayModifierData &>(md);
1684 auto &legacy_md_array = reinterpret_cast<ArrayGpencilModifierData &>(legacy_md);
1685
1686 md_array.object = legacy_md_array.object;
1687 legacy_md_array.object = nullptr;
1688 md_array.count = legacy_md_array.count;
1689 md_array.flag = 0;
1690 if (legacy_md_array.flag & GP_ARRAY_UNIFORM_RANDOM_SCALE) {
1692 }
1693 if (legacy_md_array.flag & GP_ARRAY_USE_OB_OFFSET) {
1695 }
1696 if (legacy_md_array.flag & GP_ARRAY_USE_OFFSET) {
1697 md_array.flag |= MOD_GREASE_PENCIL_ARRAY_USE_OFFSET;
1698 }
1699 if (legacy_md_array.flag & GP_ARRAY_USE_RELATIVE) {
1700 md_array.flag |= MOD_GREASE_PENCIL_ARRAY_USE_RELATIVE;
1701 }
1702 copy_v3_v3(md_array.offset, legacy_md_array.offset);
1703 copy_v3_v3(md_array.shift, legacy_md_array.shift);
1704 copy_v3_v3(md_array.rnd_offset, legacy_md_array.rnd_offset);
1705 copy_v3_v3(md_array.rnd_rot, legacy_md_array.rnd_rot);
1706 copy_v3_v3(md_array.rnd_scale, legacy_md_array.rnd_scale);
1707 md_array.seed = legacy_md_array.seed;
1708 md_array.mat_rpl = legacy_md_array.mat_rpl;
1709
1710 legacy_object_modifier_influence(md_array.influence,
1711 legacy_md_array.layername,
1712 legacy_md_array.layer_pass,
1713 legacy_md_array.flag & GP_ARRAY_INVERT_LAYER,
1714 legacy_md_array.flag & GP_ARRAY_INVERT_LAYERPASS,
1715 &legacy_md_array.material,
1716 legacy_md_array.pass_index,
1717 legacy_md_array.flag & GP_ARRAY_INVERT_MATERIAL,
1718 legacy_md_array.flag & GP_ARRAY_INVERT_PASS,
1719 "",
1720 false,
1721 nullptr,
1722 false);
1723}
1724
1726 Object &object,
1727 GpencilModifierData &legacy_md)
1728{
1730 conversion_data, object, eModifierType_GreasePencilColor, legacy_md);
1731 auto &md_color = reinterpret_cast<GreasePencilColorModifierData &>(md);
1732 auto &legacy_md_color = reinterpret_cast<ColorGpencilModifierData &>(legacy_md);
1733
1734 switch (eModifyColorGpencil_Flag(legacy_md_color.modify_color)) {
1736 md_color.color_mode = MOD_GREASE_PENCIL_COLOR_BOTH;
1737 break;
1739 md_color.color_mode = MOD_GREASE_PENCIL_COLOR_STROKE;
1740 break;
1742 md_color.color_mode = MOD_GREASE_PENCIL_COLOR_FILL;
1743 break;
1745 md_color.color_mode = MOD_GREASE_PENCIL_COLOR_HARDNESS;
1746 break;
1747 }
1748 copy_v3_v3(md_color.hsv, legacy_md_color.hsv);
1749
1750 legacy_object_modifier_influence(md_color.influence,
1751 legacy_md_color.layername,
1752 legacy_md_color.layer_pass,
1753 legacy_md_color.flag & GP_COLOR_INVERT_LAYER,
1754 legacy_md_color.flag & GP_COLOR_INVERT_LAYERPASS,
1755 &legacy_md_color.material,
1756 legacy_md_color.pass_index,
1757 legacy_md_color.flag & GP_COLOR_INVERT_MATERIAL,
1758 legacy_md_color.flag & GP_COLOR_INVERT_PASS,
1759 "",
1760 false,
1761 &legacy_md_color.curve_intensity,
1762 legacy_md_color.flag & GP_COLOR_CUSTOM_CURVE);
1763}
1764
1765static void legacy_object_modifier_dash(ConversionData &conversion_data,
1766 Object &object,
1767 GpencilModifierData &legacy_md)
1768{
1770 conversion_data, object, eModifierType_GreasePencilDash, legacy_md);
1771 auto &md_dash = reinterpret_cast<GreasePencilDashModifierData &>(md);
1772 auto &legacy_md_dash = reinterpret_cast<DashGpencilModifierData &>(legacy_md);
1773
1774 md_dash.dash_offset = legacy_md_dash.dash_offset;
1775 md_dash.segment_active_index = legacy_md_dash.segment_active_index;
1776 md_dash.segments_num = legacy_md_dash.segments_len;
1777 MEM_SAFE_FREE(md_dash.segments_array);
1779 legacy_md_dash.segments_len, __func__);
1780 for (const int i : IndexRange(md_dash.segments_num)) {
1781 GreasePencilDashModifierSegment &dst_segment = md_dash.segments_array[i];
1782 const DashGpencilModifierSegment &src_segment = legacy_md_dash.segments[i];
1783 STRNCPY(dst_segment.name, src_segment.name);
1784 dst_segment.flag = 0;
1785 if (src_segment.flag & GP_DASH_USE_CYCLIC) {
1787 }
1788 dst_segment.dash = src_segment.dash;
1789 dst_segment.gap = src_segment.gap;
1790 dst_segment.opacity = src_segment.opacity;
1791 dst_segment.radius = src_segment.radius;
1792 dst_segment.mat_nr = src_segment.mat_nr;
1793 }
1794
1795 legacy_object_modifier_influence(md_dash.influence,
1796 legacy_md_dash.layername,
1797 legacy_md_dash.layer_pass,
1798 legacy_md_dash.flag & GP_DASH_INVERT_LAYER,
1799 legacy_md_dash.flag & GP_DASH_INVERT_LAYERPASS,
1800 &legacy_md_dash.material,
1801 legacy_md_dash.pass_index,
1802 legacy_md_dash.flag & GP_DASH_INVERT_MATERIAL,
1803 legacy_md_dash.flag & GP_DASH_INVERT_PASS,
1804 "",
1805 false,
1806 nullptr,
1807 false);
1808}
1809
1811 Object &object,
1812 GpencilModifierData &legacy_md)
1813{
1815 conversion_data, object, eModifierType_GreasePencilEnvelope, legacy_md);
1816 auto &md_envelope = reinterpret_cast<GreasePencilEnvelopeModifierData &>(md);
1817 auto &legacy_md_envelope = reinterpret_cast<EnvelopeGpencilModifierData &>(legacy_md);
1818
1819 switch (eEnvelopeGpencil_Mode(legacy_md_envelope.mode)) {
1820 case GP_ENVELOPE_DEFORM:
1821 md_envelope.mode = MOD_GREASE_PENCIL_ENVELOPE_DEFORM;
1822 break;
1824 md_envelope.mode = MOD_GREASE_PENCIL_ENVELOPE_SEGMENTS;
1825 break;
1826 case GP_ENVELOPE_FILLS:
1827 md_envelope.mode = MOD_GREASE_PENCIL_ENVELOPE_FILLS;
1828 break;
1829 }
1830 md_envelope.mat_nr = legacy_md_envelope.mat_nr;
1831 md_envelope.thickness = legacy_md_envelope.thickness;
1832 md_envelope.strength = legacy_md_envelope.strength;
1833 md_envelope.skip = legacy_md_envelope.skip;
1834 md_envelope.spread = legacy_md_envelope.spread;
1835
1836 legacy_object_modifier_influence(md_envelope.influence,
1837 legacy_md_envelope.layername,
1838 legacy_md_envelope.layer_pass,
1839 legacy_md_envelope.flag & GP_ENVELOPE_INVERT_LAYER,
1840 legacy_md_envelope.flag & GP_ENVELOPE_INVERT_LAYERPASS,
1841 &legacy_md_envelope.material,
1842 legacy_md_envelope.pass_index,
1843 legacy_md_envelope.flag & GP_ENVELOPE_INVERT_MATERIAL,
1844 legacy_md_envelope.flag & GP_ENVELOPE_INVERT_PASS,
1845 legacy_md_envelope.vgname,
1846 legacy_md_envelope.flag & GP_ENVELOPE_INVERT_VGROUP,
1847 nullptr,
1848 false);
1849}
1850
1851static void legacy_object_modifier_hook(ConversionData &conversion_data,
1852 Object &object,
1853 GpencilModifierData &legacy_md)
1854{
1856 conversion_data, object, eModifierType_GreasePencilHook, legacy_md);
1857 auto &md_hook = reinterpret_cast<GreasePencilHookModifierData &>(md);
1858 auto &legacy_md_hook = reinterpret_cast<HookGpencilModifierData &>(legacy_md);
1859
1860 md_hook.flag = 0;
1861 if (legacy_md_hook.flag & GP_HOOK_UNIFORM_SPACE) {
1863 }
1864 switch (eHookGpencil_Falloff(legacy_md_hook.falloff_type)) {
1866 md_hook.falloff_type = MOD_GREASE_PENCIL_HOOK_Falloff_None;
1867 break;
1869 md_hook.falloff_type = MOD_GREASE_PENCIL_HOOK_Falloff_Curve;
1870 break;
1872 md_hook.falloff_type = MOD_GREASE_PENCIL_HOOK_Falloff_Sharp;
1873 break;
1875 md_hook.falloff_type = MOD_GREASE_PENCIL_HOOK_Falloff_Smooth;
1876 break;
1878 md_hook.falloff_type = MOD_GREASE_PENCIL_HOOK_Falloff_Root;
1879 break;
1881 md_hook.falloff_type = MOD_GREASE_PENCIL_HOOK_Falloff_Linear;
1882 break;
1884 md_hook.falloff_type = MOD_GREASE_PENCIL_HOOK_Falloff_Const;
1885 break;
1887 md_hook.falloff_type = MOD_GREASE_PENCIL_HOOK_Falloff_Sphere;
1888 break;
1890 md_hook.falloff_type = MOD_GREASE_PENCIL_HOOK_Falloff_InvSquare;
1891 break;
1892 }
1893 md_hook.object = legacy_md_hook.object;
1894 legacy_md_hook.object = nullptr;
1895 STRNCPY(md_hook.subtarget, legacy_md_hook.subtarget);
1896 copy_m4_m4(md_hook.parentinv, legacy_md_hook.parentinv);
1897 copy_v3_v3(md_hook.cent, legacy_md_hook.cent);
1898 md_hook.falloff = legacy_md_hook.falloff;
1899 md_hook.force = legacy_md_hook.force;
1900
1901 legacy_object_modifier_influence(md_hook.influence,
1902 legacy_md_hook.layername,
1903 legacy_md_hook.layer_pass,
1904 legacy_md_hook.flag & GP_HOOK_INVERT_LAYER,
1905 legacy_md_hook.flag & GP_HOOK_INVERT_LAYERPASS,
1906 &legacy_md_hook.material,
1907 legacy_md_hook.pass_index,
1908 legacy_md_hook.flag & GP_HOOK_INVERT_MATERIAL,
1909 legacy_md_hook.flag & GP_HOOK_INVERT_PASS,
1910 legacy_md_hook.vgname,
1911 legacy_md_hook.flag & GP_HOOK_INVERT_VGROUP,
1912 &legacy_md_hook.curfalloff,
1913 true);
1914}
1915
1917 Object &object,
1918 GpencilModifierData &legacy_md)
1919{
1921 conversion_data, object, eModifierType_GreasePencilLattice, legacy_md);
1922 auto &md_lattice = reinterpret_cast<GreasePencilLatticeModifierData &>(md);
1923 auto &legacy_md_lattice = reinterpret_cast<LatticeGpencilModifierData &>(legacy_md);
1924
1925 md_lattice.object = legacy_md_lattice.object;
1926 legacy_md_lattice.object = nullptr;
1927 md_lattice.strength = legacy_md_lattice.strength;
1928
1929 legacy_object_modifier_influence(md_lattice.influence,
1930 legacy_md_lattice.layername,
1931 legacy_md_lattice.layer_pass,
1932 legacy_md_lattice.flag & GP_LATTICE_INVERT_LAYER,
1933 legacy_md_lattice.flag & GP_LATTICE_INVERT_LAYERPASS,
1934 &legacy_md_lattice.material,
1935 legacy_md_lattice.pass_index,
1936 legacy_md_lattice.flag & GP_LATTICE_INVERT_MATERIAL,
1937 legacy_md_lattice.flag & GP_LATTICE_INVERT_PASS,
1938 legacy_md_lattice.vgname,
1939 legacy_md_lattice.flag & GP_LATTICE_INVERT_VGROUP,
1940 nullptr,
1941 false);
1942}
1943
1945 Object &object,
1946 GpencilModifierData &legacy_md)
1947{
1949 conversion_data, object, eModifierType_GreasePencilLength, legacy_md);
1950 auto &md_length = reinterpret_cast<GreasePencilLengthModifierData &>(md);
1951 auto &legacy_md_length = reinterpret_cast<LengthGpencilModifierData &>(legacy_md);
1952
1953 md_length.flag = legacy_md_length.flag;
1954 md_length.start_fac = legacy_md_length.start_fac;
1955 md_length.end_fac = legacy_md_length.end_fac;
1956 md_length.rand_start_fac = legacy_md_length.rand_start_fac;
1957 md_length.rand_end_fac = legacy_md_length.rand_end_fac;
1958 md_length.rand_offset = legacy_md_length.rand_offset;
1959 md_length.overshoot_fac = legacy_md_length.overshoot_fac;
1960 md_length.seed = legacy_md_length.seed;
1961 md_length.step = legacy_md_length.step;
1962 md_length.mode = legacy_md_length.mode;
1963 md_length.point_density = legacy_md_length.point_density;
1964 md_length.segment_influence = legacy_md_length.segment_influence;
1965 md_length.max_angle = legacy_md_length.max_angle;
1966
1967 legacy_object_modifier_influence(md_length.influence,
1968 legacy_md_length.layername,
1969 legacy_md_length.layer_pass,
1970 legacy_md_length.flag & GP_LENGTH_INVERT_LAYER,
1971 legacy_md_length.flag & GP_LENGTH_INVERT_LAYERPASS,
1972 &legacy_md_length.material,
1973 legacy_md_length.pass_index,
1974 legacy_md_length.flag & GP_LENGTH_INVERT_MATERIAL,
1975 legacy_md_length.flag & GP_LENGTH_INVERT_PASS,
1976 "",
1977 false,
1978 nullptr,
1979 false);
1980}
1981
1983 Object &object,
1984 GpencilModifierData &legacy_md)
1985{
1987 conversion_data, object, eModifierType_GreasePencilMirror, legacy_md);
1988 auto &md_mirror = reinterpret_cast<GreasePencilMirrorModifierData &>(md);
1989 auto &legacy_md_mirror = reinterpret_cast<MirrorGpencilModifierData &>(legacy_md);
1990
1991 md_mirror.object = legacy_md_mirror.object;
1992 legacy_md_mirror.object = nullptr;
1993 md_mirror.flag = 0;
1994 if (legacy_md_mirror.flag & GP_MIRROR_AXIS_X) {
1995 md_mirror.flag |= MOD_GREASE_PENCIL_MIRROR_AXIS_X;
1996 }
1997 if (legacy_md_mirror.flag & GP_MIRROR_AXIS_Y) {
1998 md_mirror.flag |= MOD_GREASE_PENCIL_MIRROR_AXIS_Y;
1999 }
2000 if (legacy_md_mirror.flag & GP_MIRROR_AXIS_Z) {
2001 md_mirror.flag |= MOD_GREASE_PENCIL_MIRROR_AXIS_Z;
2002 }
2003
2004 legacy_object_modifier_influence(md_mirror.influence,
2005 legacy_md_mirror.layername,
2006 legacy_md_mirror.layer_pass,
2007 legacy_md_mirror.flag & GP_MIRROR_INVERT_LAYER,
2008 legacy_md_mirror.flag & GP_MIRROR_INVERT_LAYERPASS,
2009 &legacy_md_mirror.material,
2010 legacy_md_mirror.pass_index,
2011 legacy_md_mirror.flag & GP_MIRROR_INVERT_MATERIAL,
2012 legacy_md_mirror.flag & GP_MIRROR_INVERT_PASS,
2013 "",
2014 false,
2015 nullptr,
2016 false);
2017}
2018
2020 Object &object,
2021 GpencilModifierData &legacy_md)
2022{
2024 conversion_data, object, eModifierType_GreasePencilMultiply, legacy_md);
2025 auto &md_multiply = reinterpret_cast<GreasePencilMultiModifierData &>(md);
2026 auto &legacy_md_multiply = reinterpret_cast<MultiplyGpencilModifierData &>(legacy_md);
2027
2028 md_multiply.flag = 0;
2029 if (legacy_md_multiply.flags & GP_MULTIPLY_ENABLE_FADING) {
2030 md_multiply.flag |= MOD_GREASE_PENCIL_MULTIPLY_ENABLE_FADING;
2031 }
2032 md_multiply.duplications = legacy_md_multiply.duplications;
2033 md_multiply.distance = legacy_md_multiply.distance;
2034 md_multiply.offset = legacy_md_multiply.offset;
2035 md_multiply.fading_center = legacy_md_multiply.fading_center;
2036 md_multiply.fading_thickness = legacy_md_multiply.fading_thickness;
2037 md_multiply.fading_opacity = legacy_md_multiply.fading_opacity;
2038
2039 /* NOTE: This looks wrong, but GPv2 version uses Mirror modifier flags in its `flag` property
2040 * and own flags in its `flags` property. */
2041 legacy_object_modifier_influence(md_multiply.influence,
2042 legacy_md_multiply.layername,
2043 legacy_md_multiply.layer_pass,
2044 legacy_md_multiply.flag & GP_MIRROR_INVERT_LAYER,
2045 legacy_md_multiply.flag & GP_MIRROR_INVERT_LAYERPASS,
2046 &legacy_md_multiply.material,
2047 legacy_md_multiply.pass_index,
2048 legacy_md_multiply.flag & GP_MIRROR_INVERT_MATERIAL,
2049 legacy_md_multiply.flag & GP_MIRROR_INVERT_PASS,
2050 "",
2051 false,
2052 nullptr,
2053 false);
2054}
2055
2057 Object &object,
2058 GpencilModifierData &legacy_md)
2059{
2061 conversion_data, object, eModifierType_GreasePencilNoise, legacy_md);
2062 auto &md_noise = reinterpret_cast<GreasePencilNoiseModifierData &>(md);
2063 auto &legacy_md_noise = reinterpret_cast<NoiseGpencilModifierData &>(legacy_md);
2064
2065 md_noise.flag = legacy_md_noise.flag;
2066 md_noise.factor = legacy_md_noise.factor;
2067 md_noise.factor_strength = legacy_md_noise.factor_strength;
2068 md_noise.factor_thickness = legacy_md_noise.factor_thickness;
2069 md_noise.factor_uvs = legacy_md_noise.factor_uvs;
2070 md_noise.noise_scale = legacy_md_noise.noise_scale;
2071 md_noise.noise_offset = legacy_md_noise.noise_offset;
2072 md_noise.noise_mode = legacy_md_noise.noise_mode;
2073 md_noise.step = legacy_md_noise.step;
2074 md_noise.seed = legacy_md_noise.seed;
2075
2076 legacy_object_modifier_influence(md_noise.influence,
2077 legacy_md_noise.layername,
2078 legacy_md_noise.layer_pass,
2079 legacy_md_noise.flag & GP_NOISE_INVERT_LAYER,
2080 legacy_md_noise.flag & GP_NOISE_INVERT_LAYERPASS,
2081 &legacy_md_noise.material,
2082 legacy_md_noise.pass_index,
2083 legacy_md_noise.flag & GP_NOISE_INVERT_MATERIAL,
2084 legacy_md_noise.flag & GP_NOISE_INVERT_PASS,
2085 legacy_md_noise.vgname,
2086 legacy_md_noise.flag & GP_NOISE_INVERT_VGROUP,
2087 &legacy_md_noise.curve_intensity,
2088 legacy_md_noise.flag & GP_NOISE_CUSTOM_CURVE);
2089}
2090
2092 Object &object,
2093 GpencilModifierData &legacy_md)
2094{
2096 conversion_data, object, eModifierType_GreasePencilOffset, legacy_md);
2097 auto &md_offset = reinterpret_cast<GreasePencilOffsetModifierData &>(md);
2098 auto &legacy_md_offset = reinterpret_cast<OffsetGpencilModifierData &>(legacy_md);
2099
2100 md_offset.flag = 0;
2101 if (legacy_md_offset.flag & GP_OFFSET_UNIFORM_RANDOM_SCALE) {
2103 }
2104 switch (eOffsetGpencil_Mode(legacy_md_offset.mode)) {
2105 case GP_OFFSET_RANDOM:
2106 md_offset.offset_mode = MOD_GREASE_PENCIL_OFFSET_RANDOM;
2107 break;
2108 case GP_OFFSET_LAYER:
2109 md_offset.offset_mode = MOD_GREASE_PENCIL_OFFSET_LAYER;
2110 break;
2111 case GP_OFFSET_MATERIAL:
2112 md_offset.offset_mode = MOD_GREASE_PENCIL_OFFSET_MATERIAL;
2113 break;
2114 case GP_OFFSET_STROKE:
2115 md_offset.offset_mode = MOD_GREASE_PENCIL_OFFSET_STROKE;
2116 break;
2117 }
2118 copy_v3_v3(md_offset.loc, legacy_md_offset.loc);
2119 copy_v3_v3(md_offset.rot, legacy_md_offset.rot);
2120 copy_v3_v3(md_offset.scale, legacy_md_offset.scale);
2121 copy_v3_v3(md_offset.stroke_loc, legacy_md_offset.rnd_offset);
2122 copy_v3_v3(md_offset.stroke_rot, legacy_md_offset.rnd_rot);
2123 copy_v3_v3(md_offset.stroke_scale, legacy_md_offset.rnd_scale);
2124 md_offset.seed = legacy_md_offset.seed;
2125 md_offset.stroke_step = legacy_md_offset.stroke_step;
2126 md_offset.stroke_start_offset = legacy_md_offset.stroke_start_offset;
2127
2128 legacy_object_modifier_influence(md_offset.influence,
2129 legacy_md_offset.layername,
2130 legacy_md_offset.layer_pass,
2131 legacy_md_offset.flag & GP_OFFSET_INVERT_LAYER,
2132 legacy_md_offset.flag & GP_OFFSET_INVERT_LAYERPASS,
2133 &legacy_md_offset.material,
2134 legacy_md_offset.pass_index,
2135 legacy_md_offset.flag & GP_OFFSET_INVERT_MATERIAL,
2136 legacy_md_offset.flag & GP_OFFSET_INVERT_PASS,
2137 legacy_md_offset.vgname,
2138 legacy_md_offset.flag & GP_OFFSET_INVERT_VGROUP,
2139 nullptr,
2140 false);
2141}
2142
2144 Object &object,
2145 GpencilModifierData &legacy_md)
2146{
2148 conversion_data, object, eModifierType_GreasePencilOpacity, legacy_md);
2149 auto &md_opacity = reinterpret_cast<GreasePencilOpacityModifierData &>(md);
2150 auto &legacy_md_opacity = reinterpret_cast<OpacityGpencilModifierData &>(legacy_md);
2151
2152 md_opacity.flag = 0;
2153 if (legacy_md_opacity.flag & GP_OPACITY_NORMALIZE) {
2155 }
2156 if (legacy_md_opacity.flag & GP_OPACITY_WEIGHT_FACTOR) {
2158 }
2159 switch (eModifyColorGpencil_Flag(legacy_md_opacity.modify_color)) {
2161 md_opacity.color_mode = MOD_GREASE_PENCIL_COLOR_BOTH;
2162 break;
2164 md_opacity.color_mode = MOD_GREASE_PENCIL_COLOR_STROKE;
2165 break;
2167 md_opacity.color_mode = MOD_GREASE_PENCIL_COLOR_FILL;
2168 break;
2170 md_opacity.color_mode = MOD_GREASE_PENCIL_COLOR_HARDNESS;
2171 break;
2172 }
2173 md_opacity.color_factor = legacy_md_opacity.factor;
2174 md_opacity.hardness_factor = legacy_md_opacity.hardness;
2175
2176 /* Account for animation on renamed properties. */
2177 char modifier_name[MAX_NAME * 2];
2179 AnimDataConvertor anim_convertor_factor(
2180 conversion_data, object.id, object.id, {{".factor", ".color_factor"}});
2181 anim_convertor_factor.root_path_src = fmt::format("modifiers[\"{}\"]", modifier_name);
2182 anim_convertor_factor.root_path_dst = fmt::format("modifiers[\"{}\"]", modifier_name);
2183 anim_convertor_factor.fcurves_convert();
2184 anim_convertor_factor.fcurves_convert_finalize();
2185 AnimDataConvertor anim_convertor_hardness(
2186 conversion_data, object.id, object.id, {{".hardness", ".hardness_factor"}});
2187 anim_convertor_hardness.root_path_src = fmt::format("modifiers[\"{}\"]", modifier_name);
2188 anim_convertor_hardness.root_path_dst = fmt::format("modifiers[\"{}\"]", modifier_name);
2189 anim_convertor_hardness.fcurves_convert();
2190 anim_convertor_hardness.fcurves_convert_finalize();
2191 DEG_relations_tag_update(&conversion_data.bmain);
2192
2193 legacy_object_modifier_influence(md_opacity.influence,
2194 legacy_md_opacity.layername,
2195 legacy_md_opacity.layer_pass,
2196 legacy_md_opacity.flag & GP_OPACITY_INVERT_LAYER,
2197 legacy_md_opacity.flag & GP_OPACITY_INVERT_LAYERPASS,
2198 &legacy_md_opacity.material,
2199 legacy_md_opacity.pass_index,
2200 legacy_md_opacity.flag & GP_OPACITY_INVERT_MATERIAL,
2201 legacy_md_opacity.flag & GP_OPACITY_INVERT_PASS,
2202 legacy_md_opacity.vgname,
2203 legacy_md_opacity.flag & GP_OPACITY_INVERT_VGROUP,
2204 &legacy_md_opacity.curve_intensity,
2205 legacy_md_opacity.flag & GP_OPACITY_CUSTOM_CURVE);
2206}
2207
2209 Object &object,
2210 GpencilModifierData &legacy_md)
2211{
2213 conversion_data, object, eModifierType_GreasePencilOutline, legacy_md);
2214 auto &md_outline = reinterpret_cast<GreasePencilOutlineModifierData &>(md);
2215 auto &legacy_md_outline = reinterpret_cast<OutlineGpencilModifierData &>(legacy_md);
2216
2217 md_outline.flag = 0;
2218 if (legacy_md_outline.flag & GP_OUTLINE_KEEP_SHAPE) {
2219 md_outline.flag |= MOD_GREASE_PENCIL_OUTLINE_KEEP_SHAPE;
2220 }
2221 md_outline.object = legacy_md_outline.object;
2222 legacy_md_outline.object = nullptr;
2223 md_outline.outline_material = legacy_md_outline.outline_material;
2224 legacy_md_outline.outline_material = nullptr;
2225 md_outline.sample_length = legacy_md_outline.sample_length;
2226 md_outline.subdiv = legacy_md_outline.subdiv;
2227 md_outline.thickness = legacy_md_outline.thickness;
2228
2229 legacy_object_modifier_influence(md_outline.influence,
2230 legacy_md_outline.layername,
2231 legacy_md_outline.layer_pass,
2232 legacy_md_outline.flag & GP_OUTLINE_INVERT_LAYER,
2233 legacy_md_outline.flag & GP_OUTLINE_INVERT_LAYERPASS,
2234 &legacy_md_outline.material,
2235 legacy_md_outline.pass_index,
2236 legacy_md_outline.flag & GP_OUTLINE_INVERT_MATERIAL,
2237 legacy_md_outline.flag & GP_OUTLINE_INVERT_PASS,
2238 "",
2239 false,
2240 nullptr,
2241 false);
2242}
2243
2245 Object &object,
2246 GpencilModifierData &legacy_md)
2247{
2249 conversion_data, object, eModifierType_GreasePencilShrinkwrap, legacy_md);
2250 auto &md_shrinkwrap = reinterpret_cast<GreasePencilShrinkwrapModifierData &>(md);
2251 auto &legacy_md_shrinkwrap = reinterpret_cast<ShrinkwrapGpencilModifierData &>(legacy_md);
2252
2253 /* Shrinkwrap enums and flags do not have named types. */
2254 /* MOD_SHRINKWRAP_NEAREST_SURFACE etc. */
2255 md_shrinkwrap.shrink_type = legacy_md_shrinkwrap.shrink_type;
2256 /* MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR etc. */
2257 md_shrinkwrap.shrink_opts = legacy_md_shrinkwrap.shrink_opts;
2258 /* MOD_SHRINKWRAP_ON_SURFACE etc. */
2259 md_shrinkwrap.shrink_mode = legacy_md_shrinkwrap.shrink_mode;
2260 /* MOD_SHRINKWRAP_PROJECT_OVER_NORMAL etc. */
2261 md_shrinkwrap.proj_axis = legacy_md_shrinkwrap.proj_axis;
2262
2263 md_shrinkwrap.target = legacy_md_shrinkwrap.target;
2264 legacy_md_shrinkwrap.target = nullptr;
2265 md_shrinkwrap.aux_target = legacy_md_shrinkwrap.aux_target;
2266 legacy_md_shrinkwrap.aux_target = nullptr;
2267 md_shrinkwrap.keep_dist = legacy_md_shrinkwrap.keep_dist;
2268 md_shrinkwrap.proj_limit = legacy_md_shrinkwrap.proj_limit;
2269 md_shrinkwrap.subsurf_levels = legacy_md_shrinkwrap.subsurf_levels;
2270 md_shrinkwrap.smooth_factor = legacy_md_shrinkwrap.smooth_factor;
2271 md_shrinkwrap.smooth_step = legacy_md_shrinkwrap.smooth_step;
2272
2273 legacy_object_modifier_influence(md_shrinkwrap.influence,
2274 legacy_md_shrinkwrap.layername,
2275 legacy_md_shrinkwrap.layer_pass,
2276 legacy_md_shrinkwrap.flag & GP_SHRINKWRAP_INVERT_LAYER,
2277 legacy_md_shrinkwrap.flag & GP_SHRINKWRAP_INVERT_LAYERPASS,
2278 &legacy_md_shrinkwrap.material,
2279 legacy_md_shrinkwrap.pass_index,
2280 legacy_md_shrinkwrap.flag & GP_SHRINKWRAP_INVERT_MATERIAL,
2281 legacy_md_shrinkwrap.flag & GP_SHRINKWRAP_INVERT_PASS,
2282 legacy_md_shrinkwrap.vgname,
2283 legacy_md_shrinkwrap.flag & GP_SHRINKWRAP_INVERT_VGROUP,
2284 nullptr,
2285 false);
2286}
2287
2289 Object &object,
2290 GpencilModifierData &legacy_md)
2291{
2293 conversion_data, object, eModifierType_GreasePencilSmooth, legacy_md);
2294 auto &md_smooth = reinterpret_cast<GreasePencilSmoothModifierData &>(md);
2295 auto &legacy_md_smooth = reinterpret_cast<SmoothGpencilModifierData &>(legacy_md);
2296
2297 md_smooth.flag = 0;
2298 if (legacy_md_smooth.flag & GP_SMOOTH_MOD_LOCATION) {
2299 md_smooth.flag |= MOD_GREASE_PENCIL_SMOOTH_MOD_LOCATION;
2300 }
2301 if (legacy_md_smooth.flag & GP_SMOOTH_MOD_STRENGTH) {
2302 md_smooth.flag |= MOD_GREASE_PENCIL_SMOOTH_MOD_STRENGTH;
2303 }
2304 if (legacy_md_smooth.flag & GP_SMOOTH_MOD_THICKNESS) {
2306 }
2307 if (legacy_md_smooth.flag & GP_SMOOTH_MOD_UV) {
2308 md_smooth.flag |= MOD_GREASE_PENCIL_SMOOTH_MOD_UV;
2309 }
2310 if (legacy_md_smooth.flag & GP_SMOOTH_KEEP_SHAPE) {
2311 md_smooth.flag |= MOD_GREASE_PENCIL_SMOOTH_KEEP_SHAPE;
2312 }
2313 md_smooth.factor = legacy_md_smooth.factor;
2314 md_smooth.step = legacy_md_smooth.step;
2315
2316 legacy_object_modifier_influence(md_smooth.influence,
2317 legacy_md_smooth.layername,
2318 legacy_md_smooth.layer_pass,
2319 legacy_md_smooth.flag & GP_SMOOTH_INVERT_LAYER,
2320 legacy_md_smooth.flag & GP_SMOOTH_INVERT_LAYERPASS,
2321 &legacy_md_smooth.material,
2322 legacy_md_smooth.pass_index,
2323 legacy_md_smooth.flag & GP_SMOOTH_INVERT_MATERIAL,
2324 legacy_md_smooth.flag & GP_SMOOTH_INVERT_PASS,
2325 legacy_md_smooth.vgname,
2326 legacy_md_smooth.flag & GP_SMOOTH_INVERT_VGROUP,
2327 &legacy_md_smooth.curve_intensity,
2328 legacy_md_smooth.flag & GP_SMOOTH_CUSTOM_CURVE);
2329}
2330
2332 Object &object,
2333 GpencilModifierData &legacy_md)
2334{
2336 conversion_data, object, eModifierType_GreasePencilSubdiv, legacy_md);
2337 auto &md_subdiv = reinterpret_cast<GreasePencilSubdivModifierData &>(md);
2338 auto &legacy_md_subdiv = reinterpret_cast<SubdivGpencilModifierData &>(legacy_md);
2339
2340 switch (eSubdivGpencil_Type(legacy_md_subdiv.type)) {
2341 case GP_SUBDIV_CATMULL:
2342 md_subdiv.type = MOD_GREASE_PENCIL_SUBDIV_CATMULL;
2343 break;
2344 case GP_SUBDIV_SIMPLE:
2345 md_subdiv.type = MOD_GREASE_PENCIL_SUBDIV_SIMPLE;
2346 break;
2347 }
2348 md_subdiv.level = legacy_md_subdiv.level;
2349
2350 legacy_object_modifier_influence(md_subdiv.influence,
2351 legacy_md_subdiv.layername,
2352 legacy_md_subdiv.layer_pass,
2353 legacy_md_subdiv.flag & GP_SUBDIV_INVERT_LAYER,
2354 legacy_md_subdiv.flag & GP_SUBDIV_INVERT_LAYERPASS,
2355 &legacy_md_subdiv.material,
2356 legacy_md_subdiv.pass_index,
2357 legacy_md_subdiv.flag & GP_SUBDIV_INVERT_MATERIAL,
2358 legacy_md_subdiv.flag & GP_SUBDIV_INVERT_PASS,
2359 "",
2360 false,
2361 nullptr,
2362 false);
2363}
2364
2366 Object &object,
2367 GpencilModifierData &legacy_md)
2368{
2370 conversion_data, object, eModifierType_GreasePencilTexture, legacy_md);
2371 auto &md_texture = reinterpret_cast<GreasePencilTextureModifierData &>(md);
2372 auto &legacy_md_texture = reinterpret_cast<TextureGpencilModifierData &>(legacy_md);
2373
2374 switch (eTextureGpencil_Mode(legacy_md_texture.mode)) {
2375 case STROKE:
2376 md_texture.mode = MOD_GREASE_PENCIL_TEXTURE_STROKE;
2377 break;
2378 case FILL:
2379 md_texture.mode = MOD_GREASE_PENCIL_TEXTURE_FILL;
2380 break;
2381 case STROKE_AND_FILL:
2383 break;
2384 }
2385 switch (eTextureGpencil_Fit(legacy_md_texture.fit_method)) {
2386 case GP_TEX_FIT_STROKE:
2387 md_texture.fit_method = MOD_GREASE_PENCIL_TEXTURE_FIT_STROKE;
2388 break;
2390 md_texture.fit_method = MOD_GREASE_PENCIL_TEXTURE_CONSTANT_LENGTH;
2391 break;
2392 }
2393 md_texture.uv_offset = legacy_md_texture.uv_offset;
2394 md_texture.uv_scale = legacy_md_texture.uv_scale;
2395 md_texture.fill_rotation = legacy_md_texture.fill_rotation;
2396 copy_v2_v2(md_texture.fill_offset, legacy_md_texture.fill_offset);
2397 md_texture.fill_scale = legacy_md_texture.fill_scale;
2398 md_texture.layer_pass = legacy_md_texture.layer_pass;
2399 md_texture.alignment_rotation = legacy_md_texture.alignment_rotation;
2400
2401 legacy_object_modifier_influence(md_texture.influence,
2402 legacy_md_texture.layername,
2403 legacy_md_texture.layer_pass,
2404 legacy_md_texture.flag & GP_TEX_INVERT_LAYER,
2405 legacy_md_texture.flag & GP_TEX_INVERT_LAYERPASS,
2406 &legacy_md_texture.material,
2407 legacy_md_texture.pass_index,
2408 legacy_md_texture.flag & GP_TEX_INVERT_MATERIAL,
2409 legacy_md_texture.flag & GP_TEX_INVERT_PASS,
2410 legacy_md_texture.vgname,
2411 legacy_md_texture.flag & GP_TEX_INVERT_VGROUP,
2412 nullptr,
2413 false);
2414}
2415
2417 Object &object,
2418 GpencilModifierData &legacy_md)
2419{
2421 conversion_data, object, eModifierType_GreasePencilThickness, legacy_md);
2422 auto &md_thickness = reinterpret_cast<GreasePencilThickModifierData &>(md);
2423 auto &legacy_md_thickness = reinterpret_cast<ThickGpencilModifierData &>(legacy_md);
2424
2425 md_thickness.flag = 0;
2426 if (legacy_md_thickness.flag & GP_THICK_NORMALIZE) {
2427 md_thickness.flag |= MOD_GREASE_PENCIL_THICK_NORMALIZE;
2428 }
2429 if (legacy_md_thickness.flag & GP_THICK_WEIGHT_FACTOR) {
2430 md_thickness.flag |= MOD_GREASE_PENCIL_THICK_WEIGHT_FACTOR;
2431 }
2432 md_thickness.thickness_fac = legacy_md_thickness.thickness_fac;
2433 md_thickness.thickness = legacy_md_thickness.thickness * LEGACY_RADIUS_CONVERSION_FACTOR;
2434
2435 legacy_object_modifier_influence(md_thickness.influence,
2436 legacy_md_thickness.layername,
2437 legacy_md_thickness.layer_pass,
2438 legacy_md_thickness.flag & GP_THICK_INVERT_LAYER,
2439 legacy_md_thickness.flag & GP_THICK_INVERT_LAYERPASS,
2440 &legacy_md_thickness.material,
2441 legacy_md_thickness.pass_index,
2442 legacy_md_thickness.flag & GP_THICK_INVERT_MATERIAL,
2443 legacy_md_thickness.flag & GP_THICK_INVERT_PASS,
2444 legacy_md_thickness.vgname,
2445 legacy_md_thickness.flag & GP_THICK_INVERT_VGROUP,
2446 &legacy_md_thickness.curve_thickness,
2447 legacy_md_thickness.flag & GP_THICK_CUSTOM_CURVE);
2448}
2449
2450static void legacy_object_modifier_time(ConversionData &conversion_data,
2451 Object &object,
2452 GpencilModifierData &legacy_md)
2453{
2455 conversion_data, object, eModifierType_GreasePencilTime, legacy_md);
2456 auto &md_time = reinterpret_cast<GreasePencilTimeModifierData &>(md);
2457 auto &legacy_md_time = reinterpret_cast<TimeGpencilModifierData &>(legacy_md);
2458
2459 md_time.flag = 0;
2460 if (legacy_md_time.flag & GP_TIME_CUSTOM_RANGE) {
2462 }
2463 if (legacy_md_time.flag & GP_TIME_KEEP_LOOP) {
2464 md_time.flag |= MOD_GREASE_PENCIL_TIME_KEEP_LOOP;
2465 }
2466 switch (eTimeGpencil_Mode(legacy_md_time.mode)) {
2469 break;
2472 break;
2473 case GP_TIME_MODE_FIX:
2474 md_time.mode = MOD_GREASE_PENCIL_TIME_MODE_FIX;
2475 break;
2478 break;
2479 case GP_TIME_MODE_CHAIN:
2480 md_time.mode = MOD_GREASE_PENCIL_TIME_MODE_CHAIN;
2481 break;
2482 }
2483 md_time.offset = legacy_md_time.offset;
2484 md_time.frame_scale = legacy_md_time.frame_scale;
2485 md_time.sfra = legacy_md_time.sfra;
2486 md_time.efra = legacy_md_time.efra;
2487 md_time.segment_active_index = legacy_md_time.segment_active_index;
2488 md_time.segments_num = legacy_md_time.segments_len;
2489 MEM_SAFE_FREE(md_time.segments_array);
2491 legacy_md_time.segments_len, __func__);
2492 for (const int i : IndexRange(md_time.segments_num)) {
2493 GreasePencilTimeModifierSegment &dst_segment = md_time.segments_array[i];
2494 const TimeGpencilModifierSegment &src_segment = legacy_md_time.segments[i];
2495 STRNCPY(dst_segment.name, src_segment.name);
2496 switch (eTimeGpencil_Seg_Mode(src_segment.seg_mode)) {
2499 break;
2502 break;
2505 break;
2506 }
2507 dst_segment.segment_start = src_segment.seg_start;
2508 dst_segment.segment_end = src_segment.seg_end;
2509 dst_segment.segment_repeat = src_segment.seg_repeat;
2510 }
2511
2512 /* NOTE: GPv2 time modifier has a material pointer but it is unused. */
2513 legacy_object_modifier_influence(md_time.influence,
2514 legacy_md_time.layername,
2515 legacy_md_time.layer_pass,
2516 legacy_md_time.flag & GP_TIME_INVERT_LAYER,
2517 legacy_md_time.flag & GP_TIME_INVERT_LAYERPASS,
2518 nullptr,
2519 0,
2520 false,
2521 false,
2522 "",
2523 false,
2524 nullptr,
2525 false);
2526}
2527
2528static void legacy_object_modifier_tint(ConversionData &conversion_data,
2529 Object &object,
2530 GpencilModifierData &legacy_md)
2531{
2533 conversion_data, object, eModifierType_GreasePencilTint, legacy_md);
2534 auto &md_tint = reinterpret_cast<GreasePencilTintModifierData &>(md);
2535 auto &legacy_md_tint = reinterpret_cast<TintGpencilModifierData &>(legacy_md);
2536
2537 md_tint.flag = 0;
2538 if (legacy_md_tint.flag & GP_TINT_WEIGHT_FACTOR) {
2540 }
2541 switch (eGp_Vertex_Mode(legacy_md_tint.mode)) {
2542 case GPPAINT_MODE_BOTH:
2543 md_tint.color_mode = MOD_GREASE_PENCIL_COLOR_BOTH;
2544 break;
2546 md_tint.color_mode = MOD_GREASE_PENCIL_COLOR_STROKE;
2547 break;
2548 case GPPAINT_MODE_FILL:
2549 md_tint.color_mode = MOD_GREASE_PENCIL_COLOR_FILL;
2550 break;
2551 }
2552 switch (eTintGpencil_Type(legacy_md_tint.type)) {
2553 case GP_TINT_UNIFORM:
2554 md_tint.tint_mode = MOD_GREASE_PENCIL_TINT_UNIFORM;
2555 break;
2556 case GP_TINT_GRADIENT:
2557 md_tint.tint_mode = MOD_GREASE_PENCIL_TINT_GRADIENT;
2558 break;
2559 }
2560 md_tint.factor = legacy_md_tint.factor;
2561 md_tint.radius = legacy_md_tint.radius;
2562 copy_v3_v3(md_tint.color, legacy_md_tint.rgb);
2563 md_tint.object = legacy_md_tint.object;
2564 legacy_md_tint.object = nullptr;
2565 MEM_SAFE_FREE(md_tint.color_ramp);
2566 md_tint.color_ramp = legacy_md_tint.colorband;
2567 legacy_md_tint.colorband = nullptr;
2568
2569 legacy_object_modifier_influence(md_tint.influence,
2570 legacy_md_tint.layername,
2571 legacy_md_tint.layer_pass,
2572 legacy_md_tint.flag & GP_TINT_INVERT_LAYER,
2573 legacy_md_tint.flag & GP_TINT_INVERT_LAYERPASS,
2574 &legacy_md_tint.material,
2575 legacy_md_tint.pass_index,
2576 legacy_md_tint.flag & GP_TINT_INVERT_MATERIAL,
2577 legacy_md_tint.flag & GP_TINT_INVERT_PASS,
2578 legacy_md_tint.vgname,
2579 legacy_md_tint.flag & GP_TINT_INVERT_VGROUP,
2580 &legacy_md_tint.curve_intensity,
2581 legacy_md_tint.flag & GP_TINT_CUSTOM_CURVE);
2582}
2583
2585 Object &object,
2586 GpencilModifierData &legacy_md)
2587{
2589 conversion_data, object, eModifierType_GreasePencilWeightAngle, legacy_md);
2590 auto &md_weight_angle = reinterpret_cast<GreasePencilWeightAngleModifierData &>(md);
2591 auto &legacy_md_weight_angle = reinterpret_cast<WeightAngleGpencilModifierData &>(legacy_md);
2592
2593 md_weight_angle.flag = 0;
2594 if (legacy_md_weight_angle.flag & GP_WEIGHT_MULTIPLY_DATA) {
2595 md_weight_angle.flag |= MOD_GREASE_PENCIL_WEIGHT_ANGLE_MULTIPLY_DATA;
2596 }
2597 if (legacy_md_weight_angle.flag & GP_WEIGHT_INVERT_OUTPUT) {
2598 md_weight_angle.flag |= MOD_GREASE_PENCIL_WEIGHT_ANGLE_INVERT_OUTPUT;
2599 }
2600 switch (eGpencilModifierSpace(legacy_md_weight_angle.space)) {
2601 case GP_SPACE_LOCAL:
2602 md_weight_angle.space = MOD_GREASE_PENCIL_WEIGHT_ANGLE_SPACE_LOCAL;
2603 break;
2604 case GP_SPACE_WORLD:
2605 md_weight_angle.space = MOD_GREASE_PENCIL_WEIGHT_ANGLE_SPACE_WORLD;
2606 break;
2607 }
2608 md_weight_angle.axis = legacy_md_weight_angle.axis;
2609 STRNCPY(md_weight_angle.target_vgname, legacy_md_weight_angle.target_vgname);
2610 md_weight_angle.min_weight = legacy_md_weight_angle.min_weight;
2611 md_weight_angle.angle = legacy_md_weight_angle.angle;
2612
2613 legacy_object_modifier_influence(md_weight_angle.influence,
2614 legacy_md_weight_angle.layername,
2615 legacy_md_weight_angle.layer_pass,
2616 legacy_md_weight_angle.flag & GP_WEIGHT_INVERT_LAYER,
2617 legacy_md_weight_angle.flag & GP_WEIGHT_INVERT_LAYERPASS,
2618 &legacy_md_weight_angle.material,
2619 legacy_md_weight_angle.pass_index,
2620 legacy_md_weight_angle.flag & GP_WEIGHT_INVERT_MATERIAL,
2621 legacy_md_weight_angle.flag & GP_WEIGHT_INVERT_PASS,
2622 legacy_md_weight_angle.vgname,
2623 legacy_md_weight_angle.flag & GP_WEIGHT_INVERT_VGROUP,
2624 nullptr,
2625 false);
2626}
2627
2629 Object &object,
2630 GpencilModifierData &legacy_md)
2631{
2633 conversion_data, object, eModifierType_GreasePencilWeightProximity, legacy_md);
2634 auto &md_weight_prox = reinterpret_cast<GreasePencilWeightProximityModifierData &>(md);
2635 auto &legacy_md_weight_prox = reinterpret_cast<WeightProxGpencilModifierData &>(legacy_md);
2636
2637 md_weight_prox.flag = 0;
2638 if (legacy_md_weight_prox.flag & GP_WEIGHT_MULTIPLY_DATA) {
2640 }
2641 if (legacy_md_weight_prox.flag & GP_WEIGHT_INVERT_OUTPUT) {
2643 }
2644 STRNCPY(md_weight_prox.target_vgname, legacy_md_weight_prox.target_vgname);
2645 md_weight_prox.min_weight = legacy_md_weight_prox.min_weight;
2646 md_weight_prox.dist_start = legacy_md_weight_prox.dist_start;
2647 md_weight_prox.dist_end = legacy_md_weight_prox.dist_end;
2648 md_weight_prox.object = legacy_md_weight_prox.object;
2649 legacy_md_weight_prox.object = nullptr;
2650
2651 legacy_object_modifier_influence(md_weight_prox.influence,
2652 legacy_md_weight_prox.layername,
2653 legacy_md_weight_prox.layer_pass,
2654 legacy_md_weight_prox.flag & GP_WEIGHT_INVERT_LAYER,
2655 legacy_md_weight_prox.flag & GP_WEIGHT_INVERT_LAYERPASS,
2656 &legacy_md_weight_prox.material,
2657 legacy_md_weight_prox.pass_index,
2658 legacy_md_weight_prox.flag & GP_WEIGHT_INVERT_MATERIAL,
2659 legacy_md_weight_prox.flag & GP_WEIGHT_INVERT_PASS,
2660 legacy_md_weight_prox.vgname,
2661 legacy_md_weight_prox.flag & GP_WEIGHT_INVERT_VGROUP,
2662 nullptr,
2663 false);
2664}
2665
2667 Object &object,
2668 GpencilModifierData &legacy_md)
2669{
2671 conversion_data, object, eModifierType_GreasePencilLineart, legacy_md);
2672 auto &md_lineart = reinterpret_cast<GreasePencilLineartModifierData &>(md);
2673 auto &legacy_md_lineart = reinterpret_cast<LineartGpencilModifierData &>(legacy_md);
2674
2675 greasepencil::convert::lineart_wrap_v3(&legacy_md_lineart, &md_lineart);
2676}
2677
2679 Object &object,
2680 GpencilModifierData &legacy_md)
2681{
2683 conversion_data, object, eModifierType_GreasePencilBuild, legacy_md);
2684 auto &md_build = reinterpret_cast<GreasePencilBuildModifierData &>(md);
2685 auto &legacy_md_build = reinterpret_cast<BuildGpencilModifierData &>(legacy_md);
2686
2687 md_build.flag = 0;
2688 if (legacy_md_build.flag & GP_BUILD_RESTRICT_TIME) {
2690 }
2691 if (legacy_md_build.flag & GP_BUILD_USE_FADING) {
2692 md_build.flag |= MOD_GREASE_PENCIL_BUILD_USE_FADING;
2693 }
2694
2695 switch (legacy_md_build.mode) {
2698 break;
2701 break;
2703 default:
2705 break;
2706 }
2707
2708 switch (legacy_md_build.time_alignment) {
2709 default:
2711 md_build.time_alignment = MOD_GREASE_PENCIL_BUILD_TIMEALIGN_START;
2712 break;
2714 md_build.time_alignment = MOD_GREASE_PENCIL_BUILD_TIMEALIGN_END;
2715 break;
2716 }
2717
2718 switch (legacy_md_build.time_mode) {
2719 default:
2721 md_build.time_mode = MOD_GREASE_PENCIL_BUILD_TIMEMODE_FRAMES;
2722 break;
2725 break;
2727 md_build.time_mode = MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED;
2728 break;
2729 }
2730
2731 switch (legacy_md_build.transition) {
2732 default:
2734 md_build.transition = MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW;
2735 break;
2737 md_build.transition = MOD_GREASE_PENCIL_BUILD_TRANSITION_SHRINK;
2738 break;
2740 md_build.transition = MOD_GREASE_PENCIL_BUILD_TRANSITION_VANISH;
2741 break;
2742 }
2743
2744 md_build.start_frame = legacy_md_build.start_frame;
2745 md_build.end_frame = legacy_md_build.end_frame;
2746 md_build.start_delay = legacy_md_build.start_delay;
2747 md_build.length = legacy_md_build.length;
2748 md_build.fade_fac = legacy_md_build.fade_fac;
2749 md_build.fade_opacity_strength = legacy_md_build.fade_opacity_strength;
2750 md_build.fade_thickness_strength = legacy_md_build.fade_thickness_strength;
2751 md_build.percentage_fac = legacy_md_build.percentage_fac;
2752 md_build.speed_fac = legacy_md_build.speed_fac;
2753 md_build.speed_maxgap = legacy_md_build.speed_maxgap;
2754 md_build.object = legacy_md_build.object;
2755 STRNCPY(md_build.target_vgname, legacy_md_build.target_vgname);
2756
2757 legacy_object_modifier_influence(md_build.influence,
2758 legacy_md_build.layername,
2759 legacy_md_build.layer_pass,
2760 legacy_md_build.flag & GP_WEIGHT_INVERT_LAYER,
2761 legacy_md_build.flag & GP_WEIGHT_INVERT_LAYERPASS,
2762 &legacy_md_build.material,
2763 legacy_md_build.pass_index,
2764 legacy_md_build.flag & GP_WEIGHT_INVERT_MATERIAL,
2765 legacy_md_build.flag & GP_WEIGHT_INVERT_PASS,
2766 legacy_md_build.target_vgname,
2767 legacy_md_build.flag & GP_WEIGHT_INVERT_VGROUP,
2768 nullptr,
2769 false);
2770}
2771
2773 Object &object,
2774 GpencilModifierData &legacy_md)
2775{
2777 conversion_data, object, eModifierType_GreasePencilSimplify, legacy_md);
2778 auto &md_simplify = reinterpret_cast<GreasePencilSimplifyModifierData &>(md);
2779 auto &legacy_md_simplify = reinterpret_cast<SimplifyGpencilModifierData &>(legacy_md);
2780
2781 switch (legacy_md_simplify.mode) {
2782 case GP_SIMPLIFY_FIXED:
2783 md_simplify.mode = MOD_GREASE_PENCIL_SIMPLIFY_FIXED;
2784 break;
2786 md_simplify.mode = MOD_GREASE_PENCIL_SIMPLIFY_ADAPTIVE;
2787 break;
2788 case GP_SIMPLIFY_SAMPLE:
2789 md_simplify.mode = MOD_GREASE_PENCIL_SIMPLIFY_SAMPLE;
2790 break;
2791 case GP_SIMPLIFY_MERGE:
2792 md_simplify.mode = MOD_GREASE_PENCIL_SIMPLIFY_MERGE;
2793 break;
2794 }
2795
2796 md_simplify.step = legacy_md_simplify.step;
2797 md_simplify.factor = legacy_md_simplify.factor;
2798 md_simplify.length = legacy_md_simplify.length;
2799 md_simplify.sharp_threshold = legacy_md_simplify.sharp_threshold;
2800 md_simplify.distance = legacy_md_simplify.distance;
2801
2802 legacy_object_modifier_influence(md_simplify.influence,
2803 legacy_md_simplify.layername,
2804 legacy_md_simplify.layer_pass,
2805 legacy_md_simplify.flag & GP_SIMPLIFY_INVERT_LAYER,
2806 legacy_md_simplify.flag & GP_SIMPLIFY_INVERT_LAYERPASS,
2807 &legacy_md_simplify.material,
2808 legacy_md_simplify.pass_index,
2809 legacy_md_simplify.flag & GP_SIMPLIFY_INVERT_MATERIAL,
2810 legacy_md_simplify.flag & GP_SIMPLIFY_INVERT_PASS,
2811 "",
2812 false,
2813 nullptr,
2814 false);
2815}
2816
2817static void legacy_object_modifiers(ConversionData &conversion_data, Object &object)
2818{
2819 BLI_assert(BLI_listbase_is_empty(&object.modifiers));
2820
2821 while (GpencilModifierData *gpd_md = static_cast<GpencilModifierData *>(
2822 BLI_pophead(&object.greasepencil_modifiers)))
2823 {
2824 switch (gpd_md->type) {
2826 /* Unknown type, just ignore. */
2827 break;
2829 legacy_object_modifier_armature(conversion_data, object, *gpd_md);
2830 break;
2832 legacy_object_modifier_array(conversion_data, object, *gpd_md);
2833 break;
2835 legacy_object_modifier_color(conversion_data, object, *gpd_md);
2836 break;
2838 legacy_object_modifier_dash(conversion_data, object, *gpd_md);
2839 break;
2841 legacy_object_modifier_envelope(conversion_data, object, *gpd_md);
2842 break;
2844 legacy_object_modifier_hook(conversion_data, object, *gpd_md);
2845 break;
2847 legacy_object_modifier_lattice(conversion_data, object, *gpd_md);
2848 break;
2850 legacy_object_modifier_length(conversion_data, object, *gpd_md);
2851 break;
2853 legacy_object_modifier_mirror(conversion_data, object, *gpd_md);
2854 break;
2856 legacy_object_modifier_multiply(conversion_data, object, *gpd_md);
2857 break;
2859 legacy_object_modifier_noise(conversion_data, object, *gpd_md);
2860 break;
2862 legacy_object_modifier_offset(conversion_data, object, *gpd_md);
2863 break;
2865 legacy_object_modifier_opacity(conversion_data, object, *gpd_md);
2866 break;
2868 legacy_object_modifier_outline(conversion_data, object, *gpd_md);
2869 break;
2871 legacy_object_modifier_shrinkwrap(conversion_data, object, *gpd_md);
2872 break;
2874 legacy_object_modifier_smooth(conversion_data, object, *gpd_md);
2875 break;
2877 legacy_object_modifier_subdiv(conversion_data, object, *gpd_md);
2878 break;
2880 legacy_object_modifier_texture(conversion_data, object, *gpd_md);
2881 break;
2883 legacy_object_modifier_thickness(conversion_data, object, *gpd_md);
2884 break;
2886 legacy_object_modifier_time(conversion_data, object, *gpd_md);
2887 break;
2889 legacy_object_modifier_tint(conversion_data, object, *gpd_md);
2890 break;
2892 legacy_object_modifier_weight_angle(conversion_data, object, *gpd_md);
2893 break;
2895 legacy_object_modifier_weight_proximity(conversion_data, object, *gpd_md);
2896 break;
2898 legacy_object_modifier_lineart(conversion_data, object, *gpd_md);
2899 break;
2901 legacy_object_modifier_build(conversion_data, object, *gpd_md);
2902 break;
2904 legacy_object_modifier_simplify(conversion_data, object, *gpd_md);
2905 break;
2906 }
2907
2909 }
2910}
2911
2930{
2931 /* Annotations mapping, keys are existing GPv2 IDs actually used as annotations, values are
2932 * either:
2933 * - nullptr: this annotation is never used by any object, there was no need to duplicate it.
2934 * - new GPv2 ID: this annotation was also used by objects, this is its new duplicated ID. */
2935 Map<bGPdata *, bGPdata *> annotations_gpv2;
2936 /* All legacy GPv2 data used by objects. */
2937 Set<bGPdata *> object_gpv2;
2938
2939 /* Check all GP objects. */
2940 LISTBASE_FOREACH (Object *, object, &bmain.objects) {
2941 if (object->type != OB_GPENCIL_LEGACY) {
2942 continue;
2943 }
2944 bGPdata *legacy_gpd = static_cast<bGPdata *>(object->data);
2945 if (!legacy_gpd) {
2946 continue;
2947 }
2948 if ((legacy_gpd->flag & GP_DATA_ANNOTATIONS) != 0) {
2949 legacy_gpd->flag &= ~GP_DATA_ANNOTATIONS;
2950 }
2951 object_gpv2.add(legacy_gpd);
2952 }
2953
2954 /* Detect all annotations currently used as such, and de-duplicate them if they are also used by
2955 * objects. */
2956
2957 auto sanitize_gpv2_annotation = [&](bGPdata **legacy_gpd_p) {
2958 bGPdata *legacy_gpd = *legacy_gpd_p;
2959 if (!legacy_gpd) {
2960 return;
2961 }
2962
2963 bGPdata *new_annotation_gpd = annotations_gpv2.lookup_or_add(legacy_gpd, nullptr);
2964 if (!object_gpv2.contains(legacy_gpd)) {
2965 /* Legacy annotation GPv2 data not used by any object, just ensure that it is properly
2966 * tagged. */
2967 BLI_assert(!new_annotation_gpd);
2968 if ((legacy_gpd->flag & GP_DATA_ANNOTATIONS) == 0) {
2969 legacy_gpd->flag |= GP_DATA_ANNOTATIONS;
2970 }
2971 return;
2972 }
2973
2974 /* Legacy GP data also used by objects. Create the duplicate of legacy GPv2 data for
2975 * annotations, if not yet done. */
2976 if (!new_annotation_gpd) {
2977 new_annotation_gpd = reinterpret_cast<bGPdata *>(BKE_id_copy_in_lib(&bmain,
2978 legacy_gpd->id.lib,
2979 &legacy_gpd->id,
2980 std::nullopt,
2981 nullptr,
2983 new_annotation_gpd->flag |= GP_DATA_ANNOTATIONS;
2984 id_us_min(&new_annotation_gpd->id);
2985 annotations_gpv2.add_overwrite(legacy_gpd, new_annotation_gpd);
2986 }
2987
2988 /* Assign the annotation duplicate ID to the annotation pointer. */
2989 BLI_assert(new_annotation_gpd->flag & GP_DATA_ANNOTATIONS);
2990 id_us_min(&legacy_gpd->id);
2991 *legacy_gpd_p = new_annotation_gpd;
2992 id_us_plus_no_lib(&new_annotation_gpd->id);
2993 };
2994
2995 LISTBASE_FOREACH (Scene *, scene, &bmain.scenes) {
2996 sanitize_gpv2_annotation(&scene->gpd);
2997 }
2998
2999 ID *id_iter;
3000 FOREACH_MAIN_ID_BEGIN (&bmain, id_iter) {
3001 if (bNodeTree *node_tree = bke::node_tree_from_id(id_iter)) {
3002 sanitize_gpv2_annotation(&node_tree->gpd);
3003 }
3004 }
3006 LISTBASE_FOREACH (bNodeTree *, node_tree, &bmain.nodetrees) {
3007 sanitize_gpv2_annotation(&node_tree->gpd);
3008 }
3009
3010 LISTBASE_FOREACH (MovieClip *, movie_clip, &bmain.movieclips) {
3011 sanitize_gpv2_annotation(&movie_clip->gpd);
3012
3013 LISTBASE_FOREACH (MovieTrackingObject *, mvc_tracking_object, &movie_clip->tracking.objects) {
3014 LISTBASE_FOREACH (MovieTrackingTrack *, mvc_track, &mvc_tracking_object->tracks) {
3015 sanitize_gpv2_annotation(&mvc_track->gpd);
3016 }
3018 MovieTrackingPlaneTrack *, mvc_plane_track, &mvc_tracking_object->plane_tracks)
3019 {
3020 for (int i = 0; i < mvc_plane_track->point_tracksnr; i++) {
3021 sanitize_gpv2_annotation(&mvc_plane_track->point_tracks[i]->gpd);
3022 }
3023 }
3024 }
3025 }
3026
3027 LISTBASE_FOREACH (bScreen *, screen, &bmain.screens) {
3028 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
3029 LISTBASE_FOREACH (SpaceLink *, space_link, &area->spacedata) {
3030 switch (eSpace_Type(space_link->spacetype)) {
3031 case SPACE_SEQ: {
3032 SpaceSeq *space_sequencer = reinterpret_cast<SpaceSeq *>(space_link);
3033 sanitize_gpv2_annotation(&space_sequencer->gpd);
3034 break;
3035 }
3036 case SPACE_IMAGE: {
3037 SpaceImage *space_image = reinterpret_cast<SpaceImage *>(space_link);
3038 sanitize_gpv2_annotation(&space_image->gpd);
3039 break;
3040 }
3041 case SPACE_NODE: {
3042 SpaceNode *space_node = reinterpret_cast<SpaceNode *>(space_link);
3043 sanitize_gpv2_annotation(&space_node->gpd);
3044 break;
3045 }
3046 case SPACE_EMPTY:
3047 case SPACE_VIEW3D:
3048 /* #View3D.gpd is deprecated and can be ignored here. */
3049 case SPACE_GRAPH:
3050 case SPACE_OUTLINER:
3051 case SPACE_PROPERTIES:
3052 case SPACE_FILE:
3053 case SPACE_INFO:
3054 case SPACE_TEXT:
3055 case SPACE_ACTION:
3056 case SPACE_NLA:
3057 case SPACE_SCRIPT:
3058 case SPACE_CONSOLE:
3059 case SPACE_USERPREF:
3060 case SPACE_CLIP:
3061 case SPACE_TOPBAR:
3062 case SPACE_STATUSBAR:
3063 case SPACE_SPREADSHEET:
3064 break;
3065 }
3066 }
3067 }
3068 }
3069}
3070
3071static void legacy_gpencil_object(ConversionData &conversion_data, Object &object)
3072{
3073 BLI_assert((GS(static_cast<ID *>(object.data)->name) == ID_GD_LEGACY));
3074
3075 bGPdata *gpd = static_cast<bGPdata *>(object.data);
3076
3077 GreasePencil *new_grease_pencil = conversion_data.legacy_to_greasepencil_data.lookup_default(
3078 gpd, nullptr);
3079 const bool do_gpencil_data_conversion = (new_grease_pencil == nullptr);
3080
3081 if (!new_grease_pencil) {
3082 new_grease_pencil = static_cast<GreasePencil *>(
3083 BKE_id_new_in_lib(&conversion_data.bmain, gpd->id.lib, ID_GP, gpd->id.name + 2));
3084 id_us_min(&new_grease_pencil->id);
3085 }
3086
3087 object.data = new_grease_pencil;
3088 object.type = OB_GREASE_PENCIL;
3089
3090 /* NOTE: Could also use #BKE_id_free_us, to also free the legacy GP if not used anymore? */
3091 id_us_min(&gpd->id);
3092 id_us_plus(&new_grease_pencil->id);
3093
3094 if (do_gpencil_data_conversion) {
3095 legacy_gpencil_to_grease_pencil(conversion_data, *new_grease_pencil, *gpd);
3096 conversion_data.legacy_to_greasepencil_data.add(gpd, new_grease_pencil);
3097 }
3098
3099 legacy_object_modifiers(conversion_data, object);
3100 /* Convert the animation of the "uniform thickness" setting of the thickness modifier. */
3101 legacy_object_thickness_modifier_thickness_anim(conversion_data, object);
3102
3103 /* Layer adjustments should be added after all other modifiers. */
3104 layer_adjustments_to_modifiers(conversion_data, *gpd, object);
3105 /* Thickness factor is applied after all other changes to the radii. */
3106 thickness_factor_to_modifier(conversion_data, *gpd, object);
3107
3109}
3110
3111void legacy_main(Main &bmain,
3112 BlendfileLinkAppendContext *lapp_context,
3113 BlendFileReadReport & /*reports*/)
3114{
3115 ConversionData conversion_data(bmain, lapp_context);
3116
3117 /* Ensure that annotations are fully separated from object usages of legacy GPv2 data. */
3119
3120 LISTBASE_FOREACH (Object *, object, &bmain.objects) {
3121 if (object->type != OB_GPENCIL_LEGACY) {
3122 continue;
3123 }
3124 legacy_gpencil_object(conversion_data, *object);
3125 }
3126
3127 /* Potential other usages of legacy bGPdata IDs also need to be remapped to their matching new
3128 * GreasePencil counterparts. */
3129 bke::id::IDRemapper gpd_remapper;
3130 /* Allow remapping from legacy bGPdata IDs to new GreasePencil ones. */
3131 gpd_remapper.allow_idtype_mismatch = true;
3132
3133 LISTBASE_FOREACH (bGPdata *, legacy_gpd, &bmain.gpencils) {
3134 /* Annotations still use legacy `bGPdata`, these should not be converted. Call to
3135 * #legacy_gpencil_sanitize_annotations above ensured to fully separate annotations from object
3136 * legacy grease pencil. */
3137 if ((legacy_gpd->flag & GP_DATA_ANNOTATIONS) != 0) {
3138 continue;
3139 }
3140 GreasePencil *new_grease_pencil = conversion_data.legacy_to_greasepencil_data.lookup_default(
3141 legacy_gpd, nullptr);
3142 if (!new_grease_pencil) {
3143 new_grease_pencil = static_cast<GreasePencil *>(
3144 BKE_id_new_in_lib(&bmain, legacy_gpd->id.lib, ID_GP, legacy_gpd->id.name + 2));
3145 id_us_min(&new_grease_pencil->id);
3146 legacy_gpencil_to_grease_pencil(conversion_data, *new_grease_pencil, *legacy_gpd);
3147 conversion_data.legacy_to_greasepencil_data.add(legacy_gpd, new_grease_pencil);
3148 }
3149 gpd_remapper.add(&legacy_gpd->id, &new_grease_pencil->id);
3150 }
3151
3153
3154 if (conversion_data.lapp_context) {
3156 conversion_data.lapp_context,
3157 [&conversion_data](BlendfileLinkAppendContext *lapp_context,
3158 BlendfileLinkAppendContextItem *item) -> bool {
3159 ID *item_new_id = BKE_blendfile_link_append_context_item_newid_get(lapp_context, item);
3160 if (!item_new_id || GS(item_new_id->name) != ID_GD_LEGACY) {
3161 return true;
3162 }
3163 GreasePencil **item_grease_pencil =
3165 reinterpret_cast<bGPdata *>(item_new_id));
3166 if (item_grease_pencil && *item_grease_pencil) {
3168 lapp_context, item, &(*item_grease_pencil)->id);
3169 }
3170 return true;
3171 },
3175 }
3176}
3177
3180{
3181 lmd->edge_types = lmd_legacy->edge_types;
3182 lmd->source_type = lmd_legacy->source_type;
3183 lmd->use_multiple_levels = lmd_legacy->use_multiple_levels;
3184 lmd->level_start = lmd_legacy->level_start;
3185 lmd->level_end = lmd_legacy->level_end;
3186 lmd->source_camera = lmd_legacy->source_camera;
3187 lmd->light_contour_object = lmd_legacy->light_contour_object;
3188 lmd->source_object = lmd_legacy->source_object;
3189 lmd->source_collection = lmd_legacy->source_collection;
3190 lmd->target_material = lmd_legacy->target_material;
3191 STRNCPY(lmd->target_layer, lmd_legacy->target_layer);
3193 STRNCPY(lmd->vgname, lmd_legacy->vgname);
3194 lmd->overscan = lmd_legacy->overscan;
3195 lmd->shadow_camera_fov = lmd_legacy->shadow_camera_fov;
3196 lmd->shadow_camera_size = lmd_legacy->shadow_camera_size;
3197 lmd->shadow_camera_near = lmd_legacy->shadow_camera_near;
3198 lmd->shadow_camera_far = lmd_legacy->shadow_camera_far;
3199 lmd->opacity = lmd_legacy->opacity;
3201 lmd->mask_switches = lmd_legacy->mask_switches;
3202 lmd->material_mask_bits = lmd_legacy->material_mask_bits;
3203 lmd->intersection_mask = lmd_legacy->intersection_mask;
3204 lmd->shadow_selection = lmd_legacy->shadow_selection;
3205 lmd->silhouette_selection = lmd_legacy->silhouette_selection;
3206 lmd->crease_threshold = lmd_legacy->crease_threshold;
3210 lmd->calculation_flags = lmd_legacy->calculation_flags;
3211 lmd->flags = lmd_legacy->flags;
3212 lmd->stroke_depth_offset = lmd_legacy->stroke_depth_offset;
3213 lmd->level_start_override = lmd_legacy->level_start_override;
3214 lmd->level_end_override = lmd_legacy->level_end_override;
3215 lmd->edge_types_override = lmd_legacy->edge_types_override;
3218 lmd->cache = lmd_legacy->cache;
3219 lmd->la_data_ptr = lmd_legacy->la_data_ptr;
3220}
3221
3224{
3225 lmd_legacy->edge_types = lmd->edge_types;
3226 lmd_legacy->source_type = lmd->source_type;
3227 lmd_legacy->use_multiple_levels = lmd->use_multiple_levels;
3228 lmd_legacy->level_start = lmd->level_start;
3229 lmd_legacy->level_end = lmd->level_end;
3230 lmd_legacy->source_camera = lmd->source_camera;
3231 lmd_legacy->light_contour_object = lmd->light_contour_object;
3232 lmd_legacy->source_object = lmd->source_object;
3233 lmd_legacy->source_collection = lmd->source_collection;
3234 lmd_legacy->target_material = lmd->target_material;
3236 STRNCPY(lmd_legacy->vgname, lmd->vgname);
3237 lmd_legacy->overscan = lmd->overscan;
3238 lmd_legacy->shadow_camera_fov = lmd->shadow_camera_fov;
3239 lmd_legacy->shadow_camera_size = lmd->shadow_camera_size;
3240 lmd_legacy->shadow_camera_near = lmd->shadow_camera_near;
3241 lmd_legacy->shadow_camera_far = lmd->shadow_camera_far;
3242 lmd_legacy->opacity = lmd->opacity;
3244 lmd_legacy->mask_switches = lmd->mask_switches;
3245 lmd_legacy->material_mask_bits = lmd->material_mask_bits;
3246 lmd_legacy->intersection_mask = lmd->intersection_mask;
3247 lmd_legacy->shadow_selection = lmd->shadow_selection;
3248 lmd_legacy->silhouette_selection = lmd->silhouette_selection;
3249 lmd_legacy->crease_threshold = lmd->crease_threshold;
3253 lmd_legacy->calculation_flags = lmd->calculation_flags;
3254 lmd_legacy->flags = lmd->flags;
3255 lmd_legacy->stroke_depth_offset = lmd->stroke_depth_offset;
3256 lmd_legacy->level_start_override = lmd->level_start_override;
3257 lmd_legacy->level_end_override = lmd->level_end_override;
3258 lmd_legacy->edge_types_override = lmd->edge_types_override;
3261 lmd_legacy->cache = lmd->cache;
3262 lmd_legacy->la_data_ptr = lmd->la_data_ptr;
3263}
3264
3265} // namespace blender::bke::greasepencil::convert
Functions and classes to work with Actions.
Functionality to iterate an Action in various ways.
Blender kernel action and pose functionality.
AnimData * BKE_animdata_copy_in_lib(Main *bmain, std::optional< Library * > owner_library, AnimData *adt, int flag)
Definition anim_data.cc:281
bool BKE_animdata_action_ensure_idroot(const ID *owner, bAction *action)
Definition anim_data.cc:159
AnimData * BKE_animdata_ensure_id(ID *id)
Definition anim_data.cc:97
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:83
void BKE_curvemapping_free(CurveMapping *cumap)
Low-level operations for curves.
support for deformation groups and hooks.
void BKE_defgroup_copy_list(ListBase *outbase, const ListBase *inbase)
Definition deform.cc:73
void BKE_fcurve_handles_recalc(FCurve *fcu)
void BKE_gpencil_modifier_free_ex(struct GpencilModifierData *md, int flag)
Low-level operations for grease pencil.
bool IDP_AddToGroup(IDProperty *group, IDProperty *prop) ATTR_NONNULL()
Definition idprop.cc:717
IDProperty * IDP_CopyProperty(const IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:863
IDPropertyUIData * IDP_ui_data_ensure(IDProperty *prop)
Definition idprop.cc:1761
struct ID * BKE_id_copy_in_lib(Main *bmain, std::optional< Library * > owner_library, const ID *id, std::optional< const ID * > new_owner_id, ID **new_id_p, int flag)
Definition lib_id.cc:675
void id_us_plus(ID *id)
Definition lib_id.cc:358
void * BKE_id_new_in_lib(Main *bmain, std::optional< Library * > owner_library, short type, const char *name)
Definition lib_id.cc:1496
void id_fake_user_set(ID *id)
Definition lib_id.cc:396
void id_us_plus_no_lib(ID *id)
Definition lib_id.cc:342
@ LIB_ID_COPY_DEFAULT
void id_us_min(ID *id)
Definition lib_id.cc:366
void BKE_libblock_remap_multiple(Main *bmain, blender::bke::id::IDRemapper &mappings, const int remap_flags)
Definition lib_remap.cc:711
@ ID_REMAP_ALLOW_IDTYPE_MISMATCH
#define FOREACH_MAIN_ID_END
Definition BKE_main.hh:583
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition BKE_main.hh:577
General operations, lookup, etc. for materials.
void BKE_id_materials_copy(Main *bmain, ID *id_src, ID *id_dst)
const ModifierTypeInfo * BKE_modifier_get_info(ModifierType type)
void BKE_modifiers_persistent_uid_init(const Object &object, ModifierData &md)
@ eModifierTypeFlag_RequiresOriginalData
void BKE_modifier_unique_name(ListBase *modifiers, ModifierData *md)
ModifierData * BKE_modifier_new(int type)
void BKE_ntree_update_after_single_tree_change(Main &bmain, bNodeTree &modified_tree, const NodeTreeUpdateExtraParams &params={})
General operations, lookup, etc. for blender objects.
void BKE_object_free_derived_caches(Object *ob)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:586
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:252
void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:371
MINLINE float max_ff(float a, float b)
void copy_m4_m4(float m1[4][4], const float m2[4][4])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
char * BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.cc:30
#define STRNLEN(str)
Definition BLI_string.h:613
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define SNPRINTF_UTF8(dst, format,...)
#define STRNCPY_UTF8(dst, src)
unsigned int uint
#define UNUSED_VARS_NDEBUG(...)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define ELEM(...)
#define STREQ(a, b)
external readfile function prototypes.
#define DATA_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
@ ID_RECALC_ANIMATION
Definition DNA_ID.h:1077
@ ID_FLAG_FAKEUSER
Definition DNA_ID.h:769
@ ID_GD_LEGACY
@ ID_GP
struct bAction bAction
@ FCURVE_INT_VALUES
struct FCurve FCurve
struct NlaStrip NlaStrip
struct AnimData AnimData
struct NlaTrack NlaTrack
@ ARM_DEF_INVERT_VGROUP
eGp_Vertex_Mode
@ GPPAINT_MODE_STROKE
@ GPPAINT_MODE_FILL
@ GPPAINT_MODE_BOTH
eBezTriple_KeyframeType
#define MAX_NAME
Definition DNA_defs.h:50
@ GP_CURVE_NEEDS_STROKE_UPDATE
@ GP_LAYER_DISABLE_MASKS_IN_VIEWLAYER
@ GP_ONION_GHOST_NEXTCOL
@ GP_ONION_GHOST_PREVCOL
@ GP_DATA_AUTOLOCK_LAYERS
@ GP_OUTLINE_INVERT_MATERIAL
@ GP_OUTLINE_INVERT_LAYERPASS
@ GP_TIME_SEG_MODE_PINGPONG
@ GP_SUBDIV_INVERT_MATERIAL
@ GP_SUBDIV_INVERT_LAYERPASS
@ GP_LATTICE_INVERT_LAYERPASS
@ GP_LATTICE_INVERT_MATERIAL
@ GP_BUILD_TRANSITION_SHRINK
@ GP_BUILD_TRANSITION_VANISH
@ GP_ENVELOPE_INVERT_LAYERPASS
@ GP_ENVELOPE_INVERT_MATERIAL
@ GP_SIMPLIFY_INVERT_MATERIAL
@ GP_SIMPLIFY_INVERT_LAYERPASS
@ GP_COLOR_INVERT_LAYERPASS
@ GP_SMOOTH_INVERT_LAYERPASS
@ GP_SMOOTH_INVERT_MATERIAL
@ GP_OPACITY_INVERT_MATERIAL
@ GP_OPACITY_INVERT_LAYERPASS
@ GP_THICK_INVERT_LAYERPASS
@ GP_MULTIPLY_ENABLE_FADING
@ GP_BUILD_TIMEMODE_PERCENTAGE
@ GP_BUILD_TIMEMODE_DRAWSPEED
@ eGPHook_Falloff_InvSquare
@ GP_OFFSET_INVERT_MATERIAL
@ GP_OFFSET_UNIFORM_RANDOM_SCALE
@ GP_OFFSET_INVERT_LAYERPASS
@ GP_MIRROR_INVERT_MATERIAL
@ GP_MIRROR_INVERT_LAYERPASS
@ GP_SHRINKWRAP_INVERT_VGROUP
@ GP_SHRINKWRAP_INVERT_LAYERPASS
@ GP_SHRINKWRAP_INVERT_MATERIAL
@ eGpencilModifierType_Dash
@ eGpencilModifierType_Array
@ eGpencilModifierType_Noise
@ eGpencilModifierType_Mirror
@ eGpencilModifierType_Color
@ eGpencilModifierType_Multiply
@ eGpencilModifierType_Texture
@ eGpencilModifierType_Subdiv
@ eGpencilModifierType_Length
@ eGpencilModifierType_Lattice
@ eGpencilModifierType_Opacity
@ eGpencilModifierType_Hook
@ eGpencilModifierType_Simplify
@ eGpencilModifierType_Shrinkwrap
@ eGpencilModifierType_WeightProximity
@ eGpencilModifierType_Armature
@ eGpencilModifierType_WeightAngle
@ eGpencilModifierType_Lineart
@ eGpencilModifierType_None
@ eGpencilModifierType_Smooth
@ eGpencilModifierType_Tint
@ eGpencilModifierType_Outline
@ eGpencilModifierType_Envelope
@ eGpencilModifierType_Time
@ eGpencilModifierType_Thick
@ eGpencilModifierType_Build
@ eGpencilModifierType_Offset
@ GP_LAYER_TREE_NODE_MUTE
@ GP_LAYER_TREE_NODE_HIDE_ONION_SKINNING
@ GP_LAYER_TREE_NODE_USE_LIGHTS
@ GP_LAYER_TREE_NODE_HIDE_MASKS
@ GP_LAYER_TREE_NODE_DISABLE_MASKS_IN_VIEWLAYER
@ GREASE_PENCIL_AUTOLOCK_LAYERS
@ GREASE_PENCIL_ANIM_CHANNEL_EXPANDED
@ GREASE_PENCIL_STROKE_ORDER_3D
@ GP_ONION_SKINNING_USE_FADE
@ GP_ONION_SKINNING_SHOW_LOOP
@ GP_ONION_SKINNING_USE_CUSTOM_COLORS
#define GREASE_PENCIL_ONION_SKINNING_FILTER_ALL
struct ListBase ListBase
@ GP_LENGTH_INVERT_PASS
@ GP_LENGTH_INVERT_MATERIAL
@ GP_LENGTH_INVERT_LAYER
@ GP_LENGTH_INVERT_LAYERPASS
eTextureGpencil_Fit
@ GP_TEX_FIT_STROKE
@ GP_TEX_CONSTANT_LENGTH
@ GP_ARRAY_USE_OFFSET
@ GP_ARRAY_UNIFORM_RANDOM_SCALE
@ GP_ARRAY_INVERT_MATERIAL
@ GP_ARRAY_INVERT_LAYER
@ GP_ARRAY_USE_RELATIVE
@ GP_ARRAY_INVERT_LAYERPASS
@ GP_ARRAY_USE_OB_OFFSET
@ GP_ARRAY_INVERT_PASS
@ GP_NOISE_INVERT_PASS
@ GP_NOISE_INVERT_LAYER
@ GP_NOISE_INVERT_VGROUP
@ GP_NOISE_INVERT_MATERIAL
@ GP_NOISE_CUSTOM_CURVE
@ GP_NOISE_INVERT_LAYERPASS
@ eModifierFlag_OverrideLibrary_Local
@ eModifierFlag_Active
@ MOD_GREASE_PENCIL_MULTIPLY_ENABLE_FADING
@ MOD_GREASE_PENCIL_SMOOTH_MOD_LOCATION
@ MOD_GREASE_PENCIL_SMOOTH_MOD_STRENGTH
@ MOD_GREASE_PENCIL_SMOOTH_KEEP_SHAPE
@ MOD_GREASE_PENCIL_SMOOTH_MOD_UV
@ MOD_GREASE_PENCIL_SMOOTH_MOD_THICKNESS
@ GREASE_PENCIL_INFLUENCE_INVERT_VERTEX_GROUP
@ GREASE_PENCIL_INFLUENCE_USE_MATERIAL_PASS_FILTER
@ GREASE_PENCIL_INFLUENCE_USE_LAYER_PASS_FILTER
@ GREASE_PENCIL_INFLUENCE_INVERT_LAYER_FILTER
@ GREASE_PENCIL_INFLUENCE_USE_CUSTOM_CURVE
@ GREASE_PENCIL_INFLUENCE_INVERT_MATERIAL_PASS_FILTER
@ GREASE_PENCIL_INFLUENCE_INVERT_MATERIAL_FILTER
@ GREASE_PENCIL_INFLUENCE_INVERT_LAYER_PASS_FILTER
@ MOD_GREASE_PENCIL_WEIGHT_ANGLE_SPACE_WORLD
@ MOD_GREASE_PENCIL_WEIGHT_ANGLE_SPACE_LOCAL
@ MOD_GREASE_PENCIL_HOOK_UNIFORM_SPACE
@ MOD_GREASE_PENCIL_OFFSET_UNIFORM_RANDOM_SCALE
@ MOD_GREASE_PENCIL_MIRROR_AXIS_Z
@ MOD_GREASE_PENCIL_MIRROR_AXIS_X
@ MOD_GREASE_PENCIL_MIRROR_AXIS_Y
@ MOD_GREASE_PENCIL_WEIGHT_ANGLE_MULTIPLY_DATA
@ MOD_GREASE_PENCIL_WEIGHT_ANGLE_INVERT_OUTPUT
@ MOD_GREASE_PENCIL_OPACITY_USE_WEIGHT_AS_FACTOR
@ MOD_GREASE_PENCIL_OPACITY_USE_UNIFORM_OPACITY
@ MOD_GREASE_PENCIL_ARRAY_USE_OFFSET
@ MOD_GREASE_PENCIL_ARRAY_USE_RELATIVE
@ MOD_GREASE_PENCIL_ARRAY_USE_OB_OFFSET
@ MOD_GREASE_PENCIL_ARRAY_UNIFORM_RANDOM_SCALE
@ MOD_GREASE_PENCIL_BUILD_TIMEMODE_PERCENTAGE
@ MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED
@ MOD_GREASE_PENCIL_BUILD_TIMEMODE_FRAMES
@ MOD_GREASE_PENCIL_BUILD_TIMEALIGN_START
@ MOD_GREASE_PENCIL_BUILD_TIMEALIGN_END
@ MOD_GREASE_PENCIL_THICK_WEIGHT_FACTOR
@ MOD_GREASE_PENCIL_THICK_NORMALIZE
@ MOD_GREASE_PENCIL_SIMPLIFY_FIXED
@ MOD_GREASE_PENCIL_SIMPLIFY_MERGE
@ MOD_GREASE_PENCIL_SIMPLIFY_ADAPTIVE
@ MOD_GREASE_PENCIL_SIMPLIFY_SAMPLE
@ MOD_GREASE_PENCIL_TIME_MODE_FIX
@ MOD_GREASE_PENCIL_TIME_MODE_CHAIN
@ MOD_GREASE_PENCIL_TIME_MODE_PINGPONG
@ MOD_GREASE_PENCIL_TIME_MODE_NORMAL
@ MOD_GREASE_PENCIL_TIME_MODE_REVERSE
@ MOD_GREASE_PENCIL_SUBDIV_CATMULL
@ MOD_GREASE_PENCIL_SUBDIV_SIMPLE
@ MOD_GREASE_PENCIL_COLOR_FILL
@ MOD_GREASE_PENCIL_COLOR_STROKE
@ MOD_GREASE_PENCIL_COLOR_BOTH
@ MOD_GREASE_PENCIL_COLOR_HARDNESS
@ MOD_GREASE_PENCIL_BUILD_MODE_SEQUENTIAL
@ MOD_GREASE_PENCIL_BUILD_MODE_ADDITIVE
@ MOD_GREASE_PENCIL_BUILD_MODE_CONCURRENT
@ MOD_GREASE_PENCIL_TIME_KEEP_LOOP
@ MOD_GREASE_PENCIL_TIME_CUSTOM_RANGE
@ MOD_GREASE_PENCIL_BUILD_RESTRICT_TIME
@ MOD_GREASE_PENCIL_BUILD_USE_FADING
@ MOD_GREASE_PENCIL_DASH_USE_CYCLIC
@ MOD_GREASE_PENCIL_TINT_UNIFORM
@ MOD_GREASE_PENCIL_TINT_GRADIENT
@ MOD_GREASE_PENCIL_OUTLINE_KEEP_SHAPE
@ MOD_GREASE_PENCIL_TINT_USE_WEIGHT_AS_FACTOR
@ eModifierType_GreasePencilSmooth
@ eModifierType_GreasePencilWeightProximity
@ eModifierType_GreasePencilMirror
@ eModifierType_GreasePencilOffset
@ eModifierType_GreasePencilThickness
@ eModifierType_GreasePencilEnvelope
@ eModifierType_GreasePencilArmature
@ eModifierType_GreasePencilSubdiv
@ eModifierType_GreasePencilTint
@ eModifierType_GreasePencilNoise
@ eModifierType_GreasePencilMultiply
@ eModifierType_GreasePencilBuild
@ eModifierType_GreasePencilTime
@ eModifierType_GreasePencilTexture
@ eModifierType_GreasePencilSimplify
@ eModifierType_GreasePencilColor
@ eModifierType_GreasePencilDash
@ eModifierType_GreasePencilLineart
@ eModifierType_Nodes
@ eModifierType_GreasePencilOutline
@ eModifierType_GreasePencilWeightAngle
@ eModifierType_GreasePencilOpacity
@ eModifierType_GreasePencilLength
@ eModifierType_GreasePencilShrinkwrap
@ eModifierType_GreasePencilLattice
@ eModifierType_GreasePencilHook
@ eModifierType_GreasePencilArray
@ MOD_GREASE_PENCIL_HOOK_Falloff_None
@ MOD_GREASE_PENCIL_HOOK_Falloff_Root
@ MOD_GREASE_PENCIL_HOOK_Falloff_InvSquare
@ MOD_GREASE_PENCIL_HOOK_Falloff_Const
@ MOD_GREASE_PENCIL_HOOK_Falloff_Linear
@ MOD_GREASE_PENCIL_HOOK_Falloff_Sphere
@ MOD_GREASE_PENCIL_HOOK_Falloff_Smooth
@ MOD_GREASE_PENCIL_HOOK_Falloff_Curve
@ MOD_GREASE_PENCIL_HOOK_Falloff_Sharp
@ MOD_GREASE_PENCIL_TEXTURE_STROKE_AND_FILL
@ MOD_GREASE_PENCIL_TEXTURE_FILL
@ MOD_GREASE_PENCIL_TEXTURE_STROKE
@ MOD_GREASE_PENCIL_WEIGHT_PROXIMITY_INVERT_OUTPUT
@ MOD_GREASE_PENCIL_WEIGHT_PROXIMITY_MULTIPLY_DATA
@ MOD_GREASE_PENCIL_ENVELOPE_SEGMENTS
@ MOD_GREASE_PENCIL_ENVELOPE_FILLS
@ MOD_GREASE_PENCIL_ENVELOPE_DEFORM
@ MOD_GREASE_PENCIL_BUILD_TRANSITION_VANISH
@ MOD_GREASE_PENCIL_BUILD_TRANSITION_SHRINK
@ MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW
@ MOD_GREASE_PENCIL_TEXTURE_FIT_STROKE
@ MOD_GREASE_PENCIL_TEXTURE_CONSTANT_LENGTH
@ MOD_GREASE_PENCIL_OFFSET_STROKE
@ MOD_GREASE_PENCIL_OFFSET_MATERIAL
@ MOD_GREASE_PENCIL_OFFSET_LAYER
@ MOD_GREASE_PENCIL_OFFSET_RANDOM
@ MOD_GREASE_PENCIL_TIME_SEG_MODE_NORMAL
@ MOD_GREASE_PENCIL_TIME_SEG_MODE_REVERSE
@ MOD_GREASE_PENCIL_TIME_SEG_MODE_PINGPONG
@ NODE_MATH_ADD
@ GEO_NODE_ASSET_MODIFIER
@ SOCK_OUT
@ SOCK_IN
@ OB_GREASE_PENCIL
@ OB_GPENCIL_LEGACY
eSpace_Type
@ SPACE_TEXT
@ SPACE_CLIP
@ SPACE_ACTION
@ SPACE_CONSOLE
@ SPACE_OUTLINER
@ SPACE_STATUSBAR
@ SPACE_TOPBAR
@ SPACE_NODE
@ SPACE_SPREADSHEET
@ SPACE_USERPREF
@ SPACE_FILE
@ SPACE_PROPERTIES
@ SPACE_NLA
@ SPACE_SEQ
@ SPACE_EMPTY
@ SPACE_SCRIPT
@ SPACE_IMAGE
@ SPACE_GRAPH
@ SPACE_VIEW3D
@ SPACE_INFO
#define MEM_SAFE_FREE(v)
@ PROP_DISTANCE
Definition RNA_types.hh:256
@ PROP_TRANSLATION
Definition RNA_types.hh:261
BMesh const char void * data
return true
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
long long int int64_t
const Value * lookup_ptr(const Key &key) const
Definition BLI_map.hh:508
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:570
void add_new(const Key &key, const Value &value)
Definition BLI_map.hh:265
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:419
bool is_empty() const
Definition BLI_array.hh:264
constexpr int64_t size() const
bool add_overwrite(const Key &key, const Value &value)
Definition BLI_map.hh:325
Value & lookup_or_add(const Key &key, const Value &value)
Definition BLI_map.hh:588
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:573
bool contains(const Key &key) const
Definition BLI_set.hh:310
bool add(const Key &key)
Definition BLI_set.hh:248
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr StringRef substr(int64_t start, int64_t size) const
constexpr bool startswith(StringRef prefix) const
void copy_utf8_truncated(char *dst, int64_t dst_size) const
Definition string_ref.cc:28
void append(const T &value)
bool is_empty() const
Slot & slot_add_for_id(const ID &animated_id)
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, AttrType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
MutableSpan< float > opacities_for_write()
MutableSpan< float > radii_for_write()
bke::CurvesGeometry & strokes_for_write()
MutableSpan< ColorGeometry4f > fill_colors_for_write()
MutableSpan< ColorGeometry4f > vertex_colors_for_write()
void set_view_layer_name(StringRef new_name)
const GreasePencilFrame * frame_at(const int frame_number) const
void set_parent_bone_name(StringRef new_name)
AnimDataConvertor(ConversionData &conversion_data, ID &id_dst, ID &id_src, const Array< AnimDataFCurveConvertor > fcurve_convertors={})
AnimDataConvertor(ConversionData &conversion_data, ID &id_src, const Array< AnimDataFCurveConvertor > fcurve_convertors={})
void add(ID *old_id, ID *new_id)
nullptr float
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
#define GS(x)
#define sin
#define cos
VecBase< float, D > normalize(VecOp< float, D >) RET
MatBase< R, C > transpose(MatBase< C, R >) RET
VecBase< float, 3 > cross(VecOp< float, 3 >, VecOp< float, 3 >) RET
VecBase< float, 3 > float3
static const char * modifier_name[LS_MODIFIER_NUM]
Definition linestyle.cc:689
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static void add(blender::Map< std::string, std::string > &messages, Message &msg)
Definition msgfmt.cc:222
void action_fcurve_move(Action &action_dst, slot_handle_t action_slot_dst, Action &action_src, FCurve &fcurve)
Action & action_add(Main &bmain, StringRefNull name)
void foreach_fcurve_in_action(Action &action, FunctionRef< void(FCurve &fcurve)> callback)
decltype(::ActionSlot::handle) slot_handle_t
bool assign_tmpaction(bAction *action, OwnedAnimData owned_adt)
bool assign_action(bAction *action, ID &animated_id)
static void legacy_object_modifier_subdiv(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static void legacy_object_modifier_mirror(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static bNodeTree * offset_radius_node_tree_add(ConversionData &conversion_data, Library *library)
static void legacy_object_modifier_time(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static void legacy_object_modifier_color(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static ModifierData & legacy_object_modifier_common(ConversionData &conversion_data, Object &object, const ModifierType type, GpencilModifierData &legacy_md)
static void legacy_object_modifier_offset(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static void legacy_object_modifier_opacity(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static void legacy_object_modifier_lineart(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static void legacy_object_modifier_armature(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static void legacy_object_modifier_shrinkwrap(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static void thickness_factor_to_modifier(ConversionData &conversion_data, bGPdata &src_object_data, Object &dst_object)
static void legacy_object_modifier_envelope(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static void legacy_object_modifier_outline(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static void legacy_object_modifier_thickness(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static void legacy_gpencil_to_grease_pencil(ConversionData &conversion_data, GreasePencil &grease_pencil, bGPdata &gpd)
static void legacy_object_modifier_weight_angle(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static void legacy_object_modifier_tint(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
void lineart_unwrap_v3(LineartGpencilModifierData *lmd_legacy, const GreasePencilLineartModifierData *lmd)
static void legacy_object_modifier_noise(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
void legacy_main(Main &bmain, BlendfileLinkAppendContext *lapp_context, BlendFileReadReport &reports)
static blender::float4x2 get_legacy_texture_matrix(bGPDstroke *gps)
static void legacy_object_thickness_modifier_thickness_anim(ConversionData &conversion_data, Object &object)
static void layer_adjustments_to_modifiers(ConversionData &conversion_data, bGPdata &src_object_data, Object &dst_object)
static void legacy_object_modifier_texture(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static void legacy_object_modifiers(ConversionData &conversion_data, Object &object)
static Drawing legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf, const ListBase &vertex_group_names)
static float3x2 get_legacy_stroke_to_texture_matrix(const float2 uv_translation, const float uv_rotation, const float2 uv_scale)
static void legacy_object_modifier_dash(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static void legacy_object_modifier_build(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static void legacy_object_modifier_array(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static void legacy_object_modifier_multiply(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static void legacy_object_modifier_smooth(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static void find_used_vertex_groups(const bGPDframe &gpf, const ListBase &vertex_group_names, const int num_vertex_groups, ListBase &r_vertex_group_names, Array< int > &r_indices)
static blender::float4x2 get_legacy_layer_to_stroke_matrix(bGPDstroke *gps)
void lineart_wrap_v3(const LineartGpencilModifierData *lmd_legacy, GreasePencilLineartModifierData *lmd)
static void legacy_object_modifier_lattice(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static void legacy_object_modifier_weight_proximity(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static void legacy_object_modifier_influence(GreasePencilModifierInfluenceData &influence, StringRef layername, const int layer_pass, const bool invert_layer, const bool invert_layer_pass, Material **material, const int material_pass, const bool invert_material, const bool invert_material_pass, StringRef vertex_group_name, const bool invert_vertex_group, CurveMapping **custom_curve, const bool use_custom_curve)
static void legacy_object_modifier_hook(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static void legacy_gpencil_object(ConversionData &conversion_data, Object &object)
static void legacy_object_modifier_length(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
static void legacy_object_modifier_simplify(ConversionData &conversion_data, Object &object, GpencilModifierData &legacy_md)
constexpr float LEGACY_RADIUS_CONVERSION_FACTOR
std::unique_ptr< IDProperty, IDPropertyDeleter > create(StringRef prop_name, int32_t value, eIDPropertyFlag flags={})
Allocate a new IDProperty of type IDP_INT, set its name and value.
std::unique_ptr< IDProperty, IDPropertyDeleter > create_group(StringRef prop_name, eIDPropertyFlag flags={})
Allocate a new IDProperty of type IDP_GROUP.
bNodeSocket * node_find_socket(bNode &node, eNodeSocketInOut in_out, StringRef identifier)
Definition node.cc:2532
bNode * node_add_node(const bContext *C, bNodeTree &ntree, StringRef idname, std::optional< int > unique_identifier=std::nullopt)
Definition node.cc:3477
bool node_set_selected(bNode &node, bool select)
Definition node.cc:4695
bNodeLink & node_add_link(bNodeTree &ntree, bNode &fromnode, bNodeSocket &fromsock, bNode &tonode, bNodeSocket &tosock)
Definition node.cc:3810
bNodeTree * node_tree_add_in_lib(Main *bmain, Library *owner_library, StringRefNull name, StringRefNull idname)
Definition node.cc:4090
bNodeTree * node_tree_from_id(ID *id)
Definition node.cc:4568
T safe_rcp(const T &a)
T safe_divide(const T &a, const T &b)
T average(const VecBase< T, Size > &a)
MatT from_scale(const VecBase< typename MatT::base_type, ScaleDim > &scale)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
MatBase< float, 2, 2 > float2x2
MatBase< float, 2, 4 > float2x4
VecBase< float, 4 > float4
VecBase< float, 2 > float2
MatBase< float, 4, 2 > float4x2
MatBase< float, 3, 2 > float3x2
MatBase< float, 4, 3 > float4x3
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
VecBase< float, 3 > float3
const char * name
static void def_group(BlenderRNA *, StructRNA *srna)
#define FLT_MAX
Definition stdcycles.h:14
bAction * action
bAction * tmpact
ListBase drivers
ListBase nla_tracks
float vec[3][3]
char * rna_path
FPoint * fpt
BezTriple * bezt
unsigned int totvert
float vec[2]
GreasePencilLayerTreeNode base
GreasePencilModifierInfluenceData influence
GreasePencilOnionSkinningSettings onion_skinning_settings
struct AnimData * adt
Definition DNA_ID.h:414
struct Library * lib
Definition DNA_ID.h:420
char name[258]
Definition DNA_ID.h:432
IDProperty * system_properties
Definition DNA_ID.h:489
IDProperty * properties
Definition DNA_ID.h:480
struct MDeformWeight * dw
ListBase scenes
Definition BKE_main.hh:278
ListBase movieclips
Definition BKE_main.hh:311
ListBase nodetrees
Definition BKE_main.hh:301
ListBase screens
Definition BKE_main.hh:292
ListBase gpencils
Definition BKE_main.hh:309
ListBase objects
Definition BKE_main.hh:280
struct ModifierData * next
ModifierTypeFlag flags
ListBase strips
bAction * act
struct Object * parent
struct bGPdata * gpd
struct bGPdata * gpd
struct bGPdata * gpd
ListBase vertex_group_names
void * default_value
struct GeometryNodeAssetTraits * geometry_node_asset_traits
bNodeTreeInterface tree_interface
ListBase nodes
float location[2]
AnimDataFCurveConvertor(const char *relative_rna_path_src, const char *relative_rna_path_dst, blender::FunctionRef< FCurveConvertCB > convert_cb={nullptr})
ConversionData(Main &bmain, BlendfileLinkAppendContext *lapp_context)
i
Definition text_draw.cc:230