Files
test2/source/blender/modifiers/intern/MOD_grease_pencil_time.cc
Bastien Montagne c607ead4b7 Refactor: Makesrna: move generated code further in C++.
This commit moves generated `RNA_blender.h`, `RNA_prototype.h` and
`RNA_blender_cpp.h` headers to become C++ header files.

It also removes the now useless `RNA_EXTERN_C` defines, and just
directly use the `extern` keyword. We do not need anymore `extern "C"`
declarations here.

Pull Request: https://projects.blender.org/blender/blender/pulls/124469
2024-07-15 16:39:45 +02:00

717 lines
27 KiB
C++

/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup modifiers
*/
#include "BLI_index_range.hh"
#include "BLI_map.hh"
#include "BLI_span.hh"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_vector_set.hh"
#include "DNA_defaults.h"
#include "DNA_modifier_types.h"
#include "DNA_scene_types.h"
#include "BKE_curves.hh"
#include "BKE_geometry_set.hh"
#include "BKE_grease_pencil.hh"
#include "BKE_instances.hh"
#include "BKE_modifier.hh"
#include "BKE_screen.hh"
#include "BLO_read_write.hh"
#include "DEG_depsgraph_query.hh"
#include "UI_interface.hh"
#include "UI_resources.hh"
#include "BLT_translation.hh"
#include "WM_api.hh"
#include "WM_types.hh"
#include "RNA_access.hh"
#include "RNA_prototypes.hh"
#include "MOD_grease_pencil_util.hh"
#include "MOD_ui_common.hh"
#include <iostream>
namespace blender {
static void init_data(ModifierData *md)
{
auto *tmd = reinterpret_cast<GreasePencilTimeModifierData *>(md);
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(tmd, modifier));
MEMCPY_STRUCT_AFTER(tmd, DNA_struct_default_get(GreasePencilTimeModifierData), modifier);
modifier::greasepencil::init_influence_data(&tmd->influence, false);
GreasePencilTimeModifierSegment *segment = DNA_struct_default_alloc(
GreasePencilTimeModifierSegment);
STRNCPY_UTF8(segment->name, DATA_("Segment"));
tmd->segments_array = segment;
tmd->segments_num = 1;
}
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
{
const auto *tmd = reinterpret_cast<const GreasePencilTimeModifierData *>(md);
auto *tmmd = reinterpret_cast<GreasePencilTimeModifierData *>(target);
modifier::greasepencil::free_influence_data(&tmmd->influence);
BKE_modifier_copydata_generic(md, target, flag);
modifier::greasepencil::copy_influence_data(&tmd->influence, &tmmd->influence, flag);
tmmd->segments_array = static_cast<GreasePencilTimeModifierSegment *>(
MEM_dupallocN(tmd->segments_array));
}
static void free_data(ModifierData *md)
{
auto *tmd = reinterpret_cast<GreasePencilTimeModifierData *>(md);
modifier::greasepencil::free_influence_data(&tmd->influence);
MEM_SAFE_FREE(tmd->segments_array);
}
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
{
auto *tmd = reinterpret_cast<GreasePencilTimeModifierData *>(md);
modifier::greasepencil::foreach_influence_ID_link(&tmd->influence, ob, walk, user_data);
}
struct FrameRange {
/* Start frame. */
int sfra;
/* End frame (unlimited range when undefined). */
int efra;
bool is_empty() const
{
return efra < sfra;
}
bool is_single_frame() const
{
return efra == sfra;
}
int duration() const
{
return std::max(efra + 1 - sfra, 0);
}
FrameRange drop_front(const int n) const
{
BLI_assert(n >= 0);
return FrameRange{std::min(sfra + n, efra), efra};
}
FrameRange drop_back(const int n) const
{
BLI_assert(n >= 0);
return FrameRange{sfra, std::max(efra - n, sfra)};
}
FrameRange shift(const int n) const
{
return FrameRange{sfra + n, efra + n};
}
};
/**
* Find the index range of sorted keys that covers the frame range, including the key right before
* and after the interval. The extra keys are needed when frames are held at the beginning or when
* reversing the direction.
*/
static const IndexRange find_key_range(const Span<int> sorted_keys, const FrameRange &frame_range)
{
IndexRange result = sorted_keys.index_range();
for (const int i : result.index_range()) {
const int irev = result.size() - 1 - i;
if (sorted_keys[result[irev]] <= frame_range.sfra) {
/* Found first key affecting the frame range, drop any earlier keys. */
result = result.drop_front(irev);
break;
}
}
for (const int i : result.index_range()) {
if (sorted_keys[result[i]] > frame_range.efra) {
/* Found first key outside the frame range, drop this and later keys. */
result = result.take_front(i);
break;
}
}
return result;
}
struct TimeMapping {
private:
float offset_;
float scale_;
bool use_loop_;
public:
TimeMapping(const GreasePencilTimeModifierData &tmd)
: offset_(tmd.offset),
scale_(tmd.frame_scale),
use_loop_(tmd.flag & MOD_GREASE_PENCIL_TIME_KEEP_LOOP)
{
}
float offset() const
{
return offset_;
}
float scale() const
{
return scale_;
}
bool use_loop() const
{
return use_loop_;
}
float to_scene_time(const float local_frame) const
{
return float(local_frame - offset_) / scale_;
}
float to_local_time(const float scene_frame) const
{
return scene_frame * scale_ + offset_;
}
/* Compute scene frame number on or after the local frame. */
int scene_frame_before_local_frame(const int local_frame) const
{
return int(math::floor(to_scene_time(local_frame)));
}
/* Compute scene frame number on or after the local frame. */
int scene_frame_after_local_frame(const int local_frame) const
{
return int(math::ceil(to_scene_time(local_frame)));
}
/* Compute local frame number on or before the scene frame. */
int local_frame_before_scene_frame(const int scene_frame) const
{
return int(math::floor(to_local_time(scene_frame)));
}
/* Compute local frame number on or after the scene frame. */
int local_frame_after_scene_frame(const int scene_frame) const
{
return int(math::ceil(to_local_time(scene_frame)));
}
};
/* Determine how many times the source range must be repeated to cover the destination range. */
static void calculate_repetitions(const TimeMapping &mapping,
const FrameRange &gp_src,
const FrameRange &scene_dst,
int &r_start,
int &r_count)
{
if (!mapping.use_loop()) {
r_start = 0;
r_count = 1;
return;
}
const int duration = gp_src.duration();
if (duration <= 0) {
r_start = 0;
r_count = 0;
return;
}
const FrameRange gp_dst = {mapping.local_frame_before_scene_frame(scene_dst.sfra),
mapping.local_frame_after_scene_frame(scene_dst.efra)};
r_start = math::floor(float(gp_dst.sfra - gp_src.sfra) / float(duration));
r_count = math::floor(float(gp_dst.efra - gp_src.sfra) / float(duration)) + 1 - r_start;
}
static void insert_keys_forward(const TimeMapping &mapping,
const Map<int, GreasePencilFrame> &frames,
const Span<int> sorted_keys,
const FrameRange gp_src_range,
const FrameRange gp_dst_range,
Map<int, GreasePencilFrame> &dst_frames)
{
const int offset = gp_dst_range.sfra - gp_src_range.sfra;
for (const int i : sorted_keys.index_range()) {
const int gp_key = sorted_keys[i];
const int gp_insert_key = std::max(gp_key, gp_src_range.sfra);
if (gp_insert_key > gp_src_range.efra) {
continue;
}
const int scene_key = mapping.scene_frame_after_local_frame(gp_insert_key + offset);
dst_frames.add_overwrite(scene_key, frames.lookup(gp_key));
}
}
/* Insert keys in reverse order. */
static void insert_keys_reverse(const TimeMapping &mapping,
const Map<int, GreasePencilFrame> &frames,
const Span<int> sorted_keys,
const FrameRange gp_src_range,
const FrameRange gp_dst_range,
Map<int, GreasePencilFrame> &dst_frames)
{
const int offset = gp_dst_range.sfra - gp_src_range.sfra;
for (const int i : sorted_keys.index_range()) {
/* In reverse mode keys need to be inserted in reverse order to ensure "earlier" frames can
* overwrite "later" frames. */
const int irev = sorted_keys.size() - 1 - i;
/* This finds the correct scene frame starting at the end of the frame interval. */
const int gp_key = sorted_keys[irev];
/* The insertion scene time is the end of the keyframe interval instead of the start.
* This is the frame after the end frame (efra) to cover the full extent of the end frame
* interval. */
const int gp_end_key = (irev < sorted_keys.size() - 1) ?
std::min(sorted_keys[irev + 1], gp_src_range.efra + 1) :
gp_src_range.efra + 1;
if (gp_end_key < gp_src_range.sfra) {
return;
}
/* Reverse key frame inside the range. */
const int gp_key_rev = gp_src_range.efra + 1 - (gp_end_key - gp_src_range.sfra);
const int scene_key = mapping.scene_frame_after_local_frame(gp_key_rev + offset);
dst_frames.add_overwrite(scene_key, frames.lookup(gp_key));
}
}
static void fill_scene_range_fixed(const TimeMapping &mapping,
const Map<int, GreasePencilFrame> &frames,
const Span<int> sorted_keys,
const int gp_src_frame,
const FrameRange scene_dst_range,
Map<int, GreasePencilFrame> &dst_frames)
{
const FrameRange gp_src_range = {gp_src_frame, gp_src_frame};
const FrameRange gp_dst_range = {mapping.local_frame_before_scene_frame(scene_dst_range.sfra),
mapping.local_frame_after_scene_frame(scene_dst_range.efra)};
const Span<int> src_keys = sorted_keys.slice(find_key_range(sorted_keys, gp_src_range));
insert_keys_forward(mapping, frames, src_keys, gp_src_range, gp_dst_range, dst_frames);
}
static void fill_scene_range_forward(const TimeMapping &mapping,
const Map<int, GreasePencilFrame> &frames,
const Span<int> sorted_keys,
const FrameRange gp_src_range,
const FrameRange scene_dst_range,
Map<int, GreasePencilFrame> &dst_frames)
{
int repeat_start = 0, repeat_count = 1;
calculate_repetitions(mapping, gp_src_range, scene_dst_range, repeat_start, repeat_count);
const Span<int> src_keys = sorted_keys.slice(find_key_range(sorted_keys, gp_src_range));
FrameRange gp_dst_range = gp_src_range.shift(repeat_start * gp_src_range.duration());
for ([[maybe_unused]] const int repeat_i : IndexRange(repeat_count)) {
insert_keys_forward(mapping, frames, src_keys, gp_src_range, gp_dst_range, dst_frames);
gp_dst_range = gp_dst_range.shift(gp_src_range.duration());
}
}
static void fill_scene_range_reverse(const TimeMapping &mapping,
const Map<int, GreasePencilFrame> &frames,
const Span<int> sorted_keys,
const FrameRange gp_src_range,
const FrameRange scene_dst_range,
Map<int, GreasePencilFrame> &dst_frames)
{
int repeat_start = 0, repeat_count = 1;
calculate_repetitions(mapping, gp_src_range, scene_dst_range, repeat_start, repeat_count);
const Span<int> src_keys = sorted_keys.slice(find_key_range(sorted_keys, gp_src_range));
FrameRange gp_dst_range = gp_src_range.shift(repeat_start * gp_src_range.duration());
for ([[maybe_unused]] const int repeat_i : IndexRange(repeat_count)) {
insert_keys_reverse(mapping, frames, src_keys, gp_src_range, gp_dst_range, dst_frames);
gp_dst_range = gp_dst_range.shift(gp_src_range.duration());
}
}
static void fill_scene_range_ping_pong(const TimeMapping &mapping,
const Map<int, GreasePencilFrame> &frames,
const Span<int> sorted_keys,
const FrameRange gp_src_range,
const FrameRange scene_dst_range,
Map<int, GreasePencilFrame> &dst_frames)
{
/* Double interval for ping-pong mode, start and end frame only appear once. */
const FrameRange gp_src_range_ping = {gp_src_range.sfra, gp_src_range.efra - 1};
const FrameRange gp_src_range_pong = {gp_src_range.sfra + 1, gp_src_range.efra};
const FrameRange gp_range_full = {gp_src_range.sfra,
2 * gp_src_range.efra - gp_src_range.sfra - 1};
int repeat_start = 0, repeat_count = 1;
calculate_repetitions(mapping, gp_range_full, scene_dst_range, repeat_start, repeat_count);
const Span<int> src_keys = sorted_keys.slice(find_key_range(sorted_keys, gp_src_range));
FrameRange gp_dst_range = gp_src_range.shift(repeat_start * gp_range_full.duration());
for ([[maybe_unused]] const int repeat_i : IndexRange(repeat_count)) {
/* Ping. */
insert_keys_forward(mapping, frames, src_keys, gp_src_range, gp_dst_range, dst_frames);
gp_dst_range = gp_dst_range.shift(gp_src_range_ping.duration());
/* Pong. */
insert_keys_reverse(mapping, frames, src_keys, gp_src_range, gp_dst_range, dst_frames);
gp_dst_range = gp_dst_range.shift(gp_src_range_pong.duration());
}
}
static void fill_scene_range_chain(const TimeMapping &mapping,
const Map<int, GreasePencilFrame> &frames,
const Span<int> sorted_keys,
const Span<GreasePencilTimeModifierSegment> segments,
const FrameRange gp_src_range,
const FrameRange scene_dst_range,
Map<int, GreasePencilFrame> &dst_frames)
{
using Segment = GreasePencilTimeModifierSegment;
if (segments.is_empty()) {
return;
}
/* Segment settings tolerate start frame after end frame. */
auto segment_base_range = [](const Segment &segment) {
return FrameRange{std::min(segment.segment_start, segment.segment_end),
std::max(segment.segment_start, segment.segment_end)};
};
auto segment_full_range = [](const Segment &segment) {
const FrameRange base_range = FrameRange{std::min(segment.segment_start, segment.segment_end),
std::max(segment.segment_start, segment.segment_end)};
const int base_duration = (segment.segment_mode == MOD_GREASE_PENCIL_TIME_SEG_MODE_PINGPONG ?
base_range.duration() * 2 - 2 :
base_range.duration());
return FrameRange{base_range.sfra,
base_range.sfra + segment.segment_repeat * base_duration - 1};
};
/* Find src range by adding up all segments. */
const FrameRange gp_range_full = [&]() {
int duration = segment_full_range(segments.first()).duration();
for (const Segment &segment : segments.drop_front(1)) {
duration += segment_full_range(segment).duration();
}
/* Same start as the source range. */
return FrameRange{gp_src_range.sfra, gp_src_range.sfra + duration - 1};
}();
int repeat_start = 0, repeat_count = 1;
calculate_repetitions(mapping, gp_range_full, scene_dst_range, repeat_start, repeat_count);
const Span<int> src_keys = sorted_keys;
FrameRange gp_dst_range = gp_src_range.shift(repeat_start * gp_range_full.duration());
for ([[maybe_unused]] const int repeat_i : IndexRange(repeat_count)) {
for (const Segment &segment : segments) {
const FrameRange segment_src_range = segment_base_range(segment);
for ([[maybe_unused]] const int segment_repeat_i : IndexRange(segment.segment_repeat)) {
switch (GreasePencilTimeModifierSegmentMode(segment.segment_mode)) {
case MOD_GREASE_PENCIL_TIME_SEG_MODE_NORMAL:
insert_keys_forward(
mapping, frames, src_keys, segment_src_range, gp_dst_range, dst_frames);
gp_dst_range = gp_dst_range.shift(segment_src_range.duration());
break;
case MOD_GREASE_PENCIL_TIME_SEG_MODE_REVERSE:
insert_keys_reverse(
mapping, frames, src_keys, segment_src_range, gp_dst_range, dst_frames);
gp_dst_range = gp_dst_range.shift(segment_src_range.duration());
break;
case MOD_GREASE_PENCIL_TIME_SEG_MODE_PINGPONG: {
/* Ping. */
const FrameRange segment_src_range_ping = {segment_src_range.sfra,
segment_src_range.efra - 1};
insert_keys_forward(
mapping, frames, src_keys, segment_src_range_ping, gp_dst_range, dst_frames);
gp_dst_range = gp_dst_range.shift(segment_src_range_ping.duration());
/* Pong. */
const FrameRange segment_src_range_pong = {segment_src_range.sfra + 1,
segment_src_range.efra};
insert_keys_reverse(
mapping, frames, src_keys, segment_src_range_pong, gp_dst_range, dst_frames);
gp_dst_range = gp_dst_range.shift(segment_src_range_pong.duration());
break;
}
}
}
}
}
}
static void fill_scene_timeline(const GreasePencilTimeModifierData &tmd,
const Scene &eval_scene,
const Map<int, GreasePencilFrame> &frames,
const Span<int> sorted_keys,
const FrameRange scene_dst_range,
Map<int, GreasePencilFrame> &dst_frames)
{
const TimeMapping mapping(tmd);
const auto mode = GreasePencilTimeModifierMode(tmd.mode);
const bool use_custom_range = tmd.flag & MOD_GREASE_PENCIL_TIME_CUSTOM_RANGE;
const FrameRange scene_range = FrameRange{eval_scene.r.sfra, eval_scene.r.efra};
const FrameRange custom_range = use_custom_range ? FrameRange{tmd.sfra, tmd.efra} : scene_range;
switch (mode) {
case MOD_GREASE_PENCIL_TIME_MODE_NORMAL:
fill_scene_range_forward(
tmd, frames, sorted_keys, custom_range, scene_dst_range, dst_frames);
break;
case MOD_GREASE_PENCIL_TIME_MODE_REVERSE:
fill_scene_range_reverse(
tmd, frames, sorted_keys, custom_range, scene_dst_range, dst_frames);
break;
case MOD_GREASE_PENCIL_TIME_MODE_FIX:
fill_scene_range_fixed(tmd, frames, sorted_keys, tmd.offset, scene_dst_range, dst_frames);
break;
case MOD_GREASE_PENCIL_TIME_MODE_PINGPONG:
fill_scene_range_ping_pong(
tmd, frames, sorted_keys, custom_range, scene_dst_range, dst_frames);
break;
case MOD_GREASE_PENCIL_TIME_MODE_CHAIN:
fill_scene_range_chain(
tmd, frames, sorted_keys, tmd.segments(), scene_range, scene_dst_range, dst_frames);
break;
}
}
static void modify_geometry_set(ModifierData *md,
const ModifierEvalContext *ctx,
bke::GeometrySet *geometry_set)
{
using bke::greasepencil::Drawing;
using bke::greasepencil::Layer;
auto *tmd = reinterpret_cast<GreasePencilTimeModifierData *>(md);
const Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
/* Just include the current frame for now. The method can be applied to arbitrary ranges. */
const FrameRange dst_keyframe_range = {scene->r.cfra, scene->r.cfra};
if (!geometry_set->has_grease_pencil()) {
return;
}
GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write();
IndexMaskMemory mask_memory;
const IndexMask layer_mask = modifier::greasepencil::get_filtered_layer_mask(
grease_pencil, tmd->influence, mask_memory);
const Span<Layer *> layers_for_write = grease_pencil.layers_for_write();
layer_mask.foreach_index([&](const int64_t layer_i) {
Layer &layer = *layers_for_write[layer_i];
const Span<int> sorted_keys = layer.sorted_keys();
const Map<int, GreasePencilFrame> &src_frames = layer.frames();
Map<int, GreasePencilFrame> new_frames;
fill_scene_timeline(*tmd, *scene, src_frames, sorted_keys, dst_keyframe_range, new_frames);
layer.frames_for_write() = std::move(new_frames);
layer.tag_frames_map_keys_changed();
});
}
static void panel_draw(const bContext *C, Panel *panel)
{
uiLayout *layout = panel->layout;
PointerRNA ob_ptr;
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
auto *tmd = static_cast<GreasePencilTimeModifierData *>(ptr->data);
const auto mode = GreasePencilTimeModifierMode(RNA_enum_get(ptr, "mode"));
const bool use_fixed_offset = (mode == MOD_GREASE_PENCIL_TIME_MODE_FIX);
const bool use_custom_range = !ELEM(
mode, MOD_GREASE_PENCIL_TIME_MODE_FIX, MOD_GREASE_PENCIL_TIME_MODE_CHAIN);
uiLayout *row, *col;
uiLayoutSetPropSep(layout, true);
uiItemR(layout, ptr, "mode", UI_ITEM_NONE, nullptr, ICON_NONE);
col = uiLayoutColumn(layout, false);
const char *text = use_fixed_offset ? IFACE_("Frame") : IFACE_("Frame Offset");
uiItemR(col, ptr, "offset", UI_ITEM_NONE, text, ICON_NONE);
row = uiLayoutRow(col, false);
uiLayoutSetActive(row, !use_fixed_offset);
uiItemR(row, ptr, "frame_scale", UI_ITEM_NONE, IFACE_("Scale"), ICON_NONE);
row = uiLayoutRow(layout, false);
uiLayoutSetActive(row, !use_fixed_offset);
uiItemR(row, ptr, "use_keep_loop", UI_ITEM_NONE, nullptr, ICON_NONE);
if (mode == MOD_GREASE_PENCIL_TIME_MODE_CHAIN) {
row = uiLayoutRow(layout, false);
uiLayoutSetPropSep(row, false);
uiTemplateList(row,
(bContext *)C,
"MOD_UL_grease_pencil_time_modifier_segments",
"",
ptr,
"segments",
ptr,
"segment_active_index",
nullptr,
3,
10,
0,
1,
UI_TEMPLATE_LIST_FLAG_NONE);
col = uiLayoutColumn(row, false);
uiLayout *sub = uiLayoutColumn(col, true);
uiItemO(sub, "", ICON_ADD, "OBJECT_OT_grease_pencil_time_modifier_segment_add");
uiItemO(sub, "", ICON_REMOVE, "OBJECT_OT_grease_pencil_time_modifier_segment_remove");
uiItemS(col);
sub = uiLayoutColumn(col, true);
uiItemEnumO_string(
sub, "", ICON_TRIA_UP, "OBJECT_OT_grease_pencil_time_modifier_segment_move", "type", "UP");
uiItemEnumO_string(sub,
"",
ICON_TRIA_DOWN,
"OBJECT_OT_grease_pencil_time_modifier_segment_move",
"type",
"DOWN");
if (tmd->segments().index_range().contains(tmd->segment_active_index)) {
PointerRNA segment_ptr = RNA_pointer_create(ptr->owner_id,
&RNA_GreasePencilTimeModifierSegment,
&tmd->segments()[tmd->segment_active_index]);
sub = uiLayoutColumn(layout, true);
uiItemR(sub, &segment_ptr, "segment_mode", UI_ITEM_NONE, nullptr, ICON_NONE);
sub = uiLayoutColumn(layout, true);
uiItemR(sub, &segment_ptr, "segment_start", UI_ITEM_NONE, nullptr, ICON_NONE);
uiItemR(sub, &segment_ptr, "segment_end", UI_ITEM_NONE, nullptr, ICON_NONE);
uiItemR(sub, &segment_ptr, "segment_repeat", UI_ITEM_NONE, nullptr, ICON_NONE);
}
}
PanelLayout custom_range_panel_layout = uiLayoutPanelProp(
C, layout, ptr, "open_custom_range_panel");
if (uiLayout *header = custom_range_panel_layout.header) {
uiLayoutSetPropSep(header, false);
uiLayoutSetActive(header, use_custom_range);
uiItemR(header, ptr, "use_custom_frame_range", UI_ITEM_NONE, nullptr, ICON_NONE);
}
if (uiLayout *body = custom_range_panel_layout.body) {
uiLayoutSetPropSep(body, true);
uiLayoutSetActive(body, use_custom_range && RNA_boolean_get(ptr, "use_custom_frame_range"));
col = uiLayoutColumn(body, true);
uiItemR(col, ptr, "frame_start", UI_ITEM_NONE, IFACE_("Frame Start"), ICON_NONE);
uiItemR(col, ptr, "frame_end", UI_ITEM_NONE, IFACE_("End"), ICON_NONE);
}
if (uiLayout *influence_panel = uiLayoutPanelProp(
C, layout, ptr, "open_influence_panel", "Influence"))
{
modifier::greasepencil::draw_layer_filter_settings(C, influence_panel, ptr);
}
modifier_panel_end(layout, ptr);
}
static void segment_list_item_draw(uiList * /*ui_list*/,
const bContext * /*C*/,
uiLayout *layout,
PointerRNA * /*idataptr*/,
PointerRNA *itemptr,
int /*icon*/,
PointerRNA * /*active_dataptr*/,
const char * /*active_propname*/,
int /*index*/,
int /*flt_flag*/)
{
uiLayout *row = uiLayoutRow(layout, true);
uiItemR(row, itemptr, "name", UI_ITEM_R_NO_BG, "", ICON_NONE);
}
static void panel_register(ARegionType *region_type)
{
modifier_panel_register(region_type, eModifierType_GreasePencilTime, panel_draw);
uiListType *list_type = static_cast<uiListType *>(
MEM_callocN(sizeof(uiListType), "Grease Pencil Time modifier segments"));
STRNCPY(list_type->idname, "MOD_UL_grease_pencil_time_modifier_segments");
list_type->draw_item = segment_list_item_draw;
WM_uilisttype_add(list_type);
}
static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
{
const auto *tmd = reinterpret_cast<const GreasePencilTimeModifierData *>(md);
BLO_write_struct(writer, GreasePencilTimeModifierData, tmd);
modifier::greasepencil::write_influence_data(writer, &tmd->influence);
BLO_write_struct_array(
writer, GreasePencilTimeModifierSegment, tmd->segments_num, tmd->segments_array);
}
static void blend_read(BlendDataReader *reader, ModifierData *md)
{
auto *tmd = reinterpret_cast<GreasePencilTimeModifierData *>(md);
modifier::greasepencil::read_influence_data(reader, &tmd->influence);
BLO_read_struct_array(
reader, GreasePencilTimeModifierSegment, tmd->segments_num, &tmd->segments_array);
}
} // namespace blender
ModifierTypeInfo modifierType_GreasePencilTime = {
/*idname*/ "GreasePencilTime",
/*name*/ N_("TimeOffset"),
/*struct_name*/ "GreasePencilTimeModifierData",
/*struct_size*/ sizeof(GreasePencilTimeModifierData),
/*srna*/ &RNA_GreasePencilTimeModifier,
/*type*/ ModifierTypeType::Nonconstructive,
/*flags*/ eModifierTypeFlag_AcceptsGreasePencil | eModifierTypeFlag_SupportsEditmode |
eModifierTypeFlag_EnableInEditmode | eModifierTypeFlag_SupportsMapping,
/*icon*/ ICON_MOD_TIME,
/*copy_data*/ blender::copy_data,
/*deform_verts*/ nullptr,
/*deform_matrices*/ nullptr,
/*deform_verts_EM*/ nullptr,
/*deform_matrices_EM*/ nullptr,
/*modify_mesh*/ nullptr,
/*modify_geometry_set*/ blender::modify_geometry_set,
/*init_data*/ blender::init_data,
/*required_data_mask*/ nullptr,
/*free_data*/ blender::free_data,
/*is_disabled*/ nullptr,
/*update_depsgraph*/ nullptr,
/*depends_on_time*/ nullptr,
/*depends_on_normals*/ nullptr,
/*foreach_ID_link*/ blender::foreach_ID_link,
/*foreach_tex_link*/ nullptr,
/*free_runtime_data*/ nullptr,
/*panel_register*/ blender::panel_register,
/*blend_write*/ blender::blend_write,
/*blend_read*/ blender::blend_read,
};
blender::Span<GreasePencilTimeModifierSegment> GreasePencilTimeModifierData::segments() const
{
return {this->segments_array, this->segments_num};
}
blender::MutableSpan<GreasePencilTimeModifierSegment> GreasePencilTimeModifierData::segments()
{
return {this->segments_array, this->segments_num};
}