Vulkan: Push constants #104880
|
@ -17,11 +17,13 @@ ExternalProject_Add(external_xvidcore
|
|||
INSTALL_DIR ${LIBDIR}/xvidcore
|
||||
)
|
||||
|
||||
ExternalProject_Add_Step(external_xvidcore after_install
|
||||
COMMAND ${CMAKE_COMMAND} -E rename ${LIBDIR}/xvidcore/lib/xvidcore.a ${LIBDIR}/xvidcore/lib/libxvidcore.a || true
|
||||
COMMAND ${CMAKE_COMMAND} -E remove ${LIBDIR}/xvidcore/lib/xvidcore.dll.a
|
||||
DEPENDEES install
|
||||
)
|
||||
if(WIN32)
|
||||
ExternalProject_Add_Step(external_xvidcore after_install
|
||||
COMMAND ${CMAKE_COMMAND} -E rename ${LIBDIR}/xvidcore/lib/xvidcore.a ${LIBDIR}/xvidcore/lib/libxvidcore.a || true
|
||||
COMMAND ${CMAKE_COMMAND} -E remove ${LIBDIR}/xvidcore/lib/xvidcore.dll.a
|
||||
DEPENDEES install
|
||||
)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
set_target_properties(external_xvidcore PROPERTIES FOLDER Mingw)
|
||||
|
|
|
@ -142,7 +142,7 @@ def cmake_advanced_info() -> Union[Tuple[List[str], List[Tuple[str, str]]], Tupl
|
|||
|
||||
make_exe = cmake_cache_var("CMAKE_MAKE_PROGRAM")
|
||||
if make_exe is None:
|
||||
print("Make command not found in: %r not found" % project_path)
|
||||
print("Make command not found: CMAKE_MAKE_PROGRAM")
|
||||
return None, None
|
||||
|
||||
make_exe_basename = os.path.basename(make_exe)
|
||||
|
|
|
@ -42,6 +42,7 @@ def parse_arguments() -> argparse.Namespace:
|
|||
parser.add_argument("--svn-branch", default=None)
|
||||
parser.add_argument("--git-command", default="git")
|
||||
parser.add_argument("--use-linux-libraries", action="store_true")
|
||||
parser.add_argument("--architecture", type=str, choices=("x86_64", "amd64", "arm64",))
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
|
@ -51,6 +52,19 @@ def get_blender_git_root() -> str:
|
|||
# Setup for precompiled libraries and tests from svn.
|
||||
|
||||
|
||||
def get_effective_architecture(args: argparse.Namespace) -> str:
|
||||
architecture = args.architecture
|
||||
if architecture:
|
||||
assert isinstance(architecture, str)
|
||||
return architecture
|
||||
|
||||
# Check platform.version to detect arm64 with x86_64 python binary.
|
||||
if "ARM64" in platform.version():
|
||||
return "arm64"
|
||||
|
||||
return platform.machine().lower()
|
||||
|
||||
|
||||
def svn_update(args: argparse.Namespace, release_version: Optional[str]) -> None:
|
||||
svn_non_interactive = [args.svn_command, '--non-interactive']
|
||||
|
||||
|
@ -58,11 +72,11 @@ def svn_update(args: argparse.Namespace, release_version: Optional[str]) -> None
|
|||
svn_url = make_utils.svn_libraries_base_url(release_version, args.svn_branch)
|
||||
|
||||
# Checkout precompiled libraries
|
||||
architecture = get_effective_architecture(args)
|
||||
if sys.platform == 'darwin':
|
||||
# Check platform.version to detect arm64 with x86_64 python binary.
|
||||
if platform.machine() == 'arm64' or ('ARM64' in platform.version()):
|
||||
if architecture == 'arm64':
|
||||
lib_platform = "darwin_arm64"
|
||||
elif platform.machine() == 'x86_64':
|
||||
elif architecture == 'x86_64':
|
||||
lib_platform = "darwin"
|
||||
else:
|
||||
lib_platform = None
|
||||
|
@ -256,14 +270,15 @@ if __name__ == "__main__":
|
|||
blender_skip_msg = ""
|
||||
submodules_skip_msg = ""
|
||||
|
||||
# Test if we are building a specific release version.
|
||||
branch = make_utils.git_branch(args.git_command)
|
||||
if branch == 'HEAD':
|
||||
sys.stderr.write('Blender git repository is in detached HEAD state, must be in a branch\n')
|
||||
sys.exit(1)
|
||||
|
||||
tag = make_utils.git_tag(args.git_command)
|
||||
release_version = make_utils.git_branch_release_version(branch, tag)
|
||||
blender_version = make_utils. parse_blender_version()
|
||||
if blender_version.cycle != 'alpha':
|
||||
major = blender_version.version // 100
|
||||
minor = blender_version.version % 100
|
||||
branch = f"blender-v{major}.{minor}-release"
|
||||
release_version: Optional[str] = f"{major}.{minor}"
|
||||
else:
|
||||
branch = 'main'
|
||||
release_version = None
|
||||
|
||||
if not args.no_libraries:
|
||||
svn_update(args, release_version)
|
||||
|
|
|
@ -122,7 +122,7 @@ KERNEL_STRUCT_MEMBER(guiding, bool, use_surface_guiding, KERNEL_FEATURE_PATH_GUI
|
|||
KERNEL_STRUCT_MEMBER(guiding, float, sample_surface_guiding_rand, KERNEL_FEATURE_PATH_GUIDING)
|
||||
/* The probability to use surface guiding (i.e., diffuse sampling prob * guiding prob)*/
|
||||
KERNEL_STRUCT_MEMBER(guiding, float, surface_guiding_sampling_prob, KERNEL_FEATURE_PATH_GUIDING)
|
||||
/* Probability of sampling a BSSRDF closure instead of a BSDF closure*/
|
||||
/* Probability of sampling a BSSRDF closure instead of a BSDF closure. */
|
||||
KERNEL_STRUCT_MEMBER(guiding, float, bssrdf_sampling_prob, KERNEL_FEATURE_PATH_GUIDING)
|
||||
/* If volume guiding is enabled */
|
||||
KERNEL_STRUCT_MEMBER(guiding, bool, use_volume_guiding, KERNEL_FEATURE_PATH_GUIDING)
|
||||
|
|
|
@ -1177,7 +1177,7 @@ void LightManager::device_update(Device *device,
|
|||
|
||||
void LightManager::device_free(Device *, DeviceScene *dscene, const bool free_background)
|
||||
{
|
||||
/* to-do: check if the light tree member variables need to be wrapped in a conditional too*/
|
||||
/* TODO: check if the light tree member variables need to be wrapped in a conditional too. */
|
||||
dscene->light_tree_nodes.free();
|
||||
dscene->light_tree_emitters.free();
|
||||
dscene->light_to_tree.free();
|
||||
|
|
|
@ -310,6 +310,9 @@ void GHOST_WindowWin32::adjustWindowRectForDesktop(LPRECT win_rect, DWORD dwStyl
|
|||
monitor.cbSize = sizeof(MONITORINFOEX);
|
||||
monitor.dwFlags = 0;
|
||||
|
||||
/* We'll need this value before it is altered for checking later. */
|
||||
LONG requested_top = win_rect->top;
|
||||
|
||||
/* Note that with MonitorFromPoint using MONITOR_DEFAULTTONEAREST, it will return
|
||||
* the exact monitor if there is one at the location or the nearest monitor if not. */
|
||||
|
||||
|
@ -355,6 +358,9 @@ void GHOST_WindowWin32::adjustWindowRectForDesktop(LPRECT win_rect, DWORD dwStyl
|
|||
/* Adjust to allow for caption, borders, shadows, scaling, etc. Resulting values can be
|
||||
* correctly outside of monitor bounds. NOTE: You cannot specify #WS_OVERLAPPED when calling. */
|
||||
if (fpAdjustWindowRectExForDpi) {
|
||||
/* Use the DPI of the monitor that is at the middle of the rect. */
|
||||
hmonitor = MonitorFromRect(win_rect, MONITOR_DEFAULTTONEAREST);
|
||||
GetMonitorInfo(hmonitor, &monitor);
|
||||
UINT dpiX, dpiY;
|
||||
GetDpiForMonitor(hmonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
|
||||
fpAdjustWindowRectExForDpi(win_rect, dwStyle & ~WS_OVERLAPPED, FALSE, dwExStyle, dpiX);
|
||||
|
@ -362,6 +368,14 @@ void GHOST_WindowWin32::adjustWindowRectForDesktop(LPRECT win_rect, DWORD dwStyl
|
|||
else {
|
||||
AdjustWindowRectEx(win_rect, dwStyle & ~WS_OVERLAPPED, FALSE, dwExStyle);
|
||||
}
|
||||
|
||||
/* Don't hide the title bar. Check the working area of the monitor at the top-left corner, using
|
||||
* the original top since the justWindowRects might have altered it to different monitor. */
|
||||
pt.x = win_rect->left;
|
||||
pt.y = requested_top;
|
||||
hmonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
|
||||
GetMonitorInfo(hmonitor, &monitor);
|
||||
win_rect->top = max(monitor.rcWork.top, win_rect->top);
|
||||
}
|
||||
|
||||
bool GHOST_WindowWin32::getValid() const
|
||||
|
|
|
@ -3513,6 +3513,9 @@ def km_animation_channels(params):
|
|||
("anim.channels_ungroup", {"type": 'G', "value": 'PRESS', "ctrl": True, "alt": True}, None),
|
||||
# Menus.
|
||||
*_template_items_context_menu("DOPESHEET_MT_channel_context_menu", params.context_menu_event),
|
||||
# View
|
||||
("anim.channel_view_pick", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "alt": True}, None),
|
||||
("anim.channels_view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
|
|
@ -25,7 +25,7 @@ def build_default_empty_geometry_node_group(name):
|
|||
|
||||
def geometry_node_group_empty_new():
|
||||
group = build_default_empty_geometry_node_group(data_("Geometry Nodes"))
|
||||
group.links.new(group.nodes["Group Input"].outputs[0], group.nodes["Group Output"].inputs[0])
|
||||
group.links.new(group.nodes[data_("Group Input")].outputs[0], group.nodes[data_("Group Output")].inputs[0])
|
||||
return group
|
||||
|
||||
|
||||
|
@ -121,8 +121,8 @@ class MoveModifierToNodes(Operator):
|
|||
group_node.node_tree = old_group
|
||||
group_node.update()
|
||||
|
||||
group_input_node = group.nodes["Group Input"]
|
||||
group_output_node = group.nodes["Group Output"]
|
||||
group_input_node = group.nodes[data_("Group Input")]
|
||||
group_output_node = group.nodes[data_("Group Output")]
|
||||
|
||||
# Copy default values for inputs and create named attribute input nodes.
|
||||
input_nodes = []
|
||||
|
@ -173,6 +173,7 @@ class MoveModifierToNodes(Operator):
|
|||
first_geometry_output = group_node_output
|
||||
|
||||
# Adjust locations of store named attribute nodes and move group output.
|
||||
# Note that the node group has its sockets names translated, while the built-in nodes don't.
|
||||
if store_nodes:
|
||||
for i, node in enumerate(store_nodes):
|
||||
node.location.x = (i + 1) * 175
|
||||
|
@ -182,9 +183,10 @@ class MoveModifierToNodes(Operator):
|
|||
group.links.new(first_geometry_output, store_nodes[0].inputs["Geometry"])
|
||||
for i in range(len(store_nodes) - 1):
|
||||
group.links.new(store_nodes[i].outputs["Geometry"], store_nodes[i + 1].inputs["Geometry"])
|
||||
group.links.new(store_nodes[-1].outputs["Geometry"], group_output_node.inputs["Geometry"])
|
||||
|
||||
group.links.new(store_nodes[-1].outputs["Geometry"], group_output_node.inputs[data_("Geometry")])
|
||||
else:
|
||||
group.links.new(first_geometry_output, group_output_node.inputs["Geometry"])
|
||||
group.links.new(first_geometry_output, group_output_node.inputs[data_("Geometry")])
|
||||
|
||||
modifier.node_group = group
|
||||
|
||||
|
|
|
@ -556,7 +556,7 @@ class WM_OT_context_toggle_enum(Operator):
|
|||
|
||||
class WM_OT_context_cycle_int(Operator):
|
||||
"""Set a context value (useful for cycling active material, """ \
|
||||
"""vertex keys, groups, etc.)"""
|
||||
"""shape keys, groups, etc.)"""
|
||||
bl_idname = "wm.context_cycle_int"
|
||||
bl_label = "Context Int Cycle"
|
||||
bl_options = {'UNDO', 'INTERNAL'}
|
||||
|
|
|
@ -78,7 +78,7 @@ class PARTICLE_MT_context_menu(Menu):
|
|||
props.use_active = False
|
||||
props.remove_target_particles = True
|
||||
|
||||
if psys.settings.type == 'HAIR':
|
||||
if psys is not None and psys.settings.type == 'HAIR':
|
||||
layout.operator(
|
||||
"curves.convert_from_particle_system",
|
||||
text="Convert to Curves")
|
||||
|
|
|
@ -474,6 +474,9 @@ class DOPESHEET_MT_channel(Menu):
|
|||
layout.separator()
|
||||
layout.operator("anim.channels_fcurves_enable")
|
||||
|
||||
layout.separator()
|
||||
layout.operator("anim.channels_view_selected")
|
||||
|
||||
|
||||
class DOPESHEET_MT_key(Menu):
|
||||
bl_label = "Key"
|
||||
|
@ -601,6 +604,9 @@ class DOPESHEET_MT_gpencil_channel(Menu):
|
|||
layout.separator()
|
||||
layout.operator_menu_enum("anim.channels_move", "direction", text="Move...")
|
||||
|
||||
layout.separator()
|
||||
layout.operator("anim.channels_view_selected")
|
||||
|
||||
|
||||
class DOPESHEET_MT_gpencil_key(Menu):
|
||||
bl_label = "Key"
|
||||
|
@ -689,6 +695,9 @@ class DOPESHEET_MT_channel_context_menu(Menu):
|
|||
# This menu is used from the graph editor too.
|
||||
is_graph_editor = context.area.type == 'GRAPH_EDITOR'
|
||||
|
||||
layout.separator()
|
||||
layout.operator("anim.channels_view_selected")
|
||||
|
||||
layout.operator("anim.channels_setting_enable", text="Mute Channels").type = 'MUTE'
|
||||
layout.operator("anim.channels_setting_disable", text="Unmute Channels").type = 'MUTE'
|
||||
layout.separator()
|
||||
|
|
|
@ -239,6 +239,9 @@ class GRAPH_MT_channel(Menu):
|
|||
layout.separator()
|
||||
layout.operator("anim.channels_fcurves_enable")
|
||||
|
||||
layout.separator()
|
||||
layout.operator("anim.channels_view_selected")
|
||||
|
||||
|
||||
class GRAPH_MT_key(Menu):
|
||||
bl_label = "Key"
|
||||
|
|
|
@ -574,6 +574,11 @@ class NODE_MT_context_menu(Menu):
|
|||
layout.menu("NODE_MT_context_menu_select_menu")
|
||||
layout.menu("NODE_MT_context_menu_show_hide_menu")
|
||||
|
||||
if active_node:
|
||||
layout.separator()
|
||||
props = layout.operator("wm.doc_view_manual", text="Online Manual", icon='URL')
|
||||
props.doc_id = active_node.bl_idname
|
||||
|
||||
|
||||
class NODE_PT_active_node_generic(Panel):
|
||||
bl_space_type = 'NODE_EDITOR'
|
||||
|
|
|
@ -23,8 +23,6 @@ extern "C" {
|
|||
/** Blender release cycle stage: alpha/beta/rc/release. */
|
||||
#define BLENDER_VERSION_CYCLE alpha
|
||||
|
||||
/* TODO proper version bump. */
|
||||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 0
|
||||
|
|
|
@ -373,6 +373,8 @@ bool BKE_fcurve_calc_range(
|
|||
|
||||
/**
|
||||
* Calculate the extents of F-Curve's data.
|
||||
* \param range Only calculate the bounds of the FCurve in the given range.
|
||||
* Does the full range if NULL.
|
||||
*/
|
||||
bool BKE_fcurve_calc_bounds(const struct FCurve *fcu,
|
||||
float *xmin,
|
||||
|
@ -380,7 +382,8 @@ bool BKE_fcurve_calc_bounds(const struct FCurve *fcu,
|
|||
float *ymin,
|
||||
float *ymax,
|
||||
bool do_sel_only,
|
||||
bool include_handles);
|
||||
bool include_handles,
|
||||
const float range[2]);
|
||||
|
||||
/**
|
||||
* Return an array of keyed frames, rounded to `interval`.
|
||||
|
|
|
@ -557,10 +557,11 @@ int BKE_fcurve_bezt_binarysearch_index(const BezTriple array[],
|
|||
/* ...................................... */
|
||||
|
||||
/* Helper for calc_fcurve_* functions -> find first and last BezTriple to be used. */
|
||||
static short get_fcurve_end_keyframes(const FCurve *fcu,
|
||||
BezTriple **first,
|
||||
BezTriple **last,
|
||||
const bool do_sel_only)
|
||||
static bool get_fcurve_end_keyframes(const FCurve *fcu,
|
||||
BezTriple **first,
|
||||
BezTriple **last,
|
||||
const bool do_sel_only,
|
||||
const float range[2])
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
|
@ -573,11 +574,31 @@ static short get_fcurve_end_keyframes(const FCurve *fcu,
|
|||
return found;
|
||||
}
|
||||
|
||||
int first_index = 0;
|
||||
int last_index = fcu->totvert - 1;
|
||||
|
||||
if (range != NULL) {
|
||||
/* If a range is passed in find the first and last keyframe within that range. */
|
||||
bool replace = false;
|
||||
first_index = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, range[0], fcu->totvert, &replace);
|
||||
last_index = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, range[1], fcu->totvert, &replace);
|
||||
|
||||
/* If first and last index are the same, no keyframes were found in the range. */
|
||||
if (first_index == last_index) {
|
||||
return found;
|
||||
}
|
||||
|
||||
/* The binary search returns an index where a keyframe would be inserted,
|
||||
so it needs to be clamped to ensure it is in range of the array. */
|
||||
first_index = clamp_i(first_index, 0, fcu->totvert - 1);
|
||||
last_index = clamp_i(last_index - 1, 0, fcu->totvert - 1);
|
||||
}
|
||||
|
||||
/* Only include selected items? */
|
||||
if (do_sel_only) {
|
||||
/* Find first selected. */
|
||||
BezTriple *bezt = fcu->bezt;
|
||||
for (int i = 0; i < fcu->totvert; bezt++, i++) {
|
||||
for (int i = first_index; i <= last_index; i++) {
|
||||
BezTriple *bezt = &fcu->bezt[i];
|
||||
if (BEZT_ISSEL_ANY(bezt)) {
|
||||
*first = bezt;
|
||||
found = true;
|
||||
|
@ -586,8 +607,8 @@ static short get_fcurve_end_keyframes(const FCurve *fcu,
|
|||
}
|
||||
|
||||
/* Find last selected. */
|
||||
bezt = ARRAY_LAST_ITEM(fcu->bezt, BezTriple, fcu->totvert);
|
||||
for (int i = 0; i < fcu->totvert; bezt--, i++) {
|
||||
for (int i = last_index; i >= first_index; i--) {
|
||||
BezTriple *bezt = &fcu->bezt[i];
|
||||
if (BEZT_ISSEL_ANY(bezt)) {
|
||||
*last = bezt;
|
||||
found = true;
|
||||
|
@ -596,9 +617,8 @@ static short get_fcurve_end_keyframes(const FCurve *fcu,
|
|||
}
|
||||
}
|
||||
else {
|
||||
/* Use the whole array. */
|
||||
*first = fcu->bezt;
|
||||
*last = ARRAY_LAST_ITEM(fcu->bezt, BezTriple, fcu->totvert);
|
||||
*first = &fcu->bezt[first_index];
|
||||
*last = &fcu->bezt[last_index];
|
||||
found = true;
|
||||
}
|
||||
|
||||
|
@ -611,23 +631,25 @@ bool BKE_fcurve_calc_bounds(const FCurve *fcu,
|
|||
float *ymin,
|
||||
float *ymax,
|
||||
const bool do_sel_only,
|
||||
const bool include_handles)
|
||||
const bool include_handles,
|
||||
const float range[2])
|
||||
{
|
||||
float xminv = 999999999.0f, xmaxv = -999999999.0f;
|
||||
float yminv = 999999999.0f, ymaxv = -999999999.0f;
|
||||
bool foundvert = false;
|
||||
|
||||
const bool use_range = range != NULL;
|
||||
|
||||
if (fcu->totvert) {
|
||||
if (fcu->bezt) {
|
||||
BezTriple *bezt_first = NULL, *bezt_last = NULL;
|
||||
|
||||
if (xmin || xmax) {
|
||||
/* Get endpoint keyframes. */
|
||||
foundvert = get_fcurve_end_keyframes(fcu, &bezt_first, &bezt_last, do_sel_only);
|
||||
BezTriple *bezt_first = NULL, *bezt_last = NULL;
|
||||
foundvert = get_fcurve_end_keyframes(fcu, &bezt_first, &bezt_last, do_sel_only, range);
|
||||
|
||||
if (bezt_first) {
|
||||
BLI_assert(bezt_last != NULL);
|
||||
|
||||
foundvert = true;
|
||||
if (include_handles) {
|
||||
xminv = min_fff(xminv, bezt_first->vec[0][0], bezt_first->vec[1][0]);
|
||||
xmaxv = max_fff(xmaxv, bezt_last->vec[1][0], bezt_last->vec[2][0]);
|
||||
|
@ -645,6 +667,9 @@ bool BKE_fcurve_calc_bounds(const FCurve *fcu,
|
|||
|
||||
int i;
|
||||
for (bezt = fcu->bezt, i = 0; i < fcu->totvert; prevbezt = bezt, bezt++, i++) {
|
||||
if (use_range && (bezt->vec[1][0] < range[0] || bezt->vec[1][0] > range[1])) {
|
||||
continue;
|
||||
}
|
||||
if ((do_sel_only == false) || BEZT_ISSEL_ANY(bezt)) {
|
||||
/* Keyframe itself. */
|
||||
yminv = min_ff(yminv, bezt->vec[1][1]);
|
||||
|
@ -717,10 +742,10 @@ bool BKE_fcurve_calc_bounds(const FCurve *fcu,
|
|||
}
|
||||
|
||||
if (xmin) {
|
||||
*xmin = 0.0f;
|
||||
*xmin = use_range ? range[0] : 0.0f;
|
||||
}
|
||||
if (xmax) {
|
||||
*xmax = 1.0f;
|
||||
*xmax = use_range ? range[1] : 1.0f;
|
||||
}
|
||||
|
||||
if (ymin) {
|
||||
|
@ -745,7 +770,7 @@ bool BKE_fcurve_calc_range(
|
|||
BezTriple *bezt_first = NULL, *bezt_last = NULL;
|
||||
|
||||
/* Get endpoint keyframes. */
|
||||
get_fcurve_end_keyframes(fcu, &bezt_first, &bezt_last, do_sel_only);
|
||||
get_fcurve_end_keyframes(fcu, &bezt_first, &bezt_last, do_sel_only, NULL);
|
||||
|
||||
if (bezt_first) {
|
||||
BLI_assert(bezt_last != NULL);
|
||||
|
|
|
@ -1558,7 +1558,6 @@ void BKE_mesh_legacy_convert_uvs_to_struct(
|
|||
{
|
||||
using namespace blender;
|
||||
using namespace blender::bke;
|
||||
const AttributeAccessor attributes = mesh->attributes();
|
||||
Vector<CustomDataLayer, 16> new_layer_to_write;
|
||||
|
||||
/* Don't write the boolean UV map sublayers which will be written in the legacy #MLoopUV type. */
|
||||
|
@ -1591,24 +1590,30 @@ void BKE_mesh_legacy_convert_uvs_to_struct(
|
|||
mloopuv_layer.data = mloopuv.data();
|
||||
|
||||
char buffer[MAX_CUSTOMDATA_LAYER_NAME];
|
||||
const VArray<bool> vert_selection = attributes.lookup_or_default<bool>(
|
||||
BKE_uv_map_vert_select_name_get(layer.name, buffer), ATTR_DOMAIN_CORNER, false);
|
||||
const VArray<bool> edge_selection = attributes.lookup_or_default<bool>(
|
||||
BKE_uv_map_edge_select_name_get(layer.name, buffer), ATTR_DOMAIN_CORNER, false);
|
||||
const VArray<bool> pin = attributes.lookup_or_default<bool>(
|
||||
BKE_uv_map_pin_name_get(layer.name, buffer), ATTR_DOMAIN_CORNER, false);
|
||||
const bool *vert_selection = static_cast<const bool *>(CustomData_get_layer_named(
|
||||
&mesh->ldata, CD_PROP_BOOL, BKE_uv_map_vert_select_name_get(layer.name, buffer)));
|
||||
const bool *edge_selection = static_cast<const bool *>(CustomData_get_layer_named(
|
||||
&mesh->ldata, CD_PROP_BOOL, BKE_uv_map_edge_select_name_get(layer.name, buffer)));
|
||||
const bool *pin = static_cast<const bool *>(CustomData_get_layer_named(
|
||||
&mesh->ldata, CD_PROP_BOOL, BKE_uv_map_pin_name_get(layer.name, buffer)));
|
||||
|
||||
threading::parallel_for(mloopuv.index_range(), 2048, [&](IndexRange range) {
|
||||
for (const int i : range) {
|
||||
copy_v2_v2(mloopuv[i].uv, coords[i]);
|
||||
SET_FLAG_FROM_TEST(mloopuv[i].flag, vert_selection[i], MLOOPUV_VERTSEL);
|
||||
SET_FLAG_FROM_TEST(mloopuv[i].flag, edge_selection[i], MLOOPUV_EDGESEL);
|
||||
SET_FLAG_FROM_TEST(mloopuv[i].flag, pin[i], MLOOPUV_PINNED);
|
||||
SET_FLAG_FROM_TEST(mloopuv[i].flag, vert_selection && vert_selection[i], MLOOPUV_VERTSEL);
|
||||
SET_FLAG_FROM_TEST(mloopuv[i].flag, edge_selection && edge_selection[i], MLOOPUV_EDGESEL);
|
||||
SET_FLAG_FROM_TEST(mloopuv[i].flag, pin && pin[i], MLOOPUV_PINNED);
|
||||
}
|
||||
});
|
||||
new_layer_to_write.append(mloopuv_layer);
|
||||
}
|
||||
|
||||
/* #CustomData expects the layers to be sorted in increasing order based on type. */
|
||||
std::stable_sort(
|
||||
new_layer_to_write.begin(),
|
||||
new_layer_to_write.end(),
|
||||
[](const CustomDataLayer &a, const CustomDataLayer &b) { return a.type < b.type; });
|
||||
|
||||
loop_layers_to_write = new_layer_to_write;
|
||||
mesh->ldata.totlayer = new_layer_to_write.size();
|
||||
mesh->ldata.maxlayer = mesh->ldata.totlayer;
|
||||
|
|
|
@ -77,17 +77,17 @@ TEST(nla_track, BKE_nlatrack_remove_strip)
|
|||
strip2.start = 11;
|
||||
strip2.end = 20;
|
||||
|
||||
// Add NLA strips to the NLATrack.
|
||||
/* Add NLA strips to the NLATrack. */
|
||||
BKE_nlastrips_add_strip(&strips, &strip1);
|
||||
BKE_nlastrips_add_strip(&strips, &strip2);
|
||||
track.strips = strips;
|
||||
|
||||
// ensure we have 2 strips in the track.
|
||||
/* Ensure we have 2 strips in the track. */
|
||||
EXPECT_EQ(2, BLI_listbase_count(&track.strips));
|
||||
|
||||
BKE_nlatrack_remove_strip(&track, &strip2);
|
||||
EXPECT_EQ(1, BLI_listbase_count(&track.strips));
|
||||
// ensure the correct strip was removed.
|
||||
/* Ensure the correct strip was removed. */
|
||||
EXPECT_EQ(-1, BLI_findindex(&track.strips, &strip2));
|
||||
}
|
||||
|
||||
|
@ -97,20 +97,20 @@ TEST(nla_track, BKE_nlatrack_remove_and_free)
|
|||
NlaTrack *track1;
|
||||
NlaTrack *track2;
|
||||
|
||||
// Add NLA tracks to the Animation Data.
|
||||
/* Add NLA tracks to the Animation Data. */
|
||||
track1 = BKE_nlatrack_add(&adt, NULL, false);
|
||||
track2 = BKE_nlatrack_add(&adt, track1, false);
|
||||
|
||||
// ensure we have 2 tracks in the track.
|
||||
/* Ensure we have 2 tracks in the track. */
|
||||
EXPECT_EQ(2, BLI_listbase_count(&adt.nla_tracks));
|
||||
|
||||
BKE_nlatrack_remove_and_free(&adt.nla_tracks, track2, false);
|
||||
EXPECT_EQ(1, BLI_listbase_count(&adt.nla_tracks));
|
||||
|
||||
// ensure the correct track was removed.
|
||||
/* Ensure the correct track was removed. */
|
||||
EXPECT_EQ(-1, BLI_findindex(&adt.nla_tracks, track2));
|
||||
|
||||
// free the rest of the tracks, and ensure they are removed.
|
||||
/* Free the rest of the tracks, and ensure they are removed. */
|
||||
BKE_nlatrack_remove_and_free(&adt.nla_tracks, track1, false);
|
||||
EXPECT_EQ(0, BLI_listbase_count(&adt.nla_tracks));
|
||||
EXPECT_EQ(-1, BLI_findindex(&adt.nla_tracks, track1));
|
||||
|
|
|
@ -2479,6 +2479,8 @@ void nodeInternalRelink(bNodeTree *ntree, bNode *node)
|
|||
link.tosock->link = &link;
|
||||
}
|
||||
|
||||
Vector<bNodeLink *> duplicate_links_to_remove;
|
||||
|
||||
/* redirect downstream links */
|
||||
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
|
||||
/* do we have internal link? */
|
||||
|
@ -2495,7 +2497,7 @@ void nodeInternalRelink(bNodeTree *ntree, bNode *node)
|
|||
link_to_compare->tosock == link->tosock) {
|
||||
adjust_multi_input_indices_after_removed_link(
|
||||
ntree, link_to_compare->tosock, link_to_compare->multi_input_socket_index);
|
||||
nodeRemLink(ntree, link_to_compare);
|
||||
duplicate_links_to_remove.append_non_duplicates(link_to_compare);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2533,6 +2535,10 @@ void nodeInternalRelink(bNodeTree *ntree, bNode *node)
|
|||
}
|
||||
}
|
||||
|
||||
for (bNodeLink *link : duplicate_links_to_remove) {
|
||||
nodeRemLink(ntree, link);
|
||||
}
|
||||
|
||||
/* remove remaining upstream links */
|
||||
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
|
||||
if (link->tonode == node) {
|
||||
|
|
|
@ -956,7 +956,7 @@ ScrArea *BKE_screen_area_map_find_area_xy(const ScrAreaMap *areamap,
|
|||
const int xy[2])
|
||||
{
|
||||
LISTBASE_FOREACH (ScrArea *, area, &areamap->areabase) {
|
||||
/* Test area's outer screen verts, not inner totrct. */
|
||||
/* Test area's outer screen verts, not inner `area->totrct`. */
|
||||
if (xy[0] >= area->v1->vec.x && xy[0] <= area->v4->vec.x && xy[1] >= area->v1->vec.y &&
|
||||
xy[1] <= area->v2->vec.y) {
|
||||
if (ELEM(spacetype, SPACE_TYPE_ANY, area->spacetype)) {
|
||||
|
|
|
@ -304,6 +304,13 @@ void rotate_eul(float beul[3], char axis, float angle);
|
|||
|
||||
/* Order independent. */
|
||||
|
||||
/**
|
||||
* Manipulate `eul` so it's close to `oldrot` while representing the same rotation
|
||||
* with the aim of having the minimum difference between all axes.
|
||||
*
|
||||
* This is typically done so interpolating the values between two euler rotations
|
||||
* doesn't add undesired rotation (even rotating multiple times around one axis).
|
||||
*/
|
||||
void compatible_eul(float eul[3], const float oldrot[3]);
|
||||
|
||||
void add_eul_euleul(float r_eul[3], float a[3], float b[3], short order);
|
||||
|
|
|
@ -1491,14 +1491,17 @@ void rotate_eul(float beul[3], const char axis, const float angle)
|
|||
void compatible_eul(float eul[3], const float oldrot[3])
|
||||
{
|
||||
/* When the rotation exceeds 180 degrees, it can be wrapped by 360 degrees
|
||||
* to produce a closer match, see !104856. */
|
||||
* to produce a closer match.
|
||||
* NOTE: Values between `pi` & `2 * pi` work, where `pi` has the lowest number of
|
||||
* discontinuities and values approaching `2 * pi` center the resulting rotation around zero,
|
||||
* at the expense of the result being less compatible, see !104856. */
|
||||
const float pi_thresh = (float)M_PI;
|
||||
const float pi_x2 = (2.0f * (float)M_PI);
|
||||
|
||||
float deul[3];
|
||||
uint i;
|
||||
|
||||
/* correct differences of about 360 degrees first */
|
||||
/* Correct differences around 360 degrees first. */
|
||||
for (i = 0; i < 3; i++) {
|
||||
deul[i] = eul[i] - oldrot[i];
|
||||
if (deul[i] > pi_thresh) {
|
||||
|
@ -1513,8 +1516,9 @@ void compatible_eul(float eul[3], const float oldrot[3])
|
|||
|
||||
uint j = 1, k = 2;
|
||||
for (i = 0; i < 3; j = k, k = i++) {
|
||||
/* is 1 of the axis rotations larger than 180 degrees and the other small? */
|
||||
if (fabsf(deul[i]) > 3.2f && fabsf(deul[j]) < 1.6f && fabsf(deul[k]) < 1.6f) {
|
||||
/* Check if this axis of rotations larger than 180 degrees and
|
||||
* the others are smaller than 90 degrees. */
|
||||
if (fabsf(deul[i]) > M_PI && fabsf(deul[j]) < M_PI_2 && fabsf(deul[k]) < M_PI_2) {
|
||||
if (deul[i] > 0.0f) {
|
||||
eul[i] -= pi_x2;
|
||||
}
|
||||
|
|
|
@ -59,9 +59,9 @@ void main()
|
|||
* IF PrimType == LineList: base_vertex_id = quad_id*2
|
||||
* IF PrimType == LineStrip: base_vertex_id = quad_id
|
||||
*
|
||||
* Note: This is currently used as LineList.
|
||||
* NOTE: This is currently used as LineList.
|
||||
*
|
||||
* Note: Primitive Restart Will not work with this setup as-is. We should avoid using
|
||||
* NOTE: Primitive Restart Will not work with this setup as-is. We should avoid using
|
||||
* input primitive types which use restart indices. */
|
||||
int base_vertex_id = quad_id * 2;
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "ED_anim_api.h"
|
||||
#include "ED_armature.h"
|
||||
#include "ED_keyframes_edit.h" /* XXX move the select modes out of there! */
|
||||
#include "ED_markers.h"
|
||||
#include "ED_object.h"
|
||||
#include "ED_screen.h"
|
||||
#include "ED_select_utils.h"
|
||||
|
@ -3638,6 +3639,283 @@ static void ANIM_OT_channel_select_keys(wmOperatorType *ot)
|
|||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name View Channel Operator
|
||||
* \{ */
|
||||
|
||||
static void get_normalized_fcurve_bounds(FCurve *fcu,
|
||||
bAnimContext *ac,
|
||||
const bAnimListElem *ale,
|
||||
const bool include_handles,
|
||||
const float range[2],
|
||||
rctf *r_bounds)
|
||||
{
|
||||
const bool fcu_selection_only = false;
|
||||
BKE_fcurve_calc_bounds(fcu,
|
||||
&r_bounds->xmin,
|
||||
&r_bounds->xmax,
|
||||
&r_bounds->ymin,
|
||||
&r_bounds->ymax,
|
||||
fcu_selection_only,
|
||||
include_handles,
|
||||
range);
|
||||
const short mapping_flag = ANIM_get_normalization_flags(ac);
|
||||
|
||||
const float min_height = 0.01f;
|
||||
const float height = BLI_rctf_size_y(r_bounds);
|
||||
if (height < min_height) {
|
||||
r_bounds->ymin -= (min_height - height) / 2;
|
||||
r_bounds->ymax += (min_height - height) / 2;
|
||||
}
|
||||
|
||||
float offset;
|
||||
const float unit_fac = ANIM_unit_mapping_get_factor(
|
||||
ac->scene, ale->id, fcu, mapping_flag, &offset);
|
||||
|
||||
r_bounds->ymin = (r_bounds->ymin + offset) * unit_fac;
|
||||
r_bounds->ymax = (r_bounds->ymax + offset) * unit_fac;
|
||||
}
|
||||
|
||||
static void get_gpencil_bounds(bGPDlayer *gpl, const float range[2], rctf *r_bounds)
|
||||
{
|
||||
bool found_start = false;
|
||||
int start_frame = 0;
|
||||
int end_frame = 1;
|
||||
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
|
||||
if (gpf->framenum < range[0]) {
|
||||
continue;
|
||||
}
|
||||
if (gpf->framenum > range[1]) {
|
||||
break;
|
||||
}
|
||||
if (!found_start) {
|
||||
start_frame = gpf->framenum;
|
||||
found_start = true;
|
||||
}
|
||||
end_frame = gpf->framenum;
|
||||
}
|
||||
r_bounds->xmin = start_frame;
|
||||
r_bounds->xmax = end_frame;
|
||||
r_bounds->ymin = 0;
|
||||
r_bounds->ymax = 1;
|
||||
}
|
||||
|
||||
static bool get_channel_bounds(bAnimContext *ac,
|
||||
bAnimListElem *ale,
|
||||
const float range[2],
|
||||
const bool include_handles,
|
||||
rctf *r_bounds)
|
||||
{
|
||||
bool found_bounds = false;
|
||||
switch (ale->datatype) {
|
||||
case ALE_GPFRAME: {
|
||||
bGPDlayer *gpl = (bGPDlayer *)ale->data;
|
||||
get_gpencil_bounds(gpl, range, r_bounds);
|
||||
found_bounds = true;
|
||||
break;
|
||||
}
|
||||
case ALE_FCURVE: {
|
||||
FCurve *fcu = (FCurve *)ale->key_data;
|
||||
get_normalized_fcurve_bounds(fcu, ac, ale, include_handles, range, r_bounds);
|
||||
found_bounds = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return found_bounds;
|
||||
}
|
||||
|
||||
static void get_view_range(Scene *scene, const bool use_preview_range, float r_range[2])
|
||||
{
|
||||
if (use_preview_range && scene->r.flag & SCER_PRV_RANGE) {
|
||||
r_range[0] = scene->r.psfra;
|
||||
r_range[1] = scene->r.pefra;
|
||||
}
|
||||
else {
|
||||
r_range[0] = -FLT_MAX;
|
||||
r_range[1] = FLT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pad the given rctf with regions that could block the view.
|
||||
* For example Markers and Time Scrubbing. */
|
||||
static void add_region_padding(bContext *C, bAnimContext *ac, rctf *bounds)
|
||||
{
|
||||
BLI_rctf_scale(bounds, 1.1f);
|
||||
|
||||
const float pad_top = UI_TIME_SCRUB_MARGIN_Y;
|
||||
const float pad_bottom = BLI_listbase_is_empty(ED_context_get_markers(C)) ?
|
||||
V2D_SCROLL_HANDLE_HEIGHT :
|
||||
UI_MARKER_MARGIN_Y;
|
||||
BLI_rctf_pad_y(bounds, ac->region->winy, pad_bottom, pad_top);
|
||||
}
|
||||
|
||||
/* Find the window region in the bAnimContext area and move it to bounds. */
|
||||
static void move_graph_view(bContext *C, bAnimContext *ac, rctf *bounds, const int smooth_viewtx)
|
||||
{
|
||||
LISTBASE_FOREACH (ARegion *, region, &ac->area->regionbase) {
|
||||
if (region->regiontype == RGN_TYPE_WINDOW) {
|
||||
UI_view2d_smooth_view(C, region, bounds, smooth_viewtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int graphkeys_view_selected_channels_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
bAnimContext ac;
|
||||
|
||||
/* Get editor data. */
|
||||
if (ANIM_animdata_get_context(C, &ac) == 0) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
ListBase anim_data = {NULL, NULL};
|
||||
const int filter = (ANIMFILTER_SEL | ANIMFILTER_NODUPLIS | ANIMFILTER_DATA_VISIBLE |
|
||||
ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
|
||||
size_t anim_data_length = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
|
||||
|
||||
if (anim_data_length == 0) {
|
||||
WM_report(RPT_WARNING, "No channels to operate on");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
float range[2];
|
||||
const bool use_preview_range = RNA_boolean_get(op->ptr, "use_preview_range");
|
||||
get_view_range(ac.scene, use_preview_range, range);
|
||||
|
||||
rctf bounds = {.xmin = FLT_MAX, .xmax = -FLT_MAX, .ymin = FLT_MAX, .ymax = -FLT_MAX};
|
||||
|
||||
bAnimListElem *ale;
|
||||
const bool include_handles = RNA_boolean_get(op->ptr, "include_handles");
|
||||
|
||||
bool valid_bounds = false;
|
||||
for (ale = anim_data.first; ale; ale = ale->next) {
|
||||
rctf channel_bounds;
|
||||
const bool found_bounds = get_channel_bounds(
|
||||
&ac, ale, range, include_handles, &channel_bounds);
|
||||
if (found_bounds) {
|
||||
BLI_rctf_union(&bounds, &channel_bounds);
|
||||
valid_bounds = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid_bounds) {
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
add_region_padding(C, &ac, &bounds);
|
||||
|
||||
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
|
||||
move_graph_view(C, &ac, &bounds, smooth_viewtx);
|
||||
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static bool channel_view_poll(bContext *C)
|
||||
{
|
||||
return ED_operator_action_active(C) || ED_operator_graphedit_active(C);
|
||||
}
|
||||
|
||||
static void ANIM_OT_channels_view_selected(wmOperatorType *ot)
|
||||
{
|
||||
/* Identifiers */
|
||||
ot->name = "Frame Selected Channels";
|
||||
ot->idname = "ANIM_OT_channels_view_selected";
|
||||
ot->description = "Reset viewable area to show the selected channels";
|
||||
|
||||
/* API callbacks */
|
||||
ot->exec = graphkeys_view_selected_channels_exec;
|
||||
ot->poll = channel_view_poll;
|
||||
|
||||
ot->flag = 0;
|
||||
|
||||
ot->prop = RNA_def_boolean(ot->srna,
|
||||
"include_handles",
|
||||
true,
|
||||
"Include Handles",
|
||||
"Include handles of keyframes when calculating extents");
|
||||
|
||||
ot->prop = RNA_def_boolean(ot->srna,
|
||||
"use_preview_range",
|
||||
true,
|
||||
"Use Preview Range",
|
||||
"Ignore frames outside of the preview range");
|
||||
}
|
||||
|
||||
static int graphkeys_channel_view_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
bAnimContext ac;
|
||||
|
||||
if (ANIM_animdata_get_context(C, &ac) == 0) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
ListBase anim_data = {NULL, NULL};
|
||||
const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS |
|
||||
ANIMFILTER_LIST_CHANNELS);
|
||||
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
|
||||
|
||||
bAnimListElem *ale;
|
||||
const int channel_index = animchannels_channel_get(&ac, event->mval);
|
||||
ale = BLI_findlink(&anim_data, channel_index);
|
||||
if (ale == NULL) {
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
float range[2];
|
||||
const bool use_preview_range = RNA_boolean_get(op->ptr, "use_preview_range");
|
||||
get_view_range(ac.scene, use_preview_range, range);
|
||||
|
||||
rctf bounds;
|
||||
const bool include_handles = RNA_boolean_get(op->ptr, "include_handles");
|
||||
const bool found_bounds = get_channel_bounds(&ac, ale, range, include_handles, &bounds);
|
||||
|
||||
if (!found_bounds) {
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
add_region_padding(C, &ac, &bounds);
|
||||
|
||||
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
|
||||
move_graph_view(C, &ac, &bounds, smooth_viewtx);
|
||||
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void ANIM_OT_channel_view_pick(wmOperatorType *ot)
|
||||
{
|
||||
/* Identifiers */
|
||||
ot->name = "Frame Channel Under Cursor";
|
||||
ot->idname = "ANIM_OT_channel_view_pick";
|
||||
ot->description = "Reset viewable area to show the channel under the cursor";
|
||||
|
||||
/* API callbacks */
|
||||
ot->invoke = graphkeys_channel_view_pick_invoke;
|
||||
ot->poll = channel_view_poll;
|
||||
|
||||
ot->flag = 0;
|
||||
|
||||
ot->prop = RNA_def_boolean(ot->srna,
|
||||
"include_handles",
|
||||
true,
|
||||
"Include Handles",
|
||||
"Include handles of keyframes when calculating extents");
|
||||
|
||||
ot->prop = RNA_def_boolean(ot->srna,
|
||||
"use_preview_range",
|
||||
true,
|
||||
"Use Preview Range",
|
||||
"Ignore frames outside of the preview range");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Operator Registration
|
||||
* \{ */
|
||||
|
@ -3657,6 +3935,9 @@ void ED_operatortypes_animchannels(void)
|
|||
WM_operatortype_append(ANIM_OT_channels_setting_disable);
|
||||
WM_operatortype_append(ANIM_OT_channels_setting_toggle);
|
||||
|
||||
WM_operatortype_append(ANIM_OT_channel_view_pick);
|
||||
WM_operatortype_append(ANIM_OT_channels_view_selected);
|
||||
|
||||
WM_operatortype_append(ANIM_OT_channels_delete);
|
||||
|
||||
/* XXX does this need to be a separate operator? */
|
||||
|
|
|
@ -1429,7 +1429,7 @@ static int separate_exec(bContext *C, wmOperator *op)
|
|||
|
||||
/* All curves failed due to the same error. */
|
||||
if (status.error_vertex_keys) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Cannot separate curves with vertex keys");
|
||||
BKE_report(op->reports, RPT_ERROR, "Cannot separate curves with shape keys");
|
||||
}
|
||||
else {
|
||||
BLI_assert(status.error_generic);
|
||||
|
|
|
@ -285,7 +285,7 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
|
|||
params.add_solidify = RNA_boolean_get(op->ptr, "add_solidify");
|
||||
|
||||
/* Push an undo step prior to extraction.
|
||||
* Note: A second push happens after the operator due to
|
||||
* NOTE: A second push happens after the operator due to
|
||||
* the OPTYPE_UNDO flag; having an initial undo step here
|
||||
* is just needed to preserve the active object pointer.
|
||||
*
|
||||
|
|
|
@ -400,6 +400,21 @@ static void saction_channel_region_message_subscribe(const wmRegionMessageSubscr
|
|||
}
|
||||
}
|
||||
|
||||
static void action_clamp_scroll(ARegion *region)
|
||||
{
|
||||
View2D *v2d = ®ion->v2d;
|
||||
const float cur_height_y = BLI_rctf_size_y(&v2d->cur);
|
||||
|
||||
if (BLI_rctf_size_y(&v2d->cur) > BLI_rctf_size_y(&v2d->tot)) {
|
||||
v2d->cur.ymin = -cur_height_y;
|
||||
v2d->cur.ymax = 0;
|
||||
}
|
||||
else if (v2d->cur.ymin < v2d->tot.ymin) {
|
||||
v2d->cur.ymin = v2d->tot.ymin;
|
||||
v2d->cur.ymax = v2d->cur.ymin + cur_height_y;
|
||||
}
|
||||
}
|
||||
|
||||
static void action_main_region_listener(const wmRegionListenerParams *params)
|
||||
{
|
||||
ARegion *region = params->region;
|
||||
|
@ -860,6 +875,13 @@ static void action_blend_write(BlendWriter *writer, SpaceLink *sl)
|
|||
BLO_write_struct(writer, SpaceAction, sl);
|
||||
}
|
||||
|
||||
static void action_main_region_view2d_changed(const bContext *UNUSED(C), ARegion *region)
|
||||
{
|
||||
/* V2D_KEEPTOT_STRICT cannot be used to clamp scrolling
|
||||
* because it also clamps the x-axis to 0. */
|
||||
action_clamp_scroll(region);
|
||||
}
|
||||
|
||||
void ED_spacetype_action(void)
|
||||
{
|
||||
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype action");
|
||||
|
@ -892,6 +914,7 @@ void ED_spacetype_action(void)
|
|||
art->draw_overlay = action_main_region_draw_overlay;
|
||||
art->listener = action_main_region_listener;
|
||||
art->message_subscribe = saction_main_region_message_subscribe;
|
||||
art->on_view2d_changed = action_main_region_view2d_changed;
|
||||
art->keymapflag = ED_KEYMAP_GIZMO | ED_KEYMAP_VIEW2D | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES;
|
||||
|
||||
BLI_addhead(&st->regiontypes, art);
|
||||
|
|
|
@ -785,7 +785,12 @@ void uiTemplateMovieclipInformation(uiLayout *layout,
|
|||
uiLayout *col = uiLayoutColumn(layout, false);
|
||||
uiLayoutSetAlignment(col, UI_LAYOUT_ALIGN_RIGHT);
|
||||
|
||||
ImBuf *ibuf = BKE_movieclip_get_ibuf_flag(clip, user, clip->flag, MOVIECLIP_CACHE_SKIP);
|
||||
/* NOTE: Put the frame to cache. If the panel is drawn, the display will also be shown, as well
|
||||
* as metadata panel. So if the cache is skipped here it is not really a memory saver, but
|
||||
* skipping the cache could lead to a performance impact depending on the order in which panels
|
||||
* and the main area is drawn. Basically, if it is this template drawn first and then the main
|
||||
* area it will lead to frame read and processing happening twice. */
|
||||
ImBuf *ibuf = BKE_movieclip_get_ibuf_flag(clip, user, clip->flag, 0);
|
||||
|
||||
int width, height;
|
||||
/* Display frame dimensions, channels number and buffer type. */
|
||||
|
|
|
@ -1880,6 +1880,11 @@ static bool euler_filter_single_channel(FCurve *fcu)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Skip baked FCurves. */
|
||||
if (fcu->bezt == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* `prev` follows bezt, bezt = "current" point to be fixed. */
|
||||
/* Our method depends on determining a "difference" from the previous vert. */
|
||||
bool is_modified = false;
|
||||
|
|
|
@ -91,7 +91,7 @@ void get_graph_keyframe_extents(bAnimContext *ac,
|
|||
|
||||
/* Get range. */
|
||||
if (BKE_fcurve_calc_bounds(
|
||||
fcu, &txmin, &txmax, &tymin, &tymax, do_sel_only, include_handles)) {
|
||||
fcu, &txmin, &txmax, &tymin, &tymax, do_sel_only, include_handles, NULL)) {
|
||||
short mapping_flag = ANIM_get_normalization_flags(ac);
|
||||
|
||||
/* Apply NLA scaling. */
|
||||
|
|
|
@ -2680,7 +2680,6 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
|
|||
Editing *ed = SEQ_editing_get(scene);
|
||||
SpaceSeq *sseq = CTX_wm_space_seq(C);
|
||||
View2D *v2d = ®ion->v2d;
|
||||
float col[3];
|
||||
|
||||
seq_prefetch_wm_notify(C, scene);
|
||||
|
||||
|
@ -2689,8 +2688,7 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
|
|||
GPU_framebuffer_bind_no_srgb(framebuffer_overlay);
|
||||
GPU_depth_test(GPU_DEPTH_NONE);
|
||||
|
||||
UI_GetThemeColor3fv(TH_BACK, col);
|
||||
GPU_clear_color(col[0], col[1], col[2], 0.0f);
|
||||
UI_ThemeClearColor(TH_BACK);
|
||||
|
||||
UI_view2d_view_ortho(v2d);
|
||||
draw_seq_timeline_channels(v2d);
|
||||
|
|
|
@ -68,6 +68,122 @@ std::unique_ptr<ColumnValues> ExtraColumns::get_column_values(
|
|||
return std::make_unique<ColumnValues>(column_id.name, GVArray::ForSpan(*values));
|
||||
}
|
||||
|
||||
static void add_mesh_debug_column_names(
|
||||
const Mesh &mesh,
|
||||
const eAttrDomain domain,
|
||||
FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn)
|
||||
{
|
||||
switch (domain) {
|
||||
case ATTR_DOMAIN_POINT:
|
||||
if (CustomData_has_layer(&mesh.vdata, CD_ORIGINDEX)) {
|
||||
fn({(char *)"Original Index"}, false);
|
||||
}
|
||||
break;
|
||||
case ATTR_DOMAIN_EDGE:
|
||||
if (CustomData_has_layer(&mesh.edata, CD_ORIGINDEX)) {
|
||||
fn({(char *)"Original Index"}, false);
|
||||
}
|
||||
fn({(char *)"Vertex 1"}, false);
|
||||
fn({(char *)"Vertex 2"}, false);
|
||||
break;
|
||||
case ATTR_DOMAIN_FACE:
|
||||
if (CustomData_has_layer(&mesh.pdata, CD_ORIGINDEX)) {
|
||||
fn({(char *)"Original Index"}, false);
|
||||
}
|
||||
fn({(char *)"Corner Start"}, false);
|
||||
fn({(char *)"Corner Size"}, false);
|
||||
break;
|
||||
case ATTR_DOMAIN_CORNER:
|
||||
fn({(char *)"Vertex"}, false);
|
||||
fn({(char *)"Edge"}, false);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static std::unique_ptr<ColumnValues> build_mesh_debug_columns(const Mesh &mesh,
|
||||
const eAttrDomain domain,
|
||||
const StringRef name)
|
||||
{
|
||||
switch (domain) {
|
||||
case ATTR_DOMAIN_POINT: {
|
||||
if (name == "Original Index") {
|
||||
const int *data = static_cast<const int *>(
|
||||
CustomData_get_layer(&mesh.vdata, CD_ORIGINDEX));
|
||||
if (data) {
|
||||
return std::make_unique<ColumnValues>(name, VArray<int>::ForSpan({data, mesh.totvert}));
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
case ATTR_DOMAIN_EDGE: {
|
||||
const Span<MEdge> edges = mesh.edges();
|
||||
if (name == "Original Index") {
|
||||
const int *data = static_cast<const int *>(
|
||||
CustomData_get_layer(&mesh.edata, CD_ORIGINDEX));
|
||||
if (data) {
|
||||
return std::make_unique<ColumnValues>(name, VArray<int>::ForSpan({data, mesh.totedge}));
|
||||
}
|
||||
}
|
||||
if (name == "Vertex 1") {
|
||||
return std::make_unique<ColumnValues>(
|
||||
name, VArray<int>::ForFunc(edges.size(), [edges](int64_t index) {
|
||||
return edges[index].v1;
|
||||
}));
|
||||
}
|
||||
if (name == "Vertex 2") {
|
||||
return std::make_unique<ColumnValues>(
|
||||
name, VArray<int>::ForFunc(edges.size(), [edges](int64_t index) {
|
||||
return edges[index].v2;
|
||||
}));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
case ATTR_DOMAIN_FACE: {
|
||||
const Span<MPoly> polys = mesh.polys();
|
||||
if (name == "Original Index") {
|
||||
const int *data = static_cast<const int *>(
|
||||
CustomData_get_layer(&mesh.pdata, CD_ORIGINDEX));
|
||||
if (data) {
|
||||
return std::make_unique<ColumnValues>(name, VArray<int>::ForSpan({data, mesh.totpoly}));
|
||||
}
|
||||
}
|
||||
if (name == "Corner Start") {
|
||||
return std::make_unique<ColumnValues>(
|
||||
name, VArray<int>::ForFunc(polys.size(), [polys](int64_t index) {
|
||||
return polys[index].loopstart;
|
||||
}));
|
||||
}
|
||||
if (name == "Corner Size") {
|
||||
return std::make_unique<ColumnValues>(
|
||||
name, VArray<int>::ForFunc(polys.size(), [polys](int64_t index) {
|
||||
return polys[index].totloop;
|
||||
}));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
case ATTR_DOMAIN_CORNER: {
|
||||
const Span<MLoop> loops = mesh.loops();
|
||||
if (name == "Vertex") {
|
||||
return std::make_unique<ColumnValues>(
|
||||
name,
|
||||
VArray<int>::ForFunc(loops.size(), [loops](int64_t index) { return loops[index].v; }));
|
||||
}
|
||||
if (name == "Edge") {
|
||||
return std::make_unique<ColumnValues>(
|
||||
name,
|
||||
VArray<int>::ForFunc(loops.size(), [loops](int64_t index) { return loops[index].e; }));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryDataSource::foreach_default_column_ids(
|
||||
FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
|
||||
{
|
||||
|
@ -109,17 +225,9 @@ void GeometryDataSource::foreach_default_column_ids(
|
|||
fn({(char *)"Scale"}, false);
|
||||
}
|
||||
else if (G.debug_value == 4001 && component_->type() == GEO_COMPONENT_TYPE_MESH) {
|
||||
if (domain_ == ATTR_DOMAIN_EDGE) {
|
||||
fn({(char *)"Vertex 1"}, false);
|
||||
fn({(char *)"Vertex 2"}, false);
|
||||
}
|
||||
else if (domain_ == ATTR_DOMAIN_FACE) {
|
||||
fn({(char *)"Corner Start"}, false);
|
||||
fn({(char *)"Corner Size"}, false);
|
||||
}
|
||||
else if (domain_ == ATTR_DOMAIN_CORNER) {
|
||||
fn({(char *)"Vertex"}, false);
|
||||
fn({(char *)"Edge"}, false);
|
||||
const MeshComponent &component = static_cast<const MeshComponent &>(*component_);
|
||||
if (const Mesh *mesh = component.get_for_read()) {
|
||||
add_mesh_debug_column_names(*mesh, domain_, fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -174,51 +282,9 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
|
|||
else if (G.debug_value == 4001 && component_->type() == GEO_COMPONENT_TYPE_MESH) {
|
||||
const MeshComponent &component = static_cast<const MeshComponent &>(*component_);
|
||||
if (const Mesh *mesh = component.get_for_read()) {
|
||||
const Span<MEdge> edges = mesh->edges();
|
||||
const Span<MPoly> polys = mesh->polys();
|
||||
const Span<MLoop> loops = mesh->loops();
|
||||
|
||||
if (domain_ == ATTR_DOMAIN_EDGE) {
|
||||
if (STREQ(column_id.name, "Vertex 1")) {
|
||||
return std::make_unique<ColumnValues>(
|
||||
column_id.name, VArray<int>::ForFunc(edges.size(), [edges](int64_t index) {
|
||||
return edges[index].v1;
|
||||
}));
|
||||
}
|
||||
if (STREQ(column_id.name, "Vertex 2")) {
|
||||
return std::make_unique<ColumnValues>(
|
||||
column_id.name, VArray<int>::ForFunc(edges.size(), [edges](int64_t index) {
|
||||
return edges[index].v2;
|
||||
}));
|
||||
}
|
||||
}
|
||||
else if (domain_ == ATTR_DOMAIN_FACE) {
|
||||
if (STREQ(column_id.name, "Corner Start")) {
|
||||
return std::make_unique<ColumnValues>(
|
||||
column_id.name, VArray<int>::ForFunc(polys.size(), [polys](int64_t index) {
|
||||
return polys[index].loopstart;
|
||||
}));
|
||||
}
|
||||
if (STREQ(column_id.name, "Corner Size")) {
|
||||
return std::make_unique<ColumnValues>(
|
||||
column_id.name, VArray<int>::ForFunc(polys.size(), [polys](int64_t index) {
|
||||
return polys[index].totloop;
|
||||
}));
|
||||
}
|
||||
}
|
||||
else if (domain_ == ATTR_DOMAIN_CORNER) {
|
||||
if (STREQ(column_id.name, "Vertex")) {
|
||||
return std::make_unique<ColumnValues>(
|
||||
column_id.name, VArray<int>::ForFunc(loops.size(), [loops](int64_t index) {
|
||||
return loops[index].v;
|
||||
}));
|
||||
}
|
||||
if (STREQ(column_id.name, "Edge")) {
|
||||
return std::make_unique<ColumnValues>(
|
||||
column_id.name, VArray<int>::ForFunc(loops.size(), [loops](int64_t index) {
|
||||
return loops[index].e;
|
||||
}));
|
||||
}
|
||||
if (std::unique_ptr<ColumnValues> values = build_mesh_debug_columns(
|
||||
*mesh, domain_, column_id.name)) {
|
||||
return values;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1499,7 +1499,7 @@ static Mesh *create_merged_mesh(const Mesh &mesh,
|
|||
const int totedge = mesh.totedge;
|
||||
|
||||
/* Reuse the same buffer as #vert_dest_map.
|
||||
* Note: the caller must be made aware of it changes. */
|
||||
* NOTE: the caller must be made aware of it changes. */
|
||||
MutableSpan<int> vert_group_map = vert_dest_map;
|
||||
|
||||
WeldMesh weld_mesh;
|
||||
|
|
|
@ -1895,7 +1895,7 @@ static void lineart_sort_adjacent_items(LineartAdjacentEdge *ai, int length)
|
|||
ai, ai + length, [](const LineartAdjacentEdge &p1, const LineartAdjacentEdge &p2) {
|
||||
int a = p1.v1 - p2.v1;
|
||||
int b = p1.v2 - p2.v2;
|
||||
/* parallel_sort() requires cmp() to return true when the first element needs to appear
|
||||
/* `parallel_sort()` requires `cmp()` to return true when the first element needs to appear
|
||||
* before the second element in the sorted array, false otherwise (strict weak ordering),
|
||||
* see https://en.cppreference.com/w/cpp/named_req/Compare. */
|
||||
if (a < 0) {
|
||||
|
|
|
@ -346,7 +346,7 @@ void gpu_shader_create_info_init()
|
|||
overlay_motion_path_line_clipped = overlay_motion_path_line_clipped_no_geom;
|
||||
|
||||
/* Workbench shadows.
|
||||
* Note: Updates additional-info used by workbench shadow permutations.
|
||||
* NOTE: Updates additional-info used by workbench shadow permutations.
|
||||
* Must be prepared prior to permutation preparation. */
|
||||
workbench_shadow_manifold = workbench_shadow_manifold_no_geom;
|
||||
workbench_shadow_no_manifold = workbench_shadow_no_manifold_no_geom;
|
||||
|
|
|
@ -339,7 +339,7 @@ void MTLImmediate::end()
|
|||
} break;
|
||||
case GPU_PRIM_LINE_LOOP: {
|
||||
/* Patch final vertex of line loop to close. Rendered using LineStrip.
|
||||
* Note: vertex_len represents original length, however, allocated Metal
|
||||
* NOTE: vertex_len represents original length, however, allocated Metal
|
||||
* buffer contains space for one extra vertex when LineLoop is used. */
|
||||
uchar *buffer_data = reinterpret_cast<uchar *>(current_allocation_.data);
|
||||
memcpy(buffer_data + (vertex_len)*vertex_format.stride,
|
||||
|
|
|
@ -41,7 +41,18 @@ void GLIndexBuf::bind()
|
|||
|
||||
void GLIndexBuf::bind_as_ssbo(uint binding)
|
||||
{
|
||||
bind();
|
||||
if (ibo_id_ == 0 || data_ != nullptr) {
|
||||
/* Calling `glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_id_)` changes the index buffer
|
||||
* of the currently bound VAO.
|
||||
*
|
||||
* In the OpenGL backend, the VAO state persists even after `GLVertArray::update_bindings`
|
||||
* is called.
|
||||
*
|
||||
* NOTE: For safety, we could call `glBindVertexArray(0)` right after drawing a `GPUBatch`.
|
||||
* However, for performance reasons, we have chosen not to do so. */
|
||||
glBindVertexArray(0);
|
||||
bind();
|
||||
}
|
||||
BLI_assert(ibo_id_ != 0);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, ibo_id_);
|
||||
}
|
||||
|
|
|
@ -379,6 +379,10 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
|
|||
|
||||
result = BKE_mesh_new_nomain_from_template(
|
||||
mesh, int(maxVerts), int(maxEdges), 0, int(maxPolys) * 4, int(maxPolys));
|
||||
/* The modifier doesn't support original index mapping on the edge or face domains. Remove
|
||||
* original index layers, since otherwise edges aren't displayed at all in wireframe view. */
|
||||
CustomData_free_layers(&result->edata, CD_ORIGINDEX, result->totedge);
|
||||
CustomData_free_layers(&result->pdata, CD_ORIGINDEX, result->totedge);
|
||||
|
||||
const float(*vert_positions_orig)[3] = BKE_mesh_vert_positions(mesh);
|
||||
const MEdge *medge_orig = BKE_mesh_edges(mesh);
|
||||
|
|
|
@ -394,7 +394,7 @@ PyTypeObject PyKDTree_Type = {
|
|||
/*tp_setattro*/ NULL,
|
||||
/*tp_as_buffer*/ NULL,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT,
|
||||
/*Documentation string*/ py_KDtree_doc,
|
||||
/*tp_doc*/ py_KDtree_doc,
|
||||
/*tp_traverse*/ NULL,
|
||||
/*tp_clear*/ NULL,
|
||||
/*tp_richcompare*/ NULL,
|
||||
|
|
|
@ -1119,9 +1119,28 @@ void wm_gizmomap_modal_set(
|
|||
}
|
||||
|
||||
if (do_refresh) {
|
||||
const int update_flag = GIZMOMAP_IS_REFRESH_CALLBACK;
|
||||
const eWM_GizmoFlagMapDrawStep step = WM_gizmomap_drawstep_from_gizmo_group(
|
||||
gz->parent_gzgroup);
|
||||
gzmap->update_flag[step] |= GIZMOMAP_IS_REFRESH_CALLBACK;
|
||||
gzmap->update_flag[step] |= update_flag;
|
||||
|
||||
/* Ensure the update flag is set for gizmos that were hidden while modal, see #104817. */
|
||||
for (int i = 0; i < WM_GIZMOMAP_DRAWSTEP_MAX; i++) {
|
||||
const eWM_GizmoFlagMapDrawStep step_iter = (eWM_GizmoFlagMapDrawStep)i;
|
||||
if (step_iter == step) {
|
||||
continue;
|
||||
}
|
||||
if ((gzmap->update_flag[i] & update_flag) == update_flag) {
|
||||
continue;
|
||||
}
|
||||
LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, &gzmap->groups) {
|
||||
if (((gzgroup->type->flag & WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL) == 0) &&
|
||||
wm_gizmogroup_is_visible_in_drawstep(gzgroup, step_iter)) {
|
||||
gzmap->update_flag[i] |= update_flag;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue