GPv3: Python API for frame, drawing and drawing attributes #124787
@ -122,7 +122,6 @@ def register():
|
||||
register_class(cls)
|
||||
|
||||
space_filebrowser.register_props()
|
||||
temp_anim_layers.register_props()
|
||||
|
||||
from bpy.props import (
|
||||
EnumProperty,
|
||||
|
@ -518,7 +518,7 @@ class MESH_UL_attributes(UIList):
|
||||
sub.alignment = 'RIGHT'
|
||||
sub.active = False
|
||||
sub.label(
|
||||
text="{:s} ▶ {:s}".format(iface_(domain_name), iface_(data_type.name)),
|
||||
text="{:s} - {:s}".format(iface_(domain_name), iface_(data_type.name)),
|
||||
translate=False,
|
||||
)
|
||||
|
||||
@ -640,7 +640,7 @@ class MESH_UL_color_attributes(UIList, ColorAttributesListBase):
|
||||
sub = split.row()
|
||||
sub.alignment = 'RIGHT'
|
||||
sub.active = False
|
||||
sub.label(text="{:s} ▶ {:s}".format(iface_(domain_name), iface_(data_type.name)), translate=False)
|
||||
sub.label(text="{:s} - {:s}".format(iface_(domain_name), iface_(data_type.name)), translate=False)
|
||||
|
||||
active_render = _index == data.color_attributes.render_color_index
|
||||
|
||||
|
@ -245,6 +245,16 @@ class DOPESHEET_HT_editor_buttons:
|
||||
|
||||
layout.template_ID(st, "action", new="action.new", unlink="action.unlink")
|
||||
|
||||
# context.space_data.action comes from the active object.
|
||||
adt = context.object and context.object.animation_data
|
||||
if adt and st.action and st.action.is_action_layered:
|
||||
layout.template_search(
|
||||
adt, "action_slot",
|
||||
adt, "action_slots",
|
||||
new="",
|
||||
unlink="anim.slot_unassign_object",
|
||||
)
|
||||
|
||||
# Layer management
|
||||
if st.mode == 'GPENCIL':
|
||||
ob = context.active_object
|
||||
|
@ -7,8 +7,6 @@
|
||||
It is not meant for any particular use, just to have *something* in the UI.
|
||||
"""
|
||||
|
||||
import threading
|
||||
|
||||
import bpy
|
||||
from bpy.types import (
|
||||
Panel,
|
||||
@ -32,97 +30,36 @@ class VIEW3D_PT_animation_layers(Panel):
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
# FIXME: this should be done in response to a message-bus callback, notifier, whatnot.
|
||||
adt = context.object.animation_data
|
||||
with _wm_selected_action_lock:
|
||||
selected_action = getattr(adt, "action", None)
|
||||
# Only set if it has to change, to avoid unnecessary notifies (that cause
|
||||
# a redraw, that cause this code to be called, etc.)
|
||||
if context.window_manager.selected_action != selected_action:
|
||||
context.window_manager.selected_action = selected_action
|
||||
|
||||
col = layout.column()
|
||||
# This has to go via an auxiliary property, as assigning an Animation
|
||||
# data-block should be possible even when `context.object.animation_data`
|
||||
# is `None`, and thus its `animation` property does not exist.
|
||||
col.template_ID(context.window_manager, "selected_action")
|
||||
|
||||
col = layout.column(align=False)
|
||||
|
||||
adt = context.object.animation_data
|
||||
anim = adt and adt.action
|
||||
if anim:
|
||||
slot_sub = col.column(align=True)
|
||||
|
||||
# Slot selector.
|
||||
row = slot_sub.row(align=True)
|
||||
row.prop(adt, "action_slot", text="Slot")
|
||||
row.operator("anim.slot_unassign_object", text="", icon='X')
|
||||
|
||||
slot = anim.slots.get(adt.action_slot, None)
|
||||
if slot:
|
||||
slot_sub.prop(slot, "name_display", text="Name")
|
||||
slot_sub.template_search(
|
||||
adt, "action_slot",
|
||||
adt, "action_slots",
|
||||
new="",
|
||||
unlink="anim.slot_unassign_object",
|
||||
)
|
||||
|
||||
internal_sub = slot_sub.box().column(align=True)
|
||||
internal_sub.active = False
|
||||
internal_sub.active = False # Just to dim.
|
||||
internal_sub.prop(adt, "action_slot_handle", text="handle")
|
||||
if slot:
|
||||
internal_sub.prop(slot, "name", text="Internal Name")
|
||||
if adt.action_slot:
|
||||
internal_sub.prop(adt.action_slot, "name", text="Internal Name")
|
||||
|
||||
if adt:
|
||||
col.prop(adt, "action_slot_name", text="ADT Slot Name")
|
||||
else:
|
||||
col.label(text="ADT Slot Name: -")
|
||||
|
||||
layout.separator()
|
||||
|
||||
if not anim:
|
||||
layout.label(text="No layers")
|
||||
return
|
||||
|
||||
for layer_idx, layer in reversed(list(enumerate(anim.layers))):
|
||||
layerbox = layout.box()
|
||||
col = layerbox.column(align=True)
|
||||
col.prop(layer, "name", text="Layer {:d}:".format(layer_idx + 1))
|
||||
col.prop(layer, "influence")
|
||||
col.prop(layer, "mix_mode")
|
||||
|
||||
|
||||
classes = (
|
||||
VIEW3D_PT_animation_layers,
|
||||
)
|
||||
|
||||
_wm_selected_action_lock = threading.Lock()
|
||||
|
||||
|
||||
def _wm_selected_action_update(wm, context):
|
||||
# Avoid responding to changes written by the panel above.
|
||||
lock_ok = _wm_selected_action_lock.acquire(blocking=False)
|
||||
if not lock_ok:
|
||||
return
|
||||
try:
|
||||
if wm.selected_action is None and context.object.animation_data is None:
|
||||
return
|
||||
|
||||
adt = context.object.animation_data_create()
|
||||
if adt.action == wm.selected_action:
|
||||
# Avoid writing to the property when the new value hasn't changed.
|
||||
return
|
||||
adt.action = wm.selected_action
|
||||
finally:
|
||||
_wm_selected_action_lock.release()
|
||||
|
||||
|
||||
def register_props():
|
||||
# Due to this hackyness, the WindowManager will increase the user count of
|
||||
# the pointed-to Action.
|
||||
WindowManager.selected_action = PointerProperty(
|
||||
type=bpy.types.Action,
|
||||
name="Action",
|
||||
description="Action assigned to the active Object",
|
||||
update=_wm_selected_action_update,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__": # only for live edit.
|
||||
register_, _ = bpy.utils.register_classes_factory(classes)
|
||||
register_()
|
||||
register_props()
|
||||
|
@ -495,6 +495,9 @@ Layer *Action::get_layer_for_keyframing()
|
||||
|
||||
bool Action::assign_id(Slot *slot, ID &animated_id)
|
||||
{
|
||||
BLI_assert_msg(!slot || this->slots().as_span().contains(slot),
|
||||
"Slot should be owned by this Action");
|
||||
|
||||
AnimData *adt = BKE_animdata_ensure_id(&animated_id);
|
||||
if (!adt) {
|
||||
return false;
|
||||
|
@ -115,7 +115,18 @@ static void calculate_point_handles(const HandleType type_left,
|
||||
}
|
||||
const float3 dir = next_diff / next_len + prev_diff / prev_len;
|
||||
|
||||
/* This magic number is unfortunate, but comes from elsewhere in Blender. */
|
||||
/* The magic number 2.5614 is derived from approximating a circular arc at the control
|
||||
* point. Given the constraints
|
||||
* - P0=(0,1),P1=(c,1),P2=(1,c),P3=(1,0).
|
||||
* - The first derivative of the curve must agree with the circular arc derivative at the
|
||||
* endpoints.
|
||||
* - Minimize the maximum radial drift.
|
||||
* one can compute c ≈ 0.5519150244935105707435627. The distance from P0 to P3 is sqrt(2).
|
||||
* The magic factor for `len` is (sqrt(2) / 0.5519150244935105707435627) ≈ 2.562375546255352.
|
||||
* In older code of blender a slightly worse approximation of 2.5614 is used. It's kept
|
||||
* for compatibility.
|
||||
*
|
||||
* See https://spencermortensen.com/articles/bezier-circle/. */
|
||||
const float len = math::length(dir) * 2.5614f;
|
||||
if (len != 0.0f) {
|
||||
if (type_left == BEZIER_HANDLE_AUTO) {
|
||||
|
@ -2,6 +2,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BLI_math_matrix.hh"
|
||||
|
||||
#include "COM_algorithm_realize_on_domain.hh"
|
||||
#include "COM_context.hh"
|
||||
#include "COM_domain.hh"
|
||||
@ -29,11 +31,19 @@ RealizeOnDomainOperation::RealizeOnDomainOperation(Context &context,
|
||||
|
||||
void RealizeOnDomainOperation::execute()
|
||||
{
|
||||
const Domain &in_domain = get_input().domain();
|
||||
|
||||
/* Even and odd-sized domains have different pixel locations, which produces unexpected
|
||||
* filtering. If one is odd and the other is even (detected by testing the low bit of the xor of
|
||||
* the sizes), shift the input by 1/2 pixel so the pixels align. */
|
||||
const float2 translation(((in_domain.size[0] ^ domain_.size[0]) & 1) ? -0.5f : 0.0f,
|
||||
((in_domain.size[1] ^ domain_.size[1]) & 1) ? -0.5f : 0.0f);
|
||||
|
||||
realize_on_domain(context(),
|
||||
get_input(),
|
||||
get_result(),
|
||||
domain_,
|
||||
get_input().domain().transformation,
|
||||
math::translate(in_domain.transformation, translation),
|
||||
get_input().get_realization_options());
|
||||
}
|
||||
|
||||
|
@ -20,11 +20,10 @@ void main()
|
||||
/* Since an input image with an identity transformation is supposed to be centered in the domain,
|
||||
* we subtract the offset between the lower left corners of the input image and the domain, which
|
||||
* is half the difference between their sizes, because the difference in size is on both sides of
|
||||
* the centered image. Additionally, we floor the offset to retain the 0.5 offset added above in
|
||||
* case the difference in sizes was odd. */
|
||||
* the centered image. */
|
||||
ivec2 domain_size = imageSize(domain_img);
|
||||
ivec2 input_size = texture_size(input_tx);
|
||||
vec2 offset = floor(vec2(domain_size - input_size) / 2.0);
|
||||
vec2 offset = vec2(domain_size - input_size) / 2.0;
|
||||
|
||||
/* Subtract the offset and divide by the input image size to get the relevant coordinates into
|
||||
* the sampler's expected [0, 1] range. */
|
||||
|
@ -5051,6 +5051,8 @@ void ANIM_channel_draw(
|
||||
draw_sliders = (sipo->flag & SIPO_SLIDERS);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
@ -5869,6 +5871,8 @@ void ANIM_channel_draw_widgets(const bContext *C,
|
||||
draw_sliders = (sipo->flag & SIPO_SLIDERS);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
@ -5980,11 +5984,13 @@ void ANIM_channel_draw_widgets(const bContext *C,
|
||||
UI_block_emboss_set(block, UI_EMBOSS_NONE);
|
||||
}
|
||||
|
||||
#ifdef WITH_ANIM_BAKLAVA
|
||||
/* Slot ID type indicator. */
|
||||
if (ale->type == ANIMTYPE_ACTION_SLOT) {
|
||||
offset -= ICON_WIDTH;
|
||||
UI_icon_draw(offset, ymid, acf_action_slot_idtype_icon(ale));
|
||||
}
|
||||
#endif /* WITH_ANIM_BAKLAVA */
|
||||
}
|
||||
|
||||
/* Draw slider:
|
||||
|
@ -126,6 +126,7 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
|
||||
{
|
||||
/* get dopesheet */
|
||||
ac->ads = &saction->ads;
|
||||
ac->dopesheet_mode = eAnimEdit_Context(saction->mode);
|
||||
|
||||
/* sync settings with current view status, then return appropriate data */
|
||||
switch (saction->mode) {
|
||||
@ -143,7 +144,6 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
|
||||
ac->datatype = ANIMCONT_ACTION;
|
||||
ac->data = saction->action;
|
||||
|
||||
ac->mode = saction->mode;
|
||||
return true;
|
||||
|
||||
case SACTCONT_SHAPEKEY: /* 'ShapeKey Editor' */
|
||||
@ -161,8 +161,6 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
|
||||
saction->action = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ac->mode = saction->mode;
|
||||
return true;
|
||||
|
||||
case SACTCONT_GPENCIL: /* Grease Pencil */ /* XXX review how this mode is handled... */
|
||||
@ -171,8 +169,6 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
|
||||
|
||||
ac->datatype = ANIMCONT_GPENCIL;
|
||||
ac->data = &saction->ads;
|
||||
|
||||
ac->mode = saction->mode;
|
||||
return true;
|
||||
|
||||
case SACTCONT_CACHEFILE: /* Cache File */ /* XXX review how this mode is handled... */
|
||||
@ -181,8 +177,6 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
|
||||
|
||||
ac->datatype = ANIMCONT_CHANNEL;
|
||||
ac->data = &saction->ads;
|
||||
|
||||
ac->mode = saction->mode;
|
||||
return true;
|
||||
|
||||
case SACTCONT_MASK: /* Mask */ /* XXX: review how this mode is handled. */
|
||||
@ -199,8 +193,6 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
|
||||
|
||||
ac->datatype = ANIMCONT_MASK;
|
||||
ac->data = &saction->ads;
|
||||
|
||||
ac->mode = saction->mode;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -210,8 +202,6 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
|
||||
|
||||
ac->datatype = ANIMCONT_DOPESHEET;
|
||||
ac->data = &saction->ads;
|
||||
|
||||
ac->mode = saction->mode;
|
||||
return true;
|
||||
|
||||
case SACTCONT_TIMELINE: /* Timeline */
|
||||
@ -235,15 +225,11 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
|
||||
|
||||
ac->datatype = ANIMCONT_TIMELINE;
|
||||
ac->data = &saction->ads;
|
||||
|
||||
ac->mode = saction->mode;
|
||||
return true;
|
||||
|
||||
default: /* unhandled yet */
|
||||
ac->datatype = ANIMCONT_NONE;
|
||||
ac->data = nullptr;
|
||||
|
||||
ac->mode = -1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -259,6 +245,7 @@ static bool graphedit_get_context(bAnimContext *ac, SpaceGraph *sipo)
|
||||
sipo->ads->source = (ID *)ac->scene;
|
||||
}
|
||||
ac->ads = sipo->ads;
|
||||
ac->grapheditor_mode = eGraphEdit_Mode(sipo->mode);
|
||||
|
||||
/* set settings for Graph Editor - "Selected = Editable" */
|
||||
if (U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) {
|
||||
@ -277,8 +264,6 @@ static bool graphedit_get_context(bAnimContext *ac, SpaceGraph *sipo)
|
||||
|
||||
ac->datatype = ANIMCONT_FCURVES;
|
||||
ac->data = sipo->ads;
|
||||
|
||||
ac->mode = sipo->mode;
|
||||
return true;
|
||||
|
||||
case SIPO_MODE_DRIVERS: /* Driver F-Curve Editor */
|
||||
@ -288,15 +273,11 @@ static bool graphedit_get_context(bAnimContext *ac, SpaceGraph *sipo)
|
||||
|
||||
ac->datatype = ANIMCONT_DRIVERS;
|
||||
ac->data = sipo->ads;
|
||||
|
||||
ac->mode = sipo->mode;
|
||||
return true;
|
||||
|
||||
default: /* unhandled yet */
|
||||
ac->datatype = ANIMCONT_NONE;
|
||||
ac->data = nullptr;
|
||||
|
||||
ac->mode = -1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -348,6 +329,24 @@ bool ANIM_animdata_context_getdata(bAnimContext *ac)
|
||||
ok = nlaedit_get_context(ac, snla);
|
||||
break;
|
||||
}
|
||||
case SPACE_EMPTY:
|
||||
case SPACE_VIEW3D:
|
||||
case SPACE_OUTLINER:
|
||||
case SPACE_PROPERTIES:
|
||||
case SPACE_FILE:
|
||||
case SPACE_IMAGE:
|
||||
case SPACE_INFO:
|
||||
case SPACE_SEQ:
|
||||
case SPACE_TEXT:
|
||||
case SPACE_SCRIPT:
|
||||
case SPACE_NODE:
|
||||
case SPACE_CONSOLE:
|
||||
case SPACE_USERPREF:
|
||||
case SPACE_CLIP:
|
||||
case SPACE_TOPBAR:
|
||||
case SPACE_STATUSBAR:
|
||||
case SPACE_SPREADSHEET:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -382,8 +381,8 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
|
||||
ac->area = area;
|
||||
ac->region = region;
|
||||
ac->sl = sl;
|
||||
ac->spacetype = (area) ? area->spacetype : 0;
|
||||
ac->regiontype = (region) ? region->regiontype : 0;
|
||||
ac->spacetype = eSpace_Type((area) ? area->spacetype : 0);
|
||||
ac->regiontype = eRegion_Type((region) ? region->regiontype : 0);
|
||||
|
||||
/* get data context info */
|
||||
/* XXX: if the below fails, try to grab this info from context instead...
|
||||
@ -1530,7 +1529,8 @@ static size_t animfilter_action_slot(bAnimContext *ac,
|
||||
/* Add a list element for the Slot itself, but only if in Action mode. The Dopesheet mode
|
||||
* shouldn't display Slots, as F-Curves are always shown in the context of the animated ID
|
||||
* anyway. */
|
||||
const bool is_action_mode = (ac->mode == SACTCONT_ACTION);
|
||||
const bool is_action_mode = (ac->spacetype == SPACE_ACTION &&
|
||||
ac->dopesheet_mode == SACTCONT_ACTION);
|
||||
const bool show_fcurves_only = (filter_mode & ANIMFILTER_FCURVESONLY);
|
||||
const bool include_summary_channels = (filter_mode & ANIMFILTER_LIST_CHANNELS);
|
||||
const bool show_slot_channel = (is_action_mode && selection_ok_for_slot && !show_fcurves_only &&
|
||||
@ -1643,7 +1643,8 @@ static size_t animfilter_action(bAnimContext *ac,
|
||||
|
||||
/* Only show all Slots in Action editor mode. Otherwise the F-Curves ought to be displayed
|
||||
* underneath their animated ID anyway. */
|
||||
const bool is_action_mode = (ac->mode == SACTCONT_ACTION);
|
||||
const bool is_action_mode = (ac->spacetype == SPACE_ACTION &&
|
||||
ac->dopesheet_mode == SACTCONT_ACTION);
|
||||
const bool show_all_slots = (ac->ads->filterflag & ADS_FILTER_ALL_SLOTS);
|
||||
if (is_action_mode && show_all_slots) {
|
||||
return animfilter_action_slots(ac, anim_data, action, filter_mode, owner_id);
|
||||
|
@ -923,7 +923,8 @@ bool ED_geometry_attribute_convert(Mesh *mesh,
|
||||
const GVArray varray = *attributes.lookup_or_default(name_copy, dst_domain, dst_type);
|
||||
|
||||
const CPPType &cpp_type = varray.type();
|
||||
void *new_data = MEM_malloc_arrayN(varray.size(), cpp_type.size(), __func__);
|
||||
void *new_data = MEM_mallocN_aligned(
|
||||
varray.size() * cpp_type.size(), cpp_type.alignment(), __func__);
|
||||
varray.materialize_to_uninitialized(new_data);
|
||||
attributes.remove(name_copy);
|
||||
if (!attributes.add(name_copy, dst_domain, dst_type, bke::AttributeInitMoveArray(new_data))) {
|
||||
|
@ -2462,6 +2462,9 @@ IndexRange clipboard_paste_strokes(Main &bmain,
|
||||
const bool paste_back)
|
||||
{
|
||||
const bke::CurvesGeometry &clipboard_curves = ed::greasepencil::clipboard_curves();
|
||||
if (clipboard_curves.curves_num() <= 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
/* Get a list of all materials in the scene. */
|
||||
const Array<int> clipboard_material_remap = ed::greasepencil::clipboard_materials_remap(bmain,
|
||||
|
@ -11,6 +11,9 @@
|
||||
#include "BLI_sys_types.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_screen_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
struct AnimData;
|
||||
struct Depsgraph;
|
||||
struct ID;
|
||||
@ -54,6 +57,32 @@ struct PropertyRNA;
|
||||
/** \name Context
|
||||
* \{ */
|
||||
|
||||
/** Main Data container types. */
|
||||
enum eAnimCont_Types {
|
||||
/** Invalid or no data. */
|
||||
ANIMCONT_NONE = 0,
|
||||
/** Action (#bAction). */
|
||||
ANIMCONT_ACTION = 1,
|
||||
/** Shape-key (#Key). */
|
||||
ANIMCONT_SHAPEKEY = 2,
|
||||
/** Grease pencil (screen). */
|
||||
ANIMCONT_GPENCIL = 3,
|
||||
/** Dope-sheet (#bDopesheet). */
|
||||
ANIMCONT_DOPESHEET = 4,
|
||||
/** Animation F-Curves (#bDopesheet). */
|
||||
ANIMCONT_FCURVES = 5,
|
||||
/** Drivers (#bDopesheet). */
|
||||
ANIMCONT_DRIVERS = 6,
|
||||
/** NLA (#bDopesheet). */
|
||||
ANIMCONT_NLA = 7,
|
||||
/** Animation channel (#bAnimListElem). */
|
||||
ANIMCONT_CHANNEL = 8,
|
||||
/** Mask dope-sheet. */
|
||||
ANIMCONT_MASK = 9,
|
||||
/** "timeline" editor (#bDopeSheet). */
|
||||
ANIMCONT_TIMELINE = 10,
|
||||
};
|
||||
|
||||
/**
|
||||
* This struct defines a structure used for animation-specific
|
||||
* 'context' information.
|
||||
@ -61,15 +90,17 @@ struct PropertyRNA;
|
||||
struct bAnimContext {
|
||||
/** data to be filtered for use in animation editor */
|
||||
void *data;
|
||||
/** type of data eAnimCont_Types */
|
||||
short datatype;
|
||||
/** Type of `data`. */
|
||||
eAnimCont_Types datatype;
|
||||
|
||||
/** Editor mode, which depends on `spacetype` (below). */
|
||||
eAnimEdit_Context dopesheet_mode;
|
||||
eGraphEdit_Mode grapheditor_mode;
|
||||
|
||||
/** editor->mode */
|
||||
short mode;
|
||||
/** area->spacetype */
|
||||
short spacetype;
|
||||
eSpace_Type spacetype;
|
||||
/** active region -> type (channels or main) */
|
||||
short regiontype;
|
||||
eRegion_Type regiontype;
|
||||
|
||||
/** editor host */
|
||||
ScrArea *area;
|
||||
@ -98,32 +129,6 @@ struct bAnimContext {
|
||||
ReportList *reports;
|
||||
};
|
||||
|
||||
/** Main Data container types. */
|
||||
enum eAnimCont_Types {
|
||||
/** Invalid or no data. */
|
||||
ANIMCONT_NONE = 0,
|
||||
/** Action (#bAction). */
|
||||
ANIMCONT_ACTION = 1,
|
||||
/** Shape-key (#Key). */
|
||||
ANIMCONT_SHAPEKEY = 2,
|
||||
/** Grease pencil (screen). */
|
||||
ANIMCONT_GPENCIL = 3,
|
||||
/** Dope-sheet (#bDopesheet). */
|
||||
ANIMCONT_DOPESHEET = 4,
|
||||
/** Animation F-Curves (#bDopesheet). */
|
||||
ANIMCONT_FCURVES = 5,
|
||||
/** Drivers (#bDopesheet). */
|
||||
ANIMCONT_DRIVERS = 6,
|
||||
/** NLA (#bDopesheet). */
|
||||
ANIMCONT_NLA = 7,
|
||||
/** Animation channel (#bAnimListElem). */
|
||||
ANIMCONT_CHANNEL = 8,
|
||||
/** Mask dope-sheet. */
|
||||
ANIMCONT_MASK = 9,
|
||||
/** "timeline" editor (#bDopeSheet). */
|
||||
ANIMCONT_TIMELINE = 10,
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_prototypes.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_interface_icons.hh"
|
||||
@ -457,9 +458,17 @@ void ui_rna_collection_search_update_fn(
|
||||
has_sep_char = ID_IS_LINKED(id);
|
||||
}
|
||||
}
|
||||
else {
|
||||
name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), nullptr);
|
||||
#ifdef WITH_ANIM_BAKLAVA
|
||||
else if (itemptr.type == &RNA_ActionSlot) {
|
||||
PropertyRNA *prop = RNA_struct_find_property(&itemptr, "name_display");
|
||||
name = RNA_property_string_get_alloc(&itemptr, prop, name_buf, sizeof(name_buf), nullptr);
|
||||
}
|
||||
else {
|
||||
#endif /* WITH_ANIM_BAKLAVA */
|
||||
name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), nullptr);
|
||||
#ifdef WITH_ANIM_BAKLAVA
|
||||
}
|
||||
#endif /* WITH_ANIM_BAKLAVA */
|
||||
|
||||
if (name) {
|
||||
auto cis = std::make_unique<CollItemSearch>();
|
||||
|
@ -2075,7 +2075,18 @@ static void template_search_add_button_name(uiBlock *block,
|
||||
return;
|
||||
}
|
||||
|
||||
PropertyRNA *name_prop = RNA_struct_name_property(type);
|
||||
PropertyRNA *name_prop;
|
||||
#ifdef WITH_ANIM_BAKLAVA
|
||||
if (type == &RNA_ActionSlot) {
|
||||
name_prop = RNA_struct_find_property(active_ptr, "name_display");
|
||||
}
|
||||
else {
|
||||
#endif /* WITH_ANIM_BAKLAVA */
|
||||
name_prop = RNA_struct_name_property(type);
|
||||
#ifdef WITH_ANIM_BAKLAVA
|
||||
}
|
||||
#endif /* WITH_ANIM_BAKLAVA */
|
||||
|
||||
const int width = template_search_textbut_width(active_ptr, name_prop);
|
||||
const int height = template_search_textbut_height();
|
||||
uiDefAutoButR(block, active_ptr, name_prop, 0, "", ICON_NONE, 0, 0, width, height);
|
||||
|
@ -1095,6 +1095,8 @@ static eContextResult screen_ctx_sel_actions_impl(const bContext *C,
|
||||
filter |= ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS;
|
||||
check_selected = true;
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
ANIM_animdata_filter(
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "BLI_color.hh"
|
||||
#include "BLI_index_mask.hh"
|
||||
#include "BLI_kdopbvh.h"
|
||||
#include "BLI_kdtree.h"
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_offset_indices.hh"
|
||||
@ -527,7 +528,8 @@ struct GreasePencilFillOpData {
|
||||
brush.gpencil_settings->fill_extend_mode);
|
||||
const bool show_boundaries = brush.gpencil_settings->flag & GP_BRUSH_FILL_SHOW_HELPLINES;
|
||||
const bool show_extension = brush.gpencil_settings->flag & GP_BRUSH_FILL_SHOW_EXTENDLINES;
|
||||
const float extension_length = brush.gpencil_settings->fill_extend_fac;
|
||||
const float extension_length = brush.gpencil_settings->fill_extend_fac *
|
||||
bke::greasepencil::LEGACY_RADIUS_CONVERSION_FACTOR;
|
||||
const bool extension_cut = brush.gpencil_settings->flag & GP_BRUSH_FILL_STROKE_COLLIDE;
|
||||
|
||||
return {layer,
|
||||
@ -703,6 +705,94 @@ static void grease_pencil_fill_extension_cut(const bContext &C,
|
||||
extension_data.lines.ends = std::move(new_extension_ends);
|
||||
}
|
||||
|
||||
/* Find closest point in each circle and generate extension lines between such pairs. */
|
||||
static void grease_pencil_fill_extension_lines_from_circles(
|
||||
const bContext &C,
|
||||
ed::greasepencil::ExtensionData &extension_data,
|
||||
Span<int> /*origin_drawings*/,
|
||||
Span<int> /*origin_points*/)
|
||||
{
|
||||
const RegionView3D &rv3d = *CTX_wm_region_view3d(&C);
|
||||
const Scene &scene = *CTX_data_scene(&C);
|
||||
const Object &object = *CTX_data_active_object(&C);
|
||||
const GreasePencil &grease_pencil = *static_cast<const GreasePencil *>(object.data);
|
||||
|
||||
const float4x4 view_matrix = float4x4(rv3d.viewmat);
|
||||
|
||||
const Vector<ed::greasepencil::DrawingInfo> drawings =
|
||||
ed::greasepencil::retrieve_visible_drawings(scene, grease_pencil, false);
|
||||
|
||||
const IndexRange circles_range = extension_data.circles.centers.index_range();
|
||||
/* TODO Include high-curvature feature points. */
|
||||
const IndexRange feature_points_range = circles_range.after(0);
|
||||
const IndexRange kd_points_range = IndexRange(circles_range.size() +
|
||||
feature_points_range.size());
|
||||
|
||||
/* Upper bound for segment count. Arrays are sized for easy index mapping, exact count isn't
|
||||
* necessary. Not all entries are added to the BVH tree. */
|
||||
const int max_kd_entries = kd_points_range.size();
|
||||
/* Cached view positions for lines. */
|
||||
Array<float2> view_centers(max_kd_entries);
|
||||
Array<float> view_radii(max_kd_entries);
|
||||
|
||||
KDTree_2d *kdtree = BLI_kdtree_2d_new(max_kd_entries);
|
||||
|
||||
/* Insert points for overlap tests. */
|
||||
for (const int point_i : circles_range.index_range()) {
|
||||
const float2 center =
|
||||
math::transform_point(view_matrix, extension_data.circles.centers[point_i]).xy();
|
||||
const float radius = math::average(math::to_scale(view_matrix)) *
|
||||
extension_data.circles.radii[point_i];
|
||||
|
||||
const int kd_index = circles_range[point_i];
|
||||
view_centers[kd_index] = center;
|
||||
view_radii[kd_index] = radius;
|
||||
|
||||
BLI_kdtree_2d_insert(kdtree, kd_index, center);
|
||||
}
|
||||
for (const int i_point : feature_points_range.index_range()) {
|
||||
/* TODO Insert feature points into the KDTree. */
|
||||
UNUSED_VARS(i_point);
|
||||
}
|
||||
BLI_kdtree_2d_balance(kdtree);
|
||||
|
||||
struct {
|
||||
Vector<float3> starts;
|
||||
Vector<float3> ends;
|
||||
} connection_lines;
|
||||
|
||||
for (const int point_i : circles_range.index_range()) {
|
||||
const int kd_index = circles_range[point_i];
|
||||
const float2 center = view_centers[kd_index];
|
||||
const float radius = view_radii[kd_index];
|
||||
|
||||
BLI_kdtree_2d_range_search_cb_cpp(
|
||||
kdtree,
|
||||
center,
|
||||
radius,
|
||||
[&](const int other_point_i, const float * /*co*/, float /*dist_sq*/) {
|
||||
if (other_point_i == kd_index) {
|
||||
return true;
|
||||
}
|
||||
connection_lines.starts.append(extension_data.circles.centers[point_i]);
|
||||
if (circles_range.contains(other_point_i)) {
|
||||
connection_lines.ends.append(extension_data.circles.centers[other_point_i]);
|
||||
}
|
||||
else if (feature_points_range.contains(other_point_i)) {
|
||||
/* TODO copy feature point to connection_lines (beware of start index!). */
|
||||
connection_lines.ends.append(float3(0));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
BLI_kdtree_2d_free(kdtree);
|
||||
|
||||
/* Add new extension lines. */
|
||||
extension_data.lines.starts.extend(connection_lines.starts);
|
||||
extension_data.lines.ends.extend(connection_lines.ends);
|
||||
}
|
||||
|
||||
static ed::greasepencil::ExtensionData grease_pencil_fill_get_extension_data(
|
||||
const bContext &C, const GreasePencilFillOpData &op_data)
|
||||
{
|
||||
@ -774,9 +864,17 @@ static ed::greasepencil::ExtensionData grease_pencil_fill_get_extension_data(
|
||||
}
|
||||
}
|
||||
|
||||
/* Intersection test against strokes and other extension lines. */
|
||||
if (op_data.extension_cut) {
|
||||
grease_pencil_fill_extension_cut(C, extension_data, origin_drawings, origin_points);
|
||||
switch (op_data.extension_mode) {
|
||||
case GP_FILL_EMODE_EXTEND:
|
||||
/* Intersection test against strokes and other extension lines. */
|
||||
if (op_data.extension_cut) {
|
||||
grease_pencil_fill_extension_cut(C, extension_data, origin_drawings, origin_points);
|
||||
}
|
||||
break;
|
||||
case GP_FILL_EMODE_RADIUS:
|
||||
grease_pencil_fill_extension_lines_from_circles(
|
||||
C, extension_data, origin_drawings, origin_points);
|
||||
break;
|
||||
}
|
||||
|
||||
return extension_data;
|
||||
@ -1075,7 +1173,7 @@ static bool grease_pencil_apply_fill(bContext &C, wmOperator &op, const wmEvent
|
||||
constexpr const ed::greasepencil::FillToolFitMethod fit_method =
|
||||
ed::greasepencil::FillToolFitMethod::FitToView;
|
||||
/* Debug setting: keep image data blocks for inspection. */
|
||||
constexpr const bool keep_images = false;
|
||||
constexpr const bool keep_images = true;
|
||||
|
||||
ARegion ®ion = *CTX_wm_region(&C);
|
||||
/* Perform bounds check. */
|
||||
|
@ -1109,20 +1109,6 @@ bke::CurvesGeometry fill_strokes(const ViewContext &view_context,
|
||||
line_colors,
|
||||
line_width);
|
||||
}
|
||||
const IndexRange circles_range = extensions.circles.centers.index_range();
|
||||
if (!circles_range.is_empty()) {
|
||||
const VArray<ColorGeometry4f> circle_colors = VArray<ColorGeometry4f>::ForSingle(
|
||||
draw_boundary_color, circles_range.size());
|
||||
|
||||
image_render::draw_circles(world_to_view,
|
||||
circles_range,
|
||||
extensions.circles.centers,
|
||||
VArray<float>::ForSpan(extensions.circles.radii),
|
||||
circle_colors,
|
||||
float2(image_size),
|
||||
1.0f,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
ed::greasepencil::image_render::clear_projection_matrix();
|
||||
|
@ -712,11 +712,12 @@ static void invert_visibility_mesh(Object &object, const Span<bke::pbvh::Node *>
|
||||
bke::SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_span<bool>(
|
||||
".hide_poly", bke::AttrDomain::Face);
|
||||
|
||||
undo::push_nodes(object, nodes, undo::Type::HideFace);
|
||||
|
||||
threading::EnumerableThreadSpecific<Vector<int>> all_index_data;
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
Vector<int> &faces = all_index_data.local();
|
||||
for (bke::pbvh::Node *node : nodes.slice(range)) {
|
||||
undo::push_node(object, node, undo::Type::HideFace);
|
||||
bke::pbvh::node_face_indices_calc_mesh(tri_faces, *node, faces);
|
||||
for (const int face : faces) {
|
||||
hide_poly.span[face] = !hide_poly.span[face];
|
||||
@ -737,11 +738,12 @@ static void invert_visibility_grids(Depsgraph &depsgraph,
|
||||
Mesh &mesh = *static_cast<Mesh *>(object.data);
|
||||
bke::pbvh::Tree &pbvh = *object.sculpt->pbvh;
|
||||
SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
|
||||
BitGroupVector<> &grid_hidden = BKE_subdiv_ccg_grid_hidden_ensure(subdiv_ccg);
|
||||
|
||||
undo::push_nodes(object, nodes, undo::Type::HideVert);
|
||||
|
||||
BitGroupVector<> &grid_hidden = BKE_subdiv_ccg_grid_hidden_ensure(subdiv_ccg);
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (bke::pbvh::Node *node : nodes.slice(range)) {
|
||||
undo::push_node(object, node, undo::Type::HideVert);
|
||||
for (const int i : bke::pbvh::node_grid_indices(*node)) {
|
||||
bits::invert(grid_hidden[i]);
|
||||
}
|
||||
@ -756,9 +758,10 @@ static void invert_visibility_grids(Depsgraph &depsgraph,
|
||||
|
||||
static void invert_visibility_bmesh(Object &object, const Span<bke::pbvh::Node *> nodes)
|
||||
{
|
||||
undo::push_nodes(object, nodes, undo::Type::HideVert);
|
||||
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (bke::pbvh::Node *node : nodes.slice(range)) {
|
||||
undo::push_node(object, node, undo::Type::HideVert);
|
||||
bool fully_hidden = true;
|
||||
for (BMVert *vert : BKE_pbvh_bmesh_node_unique_verts(node)) {
|
||||
BM_elem_flag_toggle(vert, BM_ELEM_HIDDEN);
|
||||
|
@ -555,13 +555,14 @@ static void invert_mask_grids(Main &bmain,
|
||||
MultiresModifierData &mmd = *BKE_sculpt_multires_active(&scene, &object);
|
||||
BKE_sculpt_mask_layers_ensure(&depsgraph, &bmain, &object, &mmd);
|
||||
|
||||
undo::push_nodes(object, nodes, undo::Type::Mask);
|
||||
|
||||
const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
|
||||
|
||||
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
|
||||
const Span<CCGElem *> grids = subdiv_ccg.grids;
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (bke::pbvh::Node *node : nodes.slice(range)) {
|
||||
undo::push_node(object, node, undo::Type::Mask);
|
||||
|
||||
const Span<int> grid_indices = bke::pbvh::node_grid_indices(*node);
|
||||
if (grid_hidden.is_empty()) {
|
||||
@ -597,7 +598,7 @@ static void invert_mask_bmesh(Object &object, const Span<bke::pbvh::Node *> node
|
||||
return;
|
||||
}
|
||||
|
||||
undo::push_node(object, nodes.first(), undo::Type::Mask);
|
||||
undo::push_nodes(object, nodes, undo::Type::Mask);
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (bke::pbvh::Node *node : nodes.slice(range)) {
|
||||
for (BMVert *vert : BKE_pbvh_bmesh_node_unique_verts(node)) {
|
||||
|
@ -1776,9 +1776,7 @@ static void vpaint_paint_leaves(bContext *C,
|
||||
GMutableSpan attribute,
|
||||
const Span<bke::pbvh::Node *> nodes)
|
||||
{
|
||||
for (bke::pbvh::Node *node : nodes) {
|
||||
undo::push_node(ob, node, undo::Type::Color);
|
||||
}
|
||||
undo::push_nodes(ob, nodes, undo::Type::Color);
|
||||
|
||||
const Brush &brush = *ob.sculpt->cache->brush;
|
||||
|
||||
@ -2223,9 +2221,7 @@ static int vertex_color_set_exec(bContext *C, wmOperator *op)
|
||||
* color attributes. */
|
||||
BKE_pbvh_ensure_node_loops(*obact.sculpt->pbvh, mesh.corner_tris());
|
||||
|
||||
for (bke::pbvh::Node *node : nodes) {
|
||||
undo::push_node(obact, node, undo::Type::Color);
|
||||
}
|
||||
undo::push_nodes(obact, nodes, undo::Type::Color);
|
||||
|
||||
fill_active_color(obact, paintcol, true, affect_alpha);
|
||||
|
||||
|
@ -321,9 +321,7 @@ static void transform_active_color(bContext *C,
|
||||
BKE_pbvh_ensure_node_loops(pbvh, mesh.corner_tris());
|
||||
|
||||
Vector<bke::pbvh::Node *> nodes = bke::pbvh::search_gather(pbvh, {});
|
||||
for (bke::pbvh::Node *node : nodes) {
|
||||
undo::push_node(obact, node, undo::Type::Color);
|
||||
}
|
||||
undo::push_nodes(obact, nodes, undo::Type::Color);
|
||||
|
||||
transform_active_color_data(*BKE_mesh_from_object(&obact), transform_fn);
|
||||
|
||||
|
@ -2205,23 +2205,16 @@ static void undo_push(Object &ob, Cache *expand_cache)
|
||||
|
||||
switch (expand_cache->target) {
|
||||
case SCULPT_EXPAND_TARGET_MASK:
|
||||
for (bke::pbvh::Node *node : nodes) {
|
||||
undo::push_node(ob, node, undo::Type::Mask);
|
||||
}
|
||||
undo::push_nodes(ob, nodes, undo::Type::Mask);
|
||||
break;
|
||||
case SCULPT_EXPAND_TARGET_FACE_SETS:
|
||||
for (bke::pbvh::Node *node : nodes) {
|
||||
undo::push_node(ob, node, undo::Type::FaceSet);
|
||||
}
|
||||
undo::push_nodes(ob, nodes, undo::Type::FaceSet);
|
||||
break;
|
||||
case SCULPT_EXPAND_TARGET_COLORS: {
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
|
||||
/* The sculpt undo system needs corner indices for corner domain color attributes. */
|
||||
BKE_pbvh_ensure_node_loops(*ss.pbvh, mesh.corner_tris());
|
||||
|
||||
for (bke::pbvh::Node *node : nodes) {
|
||||
undo::push_node(ob, node, undo::Type::Color);
|
||||
}
|
||||
undo::push_nodes(ob, nodes, undo::Type::Color);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1262,9 +1262,9 @@ static void edit_modify_coordinates(
|
||||
const float strength = RNA_float_get(op->ptr, "strength");
|
||||
|
||||
undo::push_begin(ob, op);
|
||||
undo::push_nodes(ob, nodes, undo::Type::Position);
|
||||
for (bke::pbvh::Node *node : nodes) {
|
||||
BKE_pbvh_node_mark_positions_update(node);
|
||||
undo::push_node(ob, node, undo::Type::Position);
|
||||
}
|
||||
switch (mode) {
|
||||
case EditMode::FairPositions:
|
||||
|
@ -169,10 +169,7 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
|
||||
|
||||
Vector<bke::pbvh::Node *> nodes = bke::pbvh::search_gather(pbvh, {});
|
||||
undo::push_begin(ob, op);
|
||||
|
||||
for (bke::pbvh::Node *node : nodes) {
|
||||
undo::push_node(ob, node, undo::Type::Mask);
|
||||
}
|
||||
undo::push_nodes(ob, nodes, undo::Type::Mask);
|
||||
|
||||
Array<float> prev_mask;
|
||||
int iterations = RNA_int_get(op->ptr, "iterations");
|
||||
|
@ -53,11 +53,9 @@ void write_mask_mesh(Object &object,
|
||||
Mesh &mesh = *static_cast<Mesh *>(object.data);
|
||||
bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
|
||||
const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
undo::push_node(object, nodes[i], undo::Type::Mask);
|
||||
}
|
||||
});
|
||||
|
||||
undo::push_nodes(object, nodes, undo::Type::Mask);
|
||||
|
||||
bke::SpanAttributeWriter mask = attributes.lookup_or_add_for_write_span<float>(
|
||||
".sculpt_mask", bke::AttrDomain::Point);
|
||||
if (!mask) {
|
||||
@ -90,9 +88,10 @@ static void init_mask_grids(Main &bmain,
|
||||
const Span<CCGElem *> grids = subdiv_ccg.grids;
|
||||
const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
|
||||
|
||||
undo::push_nodes(object, nodes, undo::Type::Mask);
|
||||
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
undo::push_node(object, nodes[i], undo::Type::Mask);
|
||||
for (const int grid : bke::pbvh::node_grid_indices(*nodes[i])) {
|
||||
write_fn(grid_hidden, grid, grids[grid]);
|
||||
}
|
||||
|
@ -55,8 +55,6 @@ static void apply_projection_mesh(const Sculpt &sd,
|
||||
{
|
||||
Mesh &mesh = *static_cast<Mesh *>(object.data);
|
||||
|
||||
undo::push_node(object, &node, undo::Type::Position);
|
||||
|
||||
const Span<int> verts = bke::pbvh::node_unique_verts(node);
|
||||
const MutableSpan positions = gather_data_mesh(positions_eval, verts, tls.positions);
|
||||
const MutableSpan normals = gather_data_mesh(vert_normals, verts, tls.normals);
|
||||
@ -82,7 +80,6 @@ static void apply_projection_grids(const Sculpt &sd,
|
||||
LocalData &tls)
|
||||
{
|
||||
SculptSession &ss = *object.sculpt;
|
||||
undo::push_node(object, &node, undo::Type::Position);
|
||||
|
||||
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
|
||||
|
||||
@ -116,8 +113,6 @@ static void apply_projection_bmesh(const Sculpt &sd,
|
||||
{
|
||||
const SculptSession &ss = *object.sculpt;
|
||||
|
||||
undo::push_node(object, &node, undo::Type::Position);
|
||||
|
||||
const Set<BMVert *, 0> &verts = BKE_pbvh_bmesh_node_unique_verts(&node);
|
||||
const MutableSpan positions = gather_bmesh_positions(verts, tls.positions);
|
||||
|
||||
@ -157,6 +152,7 @@ static void gesture_apply_for_symmetry_pass(bContext &C, gesture::GestureData &g
|
||||
const Span<float3> positions_eval = BKE_pbvh_get_vert_positions(pbvh);
|
||||
const Span<float3> vert_normals = BKE_pbvh_get_vert_normals(pbvh);
|
||||
MutableSpan<float3> positions_orig = mesh.vert_positions_for_write();
|
||||
undo::push_nodes(object, nodes, undo::Type::Position);
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
LocalData &tls = all_tls.local();
|
||||
for (const int i : range) {
|
||||
@ -174,6 +170,7 @@ static void gesture_apply_for_symmetry_pass(bContext &C, gesture::GestureData &g
|
||||
break;
|
||||
}
|
||||
case bke::pbvh::Type::BMesh: {
|
||||
undo::push_nodes(object, nodes, undo::Type::Position);
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
LocalData &tls = all_tls.local();
|
||||
for (const int i : range) {
|
||||
@ -184,6 +181,7 @@ static void gesture_apply_for_symmetry_pass(bContext &C, gesture::GestureData &g
|
||||
break;
|
||||
}
|
||||
case bke::pbvh::Type::Grids: {
|
||||
undo::push_nodes(object, nodes, undo::Type::Position);
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
LocalData &tls = all_tls.local();
|
||||
for (const int i : range) {
|
||||
|
@ -983,8 +983,8 @@ static void recalcData_actedit(TransInfo *t)
|
||||
ac.area = t->area;
|
||||
ac.region = t->region;
|
||||
ac.sl = static_cast<SpaceLink *>((t->area) ? t->area->spacedata.first : nullptr);
|
||||
ac.spacetype = (t->area) ? t->area->spacetype : 0;
|
||||
ac.regiontype = (t->region) ? t->region->regiontype : 0;
|
||||
ac.spacetype = eSpace_Type((t->area) ? t->area->spacetype : 0);
|
||||
ac.regiontype = eRegion_Type((t->region) ? t->region->regiontype : 0);
|
||||
|
||||
ANIM_animdata_context_getdata(&ac);
|
||||
|
||||
|