Mesh: Replace auto smooth with node group #108014
|
@ -991,6 +991,8 @@ endif()
|
||||||
|
|
||||||
if(WITH_MATERIALX)
|
if(WITH_MATERIALX)
|
||||||
include("${LIBDIR}/MaterialX/lib/cmake/MaterialX/MaterialXTargets.cmake")
|
include("${LIBDIR}/MaterialX/lib/cmake/MaterialX/MaterialXTargets.cmake")
|
||||||
|
set_target_properties(MaterialXCore PROPERTIES MAP_IMPORTED_CONFIG_RELWITHDEBINFO RELEASE)
|
||||||
|
set_target_properties(MaterialXFormat PROPERTIES MAP_IMPORTED_CONFIG_RELWITHDEBINFO RELEASE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WINDOWS_PYTHON_DEBUG)
|
if(WINDOWS_PYTHON_DEBUG)
|
||||||
|
|
|
@ -47,9 +47,31 @@
|
||||||
* twice, once here, and once by LSAN.
|
* twice, once here, and once by LSAN.
|
||||||
*/
|
*/
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
|
# ifdef WITH_ASAN
|
||||||
# define DEBUG_BACKTRACE
|
# define DEBUG_BACKTRACE
|
||||||
|
# endif
|
||||||
#else
|
#else
|
||||||
//#define DEBUG_BACKTRACE
|
/* Un-comment to report back-traces with leaks, uses ASAN when enabled.
|
||||||
|
* NOTE: The default linking options cause the stack traces only to include addresses.
|
||||||
|
* Use `addr2line` to expand into file, line & function identifiers,
|
||||||
|
* see: `tools/utils/addr2line_backtrace.py` convenience utility. */
|
||||||
|
// # define DEBUG_BACKTRACE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG_BACKTRACE
|
||||||
|
# ifdef WITH_ASAN
|
||||||
|
/* Rely on address sanitizer. */
|
||||||
|
# else
|
||||||
|
# if defined(__linux__) || defined(__APPLE__)
|
||||||
|
# define DEBUG_BACKTRACE_EXECINFO
|
||||||
|
# else
|
||||||
|
# error "DEBUG_BACKTRACE: not supported for this platform!"
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG_BACKTRACE_EXECINFO
|
||||||
|
# define BACKTRACE_SIZE 100
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG_MEMCOUNTER
|
#ifdef DEBUG_MEMCOUNTER
|
||||||
|
@ -94,6 +116,12 @@ typedef struct MemHead {
|
||||||
#ifdef DEBUG_MEMDUPLINAME
|
#ifdef DEBUG_MEMDUPLINAME
|
||||||
int need_free_name, pad;
|
int need_free_name, pad;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG_BACKTRACE_EXECINFO
|
||||||
|
void *backtrace[BACKTRACE_SIZE];
|
||||||
|
int backtrace_size;
|
||||||
|
#endif
|
||||||
|
|
||||||
} MemHead;
|
} MemHead;
|
||||||
|
|
||||||
typedef MemHead MemHeadAligned;
|
typedef MemHead MemHeadAligned;
|
||||||
|
@ -102,6 +130,10 @@ typedef struct MemTail {
|
||||||
int tag3, pad;
|
int tag3, pad;
|
||||||
} MemTail;
|
} MemTail;
|
||||||
|
|
||||||
|
#ifdef DEBUG_BACKTRACE_EXECINFO
|
||||||
|
# include <execinfo.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/* --------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------- */
|
||||||
/* local functions */
|
/* local functions */
|
||||||
/* --------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------- */
|
||||||
|
@ -354,6 +386,26 @@ void *MEM_guarded_recallocN_id(void *vmemh, size_t len, const char *str)
|
||||||
return newp;
|
return newp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_BACKTRACE_EXECINFO
|
||||||
|
static void make_memhead_backtrace(MemHead *memh)
|
||||||
|
{
|
||||||
|
memh->backtrace_size = backtrace(memh->backtrace, BACKTRACE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_memhead_backtrace(MemHead *memh)
|
||||||
|
{
|
||||||
|
char **strings;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
strings = backtrace_symbols(memh->backtrace, memh->backtrace_size);
|
||||||
|
for (i = 0; i < memh->backtrace_size; i++) {
|
||||||
|
print_error(" %s\n", strings[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(strings);
|
||||||
|
}
|
||||||
|
#endif /* DEBUG_BACKTRACE_EXECINFO */
|
||||||
|
|
||||||
static void make_memhead_header(MemHead *memh, size_t len, const char *str)
|
static void make_memhead_header(MemHead *memh, size_t len, const char *str)
|
||||||
{
|
{
|
||||||
MemTail *memt;
|
MemTail *memt;
|
||||||
|
@ -370,6 +422,10 @@ static void make_memhead_header(MemHead *memh, size_t len, const char *str)
|
||||||
memh->need_free_name = 0;
|
memh->need_free_name = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG_BACKTRACE_EXECINFO
|
||||||
|
make_memhead_backtrace(memh);
|
||||||
|
#endif
|
||||||
|
|
||||||
memt = (MemTail *)(((char *)memh) + sizeof(MemHead) + len);
|
memt = (MemTail *)(((char *)memh) + sizeof(MemHead) + len);
|
||||||
memt->tag3 = MEMTAG3;
|
memt->tag3 = MEMTAG3;
|
||||||
|
|
||||||
|
@ -720,10 +776,11 @@ static void MEM_guarded_printmemlist_internal(int pydict)
|
||||||
SIZET_ARG(membl->len),
|
SIZET_ARG(membl->len),
|
||||||
(void *)(membl + 1));
|
(void *)(membl + 1));
|
||||||
#endif
|
#endif
|
||||||
#ifdef DEBUG_BACKTRACE
|
|
||||||
# ifdef WITH_ASAN
|
#ifdef DEBUG_BACKTRACE_EXECINFO
|
||||||
|
print_memhead_backtrace(membl);
|
||||||
|
#elif defined(DEBUG_BACKTRACE) && defined(WITH_ASAN)
|
||||||
__asan_describe_address(membl);
|
__asan_describe_address(membl);
|
||||||
# endif
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (membl->next) {
|
if (membl->next) {
|
||||||
|
|
|
@ -12,6 +12,7 @@ __all__ = (
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
from bpy.types import Action
|
from bpy.types import Action
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from typing import (
|
from typing import (
|
||||||
List,
|
List,
|
||||||
|
@ -31,11 +32,35 @@ FCurveKey = Tuple[
|
||||||
ListKeyframes = List[float]
|
ListKeyframes = List[float]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class BakeOptions:
|
||||||
|
only_selected: bool
|
||||||
|
"""Only bake selected bones."""
|
||||||
|
|
||||||
|
do_pose: bool
|
||||||
|
"""Bake pose channels"""
|
||||||
|
|
||||||
|
do_object: bool
|
||||||
|
"""Bake objects."""
|
||||||
|
|
||||||
|
do_visual_keying: bool
|
||||||
|
"""Use the final transformations for baking ('visual keying')."""
|
||||||
|
|
||||||
|
do_constraint_clear: bool
|
||||||
|
"""Remove constraints after baking."""
|
||||||
|
|
||||||
|
do_parents_clear: bool
|
||||||
|
"""Unparent after baking objects."""
|
||||||
|
|
||||||
|
do_clean: bool
|
||||||
|
"""Remove redundant keyframes after baking."""
|
||||||
|
|
||||||
|
|
||||||
def bake_action(
|
def bake_action(
|
||||||
obj,
|
obj,
|
||||||
*,
|
*,
|
||||||
action, frames,
|
action, frames,
|
||||||
**kwargs
|
bake_options: BakeOptions
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
:arg obj: Object to bake.
|
:arg obj: Object to bake.
|
||||||
|
@ -49,13 +74,13 @@ def bake_action(
|
||||||
:return: an action or None
|
:return: an action or None
|
||||||
:rtype: :class:`bpy.types.Action`
|
:rtype: :class:`bpy.types.Action`
|
||||||
"""
|
"""
|
||||||
if not (kwargs.get("do_pose") or kwargs.get("do_object")):
|
if not (bake_options.do_pose or bake_options.do_object):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
action, = bake_action_objects(
|
action, = bake_action_objects(
|
||||||
[(obj, action)],
|
[(obj, action)],
|
||||||
frames=frames,
|
frames=frames,
|
||||||
**kwargs,
|
bake_options=bake_options
|
||||||
)
|
)
|
||||||
return action
|
return action
|
||||||
|
|
||||||
|
@ -64,7 +89,7 @@ def bake_action_objects(
|
||||||
object_action_pairs,
|
object_action_pairs,
|
||||||
*,
|
*,
|
||||||
frames,
|
frames,
|
||||||
**kwargs
|
bake_options: BakeOptions
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
A version of :func:`bake_action_objects_iter` that takes frames and returns the output.
|
A version of :func:`bake_action_objects_iter` that takes frames and returns the output.
|
||||||
|
@ -75,7 +100,7 @@ def bake_action_objects(
|
||||||
:return: A sequence of Action or None types (aligned with `object_action_pairs`)
|
:return: A sequence of Action or None types (aligned with `object_action_pairs`)
|
||||||
:rtype: sequence of :class:`bpy.types.Action`
|
:rtype: sequence of :class:`bpy.types.Action`
|
||||||
"""
|
"""
|
||||||
iter = bake_action_objects_iter(object_action_pairs, **kwargs)
|
iter = bake_action_objects_iter(object_action_pairs, bake_options=bake_options)
|
||||||
iter.send(None)
|
iter.send(None)
|
||||||
for frame in frames:
|
for frame in frames:
|
||||||
iter.send(frame)
|
iter.send(frame)
|
||||||
|
@ -84,7 +109,7 @@ def bake_action_objects(
|
||||||
|
|
||||||
def bake_action_objects_iter(
|
def bake_action_objects_iter(
|
||||||
object_action_pairs,
|
object_action_pairs,
|
||||||
**kwargs
|
bake_options: BakeOptions
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
An coroutine that bakes actions for multiple objects.
|
An coroutine that bakes actions for multiple objects.
|
||||||
|
@ -96,7 +121,7 @@ def bake_action_objects_iter(
|
||||||
scene = bpy.context.scene
|
scene = bpy.context.scene
|
||||||
frame_back = scene.frame_current
|
frame_back = scene.frame_current
|
||||||
iter_all = tuple(
|
iter_all = tuple(
|
||||||
bake_action_iter(obj, action=action, **kwargs)
|
bake_action_iter(obj, action=action, bake_options=bake_options)
|
||||||
for (obj, action) in object_action_pairs
|
for (obj, action) in object_action_pairs
|
||||||
)
|
)
|
||||||
for iter in iter_all:
|
for iter in iter_all:
|
||||||
|
@ -118,13 +143,7 @@ def bake_action_iter(
|
||||||
obj,
|
obj,
|
||||||
*,
|
*,
|
||||||
action,
|
action,
|
||||||
only_selected=False,
|
bake_options: BakeOptions
|
||||||
do_pose=True,
|
|
||||||
do_object=True,
|
|
||||||
do_visual_keying=True,
|
|
||||||
do_constraint_clear=False,
|
|
||||||
do_parents_clear=False,
|
|
||||||
do_clean=False
|
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
An coroutine that bakes action for a single object.
|
An coroutine that bakes action for a single object.
|
||||||
|
@ -134,20 +153,8 @@ def bake_action_iter(
|
||||||
:arg action: An action to bake the data into, or None for a new action
|
:arg action: An action to bake the data into, or None for a new action
|
||||||
to be created.
|
to be created.
|
||||||
:type action: :class:`bpy.types.Action` or None
|
:type action: :class:`bpy.types.Action` or None
|
||||||
:arg only_selected: Only bake selected bones.
|
:arg bake_options: Boolean options of what to include into the action bake.
|
||||||
:type only_selected: bool
|
:type bake_options: :class: `anim_utils.BakeOptions`
|
||||||
:arg do_pose: Bake pose channels.
|
|
||||||
:type do_pose: bool
|
|
||||||
:arg do_object: Bake objects.
|
|
||||||
:type do_object: bool
|
|
||||||
:arg do_visual_keying: Use the final transformations for baking ('visual keying')
|
|
||||||
:type do_visual_keying: bool
|
|
||||||
:arg do_constraint_clear: Remove constraints after baking.
|
|
||||||
:type do_constraint_clear: bool
|
|
||||||
:arg do_parents_clear: Unparent after baking objects.
|
|
||||||
:type do_parents_clear: bool
|
|
||||||
:arg do_clean: Remove redundant keyframes after baking.
|
|
||||||
:type do_clean: bool
|
|
||||||
|
|
||||||
:return: an action or None
|
:return: an action or None
|
||||||
:rtype: :class:`bpy.types.Action`
|
:rtype: :class:`bpy.types.Action`
|
||||||
|
@ -180,7 +187,7 @@ def bake_action_iter(
|
||||||
matrix = {}
|
matrix = {}
|
||||||
bbones = {}
|
bbones = {}
|
||||||
for name, pbone in obj.pose.bones.items():
|
for name, pbone in obj.pose.bones.items():
|
||||||
if do_visual_keying:
|
if bake_options.do_visual_keying:
|
||||||
# Get the final transform of the bone in its own local space...
|
# Get the final transform of the bone in its own local space...
|
||||||
matrix[name] = obj.convert_space(pose_bone=pbone, matrix=pbone.matrix,
|
matrix[name] = obj.convert_space(pose_bone=pbone, matrix=pbone.matrix,
|
||||||
from_space='POSE', to_space='LOCAL')
|
from_space='POSE', to_space='LOCAL')
|
||||||
|
@ -192,8 +199,8 @@ def bake_action_iter(
|
||||||
bbones[name] = {bb_prop: getattr(pbone, bb_prop) for bb_prop in BBONE_PROPS}
|
bbones[name] = {bb_prop: getattr(pbone, bb_prop) for bb_prop in BBONE_PROPS}
|
||||||
return matrix, bbones
|
return matrix, bbones
|
||||||
|
|
||||||
if do_parents_clear:
|
if bake_options.do_parents_clear:
|
||||||
if do_visual_keying:
|
if bake_options.do_visual_keying:
|
||||||
def obj_frame_info(obj):
|
def obj_frame_info(obj):
|
||||||
return obj.matrix_world.copy()
|
return obj.matrix_world.copy()
|
||||||
else:
|
else:
|
||||||
|
@ -205,7 +212,7 @@ def bake_action_iter(
|
||||||
else:
|
else:
|
||||||
return matrix.copy()
|
return matrix.copy()
|
||||||
else:
|
else:
|
||||||
if do_visual_keying:
|
if bake_options.do_visual_keying:
|
||||||
def obj_frame_info(obj):
|
def obj_frame_info(obj):
|
||||||
parent = obj.parent
|
parent = obj.parent
|
||||||
matrix = obj.matrix_world
|
matrix = obj.matrix_world
|
||||||
|
@ -221,9 +228,9 @@ def bake_action_iter(
|
||||||
# Setup the Context
|
# Setup the Context
|
||||||
|
|
||||||
if obj.pose is None:
|
if obj.pose is None:
|
||||||
do_pose = False
|
bake_options.do_pose = False
|
||||||
|
|
||||||
if not (do_pose or do_object):
|
if not (bake_options.do_pose or bake_options.do_object):
|
||||||
raise Exception("Pose and object baking is disabled, no action needed")
|
raise Exception("Pose and object baking is disabled, no action needed")
|
||||||
|
|
||||||
pose_info = []
|
pose_info = []
|
||||||
|
@ -240,14 +247,14 @@ def bake_action_iter(
|
||||||
if frame is None:
|
if frame is None:
|
||||||
break
|
break
|
||||||
|
|
||||||
if do_pose:
|
if bake_options.do_pose:
|
||||||
pose_info.append((frame, *pose_frame_info(obj)))
|
pose_info.append((frame, *pose_frame_info(obj)))
|
||||||
if do_object:
|
if bake_options.do_object:
|
||||||
obj_info.append((frame, obj_frame_info(obj)))
|
obj_info.append((frame, obj_frame_info(obj)))
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# Clean (store initial data)
|
# Clean (store initial data)
|
||||||
if do_clean and action is not None:
|
if bake_options.do_clean and action is not None:
|
||||||
clean_orig_data = {fcu: {p.co[1] for p in fcu.keyframe_points} for fcu in action.fcurves}
|
clean_orig_data = {fcu: {p.co[1] for p in fcu.keyframe_points} for fcu in action.fcurves}
|
||||||
else:
|
else:
|
||||||
clean_orig_data = {}
|
clean_orig_data = {}
|
||||||
|
@ -278,12 +285,12 @@ def bake_action_iter(
|
||||||
|
|
||||||
# pose
|
# pose
|
||||||
lookup_fcurves = {(fcurve.data_path, fcurve.array_index): fcurve for fcurve in action.fcurves}
|
lookup_fcurves = {(fcurve.data_path, fcurve.array_index): fcurve for fcurve in action.fcurves}
|
||||||
if do_pose:
|
if bake_options.do_pose:
|
||||||
for name, pbone in obj.pose.bones.items():
|
for name, pbone in obj.pose.bones.items():
|
||||||
if only_selected and not pbone.bone.select:
|
if bake_options.only_selected and not pbone.bone.select:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if do_constraint_clear:
|
if bake_options.do_constraint_clear:
|
||||||
while pbone.constraints:
|
while pbone.constraints:
|
||||||
pbone.constraints.remove(pbone.constraints[0])
|
pbone.constraints.remove(pbone.constraints[0])
|
||||||
|
|
||||||
|
@ -359,8 +366,8 @@ def bake_action_iter(
|
||||||
keyframes.insert_keyframes_into_existing_action(lookup_fcurves, total_new_keys, action, name)
|
keyframes.insert_keyframes_into_existing_action(lookup_fcurves, total_new_keys, action, name)
|
||||||
|
|
||||||
# object. TODO. multiple objects
|
# object. TODO. multiple objects
|
||||||
if do_object:
|
if bake_options.do_object:
|
||||||
if do_constraint_clear:
|
if bake_options.do_constraint_clear:
|
||||||
while obj.constraints:
|
while obj.constraints:
|
||||||
obj.constraints.remove(obj.constraints[0])
|
obj.constraints.remove(obj.constraints[0])
|
||||||
|
|
||||||
|
@ -415,13 +422,13 @@ def bake_action_iter(
|
||||||
else:
|
else:
|
||||||
keyframes.insert_keyframes_into_existing_action(lookup_fcurves, total_new_keys, action, name)
|
keyframes.insert_keyframes_into_existing_action(lookup_fcurves, total_new_keys, action, name)
|
||||||
|
|
||||||
if do_parents_clear:
|
if bake_options.do_parents_clear:
|
||||||
obj.parent = None
|
obj.parent = None
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# Clean
|
# Clean
|
||||||
|
|
||||||
if do_clean:
|
if bake_options.do_clean:
|
||||||
for fcu in action.fcurves:
|
for fcu in action.fcurves:
|
||||||
fcu_orig_data = clean_orig_data.get(fcu, set())
|
fcu_orig_data = clean_orig_data.get(fcu, set())
|
||||||
|
|
||||||
|
|
|
@ -587,8 +587,6 @@ def _template_items_tool_select(
|
||||||
{"properties": [("deselect_all", True)]}),
|
{"properties": [("deselect_all", True)]}),
|
||||||
(operator, {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
|
(operator, {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
|
||||||
{"properties": [("deselect_all", False), ("toggle", True)]}),
|
{"properties": [("deselect_all", False), ("toggle", True)]}),
|
||||||
("transform.translate", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG'},
|
|
||||||
{"properties": [("release_confirm", True)]}),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
if params.select_mouse == 'LEFTMOUSE':
|
if params.select_mouse == 'LEFTMOUSE':
|
||||||
|
@ -5431,6 +5429,27 @@ def km_sculpt(params):
|
||||||
op_menu_pie("VIEW3D_MT_sculpt_automasking_pie", {"type": 'A', "alt": True, "value": 'PRESS'}),
|
op_menu_pie("VIEW3D_MT_sculpt_automasking_pie", {"type": 'A', "alt": True, "value": 'PRESS'}),
|
||||||
op_menu_pie("VIEW3D_MT_sculpt_face_sets_edit_pie", {"type": 'W', "value": 'PRESS', "alt": True}),
|
op_menu_pie("VIEW3D_MT_sculpt_face_sets_edit_pie", {"type": 'W', "value": 'PRESS', "alt": True}),
|
||||||
*_template_items_context_panel("VIEW3D_PT_sculpt_context_menu", params.context_menu_event),
|
*_template_items_context_panel("VIEW3D_PT_sculpt_context_menu", params.context_menu_event),
|
||||||
|
# Tools
|
||||||
|
("paint.brush_select", {"type": 'V', "value": 'PRESS'},
|
||||||
|
{"properties": [("sculpt_tool", 'DRAW')]}),
|
||||||
|
("paint.brush_select", {"type": 'S', "value": 'PRESS'},
|
||||||
|
{"properties": [("sculpt_tool", 'SMOOTH')]}),
|
||||||
|
("paint.brush_select", {"type": 'P', "value": 'PRESS'},
|
||||||
|
{"properties": [("sculpt_tool", 'PINCH')]}),
|
||||||
|
("paint.brush_select", {"type": 'I', "value": 'PRESS'},
|
||||||
|
{"properties": [("sculpt_tool", 'INFLATE')]}),
|
||||||
|
("paint.brush_select", {"type": 'G', "value": 'PRESS'},
|
||||||
|
{"properties": [("sculpt_tool", 'GRAB')]}),
|
||||||
|
("paint.brush_select", {"type": 'T', "value": 'PRESS', "shift": True},
|
||||||
|
{"properties": [("sculpt_tool", 'SCRAPE')]}),
|
||||||
|
("paint.brush_select", {"type": 'C', "value": 'PRESS'},
|
||||||
|
{"properties": [("sculpt_tool", 'CLAY_STRIPS')]}),
|
||||||
|
("paint.brush_select", {"type": 'C', "value": 'PRESS', "shift": True},
|
||||||
|
{"properties": [("sculpt_tool", 'CREASE')]}),
|
||||||
|
("paint.brush_select", {"type": 'K', "value": 'PRESS'},
|
||||||
|
{"properties": [("sculpt_tool", 'SNAKE_HOOK')]}),
|
||||||
|
("paint.brush_select", {"type": 'M', "value": 'PRESS'},
|
||||||
|
{"properties": [("sculpt_tool", 'MASK'), ("toggle", True), ("create_missing", True)]}),
|
||||||
])
|
])
|
||||||
|
|
||||||
# Lasso Masking.
|
# Lasso Masking.
|
||||||
|
|
|
@ -586,7 +586,7 @@ def km_uv_editor(params):
|
||||||
{"properties": [("extend", True)]}),
|
{"properties": [("extend", True)]}),
|
||||||
("uv.select_loop", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'},
|
("uv.select_loop", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'},
|
||||||
{"properties": [("extend", False)]}),
|
{"properties": [("extend", False)]}),
|
||||||
("uv.select_linked", {"type": 'RIGHT_BRACKET', "value": 'PRESS'}, None),
|
("uv.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
|
||||||
("uv.select_more", {"type": 'UP_ARROW', "value": 'PRESS', "repeat": True}, None),
|
("uv.select_more", {"type": 'UP_ARROW', "value": 'PRESS', "repeat": True}, None),
|
||||||
("uv.select_less", {"type": 'DOWN_ARROW', "value": 'PRESS', "repeat": True}, None),
|
("uv.select_less", {"type": 'DOWN_ARROW', "value": 'PRESS', "repeat": True}, None),
|
||||||
("uv.select_all", {"type": 'A', "value": 'PRESS', "ctrl": True}, {"properties": [("action", 'SELECT')]}),
|
("uv.select_all", {"type": 'A', "value": 'PRESS', "ctrl": True}, {"properties": [("action", 'SELECT')]}),
|
||||||
|
@ -631,6 +631,8 @@ def km_view3d_generic(_params):
|
||||||
{"properties": [("data_path", 'space_data.show_region_toolbar')]}),
|
{"properties": [("data_path", 'space_data.show_region_toolbar')]}),
|
||||||
("wm.context_toggle", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "ctrl": True},
|
("wm.context_toggle", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "ctrl": True},
|
||||||
{"properties": [("data_path", 'space_data.show_region_ui')]}),
|
{"properties": [("data_path", 'space_data.show_region_ui')]}),
|
||||||
|
("wm.context_toggle", {"type": 'SPACE', "value": 'PRESS', "shift": True},
|
||||||
|
{"properties": [("data_path", 'space_data.show_region_asset_shelf')]}),
|
||||||
])
|
])
|
||||||
|
|
||||||
return keymap
|
return keymap
|
||||||
|
@ -895,6 +897,10 @@ def km_graph_editor(params):
|
||||||
|
|
||||||
items.extend([
|
items.extend([
|
||||||
("wm.search_menu", {"type": 'TAB', "value": 'PRESS'}, None),
|
("wm.search_menu", {"type": 'TAB', "value": 'PRESS'}, None),
|
||||||
|
("wm.context_toggle", {"type": 'LEFT_BRACKET', "value": 'PRESS', "ctrl": True},
|
||||||
|
{"properties": [("data_path", 'space_data.show_region_channels')]}),
|
||||||
|
("wm.context_toggle", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "ctrl": True},
|
||||||
|
{"properties": [("data_path", 'space_data.show_region_ui')]}),
|
||||||
*_template_items_animation(),
|
*_template_items_animation(),
|
||||||
("graph.cursor_set", {"type": 'RIGHTMOUSE', "value": 'PRESS', "ctrl": True}, None),
|
("graph.cursor_set", {"type": 'RIGHTMOUSE', "value": 'PRESS', "ctrl": True}, None),
|
||||||
("graph.clickselect", {"type": 'LEFTMOUSE', "value": 'PRESS'},
|
("graph.clickselect", {"type": 'LEFTMOUSE', "value": 'PRESS'},
|
||||||
|
@ -931,7 +937,7 @@ def km_graph_editor(params):
|
||||||
{"properties": [("tweak", True), ("axis_range", False), ("mode", 'SUB')]}),
|
{"properties": [("tweak", True), ("axis_range", False), ("mode", 'SUB')]}),
|
||||||
("graph.select_more", {"type": 'UP_ARROW', "value": 'PRESS', "repeat": True}, None),
|
("graph.select_more", {"type": 'UP_ARROW', "value": 'PRESS', "repeat": True}, None),
|
||||||
("graph.select_less", {"type": 'DOWN_ARROW', "value": 'PRESS', "repeat": True}, None),
|
("graph.select_less", {"type": 'DOWN_ARROW', "value": 'PRESS', "repeat": True}, None),
|
||||||
("graph.select_linked", {"type": 'RIGHT_BRACKET', "value": 'PRESS'}, None),
|
("graph.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
|
||||||
op_menu("GRAPH_MT_delete", {"type": 'BACK_SPACE', "value": 'PRESS'}),
|
op_menu("GRAPH_MT_delete", {"type": 'BACK_SPACE', "value": 'PRESS'}),
|
||||||
("graph.delete", {"type": 'DEL', "value": 'PRESS'}, {"properties": [("confirm", False)]}),
|
("graph.delete", {"type": 'DEL', "value": 'PRESS'}, {"properties": [("confirm", False)]}),
|
||||||
*_template_items_context_menu("GRAPH_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
|
*_template_items_context_menu("GRAPH_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
|
||||||
|
@ -975,6 +981,10 @@ def km_image_generic(params):
|
||||||
|
|
||||||
items.extend([
|
items.extend([
|
||||||
op_panel("TOPBAR_PT_name", {"type": 'RET', "value": 'PRESS'}, [("keep_open", False)]),
|
op_panel("TOPBAR_PT_name", {"type": 'RET', "value": 'PRESS'}, [("keep_open", False)]),
|
||||||
|
("wm.context_toggle", {"type": 'LEFT_BRACKET', "value": 'PRESS', "ctrl": True},
|
||||||
|
{"properties": [("data_path", 'space_data.show_region_toolbar')]}),
|
||||||
|
("wm.context_toggle", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "ctrl": True},
|
||||||
|
{"properties": [("data_path", 'space_data.show_region_ui')]}),
|
||||||
("wm.search_menu", {"type": 'TAB', "value": 'PRESS'}, None),
|
("wm.search_menu", {"type": 'TAB', "value": 'PRESS'}, None),
|
||||||
("image.new", {"type": 'N', "value": 'PRESS', "alt": True}, None),
|
("image.new", {"type": 'N', "value": 'PRESS', "alt": True}, None),
|
||||||
("image.open", {"type": 'O', "value": 'PRESS', "alt": True}, None),
|
("image.open", {"type": 'O', "value": 'PRESS', "alt": True}, None),
|
||||||
|
@ -1064,6 +1074,10 @@ def km_node_generic(_params):
|
||||||
|
|
||||||
items.extend([
|
items.extend([
|
||||||
op_panel("TOPBAR_PT_name", {"type": 'RET', "value": 'PRESS'}, [("keep_open", False)]),
|
op_panel("TOPBAR_PT_name", {"type": 'RET', "value": 'PRESS'}, [("keep_open", False)]),
|
||||||
|
("wm.context_toggle", {"type": 'LEFT_BRACKET', "value": 'PRESS', "ctrl": True},
|
||||||
|
{"properties": [("data_path", 'space_data.show_region_toolbar')]}),
|
||||||
|
("wm.context_toggle", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "ctrl": True},
|
||||||
|
{"properties": [("data_path", 'space_data.show_region_ui')]}),
|
||||||
])
|
])
|
||||||
|
|
||||||
return keymap
|
return keymap
|
||||||
|
@ -1201,6 +1215,8 @@ def km_file_browser(params):
|
||||||
)
|
)
|
||||||
|
|
||||||
items.extend([
|
items.extend([
|
||||||
|
("wm.context_toggle", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "ctrl": True},
|
||||||
|
{"properties": [("data_path", 'space_data.show_region_tool_props')]}),
|
||||||
("file.parent", {"type": 'UP_ARROW', "value": 'PRESS', "alt": True}, None),
|
("file.parent", {"type": 'UP_ARROW', "value": 'PRESS', "alt": True}, None),
|
||||||
("file.parent", {"type": 'UP_ARROW', "value": 'PRESS', "ctrl": True}, None),
|
("file.parent", {"type": 'UP_ARROW', "value": 'PRESS', "ctrl": True}, None),
|
||||||
("file.previous", {"type": 'LEFT_ARROW', "value": 'PRESS', "alt": True}, None),
|
("file.previous", {"type": 'LEFT_ARROW', "value": 'PRESS', "alt": True}, None),
|
||||||
|
@ -1344,6 +1360,8 @@ def km_dopesheet_generic(params):
|
||||||
items.extend([
|
items.extend([
|
||||||
op_panel("TOPBAR_PT_name", {"type": 'RET', "value": 'PRESS'}, [("keep_open", False)]),
|
op_panel("TOPBAR_PT_name", {"type": 'RET', "value": 'PRESS'}, [("keep_open", False)]),
|
||||||
("wm.search_menu", {"type": 'TAB', "value": 'PRESS'}, None),
|
("wm.search_menu", {"type": 'TAB', "value": 'PRESS'}, None),
|
||||||
|
("wm.context_toggle", {"type": 'LEFT_BRACKET', "value": 'PRESS', "ctrl": True},
|
||||||
|
{"properties": [("data_path", 'space_data.show_region_channels')]}),
|
||||||
("wm.context_toggle", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "ctrl": True},
|
("wm.context_toggle", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "ctrl": True},
|
||||||
{"properties": [("data_path", 'space_data.show_region_ui')]}),
|
{"properties": [("data_path", 'space_data.show_region_ui')]}),
|
||||||
])
|
])
|
||||||
|
@ -1403,7 +1421,7 @@ def km_dopesheet(params):
|
||||||
{"properties": [("mode", 'MARKERS_BETWEEN')]}),
|
{"properties": [("mode", 'MARKERS_BETWEEN')]}),
|
||||||
("action.select_more", {"type": 'UP_ARROW', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
|
("action.select_more", {"type": 'UP_ARROW', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
|
||||||
("action.select_less", {"type": 'DOWN_ARROW', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
|
("action.select_less", {"type": 'DOWN_ARROW', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
|
||||||
("action.select_linked", {"type": 'RIGHT_BRACKET', "value": 'PRESS'}, None),
|
("action.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
|
||||||
("action.frame_jump", {"type": 'G', "value": 'PRESS', "ctrl": True}, None),
|
("action.frame_jump", {"type": 'G', "value": 'PRESS', "ctrl": True}, None),
|
||||||
("wm.context_menu_enum", {"type": 'X', "value": 'PRESS'},
|
("wm.context_menu_enum", {"type": 'X', "value": 'PRESS'},
|
||||||
{"properties": [("data_path", 'space_data.auto_snap')]}),
|
{"properties": [("data_path", 'space_data.auto_snap')]}),
|
||||||
|
@ -1456,6 +1474,10 @@ def km_nla_generic(params):
|
||||||
|
|
||||||
items.extend([
|
items.extend([
|
||||||
op_panel("TOPBAR_PT_name", {"type": 'RET', "value": 'PRESS'}, [("keep_open", False)]),
|
op_panel("TOPBAR_PT_name", {"type": 'RET', "value": 'PRESS'}, [("keep_open", False)]),
|
||||||
|
("wm.context_toggle", {"type": 'LEFT_BRACKET', "value": 'PRESS', "ctrl": True},
|
||||||
|
{"properties": [("data_path", 'space_data.show_region_channels')]}),
|
||||||
|
("wm.context_toggle", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "ctrl": True},
|
||||||
|
{"properties": [("data_path", 'space_data.show_region_ui')]}),
|
||||||
("wm.search_menu", {"type": 'TAB', "value": 'PRESS'}, None),
|
("wm.search_menu", {"type": 'TAB', "value": 'PRESS'}, None),
|
||||||
*_template_items_animation(),
|
*_template_items_animation(),
|
||||||
("nla.tweakmode_enter", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
|
("nla.tweakmode_enter", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
|
||||||
|
@ -1723,6 +1745,8 @@ def km_sequencercommon(_params):
|
||||||
|
|
||||||
items.extend([
|
items.extend([
|
||||||
op_panel("TOPBAR_PT_name", {"type": 'RET', "value": 'PRESS'}, [("keep_open", False)]),
|
op_panel("TOPBAR_PT_name", {"type": 'RET', "value": 'PRESS'}, [("keep_open", False)]),
|
||||||
|
("wm.context_toggle", {"type": 'LEFT_BRACKET', "value": 'PRESS', "ctrl": True},
|
||||||
|
{"properties": [("data_path", 'space_data.show_region_channels')]}),
|
||||||
("wm.context_toggle", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "ctrl": True},
|
("wm.context_toggle", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "ctrl": True},
|
||||||
{"properties": [("data_path", 'space_data.show_region_ui')]}),
|
{"properties": [("data_path", 'space_data.show_region_ui')]}),
|
||||||
])
|
])
|
||||||
|
@ -1814,11 +1838,11 @@ def km_sequencer(params):
|
||||||
{"properties": [("extend", True), ("side_of_frame", True), ("linked_time", True)]}),
|
{"properties": [("extend", True), ("side_of_frame", True), ("linked_time", True)]}),
|
||||||
("sequencer.select_more", {"type": 'UP_ARROW', "value": 'PRESS', "repeat": True}, None),
|
("sequencer.select_more", {"type": 'UP_ARROW', "value": 'PRESS', "repeat": True}, None),
|
||||||
("sequencer.select_less", {"type": 'DOWN_ARROW', "value": 'PRESS', "repeat": True}, None),
|
("sequencer.select_less", {"type": 'DOWN_ARROW', "value": 'PRESS', "repeat": True}, None),
|
||||||
("sequencer.select_linked_pick", {"type": 'RIGHT_BRACKET', "value": 'PRESS'},
|
("sequencer.select_linked_pick", {"type": 'L', "value": 'PRESS', "ctrl": True},
|
||||||
{"properties": [("extend", False)]}),
|
{"properties": [("extend", False)]}),
|
||||||
("sequencer.select_linked_pick", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "shift": True},
|
("sequencer.select_linked_pick", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "shift": True},
|
||||||
{"properties": [("extend", True)]}),
|
{"properties": [("extend", True)]}),
|
||||||
("sequencer.select_linked", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "ctrl": True}, None),
|
("sequencer.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
|
||||||
("sequencer.select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG'},
|
("sequencer.select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG'},
|
||||||
{"properties": [("tweak", True), ("mode", 'SET')]}),
|
{"properties": [("tweak", True), ("mode", 'SET')]}),
|
||||||
("sequencer.select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG', "shift": True},
|
("sequencer.select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG', "shift": True},
|
||||||
|
@ -1999,6 +2023,10 @@ def km_clip_editor(params):
|
||||||
)
|
)
|
||||||
|
|
||||||
items.extend([
|
items.extend([
|
||||||
|
("wm.context_toggle", {"type": 'LEFT_BRACKET', "value": 'PRESS', "ctrl": True},
|
||||||
|
{"properties": [("data_path", 'space_data.show_region_toolbar')]}),
|
||||||
|
("wm.context_toggle", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "ctrl": True},
|
||||||
|
{"properties": [("data_path", 'space_data.show_region_ui')]}),
|
||||||
("wm.search_menu", {"type": 'TAB', "value": 'PRESS'}, None),
|
("wm.search_menu", {"type": 'TAB', "value": 'PRESS'}, None),
|
||||||
("clip.view_pan", {"type": 'MIDDLEMOUSE', "value": 'PRESS'}, None),
|
("clip.view_pan", {"type": 'MIDDLEMOUSE', "value": 'PRESS'}, None),
|
||||||
("clip.view_pan", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "shift": True}, None),
|
("clip.view_pan", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "shift": True}, None),
|
||||||
|
@ -2179,6 +2207,8 @@ def km_spreadsheet_generic(_params):
|
||||||
*_template_space_region_type_toggle(
|
*_template_space_region_type_toggle(
|
||||||
channels_key={"type": 'T', "value": 'PRESS'},
|
channels_key={"type": 'T', "value": 'PRESS'},
|
||||||
),
|
),
|
||||||
|
("wm.context_toggle", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "ctrl": True},
|
||||||
|
{"properties": [("data_path", 'space_data.show_region_ui')]}),
|
||||||
])
|
])
|
||||||
|
|
||||||
return keymap
|
return keymap
|
||||||
|
@ -3108,7 +3138,7 @@ def km_weight_paint_vertex_selection(params):
|
||||||
("paint.vert_select_hide", {"type": 'H', "value": 'PRESS', "shift": True},
|
("paint.vert_select_hide", {"type": 'H', "value": 'PRESS', "shift": True},
|
||||||
{"properties": [("unselected", True)]}),
|
{"properties": [("unselected", True)]}),
|
||||||
("paint.face_vert_reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None),
|
("paint.face_vert_reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None),
|
||||||
("paint.vert_select_linked", {"type": 'L', "value": 'PRESS', "alt": True}, None),
|
("paint.vert_select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
|
||||||
("paint.vert_select_linked_pick", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK', "alt": True},
|
("paint.vert_select_linked_pick", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK', "alt": True},
|
||||||
{"properties": [("select", True)]}),
|
{"properties": [("select", True)]}),
|
||||||
("paint.vert_select_linked_pick", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK', "ctrl": True, "alt": True},
|
("paint.vert_select_linked_pick", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK', "ctrl": True, "alt": True},
|
||||||
|
@ -3156,7 +3186,6 @@ def km_pose(params):
|
||||||
("pose.select_hierarchy", {"type": 'DOWN_ARROW', "value": 'PRESS', "shift": True, "repeat": True},
|
("pose.select_hierarchy", {"type": 'DOWN_ARROW', "value": 'PRESS', "shift": True, "repeat": True},
|
||||||
{"properties": [("direction", 'CHILD'), ("extend", True)]}),
|
{"properties": [("direction", 'CHILD'), ("extend", True)]}),
|
||||||
("pose.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
|
("pose.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
|
||||||
("pose.bone_layers", {"type": 'G', "value": 'PRESS'}, None),
|
|
||||||
("anim.keyframe_insert_menu", {"type": 'S', "value": 'PRESS', "shift": True}, None),
|
("anim.keyframe_insert_menu", {"type": 'S', "value": 'PRESS', "shift": True}, None),
|
||||||
("anim.keyframe_insert_by_name", {"type": 'S', "value": 'PRESS'},
|
("anim.keyframe_insert_by_name", {"type": 'S', "value": 'PRESS'},
|
||||||
{"properties": [("type", 'LocRotScale')]}),
|
{"properties": [("type", 'LocRotScale')]}),
|
||||||
|
@ -3730,6 +3759,8 @@ def km_mesh(params):
|
||||||
|
|
||||||
("mesh.shortest_path_pick", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True},
|
("mesh.shortest_path_pick", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True},
|
||||||
{"properties": [("use_fill", False)]}),
|
{"properties": [("use_fill", False)]}),
|
||||||
|
("mesh.shortest_path_pick", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True},
|
||||||
|
{"properties": [("use_fill", True)]}),
|
||||||
|
|
||||||
("mesh.select_all", {"type": 'A', "value": 'PRESS', "ctrl": True}, {"properties": [("action", 'SELECT')]}),
|
("mesh.select_all", {"type": 'A', "value": 'PRESS', "ctrl": True}, {"properties": [("action", 'SELECT')]}),
|
||||||
("mesh.select_all", {"type": 'A', "value": 'PRESS', "ctrl": True,
|
("mesh.select_all", {"type": 'A', "value": 'PRESS', "ctrl": True,
|
||||||
|
@ -4122,7 +4153,8 @@ def km_object_non_modal(params):
|
||||||
|
|
||||||
items.extend([
|
items.extend([
|
||||||
("object.transfer_mode", {"type": 'ACCENT_GRAVE', "value": 'PRESS'}, None),
|
("object.transfer_mode", {"type": 'ACCENT_GRAVE', "value": 'PRESS'}, None),
|
||||||
op_menu_pie("VIEW3D_MT_object_mode_pie", {"type": 'FOUR', "value": 'PRESS'}),
|
("object.mode_set", {"type": 'FOUR', "value": 'PRESS'}, {"properties": [("mode", 'OBJECT')]}),
|
||||||
|
op_menu_pie("VIEW3D_MT_object_mode_pie", {"type": 'FIVE', "value": 'PRESS'}),
|
||||||
])
|
])
|
||||||
|
|
||||||
return keymap
|
return keymap
|
||||||
|
|
|
@ -255,16 +255,24 @@ class NLA_OT_bake(Operator):
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
from bpy_extras import anim_utils
|
from bpy_extras import anim_utils
|
||||||
do_pose = 'POSE' in self.bake_types
|
|
||||||
do_object = 'OBJECT' in self.bake_types
|
|
||||||
|
|
||||||
if do_pose and self.only_selected:
|
bake_options = anim_utils.BakeOptions(
|
||||||
|
only_selected=self.only_selected,
|
||||||
|
do_pose='POSE' in self.bake_types,
|
||||||
|
do_object='OBJECT' in self.bake_types,
|
||||||
|
do_visual_keying=self.visual_keying,
|
||||||
|
do_constraint_clear=self.clear_constraints,
|
||||||
|
do_parents_clear=self.clear_parents,
|
||||||
|
do_clean=self.clean_curves
|
||||||
|
)
|
||||||
|
|
||||||
|
if bake_options.do_pose and self.only_selected:
|
||||||
pose_bones = context.selected_pose_bones or []
|
pose_bones = context.selected_pose_bones or []
|
||||||
armatures = {pose_bone.id_data for pose_bone in pose_bones}
|
armatures = {pose_bone.id_data for pose_bone in pose_bones}
|
||||||
objects = list(armatures)
|
objects = list(armatures)
|
||||||
else:
|
else:
|
||||||
objects = context.selected_editable_objects
|
objects = context.selected_editable_objects
|
||||||
if do_pose and not do_object:
|
if bake_options.do_pose and not bake_options.do_object:
|
||||||
objects = [obj for obj in objects if obj.pose is not None]
|
objects = [obj for obj in objects if obj.pose is not None]
|
||||||
|
|
||||||
object_action_pairs = (
|
object_action_pairs = (
|
||||||
|
@ -276,13 +284,7 @@ class NLA_OT_bake(Operator):
|
||||||
actions = anim_utils.bake_action_objects(
|
actions = anim_utils.bake_action_objects(
|
||||||
object_action_pairs,
|
object_action_pairs,
|
||||||
frames=range(self.frame_start, self.frame_end + 1, self.step),
|
frames=range(self.frame_start, self.frame_end + 1, self.step),
|
||||||
only_selected=self.only_selected,
|
bake_options=bake_options
|
||||||
do_pose=do_pose,
|
|
||||||
do_object=do_object,
|
|
||||||
do_visual_keying=self.visual_keying,
|
|
||||||
do_constraint_clear=self.clear_constraints,
|
|
||||||
do_parents_clear=self.clear_parents,
|
|
||||||
do_clean=self.clean_curves,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if not any(actions):
|
if not any(actions):
|
||||||
|
@ -429,9 +431,125 @@ class UpdateAnimatedTransformConstraint(Operator):
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
class ARMATURE_OT_sync_bone_color_to_selected(Operator):
|
||||||
|
"""Copy the bone color of the active bone to all selected bones"""
|
||||||
|
bl_idname = "armature.sync_bone_color_to_selected"
|
||||||
|
bl_label = "Sync to Selected"
|
||||||
|
bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
|
||||||
|
_bone_type_enum = [
|
||||||
|
('EDIT', 'Edit Bone', 'Copy Edit Bone colors from the active bone to all selected bones'),
|
||||||
|
('POSE', 'Pose Bone', 'Copy Pose Bone colors from the active bone to all selected bones'),
|
||||||
|
]
|
||||||
|
|
||||||
|
bone_type: EnumProperty(
|
||||||
|
name="Type",
|
||||||
|
items=_bone_type_enum)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return context.mode in {'EDIT_ARMATURE', 'POSE'}
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
match (self.bone_type, context.mode):
|
||||||
|
# Armature in edit mode:
|
||||||
|
case ('POSE', 'EDIT_ARMATURE'):
|
||||||
|
self.report({'ERROR'}, "Go to pose mode to copy pose bone colors")
|
||||||
|
return {'OPERATOR_CANCELLED'}
|
||||||
|
case ('EDIT', 'EDIT_ARMATURE'):
|
||||||
|
bone_source = context.active_bone
|
||||||
|
bones_dest = context.selected_bones
|
||||||
|
pose_bones_to_check = []
|
||||||
|
|
||||||
|
# Armature in pose mode:
|
||||||
|
case ('POSE', 'POSE'):
|
||||||
|
bone_source = context.active_pose_bone
|
||||||
|
bones_dest = context.selected_pose_bones
|
||||||
|
pose_bones_to_check = []
|
||||||
|
case ('EDIT', 'POSE'):
|
||||||
|
bone_source = context.active_bone
|
||||||
|
pose_bones_to_check = context.selected_pose_bones
|
||||||
|
bones_dest = [posebone.bone for posebone in pose_bones_to_check]
|
||||||
|
|
||||||
|
# Anything else:
|
||||||
|
case _:
|
||||||
|
self.report({'ERROR'}, "Cannot do anything in mode %r" % context.mode)
|
||||||
|
return {'CANCELLED'}
|
||||||
|
|
||||||
|
if not bone_source:
|
||||||
|
self.report({'ERROR'}, "No active bone to copy from.")
|
||||||
|
return {'CANCELLED'}
|
||||||
|
|
||||||
|
if not bones_dest:
|
||||||
|
self.report({'ERROR'}, "No selected bones to copy to.")
|
||||||
|
return {'CANCELLED'}
|
||||||
|
|
||||||
|
num_pose_color_overrides = 0
|
||||||
|
for index, bone_dest in enumerate(bones_dest):
|
||||||
|
bone_dest.color.palette = bone_source.color.palette
|
||||||
|
for custom_field in ('normal', 'select', 'active'):
|
||||||
|
color = getattr(bone_source.color.custom, custom_field)
|
||||||
|
setattr(bone_dest.color.custom, custom_field, color)
|
||||||
|
|
||||||
|
if self.bone_type == 'EDIT' and pose_bones_to_check:
|
||||||
|
pose_bone = pose_bones_to_check[index]
|
||||||
|
if pose_bone.color.palette != 'DEFAULT':
|
||||||
|
# A pose color has been set, and we're now syncing edit bone
|
||||||
|
# colors. This means that the synced color will not be
|
||||||
|
# visible. Better to let the user know about this.
|
||||||
|
num_pose_color_overrides += 1
|
||||||
|
|
||||||
|
if num_pose_color_overrides:
|
||||||
|
self.report(
|
||||||
|
{'INFO'},
|
||||||
|
"Bone colors were synced; for %d bones this will not be visible due to pose bone color overrides" %
|
||||||
|
num_pose_color_overrides)
|
||||||
|
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
class ARMATURE_OT_collection_solo_visibility(Operator):
|
||||||
|
"""Hide all other bone collections and show the active one"""
|
||||||
|
bl_idname = "armature.collection_solo_visibility"
|
||||||
|
bl_label = "Solo Visibility"
|
||||||
|
bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
|
||||||
|
name: StringProperty(name='Bone Collection')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return context.object and context.object.type == 'ARMATURE' and context.object.data
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
arm = context.object.data
|
||||||
|
for bcoll in arm.collections:
|
||||||
|
bcoll.is_visible = bcoll.name == self.name
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
class ARMATURE_OT_collection_show_all(Operator):
|
||||||
|
"""Show all bone collections"""
|
||||||
|
bl_idname = "armature.collection_show_all"
|
||||||
|
bl_label = "Show All"
|
||||||
|
bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return context.object and context.object.type == 'ARMATURE' and context.object.data
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
arm = context.object.data
|
||||||
|
for bcoll in arm.collections:
|
||||||
|
bcoll.is_visible = True
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
ANIM_OT_keying_set_export,
|
ANIM_OT_keying_set_export,
|
||||||
NLA_OT_bake,
|
NLA_OT_bake,
|
||||||
ClearUselessActions,
|
ClearUselessActions,
|
||||||
UpdateAnimatedTransformConstraint,
|
UpdateAnimatedTransformConstraint,
|
||||||
|
ARMATURE_OT_sync_bone_color_to_selected,
|
||||||
|
ARMATURE_OT_collection_solo_visibility,
|
||||||
|
ARMATURE_OT_collection_show_all,
|
||||||
)
|
)
|
||||||
|
|
|
@ -3183,14 +3183,37 @@ class WM_MT_splash_quick_setup(Menu):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
layout.operator_context = 'EXEC_DEFAULT'
|
layout.operator_context = 'EXEC_DEFAULT'
|
||||||
|
|
||||||
|
old_version = bpy.types.PREFERENCES_OT_copy_prev.previous_version()
|
||||||
|
can_import = bpy.types.PREFERENCES_OT_copy_prev.poll(context) and old_version
|
||||||
|
|
||||||
|
if can_import:
|
||||||
|
layout.label(text="Import Existing Settings")
|
||||||
|
split = layout.split(factor=0.20) # Left margin.
|
||||||
|
split.label()
|
||||||
|
|
||||||
|
split = split.split(factor=0.73) # Content width.
|
||||||
|
col = split.column()
|
||||||
|
col.operator(
|
||||||
|
"preferences.copy_prev",
|
||||||
|
text=iface_(
|
||||||
|
"Load Blender %d.%d Settings",
|
||||||
|
"Operator") %
|
||||||
|
old_version, icon='DUPLICATE',
|
||||||
|
translate=False)
|
||||||
|
col.operator(
|
||||||
|
"wm.url_open", text="See What's New...", icon='URL'
|
||||||
|
).url = "https://wiki.blender.org/wiki/Reference/Release_Notes/4.0"
|
||||||
|
col.separator(factor=2.0)
|
||||||
|
|
||||||
|
if can_import:
|
||||||
|
layout.label(text="Create New Settings")
|
||||||
|
else:
|
||||||
layout.label(text="Quick Setup")
|
layout.label(text="Quick Setup")
|
||||||
|
|
||||||
split = layout.split(factor=0.14) # Left margin.
|
split = layout.split(factor=0.20) # Left margin.
|
||||||
split.label()
|
split.label()
|
||||||
split = split.split(factor=0.73) # Content width.
|
split = split.split(factor=0.73) # Content width.
|
||||||
|
|
||||||
col = split.column()
|
col = split.column()
|
||||||
|
|
||||||
col.use_property_split = True
|
col.use_property_split = True
|
||||||
col.use_property_decorate = False
|
col.use_property_decorate = False
|
||||||
|
|
||||||
|
@ -3219,42 +3242,22 @@ class WM_MT_splash_quick_setup(Menu):
|
||||||
if has_spacebar_action:
|
if has_spacebar_action:
|
||||||
col.row().prop(kc_prefs, "spacebar_action", text="Spacebar")
|
col.row().prop(kc_prefs, "spacebar_action", text="Spacebar")
|
||||||
|
|
||||||
col.separator()
|
|
||||||
|
|
||||||
# Themes.
|
# Themes.
|
||||||
|
col.separator()
|
||||||
sub = col.column(heading="Theme")
|
sub = col.column(heading="Theme")
|
||||||
label = bpy.types.USERPREF_MT_interface_theme_presets.bl_label
|
label = bpy.types.USERPREF_MT_interface_theme_presets.bl_label
|
||||||
if label == "Presets":
|
if label == "Presets":
|
||||||
label = "Blender Dark"
|
label = "Blender Dark"
|
||||||
sub.menu("USERPREF_MT_interface_theme_presets", text=label)
|
sub.menu("USERPREF_MT_interface_theme_presets", text=label)
|
||||||
|
|
||||||
# Keep height constant.
|
if can_import:
|
||||||
if not has_select_mouse:
|
sub.label()
|
||||||
col.label()
|
sub.operator("wm.save_userpref", text="Save New Settings", icon='CHECKMARK')
|
||||||
if not has_spacebar_action:
|
|
||||||
col.label()
|
|
||||||
|
|
||||||
layout.separator(factor=2.0)
|
|
||||||
|
|
||||||
# Save settings buttons.
|
|
||||||
sub = layout.row()
|
|
||||||
|
|
||||||
old_version = bpy.types.PREFERENCES_OT_copy_prev.previous_version()
|
|
||||||
if bpy.types.PREFERENCES_OT_copy_prev.poll(context) and old_version:
|
|
||||||
sub.operator(
|
|
||||||
"preferences.copy_prev",
|
|
||||||
text=iface_(
|
|
||||||
"Load %d.%d Settings",
|
|
||||||
"Operator") %
|
|
||||||
old_version,
|
|
||||||
translate=False)
|
|
||||||
sub.operator("wm.save_userpref", text="Save New Settings")
|
|
||||||
else:
|
else:
|
||||||
sub.label()
|
sub.label()
|
||||||
sub.label()
|
sub.operator("wm.save_userpref", text="Continue")
|
||||||
sub.operator("wm.save_userpref", text="Next")
|
|
||||||
|
|
||||||
layout.separator(factor=2.4)
|
layout.separator(factor=2.0)
|
||||||
|
|
||||||
|
|
||||||
class WM_MT_splash(Menu):
|
class WM_MT_splash(Menu):
|
||||||
|
|
|
@ -39,8 +39,8 @@ class DATA_PT_context_arm(ArmatureButtonsPanel, Panel):
|
||||||
layout.template_ID(space, "pin_id")
|
layout.template_ID(space, "pin_id")
|
||||||
|
|
||||||
|
|
||||||
class DATA_PT_skeleton(ArmatureButtonsPanel, Panel):
|
class DATA_PT_pose(ArmatureButtonsPanel, Panel):
|
||||||
bl_label = "Skeleton"
|
bl_label = "Pose"
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
|
@ -135,6 +135,9 @@ class DATA_PT_bone_collections(ArmatureButtonsPanel, Panel):
|
||||||
col.separator()
|
col.separator()
|
||||||
col.operator("armature.collection_move", icon='TRIA_UP', text="").direction = 'UP'
|
col.operator("armature.collection_move", icon='TRIA_UP', text="").direction = 'UP'
|
||||||
col.operator("armature.collection_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
|
col.operator("armature.collection_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
|
||||||
|
col.separator()
|
||||||
|
|
||||||
|
col.menu("ARMATURE_MT_collection_context_menu", icon='DOWNARROW_HLT', text="")
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
|
|
||||||
|
@ -147,6 +150,20 @@ class DATA_PT_bone_collections(ArmatureButtonsPanel, Panel):
|
||||||
sub.operator("armature.collection_deselect", text="Deselect")
|
sub.operator("armature.collection_deselect", text="Deselect")
|
||||||
|
|
||||||
|
|
||||||
|
class ARMATURE_MT_collection_context_menu(Menu):
|
||||||
|
bl_label = "Bone Collection Specials"
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
arm = context.armature
|
||||||
|
active_bcoll = arm.collections.active
|
||||||
|
|
||||||
|
props = layout.operator("armature.collection_solo_visibility")
|
||||||
|
props.name = active_bcoll.name if active_bcoll else ""
|
||||||
|
layout.operator("armature.collection_show_all")
|
||||||
|
|
||||||
|
|
||||||
class DATA_PT_iksolver_itasc(ArmatureButtonsPanel, Panel):
|
class DATA_PT_iksolver_itasc(ArmatureButtonsPanel, Panel):
|
||||||
bl_label = "Inverse Kinematics"
|
bl_label = "Inverse Kinematics"
|
||||||
bl_options = {'DEFAULT_CLOSED'}
|
bl_options = {'DEFAULT_CLOSED'}
|
||||||
|
@ -270,9 +287,10 @@ class DATA_PT_custom_props_bcoll(ArmatureButtonsPanel, PropertyPanel, Panel):
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
DATA_PT_context_arm,
|
DATA_PT_context_arm,
|
||||||
DATA_PT_skeleton,
|
DATA_PT_pose,
|
||||||
DATA_PT_bone_collections,
|
DATA_PT_bone_collections,
|
||||||
DATA_UL_bone_collections,
|
DATA_UL_bone_collections,
|
||||||
|
ARMATURE_MT_collection_context_menu,
|
||||||
DATA_PT_motion_paths,
|
DATA_PT_motion_paths,
|
||||||
DATA_PT_motion_paths_display,
|
DATA_PT_motion_paths_display,
|
||||||
DATA_PT_display,
|
DATA_PT_display,
|
||||||
|
|
|
@ -247,6 +247,44 @@ class BONE_PT_relations(BoneButtonsPanel, Panel):
|
||||||
sub.prop(bone, "inherit_scale")
|
sub.prop(bone, "inherit_scale")
|
||||||
|
|
||||||
|
|
||||||
|
class BONE_PT_collections(BoneButtonsPanel, Panel):
|
||||||
|
bl_label = "Bone Collections"
|
||||||
|
bl_parent_id = "BONE_PT_relations"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return context.bone or context.edit_bone
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
layout.use_property_split = False
|
||||||
|
|
||||||
|
bone = context.bone or context.edit_bone
|
||||||
|
|
||||||
|
if not bone.collections:
|
||||||
|
layout.active = False
|
||||||
|
layout.label(text="Not assigned to any bone collection.")
|
||||||
|
return
|
||||||
|
|
||||||
|
box = layout.box()
|
||||||
|
sub = box.column(align=True)
|
||||||
|
for bcoll in bone.collections:
|
||||||
|
bcoll_row = sub.row()
|
||||||
|
bcoll_row.emboss = 'NONE'
|
||||||
|
|
||||||
|
# Name & visibility of bcoll. Safe things, so aligned together.
|
||||||
|
row = bcoll_row.row(align=True)
|
||||||
|
row.label(text=bcoll.name)
|
||||||
|
row.prop(bcoll, "is_visible", text="",
|
||||||
|
icon='HIDE_OFF' if bcoll.is_visible else 'HIDE_ON')
|
||||||
|
|
||||||
|
# Unassignment operator, less safe so with a bit of spacing.
|
||||||
|
props = bcoll_row.operator("armature.collection_unassign_named",
|
||||||
|
text="", icon='X')
|
||||||
|
props.name = bcoll.name
|
||||||
|
props.bone_name = bone.name
|
||||||
|
|
||||||
|
|
||||||
class BONE_PT_display(BoneButtonsPanel, Panel):
|
class BONE_PT_display(BoneButtonsPanel, Panel):
|
||||||
bl_label = "Viewport Display"
|
bl_label = "Viewport Display"
|
||||||
bl_options = {'DEFAULT_CLOSED'}
|
bl_options = {'DEFAULT_CLOSED'}
|
||||||
|
@ -278,9 +316,19 @@ class BONE_PT_display(BoneButtonsPanel, Panel):
|
||||||
return
|
return
|
||||||
pose_bone = ob.pose.bones[bone.name]
|
pose_bone = ob.pose.bones[bone.name]
|
||||||
|
|
||||||
layout.prop(bone.color, 'palette', text='Edit Bone Color')
|
# Allow the layout to use the space normally occupied by the 'set a key' diamond.
|
||||||
|
layout.use_property_decorate = False
|
||||||
|
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.prop(bone.color, 'palette', text='Edit Bone Color')
|
||||||
|
props = row.operator("armature.sync_bone_color_to_selected", text="", icon='UV_SYNC_SELECT')
|
||||||
|
props.bone_type = 'EDIT'
|
||||||
self.draw_bone_color_ui(layout, bone.color)
|
self.draw_bone_color_ui(layout, bone.color)
|
||||||
layout.prop(pose_bone.color, 'palette', text='Pose Bone Color')
|
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.prop(pose_bone.color, 'palette', text='Pose Bone Color')
|
||||||
|
props = row.operator("armature.sync_bone_color_to_selected", text="", icon='UV_SYNC_SELECT')
|
||||||
|
props.bone_type = 'POSE'
|
||||||
self.draw_bone_color_ui(layout, pose_bone.color)
|
self.draw_bone_color_ui(layout, pose_bone.color)
|
||||||
|
|
||||||
def draw_edit_bone(self, context, layout):
|
def draw_edit_bone(self, context, layout):
|
||||||
|
@ -297,8 +345,7 @@ class BONE_PT_display(BoneButtonsPanel, Panel):
|
||||||
if not bone_color.is_custom:
|
if not bone_color.is_custom:
|
||||||
return
|
return
|
||||||
|
|
||||||
layout.use_property_split = False
|
split = layout.split(factor=0.401)
|
||||||
split = layout.split(factor=0.4)
|
|
||||||
|
|
||||||
col = split.column()
|
col = split.column()
|
||||||
row = col.row()
|
row = col.row()
|
||||||
|
@ -307,6 +354,7 @@ class BONE_PT_display(BoneButtonsPanel, Panel):
|
||||||
|
|
||||||
col = split.column(align=True)
|
col = split.column(align=True)
|
||||||
row = col.row(align=True)
|
row = col.row(align=True)
|
||||||
|
row.use_property_split = False
|
||||||
row.prop(bone_color.custom, "normal", text="")
|
row.prop(bone_color.custom, "normal", text="")
|
||||||
row.prop(bone_color.custom, "select", text="")
|
row.prop(bone_color.custom, "select", text="")
|
||||||
row.prop(bone_color.custom, "active", text="")
|
row.prop(bone_color.custom, "active", text="")
|
||||||
|
@ -504,6 +552,7 @@ classes = (
|
||||||
BONE_PT_transform,
|
BONE_PT_transform,
|
||||||
BONE_PT_curved,
|
BONE_PT_curved,
|
||||||
BONE_PT_relations,
|
BONE_PT_relations,
|
||||||
|
BONE_PT_collections,
|
||||||
BONE_PT_inverse_kinematics,
|
BONE_PT_inverse_kinematics,
|
||||||
BONE_PT_deform,
|
BONE_PT_deform,
|
||||||
BONE_PT_display,
|
BONE_PT_display,
|
||||||
|
|
|
@ -547,6 +547,9 @@ def draw_attribute_warnings(context, layout):
|
||||||
ob = context.object
|
ob = context.object
|
||||||
mesh = context.mesh
|
mesh = context.mesh
|
||||||
|
|
||||||
|
if not mesh:
|
||||||
|
return
|
||||||
|
|
||||||
unique_names = set()
|
unique_names = set()
|
||||||
colliding_names = []
|
colliding_names = []
|
||||||
for collection in (
|
for collection in (
|
||||||
|
|
|
@ -3902,12 +3902,6 @@ class VIEW3D_MT_pose(Menu):
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
|
||||||
layout.operator_context = 'INVOKE_AREA'
|
|
||||||
layout.operator("armature.armature_layers", text="Change Armature Layers...")
|
|
||||||
layout.operator("pose.bone_layers", text="Change Bone Layers...")
|
|
||||||
|
|
||||||
layout.separator()
|
|
||||||
|
|
||||||
layout.menu("VIEW3D_MT_pose_showhide")
|
layout.menu("VIEW3D_MT_pose_showhide")
|
||||||
layout.menu("VIEW3D_MT_bone_options_toggle", text="Bone Settings")
|
layout.menu("VIEW3D_MT_bone_options_toggle", text="Bone Settings")
|
||||||
|
|
||||||
|
@ -3997,8 +3991,12 @@ class VIEW3D_MT_bone_collections(Menu):
|
||||||
layout.label(text="- select bones to operate on first -")
|
layout.label(text="- select bones to operate on first -")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
layout.operator("armature.collection_show_all")
|
||||||
|
layout.separator()
|
||||||
|
|
||||||
arm = context.object.data
|
arm = context.object.data
|
||||||
bone = context.active_bone
|
bone = context.active_bone
|
||||||
|
|
||||||
found_editable_bcoll = False
|
found_editable_bcoll = False
|
||||||
for bcoll in arm.collections:
|
for bcoll in arm.collections:
|
||||||
if not bcoll.is_editable:
|
if not bcoll.is_editable:
|
||||||
|
|
|
@ -915,4 +915,9 @@ inline bool bNodePanelState::is_parent_collapsed() const
|
||||||
return flag & NODE_PANEL_PARENT_COLLAPSED;
|
return flag & NODE_PANEL_PARENT_COLLAPSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool bNodePanelState::has_visible_content() const
|
||||||
|
{
|
||||||
|
return flag & NODE_PANEL_CONTENT_VISIBLE;
|
||||||
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
|
@ -533,7 +533,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
|
||||||
vi.width = vi.gridsize; \
|
vi.width = vi.gridsize; \
|
||||||
vi.height = vi.gridsize; \
|
vi.height = vi.gridsize; \
|
||||||
vi.index = vi.vertex.i = vi.grid_indices[vi.g] * vi.key.grid_area - 1; \
|
vi.index = vi.vertex.i = vi.grid_indices[vi.g] * vi.key.grid_area - 1; \
|
||||||
vi.grid = vi.grids[vi.grid_indices[vi.g]]; \
|
vi.grid = CCG_elem_offset(&vi.key, vi.grids[vi.grid_indices[vi.g]], -1); \
|
||||||
if (mode == PBVH_ITER_UNIQUE) { \
|
if (mode == PBVH_ITER_UNIQUE) { \
|
||||||
vi.gh = vi.grid_hidden[vi.grid_indices[vi.g]]; \
|
vi.gh = vi.grid_hidden[vi.grid_indices[vi.g]]; \
|
||||||
} \
|
} \
|
||||||
|
@ -546,10 +546,10 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
|
||||||
for (vi.gy = 0; vi.gy < vi.height; vi.gy++) { \
|
for (vi.gy = 0; vi.gy < vi.height; vi.gy++) { \
|
||||||
for (vi.gx = 0; vi.gx < vi.width; vi.gx++, vi.i++) { \
|
for (vi.gx = 0; vi.gx < vi.width; vi.gx++, vi.i++) { \
|
||||||
if (vi.grid) { \
|
if (vi.grid) { \
|
||||||
|
vi.grid = CCG_elem_next(&vi.key, vi.grid); \
|
||||||
vi.co = CCG_elem_co(&vi.key, vi.grid); \
|
vi.co = CCG_elem_co(&vi.key, vi.grid); \
|
||||||
vi.fno = CCG_elem_no(&vi.key, vi.grid); \
|
vi.fno = CCG_elem_no(&vi.key, vi.grid); \
|
||||||
vi.mask = vi.key.has_mask ? *CCG_elem_mask(&vi.key, vi.grid) : 0.0f; \
|
vi.mask = vi.key.has_mask ? *CCG_elem_mask(&vi.key, vi.grid) : 0.0f; \
|
||||||
vi.grid = CCG_elem_next(&vi.key, vi.grid); \
|
|
||||||
vi.index++; \
|
vi.index++; \
|
||||||
vi.vertex.i++; \
|
vi.vertex.i++; \
|
||||||
vi.visible = true; \
|
vi.visible = true; \
|
||||||
|
|
|
@ -5427,11 +5427,7 @@ void BKE_curve_material_remap(Curve *cu, const uint *remap, uint remap_len)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i <= charinfo_len; i++) {
|
for (i = 0; i <= charinfo_len; i++) {
|
||||||
if (strinfo[i].mat_nr > 0) {
|
|
||||||
strinfo[i].mat_nr -= 1;
|
|
||||||
MAT_NR_REMAP(strinfo[i].mat_nr);
|
MAT_NR_REMAP(strinfo[i].mat_nr);
|
||||||
strinfo[i].mat_nr += 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -448,8 +448,8 @@ static void build_underline(Curve *cu,
|
||||||
nu2->bezt = nullptr;
|
nu2->bezt = nullptr;
|
||||||
nu2->knotsu = nu2->knotsv = nullptr;
|
nu2->knotsu = nu2->knotsv = nullptr;
|
||||||
nu2->charidx = charidx + 1000;
|
nu2->charidx = charidx + 1000;
|
||||||
if (mat_nr > 0) {
|
if (mat_nr >= 0) {
|
||||||
nu2->mat_nr = mat_nr - 1;
|
nu2->mat_nr = mat_nr;
|
||||||
}
|
}
|
||||||
nu2->pntsu = 4;
|
nu2->pntsu = 4;
|
||||||
nu2->pntsv = 1;
|
nu2->pntsv = 1;
|
||||||
|
@ -538,7 +538,7 @@ void BKE_vfont_build_char(Curve *cu,
|
||||||
nu2->flag = CU_SMOOTH;
|
nu2->flag = CU_SMOOTH;
|
||||||
nu2->charidx = charidx;
|
nu2->charidx = charidx;
|
||||||
if (info->mat_nr > 0) {
|
if (info->mat_nr > 0) {
|
||||||
nu2->mat_nr = info->mat_nr - 1;
|
nu2->mat_nr = info->mat_nr;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
nu2->mat_nr = 0;
|
nu2->mat_nr = 0;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include "DNA_brush_types.h"
|
#include "DNA_brush_types.h"
|
||||||
#include "DNA_camera_types.h"
|
#include "DNA_camera_types.h"
|
||||||
|
#include "DNA_curve_types.h"
|
||||||
#include "DNA_defaults.h"
|
#include "DNA_defaults.h"
|
||||||
#include "DNA_light_types.h"
|
#include "DNA_light_types.h"
|
||||||
#include "DNA_lightprobe_types.h"
|
#include "DNA_lightprobe_types.h"
|
||||||
|
@ -42,6 +43,7 @@
|
||||||
|
|
||||||
#include "BKE_armature.h"
|
#include "BKE_armature.h"
|
||||||
#include "BKE_attribute.h"
|
#include "BKE_attribute.h"
|
||||||
|
#include "BKE_curve.h"
|
||||||
#include "BKE_effect.h"
|
#include "BKE_effect.h"
|
||||||
#include "BKE_grease_pencil.hh"
|
#include "BKE_grease_pencil.hh"
|
||||||
#include "BKE_idprop.hh"
|
#include "BKE_idprop.hh"
|
||||||
|
@ -1614,6 +1616,20 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 31)) {
|
||||||
|
LISTBASE_FOREACH (Curve *, curve, &bmain->curves) {
|
||||||
|
const int curvetype = BKE_curve_type_get(curve);
|
||||||
|
if (curvetype == OB_FONT) {
|
||||||
|
CharInfo *info = curve->strinfo;
|
||||||
|
for (int i = curve->len_char32 - 1; i >= 0; i--, info++) {
|
||||||
|
if (info->mat_nr > 0) {
|
||||||
|
/** CharInfo mat_nr used to start at 1, unlike mesh & nurbs, now zero-based. */
|
||||||
|
info->mat_nr--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Versioning code until next subversion bump goes here.
|
* Versioning code until next subversion bump goes here.
|
||||||
*
|
*
|
||||||
|
|
|
@ -77,6 +77,7 @@ void ARMATURE_OT_collection_remove(struct wmOperatorType *ot);
|
||||||
void ARMATURE_OT_collection_move(struct wmOperatorType *ot);
|
void ARMATURE_OT_collection_move(struct wmOperatorType *ot);
|
||||||
void ARMATURE_OT_collection_assign(struct wmOperatorType *ot);
|
void ARMATURE_OT_collection_assign(struct wmOperatorType *ot);
|
||||||
void ARMATURE_OT_collection_unassign(struct wmOperatorType *ot);
|
void ARMATURE_OT_collection_unassign(struct wmOperatorType *ot);
|
||||||
|
void ARMATURE_OT_collection_unassign_named(struct wmOperatorType *ot);
|
||||||
void ARMATURE_OT_collection_select(struct wmOperatorType *ot);
|
void ARMATURE_OT_collection_select(struct wmOperatorType *ot);
|
||||||
void ARMATURE_OT_collection_deselect(struct wmOperatorType *ot);
|
void ARMATURE_OT_collection_deselect(struct wmOperatorType *ot);
|
||||||
|
|
||||||
|
@ -134,8 +135,6 @@ void POSE_OT_rotation_mode_set(struct wmOperatorType *ot);
|
||||||
|
|
||||||
void POSE_OT_quaternions_flip(struct wmOperatorType *ot);
|
void POSE_OT_quaternions_flip(struct wmOperatorType *ot);
|
||||||
|
|
||||||
void POSE_OT_bone_layers(struct wmOperatorType *ot);
|
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
|
@ -66,6 +66,7 @@ void ED_operatortypes_armature()
|
||||||
WM_operatortype_append(ARMATURE_OT_collection_move);
|
WM_operatortype_append(ARMATURE_OT_collection_move);
|
||||||
WM_operatortype_append(ARMATURE_OT_collection_assign);
|
WM_operatortype_append(ARMATURE_OT_collection_assign);
|
||||||
WM_operatortype_append(ARMATURE_OT_collection_unassign);
|
WM_operatortype_append(ARMATURE_OT_collection_unassign);
|
||||||
|
WM_operatortype_append(ARMATURE_OT_collection_unassign_named);
|
||||||
WM_operatortype_append(ARMATURE_OT_collection_select);
|
WM_operatortype_append(ARMATURE_OT_collection_select);
|
||||||
WM_operatortype_append(ARMATURE_OT_collection_deselect);
|
WM_operatortype_append(ARMATURE_OT_collection_deselect);
|
||||||
|
|
||||||
|
@ -119,8 +120,6 @@ void ED_operatortypes_armature()
|
||||||
|
|
||||||
WM_operatortype_append(POSE_OT_quaternions_flip);
|
WM_operatortype_append(POSE_OT_quaternions_flip);
|
||||||
|
|
||||||
WM_operatortype_append(POSE_OT_bone_layers);
|
|
||||||
|
|
||||||
WM_operatortype_append(POSE_OT_propagate);
|
WM_operatortype_append(POSE_OT_propagate);
|
||||||
|
|
||||||
/* POSELIB */
|
/* POSELIB */
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "DNA_ID.h"
|
#include "DNA_ID.h"
|
||||||
#include "DNA_object_types.h"
|
#include "DNA_object_types.h"
|
||||||
|
|
||||||
|
#include "BKE_action.h"
|
||||||
#include "BKE_context.h"
|
#include "BKE_context.h"
|
||||||
#include "BKE_layer.h"
|
#include "BKE_layer.h"
|
||||||
#include "BKE_report.h"
|
#include "BKE_report.h"
|
||||||
|
@ -290,7 +291,11 @@ static void bone_collection_assign_editbones(bContext *C,
|
||||||
DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
|
DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns whether the current mode is actually supported. */
|
/**
|
||||||
|
* Assign or unassign all selected bones to/from the given bone collection.
|
||||||
|
*
|
||||||
|
* \return whether the current mode is actually supported.
|
||||||
|
*/
|
||||||
static bool bone_collection_assign_mode_specific(bContext *C,
|
static bool bone_collection_assign_mode_specific(bContext *C,
|
||||||
Object *ob,
|
Object *ob,
|
||||||
BoneCollection *bcoll,
|
BoneCollection *bcoll,
|
||||||
|
@ -327,6 +332,58 @@ static bool bone_collection_assign_mode_specific(bContext *C,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assign or unassign the named bone to/from the given bone collection.
|
||||||
|
*
|
||||||
|
* \return whether the current mode is actually supported.
|
||||||
|
*/
|
||||||
|
static bool bone_collection_assign_named_mode_specific(bContext *C,
|
||||||
|
Object *ob,
|
||||||
|
BoneCollection *bcoll,
|
||||||
|
const char *bone_name,
|
||||||
|
assign_bone_func assign_bone_func,
|
||||||
|
assign_ebone_func assign_ebone_func,
|
||||||
|
bool *made_any_changes,
|
||||||
|
bool *had_bones_to_assign)
|
||||||
|
{
|
||||||
|
bArmature *arm = static_cast<bArmature *>(ob->data);
|
||||||
|
|
||||||
|
switch (CTX_data_mode_enum(C)) {
|
||||||
|
case CTX_MODE_POSE: {
|
||||||
|
bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
|
||||||
|
if (!pchan) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
*had_bones_to_assign = true;
|
||||||
|
*made_any_changes |= assign_bone_func(bcoll, pchan->bone);
|
||||||
|
|
||||||
|
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
|
||||||
|
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_COLLECTION, ob);
|
||||||
|
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT); /* Recreate the draw buffers. */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CTX_MODE_EDIT_ARMATURE: {
|
||||||
|
EditBone *ebone = ED_armature_ebone_find_name(arm->edbo, bone_name);
|
||||||
|
if (!ebone) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
*had_bones_to_assign = true;
|
||||||
|
*made_any_changes |= assign_ebone_func(bcoll, ebone);
|
||||||
|
|
||||||
|
ED_armature_edit_sync_selection(arm->edbo);
|
||||||
|
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_COLLECTION, ob);
|
||||||
|
DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool bone_collection_assign_poll(bContext *C)
|
static bool bone_collection_assign_poll(bContext *C)
|
||||||
{
|
{
|
||||||
Object *ob = ED_object_context(C);
|
Object *ob = ED_object_context(C);
|
||||||
|
@ -484,6 +541,82 @@ void ARMATURE_OT_collection_unassign(wmOperatorType *ot)
|
||||||
"the active bone collection");
|
"the active bone collection");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int bone_collection_unassign_named_exec(bContext *C, wmOperator *op)
|
||||||
|
{
|
||||||
|
Object *ob = ED_object_context(C);
|
||||||
|
if (ob == nullptr) {
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
BoneCollection *bcoll = get_bonecoll_named_or_active(C, op, ob, FAIL_IF_MISSING);
|
||||||
|
if (bcoll == nullptr) {
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
char bone_name[MAX_NAME];
|
||||||
|
RNA_string_get(op->ptr, "bone_name", bone_name);
|
||||||
|
if (!bone_name[0]) {
|
||||||
|
WM_report(RPT_ERROR, "Missing bone name");
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool made_any_changes = false;
|
||||||
|
bool had_bones_to_unassign = false;
|
||||||
|
const bool mode_is_supported = bone_collection_assign_named_mode_specific(
|
||||||
|
C,
|
||||||
|
ob,
|
||||||
|
bcoll,
|
||||||
|
bone_name,
|
||||||
|
ANIM_armature_bonecoll_unassign,
|
||||||
|
ANIM_armature_bonecoll_unassign_editbone,
|
||||||
|
&made_any_changes,
|
||||||
|
&had_bones_to_unassign);
|
||||||
|
|
||||||
|
if (!mode_is_supported) {
|
||||||
|
WM_report(RPT_ERROR, "This operator only works in pose mode and armature edit mode");
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
if (!had_bones_to_unassign) {
|
||||||
|
WM_reportf(RPT_WARNING, "Could not find bone '%s'", bone_name);
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
if (!made_any_changes) {
|
||||||
|
WM_reportf(
|
||||||
|
RPT_WARNING, "Bone '%s' was not assigned to collection '%s'", bone_name, bcoll->name);
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
return OPERATOR_FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ARMATURE_OT_collection_unassign_named(wmOperatorType *ot)
|
||||||
|
{
|
||||||
|
/* identifiers */
|
||||||
|
ot->name = "Remove Bone from Bone collections";
|
||||||
|
ot->idname = "ARMATURE_OT_collection_unassign_named";
|
||||||
|
ot->description = "Unassign the bone from this bone collection";
|
||||||
|
|
||||||
|
/* api callbacks */
|
||||||
|
ot->exec = bone_collection_unassign_named_exec;
|
||||||
|
ot->poll = bone_collection_assign_poll;
|
||||||
|
|
||||||
|
/* flags */
|
||||||
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||||
|
|
||||||
|
RNA_def_string(ot->srna,
|
||||||
|
"name",
|
||||||
|
nullptr,
|
||||||
|
MAX_NAME,
|
||||||
|
"Bone Collection",
|
||||||
|
"Name of the bone collection to unassign this bone from; empty to unassign from "
|
||||||
|
"the active bone collection");
|
||||||
|
RNA_def_string(ot->srna,
|
||||||
|
"bone_name",
|
||||||
|
nullptr,
|
||||||
|
MAX_NAME,
|
||||||
|
"Bone Name",
|
||||||
|
"Name of the bone to unassign from the collection; empty to use the active bone");
|
||||||
|
}
|
||||||
|
|
||||||
static bool editbone_is_member(const EditBone *ebone, const BoneCollection *bcoll)
|
static bool editbone_is_member(const EditBone *ebone, const BoneCollection *bcoll)
|
||||||
{
|
{
|
||||||
LISTBASE_FOREACH (BoneCollectionReference *, ref, &ebone->bone_collections) {
|
LISTBASE_FOREACH (BoneCollectionReference *, ref, &ebone->bone_collections) {
|
||||||
|
|
|
@ -746,95 +746,6 @@ void ARMATURE_OT_layers_show_all(wmOperatorType *ot)
|
||||||
ot->srna, "all", true, "All Layers", "Enable all layers or just the first 16 (top row)");
|
ot->srna, "all", true, "All Layers", "Enable all layers or just the first 16 (top row)");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------- */
|
|
||||||
|
|
||||||
/* Present a popup to get the layers that should be used */
|
|
||||||
static int pose_bone_layers_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|
||||||
{
|
|
||||||
/* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
|
|
||||||
bool layers[32] = {false};
|
|
||||||
|
|
||||||
/* get layers that are active already */
|
|
||||||
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones) {
|
|
||||||
short bit;
|
|
||||||
|
|
||||||
/* loop over the bits for this pchan's layers, adding layers where they're needed */
|
|
||||||
for (bit = 0; bit < 32; bit++) {
|
|
||||||
layers[bit] = (pchan->bone->layer & (1u << bit)) != 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CTX_DATA_END;
|
|
||||||
|
|
||||||
/* copy layers to operator */
|
|
||||||
RNA_boolean_set_array(op->ptr, "layers", layers);
|
|
||||||
|
|
||||||
/* part to sync with other similar operators... */
|
|
||||||
return WM_operator_props_popup(C, op, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the visible layers for the active armature (edit and pose modes) */
|
|
||||||
static int pose_bone_layers_exec(bContext *C, wmOperator *op)
|
|
||||||
{
|
|
||||||
/* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
|
|
||||||
bool layers[32];
|
|
||||||
|
|
||||||
/* get the values set in the operator properties */
|
|
||||||
RNA_boolean_get_array(op->ptr, "layers", layers);
|
|
||||||
|
|
||||||
Object *prev_ob = nullptr;
|
|
||||||
|
|
||||||
/* Make sure that the pose bone data is up to date.
|
|
||||||
* (May not always be the case after undo/redo e.g.).
|
|
||||||
*/
|
|
||||||
Main *bmain = CTX_data_main(C);
|
|
||||||
wmWindow *win = CTX_wm_window(C);
|
|
||||||
View3D *v3d = CTX_wm_view3d(C); /* This may be nullptr in a lot of cases. */
|
|
||||||
const Scene *scene = WM_window_get_active_scene(win);
|
|
||||||
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
|
|
||||||
|
|
||||||
FOREACH_OBJECT_IN_MODE_BEGIN (scene, view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob_iter) {
|
|
||||||
bArmature *arm = static_cast<bArmature *>(ob_iter->data);
|
|
||||||
BKE_pose_ensure(bmain, ob_iter, arm, true);
|
|
||||||
}
|
|
||||||
FOREACH_OBJECT_IN_MODE_END;
|
|
||||||
|
|
||||||
/* set layers of pchans based on the values set in the operator props */
|
|
||||||
CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob) {
|
|
||||||
/* get pointer for pchan, and write flags this way */
|
|
||||||
PointerRNA ptr = RNA_pointer_create((ID *)ob->data, &RNA_Bone, pchan->bone);
|
|
||||||
RNA_boolean_set_array(&ptr, "layers", layers);
|
|
||||||
|
|
||||||
if (prev_ob != ob) {
|
|
||||||
/* NOTE: notifier might evolve. */
|
|
||||||
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
|
|
||||||
DEG_id_tag_update((ID *)ob->data, ID_RECALC_COPY_ON_WRITE);
|
|
||||||
prev_ob = ob;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CTX_DATA_END;
|
|
||||||
return OPERATOR_FINISHED;
|
|
||||||
}
|
|
||||||
|
|
||||||
void POSE_OT_bone_layers(wmOperatorType *ot)
|
|
||||||
{
|
|
||||||
/* identifiers */
|
|
||||||
ot->name = "Change Bone Layers";
|
|
||||||
ot->idname = "POSE_OT_bone_layers";
|
|
||||||
ot->description = "Change the layers that the selected bones belong to";
|
|
||||||
|
|
||||||
/* callbacks */
|
|
||||||
ot->invoke = pose_bone_layers_invoke;
|
|
||||||
ot->exec = pose_bone_layers_exec;
|
|
||||||
ot->poll = ED_operator_posemode_exclusive;
|
|
||||||
|
|
||||||
/* flags */
|
|
||||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
||||||
|
|
||||||
/* properties */
|
|
||||||
RNA_def_boolean_layer_member(
|
|
||||||
ot->srna, "layers", 32, nullptr, "Layer", "Armature layers that bone belongs to");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ********************************************** */
|
/* ********************************************** */
|
||||||
/* Show/Hide Bones */
|
/* Show/Hide Bones */
|
||||||
|
|
||||||
|
|
|
@ -385,7 +385,7 @@ static int insert_into_textbuf(Object *obedit, uintptr_t c)
|
||||||
ef->textbuf[ef->pos] = c;
|
ef->textbuf[ef->pos] = c;
|
||||||
ef->textbufinfo[ef->pos] = cu->curinfo;
|
ef->textbufinfo[ef->pos] = cu->curinfo;
|
||||||
ef->textbufinfo[ef->pos].kern = 0.0f;
|
ef->textbufinfo[ef->pos].kern = 0.0f;
|
||||||
ef->textbufinfo[ef->pos].mat_nr = obedit->actcol;
|
ef->textbufinfo[ef->pos].mat_nr = obedit->actcol - 1;
|
||||||
|
|
||||||
ef->pos++;
|
ef->pos++;
|
||||||
ef->len++;
|
ef->len++;
|
||||||
|
@ -418,10 +418,7 @@ static void text_update_edited(bContext *C, Object *obedit, const eEditFontMode
|
||||||
cu->curinfo = ef->textbufinfo[ef->pos ? ef->pos - 1 : 0];
|
cu->curinfo = ef->textbufinfo[ef->pos ? ef->pos - 1 : 0];
|
||||||
|
|
||||||
if (obedit->totcol > 0) {
|
if (obedit->totcol > 0) {
|
||||||
obedit->actcol = cu->curinfo.mat_nr;
|
obedit->actcol = cu->curinfo.mat_nr + 1;
|
||||||
|
|
||||||
/* since this array is calloc'd, it can be 0 even though we try ensure
|
|
||||||
* (mat_nr > 0) almost everywhere */
|
|
||||||
if (obedit->actcol < 1) {
|
if (obedit->actcol < 1) {
|
||||||
obedit->actcol = 1;
|
obedit->actcol = 1;
|
||||||
}
|
}
|
||||||
|
@ -1851,7 +1848,7 @@ static void font_cursor_set_apply(bContext *C, const wmEvent *event)
|
||||||
cu->curinfo = ef->textbufinfo[ef->pos ? ef->pos - 1 : 0];
|
cu->curinfo = ef->textbufinfo[ef->pos ? ef->pos - 1 : 0];
|
||||||
|
|
||||||
if (ob->totcol > 0) {
|
if (ob->totcol > 0) {
|
||||||
ob->actcol = cu->curinfo.mat_nr;
|
ob->actcol = cu->curinfo.mat_nr + 1;
|
||||||
if (ob->actcol < 1) {
|
if (ob->actcol < 1) {
|
||||||
ob->actcol = 1;
|
ob->actcol = 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1253,9 +1253,10 @@ static void ui_apply_but_TEX(bContext *C, uiBut *but, uiHandleButtonData *data)
|
||||||
if ((but->func_arg2 == nullptr) && (but->type == UI_BTYPE_SEARCH_MENU)) {
|
if ((but->func_arg2 == nullptr) && (but->type == UI_BTYPE_SEARCH_MENU)) {
|
||||||
uiButSearch *search_but = (uiButSearch *)but;
|
uiButSearch *search_but = (uiButSearch *)but;
|
||||||
but->func_arg2 = search_but->item_active;
|
but->func_arg2 = search_but->item_active;
|
||||||
|
if ((U.flag & USER_FLAG_RECENT_SEARCHES_DISABLE) == 0) {
|
||||||
blender::ui::string_search::add_recent_search(search_but->item_active_str);
|
blender::ui::string_search::add_recent_search(search_but->item_active_str);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ui_apply_but_func(C, but);
|
ui_apply_but_func(C, but);
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ struct RecentCacheStorage {
|
||||||
|
|
||||||
static RecentCacheStorage &get_recent_cache_storage()
|
static RecentCacheStorage &get_recent_cache_storage()
|
||||||
{
|
{
|
||||||
|
BLI_assert((U.flag & USER_FLAG_RECENT_SEARCHES_DISABLE) == 0);
|
||||||
static RecentCacheStorage storage;
|
static RecentCacheStorage storage;
|
||||||
return storage;
|
return storage;
|
||||||
}
|
}
|
||||||
|
@ -62,6 +63,10 @@ static std::optional<std::string> get_recent_searches_file_path()
|
||||||
|
|
||||||
void write_recent_searches_file()
|
void write_recent_searches_file()
|
||||||
{
|
{
|
||||||
|
if (U.flag & USER_FLAG_RECENT_SEARCHES_DISABLE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const std::optional<std::string> path = get_recent_searches_file_path();
|
const std::optional<std::string> path = get_recent_searches_file_path();
|
||||||
if (!path) {
|
if (!path) {
|
||||||
return;
|
return;
|
||||||
|
@ -83,6 +88,10 @@ void write_recent_searches_file()
|
||||||
|
|
||||||
void read_recent_searches_file()
|
void read_recent_searches_file()
|
||||||
{
|
{
|
||||||
|
if (U.flag & USER_FLAG_RECENT_SEARCHES_DISABLE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const std::optional<std::string> path = get_recent_searches_file_path();
|
const std::optional<std::string> path = get_recent_searches_file_path();
|
||||||
if (!path) {
|
if (!path) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -131,12 +131,8 @@ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode)
|
||||||
case OB_FONT:
|
case OB_FONT:
|
||||||
case OB_MBALL:
|
case OB_MBALL:
|
||||||
case OB_POINTCLOUD:
|
case OB_POINTCLOUD:
|
||||||
if (mode & OB_MODE_EDIT) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case OB_LATTICE:
|
case OB_LATTICE:
|
||||||
if (mode & (OB_MODE_EDIT | OB_MODE_WEIGHT_PAINT)) {
|
if (mode & OB_MODE_EDIT) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -347,7 +347,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator * /*op*/)
|
||||||
if (ef && BKE_vfont_select_get(ob, &selstart, &selend)) {
|
if (ef && BKE_vfont_select_get(ob, &selstart, &selend)) {
|
||||||
for (i = selstart; i <= selend; i++) {
|
for (i = selstart; i <= selend; i++) {
|
||||||
changed = true;
|
changed = true;
|
||||||
ef->textbufinfo[i].mat_nr = mat_nr_active + 1;
|
ef->textbufinfo[i].mat_nr = mat_nr_active;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -631,8 +631,10 @@ struct VisibilityUpdateState {
|
||||||
/* Recursive function to determine visibility of items before drawing. */
|
/* Recursive function to determine visibility of items before drawing. */
|
||||||
static void node_update_panel_items_visibility_recursive(int num_items,
|
static void node_update_panel_items_visibility_recursive(int num_items,
|
||||||
const bool is_parent_collapsed,
|
const bool is_parent_collapsed,
|
||||||
|
bNodePanelState &parent_state,
|
||||||
VisibilityUpdateState &state)
|
VisibilityUpdateState &state)
|
||||||
{
|
{
|
||||||
|
parent_state.flag &= ~NODE_PANEL_CONTENT_VISIBLE;
|
||||||
while (state.item_iter != state.item_end) {
|
while (state.item_iter != state.item_end) {
|
||||||
/* Stop after adding the expected number of items.
|
/* Stop after adding the expected number of items.
|
||||||
* Root panel consumes all remaining items (num_items == -1). */
|
* Root panel consumes all remaining items (num_items == -1). */
|
||||||
|
@ -651,14 +653,24 @@ static void node_update_panel_items_visibility_recursive(int num_items,
|
||||||
const bool is_collapsed = is_parent_collapsed || item.state->is_collapsed();
|
const bool is_collapsed = is_parent_collapsed || item.state->is_collapsed();
|
||||||
|
|
||||||
node_update_panel_items_visibility_recursive(
|
node_update_panel_items_visibility_recursive(
|
||||||
item.panel_decl->num_child_decls, is_collapsed, state);
|
item.panel_decl->num_child_decls, is_collapsed, *item.state, state);
|
||||||
|
if (item.state->flag & NODE_PANEL_CONTENT_VISIBLE) {
|
||||||
|
/* If child panel is visible so is the parent panel. */
|
||||||
|
parent_state.flag |= NODE_PANEL_CONTENT_VISIBLE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (item.is_valid_socket()) {
|
else if (item.is_valid_socket()) {
|
||||||
if (item.input) {
|
if (item.input) {
|
||||||
SET_FLAG_FROM_TEST(item.input->flag, is_parent_collapsed, SOCK_PANEL_COLLAPSED);
|
SET_FLAG_FROM_TEST(item.input->flag, is_parent_collapsed, SOCK_PANEL_COLLAPSED);
|
||||||
|
if (item.input->is_visible()) {
|
||||||
|
parent_state.flag |= NODE_PANEL_CONTENT_VISIBLE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (item.output) {
|
if (item.output) {
|
||||||
SET_FLAG_FROM_TEST(item.output->flag, is_parent_collapsed, SOCK_PANEL_COLLAPSED);
|
SET_FLAG_FROM_TEST(item.output->flag, is_parent_collapsed, SOCK_PANEL_COLLAPSED);
|
||||||
|
if (item.output->is_visible()) {
|
||||||
|
parent_state.flag |= NODE_PANEL_CONTENT_VISIBLE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -719,6 +731,8 @@ static void add_panel_items_recursive(const bContext &C,
|
||||||
C, ntree, node, node.typeinfo->draw_buttons, block, locy);
|
C, ntree, node, node.typeinfo->draw_buttons, block, locy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Panel visible if any content is visible. */
|
||||||
|
if (item.state->has_visible_content()) {
|
||||||
if (!is_parent_collapsed) {
|
if (!is_parent_collapsed) {
|
||||||
locy -= NODE_DY;
|
locy -= NODE_DY;
|
||||||
state.is_first = false;
|
state.is_first = false;
|
||||||
|
@ -729,12 +743,14 @@ static void add_panel_items_recursive(const bContext &C,
|
||||||
|
|
||||||
/* Round the socket location to stop it from jiggling. */
|
/* Round the socket location to stop it from jiggling. */
|
||||||
item.runtime->location_y = round(locy + NODE_DYS);
|
item.runtime->location_y = round(locy + NODE_DYS);
|
||||||
if (!is_collapsed) {
|
if (is_collapsed) {
|
||||||
locy -= NODE_ITEM_SPACING_Y / 2; /* Space at bottom of panel header. */
|
item.runtime->max_content_y = item.runtime->min_content_y = round(locy);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
locy -= NODE_ITEM_SPACING_Y / 2; /* Space at bottom of panel header. */
|
||||||
item.runtime->max_content_y = item.runtime->min_content_y = round(locy);
|
item.runtime->max_content_y = item.runtime->min_content_y = round(locy);
|
||||||
if (!is_collapsed) {
|
|
||||||
locy -= NODE_ITEM_SPACING_Y; /* Space at top of panel contents. */
|
locy -= NODE_ITEM_SPACING_Y; /* Space at top of panel contents. */
|
||||||
|
|
||||||
node_update_basis_buttons(C, ntree, node, item.panel_decl->draw_buttons, block, locy);
|
node_update_basis_buttons(C, ntree, node, item.panel_decl->draw_buttons, block, locy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -750,6 +766,7 @@ static void add_panel_items_recursive(const bContext &C,
|
||||||
item.runtime,
|
item.runtime,
|
||||||
state);
|
state);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (item.is_valid_socket()) {
|
else if (item.is_valid_socket()) {
|
||||||
if (item.input) {
|
if (item.input) {
|
||||||
/* Draw buttons before the first input. */
|
/* Draw buttons before the first input. */
|
||||||
|
@ -804,7 +821,7 @@ static void add_panel_items_recursive(const bContext &C,
|
||||||
}
|
}
|
||||||
locy -= NODE_ITEM_SPACING_Y / 2; /* Space at top of next panel header. */
|
locy -= NODE_ITEM_SPACING_Y / 2; /* Space at top of next panel header. */
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/* Advanced drawing with panels and arbitrary input/output ordering. */
|
/* Advanced drawing with panels and arbitrary input/output ordering. */
|
||||||
static void node_update_basis_from_declaration(
|
static void node_update_basis_from_declaration(
|
||||||
|
@ -819,7 +836,9 @@ static void node_update_basis_from_declaration(
|
||||||
|
|
||||||
/* Update item visibility flags first. */
|
/* Update item visibility flags first. */
|
||||||
VisibilityUpdateState visibility_state(item_data);
|
VisibilityUpdateState visibility_state(item_data);
|
||||||
node_update_panel_items_visibility_recursive(-1, false, visibility_state);
|
/* Dummy state item to write into, unused. */
|
||||||
|
bNodePanelState root_panel_state;
|
||||||
|
node_update_panel_items_visibility_recursive(-1, false, root_panel_state, visibility_state);
|
||||||
|
|
||||||
/* Space at the top. */
|
/* Space at the top. */
|
||||||
locy -= NODE_DYS / 2;
|
locy -= NODE_DYS / 2;
|
||||||
|
@ -2015,10 +2034,11 @@ static void node_draw_panels_background(const bNode &node, uiBlock &block)
|
||||||
const bke::bNodePanelRuntime &runtime = node.runtime->panels[panel_i];
|
const bke::bNodePanelRuntime &runtime = node.runtime->panels[panel_i];
|
||||||
|
|
||||||
/* Don't draw hidden or collapsed panels. */
|
/* Don't draw hidden or collapsed panels. */
|
||||||
const bool is_visible = !(state.is_collapsed() || state.is_parent_collapsed());
|
const bool is_background_visible = state.has_visible_content() &&
|
||||||
is_last_panel_visible = is_visible;
|
!(state.is_collapsed() || state.is_parent_collapsed());
|
||||||
|
is_last_panel_visible = is_background_visible;
|
||||||
last_panel_content_y = runtime.max_content_y;
|
last_panel_content_y = runtime.max_content_y;
|
||||||
if (!is_visible) {
|
if (!is_background_visible) {
|
||||||
++panel_i;
|
++panel_i;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -2068,7 +2088,8 @@ static void node_draw_panels(bNodeTree &ntree, const bNode &node, uiBlock &block
|
||||||
|
|
||||||
const bNodePanelState &state = node.panel_states()[panel_i];
|
const bNodePanelState &state = node.panel_states()[panel_i];
|
||||||
/* Don't draw hidden panels. */
|
/* Don't draw hidden panels. */
|
||||||
if (state.is_parent_collapsed()) {
|
const bool is_header_visible = state.has_visible_content() && !state.is_parent_collapsed();
|
||||||
|
if (!is_header_visible) {
|
||||||
++panel_i;
|
++panel_i;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ static const char *outliner_context_dir[] = {
|
||||||
nullptr,
|
nullptr,
|
||||||
};
|
};
|
||||||
|
|
||||||
int /*eContextResult*/ outliner_context(const bContext *C,
|
int /*eContextResult*/ outliner_main_region_context(const bContext *C,
|
||||||
const char *member,
|
const char *member,
|
||||||
bContextDataResult *result)
|
bContextDataResult *result)
|
||||||
{
|
{
|
||||||
|
|
|
@ -674,7 +674,9 @@ void outliner_sync_selection(const bContext *C, SpaceOutliner *space_outliner);
|
||||||
|
|
||||||
/* `outliner_context.cc` */
|
/* `outliner_context.cc` */
|
||||||
|
|
||||||
int outliner_context(const bContext *C, const char *member, bContextDataResult *result);
|
int outliner_main_region_context(const bContext *C,
|
||||||
|
const char *member,
|
||||||
|
bContextDataResult *result);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to safely "cast" a #TreeElement to its new C++ #AbstractTreeElement, if possible.
|
* Helper to safely "cast" a #TreeElement to its new C++ #AbstractTreeElement, if possible.
|
||||||
|
|
|
@ -618,7 +618,6 @@ void ED_spacetype_outliner()
|
||||||
st->id_remap = outliner_id_remap;
|
st->id_remap = outliner_id_remap;
|
||||||
st->foreach_id = outliner_foreach_id;
|
st->foreach_id = outliner_foreach_id;
|
||||||
st->deactivate = outliner_deactivate;
|
st->deactivate = outliner_deactivate;
|
||||||
st->context = outliner_context;
|
|
||||||
st->blend_read_data = outliner_space_blend_read_data;
|
st->blend_read_data = outliner_space_blend_read_data;
|
||||||
st->blend_read_after_liblink = outliner_space_blend_read_after_liblink;
|
st->blend_read_after_liblink = outliner_space_blend_read_after_liblink;
|
||||||
st->blend_write = outliner_space_blend_write;
|
st->blend_write = outliner_space_blend_write;
|
||||||
|
@ -633,6 +632,7 @@ void ED_spacetype_outliner()
|
||||||
art->free = outliner_main_region_free;
|
art->free = outliner_main_region_free;
|
||||||
art->listener = outliner_main_region_listener;
|
art->listener = outliner_main_region_listener;
|
||||||
art->message_subscribe = outliner_main_region_message_subscribe;
|
art->message_subscribe = outliner_main_region_message_subscribe;
|
||||||
|
art->context = outliner_main_region_context;
|
||||||
BLI_addhead(&st->regiontypes, art);
|
BLI_addhead(&st->regiontypes, art);
|
||||||
|
|
||||||
/* regions: header */
|
/* regions: header */
|
||||||
|
|
|
@ -153,6 +153,6 @@ static void recalcData_sequencer_retiming(TransInfo *t)
|
||||||
|
|
||||||
TransConvertTypeInfo TransConvertType_SequencerRetiming = {
|
TransConvertTypeInfo TransConvertType_SequencerRetiming = {
|
||||||
/*flags*/ (T_POINTS | T_2D_EDIT),
|
/*flags*/ (T_POINTS | T_2D_EDIT),
|
||||||
/*createTransData*/ createTransSeqRetimingData,
|
/*create_trans_data*/ createTransSeqRetimingData,
|
||||||
/*recalcData*/ recalcData_sequencer_retiming,
|
/*recalc_data*/ recalcData_sequencer_retiming,
|
||||||
};
|
};
|
||||||
|
|
|
@ -55,6 +55,19 @@ typedef enum eGPUSupportLevel {
|
||||||
GPU_SUPPORT_LEVEL_UNSUPPORTED,
|
GPU_SUPPORT_LEVEL_UNSUPPORTED,
|
||||||
} eGPUSupportLevel;
|
} eGPUSupportLevel;
|
||||||
|
|
||||||
|
typedef enum GPUArchitectureType {
|
||||||
|
/* Immediate Mode Renderer (IMR).
|
||||||
|
* Typically, an IMR architecture will execute GPU work in sequence, rasterizing primitives in
|
||||||
|
* order. */
|
||||||
|
GPU_ARCHITECTURE_IMR = 0,
|
||||||
|
|
||||||
|
/* Tile-Based-Deferred-Renderer (TBDR).
|
||||||
|
* A TBDR architecture will typically execute the vertex stage up-front for all primitives,
|
||||||
|
* binning geometry into distinct tiled regions. Fragments will then be rasterized within
|
||||||
|
* the bounds of one tile at a time. */
|
||||||
|
GPU_ARCHITECTURE_TBDR = 1,
|
||||||
|
} GPUArchitectureType;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
@ -74,6 +87,7 @@ const char *GPU_platform_renderer(void);
|
||||||
const char *GPU_platform_version(void);
|
const char *GPU_platform_version(void);
|
||||||
const char *GPU_platform_support_level_key(void);
|
const char *GPU_platform_support_level_key(void);
|
||||||
const char *GPU_platform_gpu_name(void);
|
const char *GPU_platform_gpu_name(void);
|
||||||
|
GPUArchitectureType GPU_platform_architecture(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,8 @@ class DummyBackend : public GPUBackend {
|
||||||
GPU_BACKEND_NONE,
|
GPU_BACKEND_NONE,
|
||||||
"Unknown",
|
"Unknown",
|
||||||
"",
|
"",
|
||||||
"");
|
"",
|
||||||
|
GPU_ARCHITECTURE_IMR);
|
||||||
}
|
}
|
||||||
void delete_resources() override {}
|
void delete_resources() override {}
|
||||||
void samplers_update() override {}
|
void samplers_update() override {}
|
||||||
|
|
|
@ -205,13 +205,17 @@ void GPU_render_end()
|
||||||
{
|
{
|
||||||
GPUBackend *backend = GPUBackend::get();
|
GPUBackend *backend = GPUBackend::get();
|
||||||
BLI_assert(backend);
|
BLI_assert(backend);
|
||||||
|
if (backend) {
|
||||||
backend->render_end();
|
backend->render_end();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void GPU_render_step()
|
void GPU_render_step()
|
||||||
{
|
{
|
||||||
GPUBackend *backend = GPUBackend::get();
|
GPUBackend *backend = GPUBackend::get();
|
||||||
BLI_assert(backend);
|
BLI_assert(backend);
|
||||||
|
if (backend) {
|
||||||
backend->render_step();
|
backend->render_step();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
|
@ -70,7 +70,8 @@ void GPUPlatformGlobal::init(eGPUDeviceType gpu_device,
|
||||||
eGPUBackendType backend,
|
eGPUBackendType backend,
|
||||||
const char *vendor_str,
|
const char *vendor_str,
|
||||||
const char *renderer_str,
|
const char *renderer_str,
|
||||||
const char *version_str)
|
const char *version_str,
|
||||||
|
GPUArchitectureType arch_type)
|
||||||
{
|
{
|
||||||
this->clear();
|
this->clear();
|
||||||
|
|
||||||
|
@ -91,6 +92,7 @@ void GPUPlatformGlobal::init(eGPUDeviceType gpu_device,
|
||||||
this->support_key = create_key(gpu_support_level, vendor, renderer, version);
|
this->support_key = create_key(gpu_support_level, vendor, renderer, version);
|
||||||
this->gpu_name = create_gpu_name(vendor, renderer, version);
|
this->gpu_name = create_gpu_name(vendor, renderer, version);
|
||||||
this->backend = backend;
|
this->backend = backend;
|
||||||
|
this->architecture_type = arch_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPUPlatformGlobal::clear()
|
void GPUPlatformGlobal::clear()
|
||||||
|
@ -149,6 +151,12 @@ const char *GPU_platform_gpu_name()
|
||||||
return GPG.gpu_name;
|
return GPG.gpu_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GPUArchitectureType GPU_platform_architecture()
|
||||||
|
{
|
||||||
|
BLI_assert(GPG.initialized);
|
||||||
|
return GPG.architecture_type;
|
||||||
|
}
|
||||||
|
|
||||||
bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver)
|
bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver)
|
||||||
{
|
{
|
||||||
return GPU_type_matches_ex(device, os, driver, GPU_BACKEND_ANY);
|
return GPU_type_matches_ex(device, os, driver, GPU_BACKEND_ANY);
|
||||||
|
|
|
@ -25,6 +25,7 @@ class GPUPlatformGlobal {
|
||||||
char *support_key = nullptr;
|
char *support_key = nullptr;
|
||||||
char *gpu_name = nullptr;
|
char *gpu_name = nullptr;
|
||||||
eGPUBackendType backend = GPU_BACKEND_NONE;
|
eGPUBackendType backend = GPU_BACKEND_NONE;
|
||||||
|
GPUArchitectureType architecture_type = GPU_ARCHITECTURE_IMR;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void init(eGPUDeviceType gpu_device,
|
void init(eGPUDeviceType gpu_device,
|
||||||
|
@ -34,7 +35,8 @@ class GPUPlatformGlobal {
|
||||||
eGPUBackendType backend,
|
eGPUBackendType backend,
|
||||||
const char *vendor_str,
|
const char *vendor_str,
|
||||||
const char *renderer_str,
|
const char *renderer_str,
|
||||||
const char *version_str);
|
const char *version_str,
|
||||||
|
GPUArchitectureType arch_type);
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
};
|
};
|
||||||
|
|
|
@ -194,6 +194,8 @@ void MTLBackend::platform_init(MTLContext *ctx)
|
||||||
if (G.debug & G_DEBUG_GPU) {
|
if (G.debug & G_DEBUG_GPU) {
|
||||||
printf("METAL API - DETECTED GPU: %s\n", vendor);
|
printf("METAL API - DETECTED GPU: %s\n", vendor);
|
||||||
}
|
}
|
||||||
|
GPUArchitectureType architecture_type = (mtl_device.hasUnifiedMemory) ? GPU_ARCHITECTURE_TBDR :
|
||||||
|
GPU_ARCHITECTURE_IMR;
|
||||||
|
|
||||||
/* macOS is the only supported platform, but check to ensure we are not building with Metal
|
/* macOS is the only supported platform, but check to ensure we are not building with Metal
|
||||||
* enablement on another platform. */
|
* enablement on another platform. */
|
||||||
|
@ -240,7 +242,15 @@ void MTLBackend::platform_init(MTLContext *ctx)
|
||||||
printf("Renderer: %s\n", renderer);
|
printf("Renderer: %s\n", renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
GPG.init(device, os, driver, support_level, GPU_BACKEND_METAL, vendor, renderer, version);
|
GPG.init(device,
|
||||||
|
os,
|
||||||
|
driver,
|
||||||
|
support_level,
|
||||||
|
GPU_BACKEND_METAL,
|
||||||
|
vendor,
|
||||||
|
renderer,
|
||||||
|
version,
|
||||||
|
architecture_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MTLBackend::platform_exit()
|
void MTLBackend::platform_exit()
|
||||||
|
|
|
@ -163,7 +163,15 @@ void GLBackend::platform_init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GPG.init(device, os, driver, support_level, GPU_BACKEND_OPENGL, vendor, renderer, version);
|
GPG.init(device,
|
||||||
|
os,
|
||||||
|
driver,
|
||||||
|
support_level,
|
||||||
|
GPU_BACKEND_OPENGL,
|
||||||
|
vendor,
|
||||||
|
renderer,
|
||||||
|
version,
|
||||||
|
GPU_ARCHITECTURE_IMR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLBackend::platform_exit()
|
void GLBackend::platform_exit()
|
||||||
|
|
|
@ -50,7 +50,8 @@ void VKBackend::platform_init()
|
||||||
GPU_BACKEND_VULKAN,
|
GPU_BACKEND_VULKAN,
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
"");
|
"",
|
||||||
|
GPU_ARCHITECTURE_IMR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKBackend::platform_init(const VKDevice &device)
|
void VKBackend::platform_init(const VKDevice &device)
|
||||||
|
@ -72,7 +73,8 @@ void VKBackend::platform_init(const VKDevice &device)
|
||||||
GPU_BACKEND_VULKAN,
|
GPU_BACKEND_VULKAN,
|
||||||
vendor_name.c_str(),
|
vendor_name.c_str(),
|
||||||
properties.deviceName,
|
properties.deviceName,
|
||||||
driver_version.c_str());
|
driver_version.c_str(),
|
||||||
|
GPU_ARCHITECTURE_IMR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKBackend::detect_workarounds(VKDevice &device)
|
void VKBackend::detect_workarounds(VKDevice &device)
|
||||||
|
|
|
@ -933,28 +933,6 @@ void convert_host_to_device(void *dst_buffer,
|
||||||
convert_buffer(dst_buffer, src_buffer, buffer_size, device_format, conversion_type);
|
convert_buffer(dst_buffer, src_buffer, buffer_size, device_format, conversion_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void convert_host_to_device(void *dst_buffer,
|
|
||||||
const void *src_buffer,
|
|
||||||
uint2 src_size,
|
|
||||||
uint src_row_length,
|
|
||||||
eGPUDataFormat host_format,
|
|
||||||
eGPUTextureFormat device_format)
|
|
||||||
{
|
|
||||||
const uint8_t *src = static_cast<const uint8_t *>(src_buffer);
|
|
||||||
uint8_t *dst = static_cast<uint8_t *>(dst_buffer);
|
|
||||||
ConversionType conversion_type = host_to_device(host_format, device_format);
|
|
||||||
size_t src_row_len = src_row_length * to_bytesize(device_format, host_format);
|
|
||||||
size_t dst_row_len = src_size.x * to_bytesize(device_format);
|
|
||||||
|
|
||||||
for (uint row : IndexRange(src_size.y)) {
|
|
||||||
convert_buffer(&dst[dst_row_len * row],
|
|
||||||
&src[src_row_len * row],
|
|
||||||
src_size.x,
|
|
||||||
device_format,
|
|
||||||
conversion_type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void convert_device_to_host(void *dst_buffer,
|
void convert_device_to_host(void *dst_buffer,
|
||||||
const void *src_buffer,
|
const void *src_buffer,
|
||||||
size_t buffer_size,
|
size_t buffer_size,
|
||||||
|
|
|
@ -33,27 +33,6 @@ void convert_host_to_device(void *dst_buffer,
|
||||||
eGPUDataFormat host_format,
|
eGPUDataFormat host_format,
|
||||||
eGPUTextureFormat device_format);
|
eGPUTextureFormat device_format);
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert host buffer to device buffer with row length.
|
|
||||||
*
|
|
||||||
* \param dst_buffer: device buffer.
|
|
||||||
* \param src_buffer: host buffer.
|
|
||||||
* \param src_size: size of the host buffer.
|
|
||||||
* \param src_row_length: Length of a single row of the buffer (in pixels).
|
|
||||||
* \param host_format: format of the host buffer.
|
|
||||||
* \param device_format: format of the device buffer.
|
|
||||||
*
|
|
||||||
* \note Will assert when the host_format/device_format combination isn't valid
|
|
||||||
* (#validate_data_format) or supported. Some combinations aren't supported in Vulkan due to
|
|
||||||
* platform incompatibility.
|
|
||||||
*/
|
|
||||||
void convert_host_to_device(void *dst_buffer,
|
|
||||||
const void *src_buffer,
|
|
||||||
uint2 src_size,
|
|
||||||
uint src_row_length,
|
|
||||||
eGPUDataFormat host_format,
|
|
||||||
eGPUTextureFormat device_format);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert device buffer to host buffer.
|
* Convert device buffer to host buffer.
|
||||||
*
|
*
|
||||||
|
|
|
@ -181,7 +181,6 @@ void VKDescriptorSetTracker::update(VKContext &context)
|
||||||
}
|
}
|
||||||
/* TODO: Based on the actual usage we should use
|
/* TODO: Based on the actual usage we should use
|
||||||
* VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL/VK_IMAGE_LAYOUT_GENERAL. */
|
* VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL/VK_IMAGE_LAYOUT_GENERAL. */
|
||||||
binding.texture->ensure_allocated();
|
|
||||||
binding.texture->layout_ensure(context, VK_IMAGE_LAYOUT_GENERAL);
|
binding.texture->layout_ensure(context, VK_IMAGE_LAYOUT_GENERAL);
|
||||||
VkDescriptorImageInfo image_info = {};
|
VkDescriptorImageInfo image_info = {};
|
||||||
image_info.sampler = binding.vk_sampler;
|
image_info.sampler = binding.vk_sampler;
|
||||||
|
|
|
@ -167,7 +167,6 @@ void VKFrameBuffer::clear(const eGPUFrameBufferBits buffers,
|
||||||
<< "PERFORMANCE: impact clearing depth texture in render pass that doesn't allow "
|
<< "PERFORMANCE: impact clearing depth texture in render pass that doesn't allow "
|
||||||
"depth writes.\n";
|
"depth writes.\n";
|
||||||
}
|
}
|
||||||
depth_texture->ensure_allocated();
|
|
||||||
depth_attachment_layout_ensure(context, VK_IMAGE_LAYOUT_GENERAL);
|
depth_attachment_layout_ensure(context, VK_IMAGE_LAYOUT_GENERAL);
|
||||||
depth_texture->clear_depth_stencil(buffers, clear_depth, clear_stencil);
|
depth_texture->clear_depth_stencil(buffers, clear_depth, clear_stencil);
|
||||||
}
|
}
|
||||||
|
@ -225,14 +224,17 @@ void VKFrameBuffer::read(eGPUFrameBufferBits plane,
|
||||||
int slot,
|
int slot,
|
||||||
void *r_data)
|
void *r_data)
|
||||||
{
|
{
|
||||||
|
VKContext &context = *VKContext::get();
|
||||||
VKTexture *texture = nullptr;
|
VKTexture *texture = nullptr;
|
||||||
switch (plane) {
|
switch (plane) {
|
||||||
case GPU_COLOR_BIT:
|
case GPU_COLOR_BIT:
|
||||||
texture = unwrap(unwrap(attachments_[GPU_FB_COLOR_ATTACHMENT0 + slot].tex));
|
color_attachment_layout_ensure(context, slot, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||||
|
texture = unwrap(unwrap(color_tex(slot)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GPU_DEPTH_BIT:
|
case GPU_DEPTH_BIT:
|
||||||
texture = unwrap(unwrap(attachments_[GPU_FB_DEPTH_ATTACHMENT].tex));
|
depth_attachment_layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||||
|
texture = unwrap(unwrap(depth_tex()));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -252,44 +254,26 @@ void VKFrameBuffer::read(eGPUFrameBufferBits plane,
|
||||||
/** \name Blit operations
|
/** \name Blit operations
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
void VKFrameBuffer::blit_to(eGPUFrameBufferBits planes,
|
static void blit_aspect(VKCommandBuffer &command_buffer,
|
||||||
int src_slot,
|
VKTexture &dst_texture,
|
||||||
FrameBuffer *dst,
|
VKTexture &src_texture,
|
||||||
int dst_slot,
|
|
||||||
int dst_offset_x,
|
int dst_offset_x,
|
||||||
int dst_offset_y)
|
int dst_offset_y,
|
||||||
|
VkImageAspectFlagBits image_aspect)
|
||||||
{
|
{
|
||||||
BLI_assert(dst);
|
/* Prefer texture copy, as some platforms don't support using D32_SFLOAT_S8_UINT to be used as
|
||||||
BLI_assert(planes == GPU_COLOR_BIT);
|
* a blit destination. */
|
||||||
UNUSED_VARS_NDEBUG(planes);
|
if (dst_offset_x == 0 && dst_offset_y == 0 &&
|
||||||
|
dst_texture.format_get() == src_texture.format_get() &&
|
||||||
VKContext &context = *VKContext::get();
|
src_texture.width_get() == dst_texture.width_get() &&
|
||||||
if (!context.has_active_framebuffer()) {
|
src_texture.height_get() == dst_texture.height_get())
|
||||||
BLI_assert_unreachable();
|
{
|
||||||
|
src_texture.copy_to(dst_texture, image_aspect);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Retrieve source texture. */
|
|
||||||
const GPUAttachment &src_attachment = attachments_[GPU_FB_COLOR_ATTACHMENT0 + src_slot];
|
|
||||||
if (src_attachment.tex == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
color_attachment_layout_ensure(context, src_slot, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
|
||||||
VKTexture &src_texture = *unwrap(unwrap(src_attachment.tex));
|
|
||||||
|
|
||||||
/* Retrieve destination texture. */
|
|
||||||
VKFrameBuffer &dst_framebuffer = *unwrap(dst);
|
|
||||||
dst_framebuffer.color_attachment_layout_ensure(
|
|
||||||
context, dst_slot, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
|
||||||
const GPUAttachment &dst_attachment =
|
|
||||||
dst_framebuffer.attachments_[GPU_FB_COLOR_ATTACHMENT0 + dst_slot];
|
|
||||||
if (dst_attachment.tex == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
VKTexture &dst_texture = *unwrap(unwrap(dst_attachment.tex));
|
|
||||||
|
|
||||||
VkImageBlit image_blit = {};
|
VkImageBlit image_blit = {};
|
||||||
image_blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
image_blit.srcSubresource.aspectMask = image_aspect;
|
||||||
image_blit.srcSubresource.mipLevel = 0;
|
image_blit.srcSubresource.mipLevel = 0;
|
||||||
image_blit.srcSubresource.baseArrayLayer = 0;
|
image_blit.srcSubresource.baseArrayLayer = 0;
|
||||||
image_blit.srcSubresource.layerCount = 1;
|
image_blit.srcSubresource.layerCount = 1;
|
||||||
|
@ -300,7 +284,7 @@ void VKFrameBuffer::blit_to(eGPUFrameBufferBits planes,
|
||||||
image_blit.srcOffsets[1].y = src_texture.height_get();
|
image_blit.srcOffsets[1].y = src_texture.height_get();
|
||||||
image_blit.srcOffsets[1].z = 1;
|
image_blit.srcOffsets[1].z = 1;
|
||||||
|
|
||||||
image_blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
image_blit.dstSubresource.aspectMask = image_aspect;
|
||||||
image_blit.dstSubresource.mipLevel = 0;
|
image_blit.dstSubresource.mipLevel = 0;
|
||||||
image_blit.dstSubresource.baseArrayLayer = 0;
|
image_blit.dstSubresource.baseArrayLayer = 0;
|
||||||
image_blit.dstSubresource.layerCount = 1;
|
image_blit.dstSubresource.layerCount = 1;
|
||||||
|
@ -311,7 +295,74 @@ void VKFrameBuffer::blit_to(eGPUFrameBufferBits planes,
|
||||||
image_blit.dstOffsets[1].y = dst_offset_y + src_texture.height_get();
|
image_blit.dstOffsets[1].y = dst_offset_y + src_texture.height_get();
|
||||||
image_blit.dstOffsets[1].z = 1;
|
image_blit.dstOffsets[1].z = 1;
|
||||||
|
|
||||||
context.command_buffer_get().blit(dst_texture, src_texture, Span<VkImageBlit>(&image_blit, 1));
|
command_buffer.blit(dst_texture, src_texture, Span<VkImageBlit>(&image_blit, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VKFrameBuffer::blit_to(eGPUFrameBufferBits planes,
|
||||||
|
int src_slot,
|
||||||
|
FrameBuffer *dst,
|
||||||
|
int dst_slot,
|
||||||
|
int dst_offset_x,
|
||||||
|
int dst_offset_y)
|
||||||
|
{
|
||||||
|
BLI_assert(dst);
|
||||||
|
BLI_assert_msg(ELEM(planes, GPU_COLOR_BIT, GPU_DEPTH_BIT),
|
||||||
|
"VKFrameBuffer::blit_to only supports a single color or depth aspect.");
|
||||||
|
UNUSED_VARS_NDEBUG(planes);
|
||||||
|
|
||||||
|
VKContext &context = *VKContext::get();
|
||||||
|
VKCommandBuffer &command_buffer = context.command_buffer_get();
|
||||||
|
if (!context.has_active_framebuffer()) {
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VKFrameBuffer &dst_framebuffer = *unwrap(dst);
|
||||||
|
if (planes & GPU_COLOR_BIT) {
|
||||||
|
const GPUAttachment &src_attachment = attachments_[GPU_FB_COLOR_ATTACHMENT0 + src_slot];
|
||||||
|
const GPUAttachment &dst_attachment =
|
||||||
|
dst_framebuffer.attachments_[GPU_FB_COLOR_ATTACHMENT0 + dst_slot];
|
||||||
|
if (src_attachment.tex && dst_attachment.tex) {
|
||||||
|
VKTexture &src_texture = *unwrap(unwrap(src_attachment.tex));
|
||||||
|
VKTexture &dst_texture = *unwrap(unwrap(dst_attachment.tex));
|
||||||
|
color_attachment_layout_ensure(context, src_slot, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||||
|
dst_framebuffer.color_attachment_layout_ensure(
|
||||||
|
context, dst_slot, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||||
|
|
||||||
|
blit_aspect(command_buffer,
|
||||||
|
dst_texture,
|
||||||
|
src_texture,
|
||||||
|
dst_offset_x,
|
||||||
|
dst_offset_y,
|
||||||
|
VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (planes & GPU_DEPTH_BIT) {
|
||||||
|
/* Retrieve source texture. */
|
||||||
|
const GPUAttachment &src_attachment = attachments_[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex ?
|
||||||
|
attachments_[GPU_FB_DEPTH_STENCIL_ATTACHMENT] :
|
||||||
|
attachments_[GPU_FB_DEPTH_ATTACHMENT];
|
||||||
|
const GPUAttachment &dst_attachment =
|
||||||
|
dst_framebuffer.attachments_[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex ?
|
||||||
|
dst_framebuffer.attachments_[GPU_FB_DEPTH_STENCIL_ATTACHMENT] :
|
||||||
|
dst_framebuffer.attachments_[GPU_FB_DEPTH_ATTACHMENT];
|
||||||
|
if (src_attachment.tex && dst_attachment.tex) {
|
||||||
|
VKTexture &src_texture = *unwrap(unwrap(src_attachment.tex));
|
||||||
|
VKTexture &dst_texture = *unwrap(unwrap(dst_attachment.tex));
|
||||||
|
depth_attachment_layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||||
|
dst_framebuffer.depth_attachment_layout_ensure(context,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||||
|
|
||||||
|
blit_aspect(command_buffer,
|
||||||
|
dst_texture,
|
||||||
|
src_texture,
|
||||||
|
dst_offset_x,
|
||||||
|
dst_offset_y,
|
||||||
|
VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
command_buffer.submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
@ -375,7 +426,6 @@ void VKFrameBuffer::render_pass_create()
|
||||||
if (attachment.tex) {
|
if (attachment.tex) {
|
||||||
/* Ensure texture is allocated to ensure the image view. */
|
/* Ensure texture is allocated to ensure the image view. */
|
||||||
VKTexture &texture = *static_cast<VKTexture *>(unwrap(attachment.tex));
|
VKTexture &texture = *static_cast<VKTexture *>(unwrap(attachment.tex));
|
||||||
texture.ensure_allocated();
|
|
||||||
image_views_.append(VKImageView(texture,
|
image_views_.append(VKImageView(texture,
|
||||||
eImageViewUsage::Attachment,
|
eImageViewUsage::Attachment,
|
||||||
IndexRange(max_ii(attachment.layer, 0), 1),
|
IndexRange(max_ii(attachment.layer, 0), 1),
|
||||||
|
@ -493,7 +543,6 @@ void VKFrameBuffer::color_attachment_layout_ensure(VKContext &context,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
color_texture->ensure_allocated();
|
|
||||||
color_texture->layout_ensure(context, requested_layout);
|
color_texture->layout_ensure(context, requested_layout);
|
||||||
dirty_attachments_ = true;
|
dirty_attachments_ = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,11 @@ class VKPixelBuffer : public PixelBuffer {
|
||||||
void unmap() override;
|
void unmap() override;
|
||||||
int64_t get_native_handle() override;
|
int64_t get_native_handle() override;
|
||||||
size_t get_size() override;
|
size_t get_size() override;
|
||||||
|
|
||||||
|
VKBuffer &buffer_get()
|
||||||
|
{
|
||||||
|
return buffer_;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace blender::gpu
|
} // namespace blender::gpu
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace blender::gpu {
|
||||||
|
|
||||||
VKTexture::~VKTexture()
|
VKTexture::~VKTexture()
|
||||||
{
|
{
|
||||||
if (is_allocated() && !is_texture_view()) {
|
if (vk_image_ != VK_NULL_HANDLE && allocation_ != VK_NULL_HANDLE) {
|
||||||
VKDevice &device = VKBackend::get().device_get();
|
VKDevice &device = VKBackend::get().device_get();
|
||||||
device.discard_image(vk_image_, allocation_);
|
device.discard_image(vk_image_, allocation_);
|
||||||
|
|
||||||
|
@ -48,8 +48,6 @@ void VKTexture::generate_mipmap()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure_allocated();
|
|
||||||
|
|
||||||
VKContext &context = *VKContext::get();
|
VKContext &context = *VKContext::get();
|
||||||
VKCommandBuffer &command_buffer = context.command_buffer_get();
|
VKCommandBuffer &command_buffer = context.command_buffer_get();
|
||||||
layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||||
|
@ -112,6 +110,26 @@ void VKTexture::generate_mipmap()
|
||||||
current_layout_set(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
current_layout_set(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VKTexture::copy_to(VKTexture &dst_texture, VkImageAspectFlagBits vk_image_aspect)
|
||||||
|
{
|
||||||
|
VKContext &context = *VKContext::get();
|
||||||
|
layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||||
|
dst_texture.layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||||
|
|
||||||
|
VkImageCopy region = {};
|
||||||
|
region.srcSubresource.aspectMask = vk_image_aspect;
|
||||||
|
region.srcSubresource.mipLevel = 0;
|
||||||
|
region.srcSubresource.layerCount = vk_layer_count(1);
|
||||||
|
region.dstSubresource.aspectMask = vk_image_aspect;
|
||||||
|
region.dstSubresource.mipLevel = 0;
|
||||||
|
region.dstSubresource.layerCount = vk_layer_count(1);
|
||||||
|
region.extent = vk_extent_3d(0);
|
||||||
|
|
||||||
|
VKCommandBuffer &command_buffer = context.command_buffer_get();
|
||||||
|
command_buffer.copy(dst_texture, *this, Span<VkImageCopy>(®ion, 1));
|
||||||
|
command_buffer.submit();
|
||||||
|
}
|
||||||
|
|
||||||
void VKTexture::copy_to(Texture *tex)
|
void VKTexture::copy_to(Texture *tex)
|
||||||
{
|
{
|
||||||
VKTexture *dst = unwrap(tex);
|
VKTexture *dst = unwrap(tex);
|
||||||
|
@ -122,32 +140,12 @@ void VKTexture::copy_to(Texture *tex)
|
||||||
BLI_assert(!is_texture_view());
|
BLI_assert(!is_texture_view());
|
||||||
UNUSED_VARS_NDEBUG(src);
|
UNUSED_VARS_NDEBUG(src);
|
||||||
|
|
||||||
VKContext &context = *VKContext::get();
|
copy_to(*dst, to_vk_image_aspect_flag_bits(format_));
|
||||||
ensure_allocated();
|
|
||||||
layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
|
||||||
dst->ensure_allocated();
|
|
||||||
dst->layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
|
||||||
|
|
||||||
VkImageCopy region = {};
|
|
||||||
region.srcSubresource.aspectMask = to_vk_image_aspect_flag_bits(format_);
|
|
||||||
region.srcSubresource.mipLevel = 0;
|
|
||||||
region.srcSubresource.layerCount = vk_layer_count(1);
|
|
||||||
region.dstSubresource.aspectMask = to_vk_image_aspect_flag_bits(format_);
|
|
||||||
region.dstSubresource.mipLevel = 0;
|
|
||||||
region.dstSubresource.layerCount = vk_layer_count(1);
|
|
||||||
region.extent = vk_extent_3d(0);
|
|
||||||
|
|
||||||
VKCommandBuffer &command_buffer = context.command_buffer_get();
|
|
||||||
command_buffer.copy(*dst, *this, Span<VkImageCopy>(®ion, 1));
|
|
||||||
command_buffer.submit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKTexture::clear(eGPUDataFormat format, const void *data)
|
void VKTexture::clear(eGPUDataFormat format, const void *data)
|
||||||
{
|
{
|
||||||
BLI_assert(!is_texture_view());
|
BLI_assert(!is_texture_view());
|
||||||
if (!is_allocated()) {
|
|
||||||
allocate();
|
|
||||||
}
|
|
||||||
|
|
||||||
VKContext &context = *VKContext::get();
|
VKContext &context = *VKContext::get();
|
||||||
VKCommandBuffer &command_buffer = context.command_buffer_get();
|
VKCommandBuffer &command_buffer = context.command_buffer_get();
|
||||||
|
@ -168,9 +166,6 @@ void VKTexture::clear_depth_stencil(const eGPUFrameBufferBits buffers,
|
||||||
{
|
{
|
||||||
BLI_assert(buffers & (GPU_DEPTH_BIT | GPU_STENCIL_BIT));
|
BLI_assert(buffers & (GPU_DEPTH_BIT | GPU_STENCIL_BIT));
|
||||||
|
|
||||||
if (!is_allocated()) {
|
|
||||||
allocate();
|
|
||||||
}
|
|
||||||
VKContext &context = *VKContext::get();
|
VKContext &context = *VKContext::get();
|
||||||
VKCommandBuffer &command_buffer = context.command_buffer_get();
|
VKCommandBuffer &command_buffer = context.command_buffer_get();
|
||||||
VkClearDepthStencilValue clear_depth_stencil;
|
VkClearDepthStencilValue clear_depth_stencil;
|
||||||
|
@ -255,13 +250,9 @@ void VKTexture::update_sub(
|
||||||
int mip, int offset[3], int extent_[3], eGPUDataFormat format, const void *data)
|
int mip, int offset[3], int extent_[3], eGPUDataFormat format, const void *data)
|
||||||
{
|
{
|
||||||
BLI_assert(!is_texture_view());
|
BLI_assert(!is_texture_view());
|
||||||
if (!is_allocated()) {
|
|
||||||
allocate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Vulkan images cannot be directly mapped to host memory and requires a staging buffer. */
|
/* Vulkan images cannot be directly mapped to host memory and requires a staging buffer. */
|
||||||
VKContext &context = *VKContext::get();
|
VKContext &context = *VKContext::get();
|
||||||
VKBuffer staging_buffer;
|
|
||||||
int layers = vk_layer_count(1);
|
int layers = vk_layer_count(1);
|
||||||
int3 extent = int3(extent_[0], max_ii(extent_[1], 1), max_ii(extent_[2], 1));
|
int3 extent = int3(extent_[0], max_ii(extent_[1], 1), max_ii(extent_[2], 1));
|
||||||
size_t sample_len = extent.x * extent.y * extent.z;
|
size_t sample_len = extent.x * extent.y * extent.z;
|
||||||
|
@ -275,26 +266,15 @@ void VKTexture::update_sub(
|
||||||
extent.z = 1;
|
extent.z = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VKBuffer staging_buffer;
|
||||||
staging_buffer.create(device_memory_size, GPU_USAGE_DYNAMIC, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
|
staging_buffer.create(device_memory_size, GPU_USAGE_DYNAMIC, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
|
||||||
|
|
||||||
uint buffer_row_length = context.state_manager_get().texture_unpack_row_length_get();
|
|
||||||
if (buffer_row_length) {
|
|
||||||
/* Use custom row length #GPU_texture_unpack_row_length */
|
|
||||||
convert_host_to_device(staging_buffer.mapped_memory_get(),
|
|
||||||
data,
|
|
||||||
uint2(extent),
|
|
||||||
buffer_row_length,
|
|
||||||
format,
|
|
||||||
format_);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
convert_host_to_device(staging_buffer.mapped_memory_get(), data, sample_len, format, format_);
|
convert_host_to_device(staging_buffer.mapped_memory_get(), data, sample_len, format, format_);
|
||||||
}
|
|
||||||
|
|
||||||
VkBufferImageCopy region = {};
|
VkBufferImageCopy region = {};
|
||||||
region.imageExtent.width = extent.x;
|
region.imageExtent.width = extent.x;
|
||||||
region.imageExtent.height = extent.y;
|
region.imageExtent.height = extent.y;
|
||||||
region.imageExtent.depth = extent.z;
|
region.imageExtent.depth = extent.z;
|
||||||
|
region.bufferRowLength = context.state_manager_get().texture_unpack_row_length_get();
|
||||||
region.imageOffset.x = offset[0];
|
region.imageOffset.x = offset[0];
|
||||||
region.imageOffset.y = offset[1];
|
region.imageOffset.y = offset[1];
|
||||||
region.imageOffset.z = offset[2];
|
region.imageOffset.z = offset[2];
|
||||||
|
@ -325,10 +305,6 @@ uint VKTexture::gl_bindcode_get() const
|
||||||
|
|
||||||
bool VKTexture::init_internal()
|
bool VKTexture::init_internal()
|
||||||
{
|
{
|
||||||
/* Initialization can only happen after the usage is known. By the current API this isn't set
|
|
||||||
* at this moment, so we cannot initialize here. The initialization is postponed until the
|
|
||||||
* allocation of the texture on the device. */
|
|
||||||
|
|
||||||
const VKDevice &device = VKBackend::get().device_get();
|
const VKDevice &device = VKBackend::get().device_get();
|
||||||
const VKWorkarounds &workarounds = device.workarounds_get();
|
const VKWorkarounds &workarounds = device.workarounds_get();
|
||||||
if (format_ == GPU_DEPTH_COMPONENT24 && workarounds.not_aligned_pixel_formats) {
|
if (format_ == GPU_DEPTH_COMPONENT24 && workarounds.not_aligned_pixel_formats) {
|
||||||
|
@ -338,7 +314,10 @@ bool VKTexture::init_internal()
|
||||||
format_ = GPU_DEPTH32F_STENCIL8;
|
format_ = GPU_DEPTH32F_STENCIL8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: return false when texture format isn't supported. */
|
if (!allocate()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,23 +367,6 @@ bool VKTexture::is_texture_view() const
|
||||||
return source_texture_ != nullptr;
|
return source_texture_ != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKTexture::ensure_allocated()
|
|
||||||
{
|
|
||||||
if (is_texture_view()) {
|
|
||||||
source_texture_->ensure_allocated();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_allocated()) {
|
|
||||||
allocate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VKTexture::is_allocated() const
|
|
||||||
{
|
|
||||||
return (vk_image_ != VK_NULL_HANDLE && allocation_ != VK_NULL_HANDLE) || is_texture_view();
|
|
||||||
}
|
|
||||||
|
|
||||||
static VkImageUsageFlagBits to_vk_image_usage(const eGPUTextureUsage usage,
|
static VkImageUsageFlagBits to_vk_image_usage(const eGPUTextureUsage usage,
|
||||||
const eGPUTextureFormatFlag format_flag)
|
const eGPUTextureFormatFlag format_flag)
|
||||||
{
|
{
|
||||||
|
@ -463,7 +425,6 @@ static VkImageCreateFlagBits to_vk_image_create(const eGPUTextureType texture_ty
|
||||||
bool VKTexture::allocate()
|
bool VKTexture::allocate()
|
||||||
{
|
{
|
||||||
BLI_assert(vk_image_ == VK_NULL_HANDLE);
|
BLI_assert(vk_image_ == VK_NULL_HANDLE);
|
||||||
BLI_assert(!is_allocated());
|
|
||||||
BLI_assert(!is_texture_view());
|
BLI_assert(!is_texture_view());
|
||||||
|
|
||||||
VKContext &context = *VKContext::get();
|
VKContext &context = *VKContext::get();
|
||||||
|
@ -524,9 +485,6 @@ bool VKTexture::allocate()
|
||||||
|
|
||||||
void VKTexture::bind(int binding, shader::ShaderCreateInfo::Resource::BindType bind_type)
|
void VKTexture::bind(int binding, shader::ShaderCreateInfo::Resource::BindType bind_type)
|
||||||
{
|
{
|
||||||
if (!is_allocated()) {
|
|
||||||
allocate();
|
|
||||||
}
|
|
||||||
VKContext &context = *VKContext::get();
|
VKContext &context = *VKContext::get();
|
||||||
VKShader *shader = static_cast<VKShader *>(context.shader);
|
VKShader *shader = static_cast<VKShader *>(context.shader);
|
||||||
const VKShaderInterface &shader_interface = shader->interface_get();
|
const VKShaderInterface &shader_interface = shader->interface_get();
|
||||||
|
|
|
@ -56,6 +56,7 @@ class VKTexture : public Texture, public VKBindableResource {
|
||||||
|
|
||||||
void generate_mipmap() override;
|
void generate_mipmap() override;
|
||||||
void copy_to(Texture *tex) override;
|
void copy_to(Texture *tex) override;
|
||||||
|
void copy_to(VKTexture &dst_texture, VkImageAspectFlagBits vk_image_aspect);
|
||||||
void clear(eGPUDataFormat format, const void *data) override;
|
void clear(eGPUDataFormat format, const void *data) override;
|
||||||
void clear_depth_stencil(const eGPUFrameBufferBits buffer,
|
void clear_depth_stencil(const eGPUFrameBufferBits buffer,
|
||||||
float clear_depth,
|
float clear_depth,
|
||||||
|
@ -85,8 +86,6 @@ class VKTexture : public Texture, public VKBindableResource {
|
||||||
return vk_image_;
|
return vk_image_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ensure_allocated();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool init_internal() override;
|
bool init_internal() override;
|
||||||
bool init_internal(GPUVertBuf *vbo) override;
|
bool init_internal(GPUVertBuf *vbo) override;
|
||||||
|
@ -96,9 +95,6 @@ class VKTexture : public Texture, public VKBindableResource {
|
||||||
/** Is this texture a view of another texture. */
|
/** Is this texture a view of another texture. */
|
||||||
bool is_texture_view() const;
|
bool is_texture_view() const;
|
||||||
|
|
||||||
/** Is this texture already allocated on device. */
|
|
||||||
bool is_allocated() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocate the texture of the device. Result is `true` when texture is successfully allocated
|
* Allocate the texture of the device. Result is `true` when texture is successfully allocated
|
||||||
* on the device.
|
* on the device.
|
||||||
|
|
|
@ -174,7 +174,7 @@ void load_plydata(PlyData &plyData, Depsgraph *depsgraph, const PLYExportParams
|
||||||
BKE_object_get_pre_modified_mesh(&export_object_eval_);
|
BKE_object_get_pre_modified_mesh(&export_object_eval_);
|
||||||
|
|
||||||
bool force_triangulation = false;
|
bool force_triangulation = false;
|
||||||
const OffsetIndices faces = mesh->faces();
|
OffsetIndices faces = mesh->faces();
|
||||||
for (const int i : faces.index_range()) {
|
for (const int i : faces.index_range()) {
|
||||||
if (faces[i].size() > 255) {
|
if (faces[i].size() > 255) {
|
||||||
force_triangulation = true;
|
force_triangulation = true;
|
||||||
|
@ -186,6 +186,7 @@ void load_plydata(PlyData &plyData, Depsgraph *depsgraph, const PLYExportParams
|
||||||
bool manually_free_mesh = false;
|
bool manually_free_mesh = false;
|
||||||
if (export_params.export_triangulated_mesh || force_triangulation) {
|
if (export_params.export_triangulated_mesh || force_triangulation) {
|
||||||
mesh = do_triangulation(mesh, export_params.export_triangulated_mesh);
|
mesh = do_triangulation(mesh, export_params.export_triangulated_mesh);
|
||||||
|
faces = mesh->faces();
|
||||||
manually_free_mesh = true;
|
manually_free_mesh = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -157,7 +157,6 @@ typedef struct Nurb {
|
||||||
|
|
||||||
typedef struct CharInfo {
|
typedef struct CharInfo {
|
||||||
float kern;
|
float kern;
|
||||||
/** Index start at 1, unlike mesh & nurbs. */
|
|
||||||
short mat_nr;
|
short mat_nr;
|
||||||
char flag;
|
char flag;
|
||||||
char _pad[1];
|
char _pad[1];
|
||||||
|
|
|
@ -315,6 +315,8 @@ typedef enum eNodePanelFlag {
|
||||||
NODE_PANEL_COLLAPSED = (1 << 0),
|
NODE_PANEL_COLLAPSED = (1 << 0),
|
||||||
/* The parent panel is collapsed. */
|
/* The parent panel is collapsed. */
|
||||||
NODE_PANEL_PARENT_COLLAPSED = (1 << 1),
|
NODE_PANEL_PARENT_COLLAPSED = (1 << 1),
|
||||||
|
/* The panel has visible content. */
|
||||||
|
NODE_PANEL_CONTENT_VISIBLE = (1 << 2),
|
||||||
} eNodePanelFlag;
|
} eNodePanelFlag;
|
||||||
|
|
||||||
typedef struct bNodePanelState {
|
typedef struct bNodePanelState {
|
||||||
|
@ -327,6 +329,7 @@ typedef struct bNodePanelState {
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
bool is_collapsed() const;
|
bool is_collapsed() const;
|
||||||
bool is_parent_collapsed() const;
|
bool is_parent_collapsed() const;
|
||||||
|
bool has_visible_content() const;
|
||||||
#endif
|
#endif
|
||||||
} bNodePanelState;
|
} bNodePanelState;
|
||||||
|
|
||||||
|
|
|
@ -1635,10 +1635,9 @@ typedef struct ToolSettings {
|
||||||
char transform_pivot_point;
|
char transform_pivot_point;
|
||||||
char transform_flag;
|
char transform_flag;
|
||||||
/** Snap elements (per space-type), #eSnapMode. */
|
/** Snap elements (per space-type), #eSnapMode. */
|
||||||
char _pad1[1];
|
|
||||||
short snap_mode;
|
|
||||||
char snap_node_mode;
|
char snap_node_mode;
|
||||||
char snap_uv_mode;
|
short snap_mode;
|
||||||
|
short snap_uv_mode;
|
||||||
short snap_anim_mode;
|
short snap_anim_mode;
|
||||||
/** Generic flags (per space-type), #eSnapFlag. */
|
/** Generic flags (per space-type), #eSnapFlag. */
|
||||||
short snap_flag;
|
short snap_flag;
|
||||||
|
|
|
@ -1083,7 +1083,7 @@ typedef enum eUserPref_SpaceData_Flag {
|
||||||
typedef enum eUserPref_Flag {
|
typedef enum eUserPref_Flag {
|
||||||
USER_AUTOSAVE = (1 << 0),
|
USER_AUTOSAVE = (1 << 0),
|
||||||
USER_FLAG_NUMINPUT_ADVANCED = (1 << 1),
|
USER_FLAG_NUMINPUT_ADVANCED = (1 << 1),
|
||||||
USER_FLAG_RECENT_SEARCHES_DISABLE = (1 << 2), /* cleared */
|
USER_FLAG_RECENT_SEARCHES_DISABLE = (1 << 2),
|
||||||
USER_FLAG_UNUSED_3 = (1 << 3), /* cleared */
|
USER_FLAG_UNUSED_3 = (1 << 3), /* cleared */
|
||||||
USER_FLAG_UNUSED_4 = (1 << 4), /* cleared */
|
USER_FLAG_UNUSED_4 = (1 << 4), /* cleared */
|
||||||
USER_TRACKBALL = (1 << 5),
|
USER_TRACKBALL = (1 << 5),
|
||||||
|
|
|
@ -724,7 +724,6 @@ void RNA_def_collections(BlenderRNA *brna)
|
||||||
RNA_def_property_update(prop, NC_SCENE, nullptr);
|
RNA_def_property_update(prop, NC_SCENE, nullptr);
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "lineart_intersection_priority", PROP_INT, PROP_NONE);
|
prop = RNA_def_property(srna, "lineart_intersection_priority", PROP_INT, PROP_NONE);
|
||||||
RNA_def_property_range(prop, 0, 255);
|
|
||||||
RNA_def_property_ui_text(prop,
|
RNA_def_property_ui_text(prop,
|
||||||
"Intersection Priority",
|
"Intersection Priority",
|
||||||
"The intersection line will be included into the object with the "
|
"The intersection line will be included into the object with the "
|
||||||
|
|
|
@ -318,13 +318,13 @@ static void rna_Curve_material_index_range(
|
||||||
static int rna_ChariInfo_material_index_get(PointerRNA *ptr)
|
static int rna_ChariInfo_material_index_get(PointerRNA *ptr)
|
||||||
{
|
{
|
||||||
CharInfo *info = static_cast<CharInfo *>(ptr->data);
|
CharInfo *info = static_cast<CharInfo *>(ptr->data);
|
||||||
return info->mat_nr ? info->mat_nr - 1 : 0;
|
return info->mat_nr ? info->mat_nr : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rna_ChariInfo_material_index_set(PointerRNA *ptr, int value)
|
static void rna_ChariInfo_material_index_set(PointerRNA *ptr, int value)
|
||||||
{
|
{
|
||||||
CharInfo *info = static_cast<CharInfo *>(ptr->data);
|
CharInfo *info = static_cast<CharInfo *>(ptr->data);
|
||||||
info->mat_nr = value + 1;
|
info->mat_nr = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rna_Curve_active_textbox_index_range(
|
static void rna_Curve_active_textbox_index_range(
|
||||||
|
|
|
@ -673,6 +673,32 @@ void RNA_identifier_sanitize(char *identifier, int property)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool rna_range_from_int_type(const char *dnatype, int r_range[2])
|
||||||
|
{
|
||||||
|
/* Type `char` is unsigned too. */
|
||||||
|
if (STREQ(dnatype, "char") || STREQ(dnatype, "uchar")) {
|
||||||
|
r_range[0] = CHAR_MIN;
|
||||||
|
r_range[1] = CHAR_MAX;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (STREQ(dnatype, "short")) {
|
||||||
|
r_range[0] = SHRT_MIN;
|
||||||
|
r_range[1] = SHRT_MAX;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (STREQ(dnatype, "int")) {
|
||||||
|
r_range[0] = INT_MIN;
|
||||||
|
r_range[1] = INT_MAX;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (STREQ(dnatype, "int8_t")) {
|
||||||
|
r_range[0] = INT8_MIN;
|
||||||
|
r_range[1] = INT8_MAX;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Blender Data Definition */
|
/* Blender Data Definition */
|
||||||
|
|
||||||
BlenderRNA *RNA_create()
|
BlenderRNA *RNA_create()
|
||||||
|
@ -1887,6 +1913,36 @@ void RNA_def_property_enum_items(PropertyRNA *prop, const EnumPropertyItem *item
|
||||||
|
|
||||||
switch (prop->type) {
|
switch (prop->type) {
|
||||||
case PROP_ENUM: {
|
case PROP_ENUM: {
|
||||||
|
|
||||||
|
/* Access DNA size & range (for additional sanity checks). */
|
||||||
|
int enum_dna_size = -1;
|
||||||
|
int enum_dna_range[2];
|
||||||
|
if (DefRNA.preprocess) {
|
||||||
|
/* If this is larger, this is likely a string which can sometimes store enums. */
|
||||||
|
if (PropertyDefRNA *dp = rna_find_struct_property_def(srna, prop)) {
|
||||||
|
if (dp->dnatype == nullptr || dp->dnatype[0] == '\0') {
|
||||||
|
/* Unfortunately this happens when #PropertyDefRNA::dnastructname is for e.g.
|
||||||
|
* `type->region_type` there isn't a convenient way to access the int size. */
|
||||||
|
}
|
||||||
|
else if (dp->dnaarraylength > 1) {
|
||||||
|
/* When an array this is likely a string using get/set functions for enum access. */
|
||||||
|
}
|
||||||
|
else if (dp->dnasize == 0) {
|
||||||
|
/* Some cases function callbacks are used, the DNA size isn't known. */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
enum_dna_size = dp->dnasize;
|
||||||
|
if (!rna_range_from_int_type(dp->dnatype, enum_dna_range)) {
|
||||||
|
CLOG_ERROR(&LOG,
|
||||||
|
"\"%s.%s\", enum type \"%s\" size is not known.",
|
||||||
|
srna->identifier,
|
||||||
|
prop->identifier,
|
||||||
|
dp->dnatype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
|
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
|
||||||
eprop->item = (EnumPropertyItem *)item;
|
eprop->item = (EnumPropertyItem *)item;
|
||||||
eprop->totitem = 0;
|
eprop->totitem = 0;
|
||||||
|
@ -1903,6 +1959,47 @@ void RNA_def_property_enum_items(PropertyRNA *prop, const EnumPropertyItem *item
|
||||||
DefRNA.error = true;
|
DefRNA.error = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* When the integer size is known, check the flag wont fit. */
|
||||||
|
if (enum_dna_size != -1) {
|
||||||
|
if (prop->flag & PROP_ENUM_FLAG) {
|
||||||
|
uint32_t enum_type_mask = 0;
|
||||||
|
if (enum_dna_size == 1) {
|
||||||
|
enum_type_mask = 0xff;
|
||||||
|
}
|
||||||
|
else if (enum_dna_size == 2) {
|
||||||
|
enum_type_mask = 0xffff;
|
||||||
|
}
|
||||||
|
if (enum_type_mask != 0) {
|
||||||
|
if (uint32_t(item[i].value) != (uint32_t(item[i].value) & enum_type_mask)) {
|
||||||
|
CLOG_ERROR(&LOG,
|
||||||
|
"\"%s.%s\", enum value for '%s' does not fit into %d byte(s).",
|
||||||
|
srna->identifier,
|
||||||
|
prop->identifier,
|
||||||
|
item[i].identifier,
|
||||||
|
enum_dna_size);
|
||||||
|
DefRNA.error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (ELEM(enum_dna_size, 1, 2)) {
|
||||||
|
if ((item[i].value < enum_dna_range[0]) || (item[i].value > enum_dna_range[1])) {
|
||||||
|
CLOG_ERROR(&LOG,
|
||||||
|
"\"%s.%s\", enum value for '%s' is outside of range [%d - %d].",
|
||||||
|
srna->identifier,
|
||||||
|
prop->identifier,
|
||||||
|
item[i].identifier,
|
||||||
|
enum_dna_range[0],
|
||||||
|
enum_dna_range[1]);
|
||||||
|
DefRNA.error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (item[i].value == eprop->defaultvalue) {
|
if (item[i].value == eprop->defaultvalue) {
|
||||||
defaultfound = 1;
|
defaultfound = 1;
|
||||||
}
|
}
|
||||||
|
@ -2385,24 +2482,26 @@ void RNA_def_property_int_sdna(PropertyRNA *prop, const char *structname, const
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SDNA doesn't pass us unsigned unfortunately. */
|
/* SDNA doesn't pass us unsigned unfortunately. */
|
||||||
if (dp->dnatype && STREQ(dp->dnatype, "char")) {
|
if (dp->dnatype != nullptr && (dp->dnatype[0] != '\0')) {
|
||||||
iprop->hardmin = iprop->softmin = CHAR_MIN;
|
int range[2];
|
||||||
iprop->hardmax = iprop->softmax = CHAR_MAX;
|
if (rna_range_from_int_type(dp->dnatype, range)) {
|
||||||
|
iprop->hardmin = iprop->softmin = range[0];
|
||||||
|
iprop->hardmax = iprop->softmax = range[1];
|
||||||
}
|
}
|
||||||
else if (dp->dnatype && STREQ(dp->dnatype, "short")) {
|
else {
|
||||||
iprop->hardmin = iprop->softmin = SHRT_MIN;
|
CLOG_ERROR(&LOG,
|
||||||
iprop->hardmax = iprop->softmax = SHRT_MAX;
|
"\"%s.%s\", type \"%s\" range not known.",
|
||||||
|
srna->identifier,
|
||||||
|
prop->identifier,
|
||||||
|
dp->dnatype);
|
||||||
|
DefRNA.error = true;
|
||||||
}
|
}
|
||||||
else if (dp->dnatype && STREQ(dp->dnatype, "int")) {
|
|
||||||
iprop->hardmin = INT_MIN;
|
|
||||||
iprop->hardmax = INT_MAX;
|
|
||||||
|
|
||||||
iprop->softmin = -10000; /* rather arbitrary. */
|
/* Rather arbitrary that this is only done for one type. */
|
||||||
|
if (STREQ(dp->dnatype, "int")) {
|
||||||
|
iprop->softmin = -10000;
|
||||||
iprop->softmax = 10000;
|
iprop->softmax = 10000;
|
||||||
}
|
}
|
||||||
else if (dp->dnatype && STREQ(dp->dnatype, "int8_t")) {
|
|
||||||
iprop->hardmin = iprop->softmin = INT8_MIN;
|
|
||||||
iprop->hardmax = iprop->softmax = INT8_MAX;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ELEM(prop->subtype, PROP_UNSIGNED, PROP_PERCENTAGE, PROP_FACTOR)) {
|
if (ELEM(prop->subtype, PROP_UNSIGNED, PROP_PERCENTAGE, PROP_FACTOR)) {
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "BKE_lib_id.h"
|
#include "BKE_lib_id.h"
|
||||||
#include "BKE_lib_query.h"
|
#include "BKE_lib_query.h"
|
||||||
#include "BKE_mesh.hh"
|
#include "BKE_mesh.hh"
|
||||||
|
#include "BKE_mesh_wrapper.hh"
|
||||||
#include "BKE_modifier.h"
|
#include "BKE_modifier.h"
|
||||||
#include "BKE_object_deform.h"
|
#include "BKE_object_deform.h"
|
||||||
#include "BKE_screen.hh"
|
#include "BKE_screen.hh"
|
||||||
|
@ -380,6 +381,15 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
|
||||||
{
|
{
|
||||||
using namespace blender;
|
using namespace blender;
|
||||||
if (mesh->totvert == 0) {
|
if (mesh->totvert == 0) {
|
||||||
|
/* Output just the start cap even if the mesh is empty. */
|
||||||
|
Object *start_cap_ob = amd->start_cap;
|
||||||
|
if (start_cap_ob && start_cap_ob != ctx->object) {
|
||||||
|
Mesh *start_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(start_cap_ob);
|
||||||
|
if (start_cap_mesh) {
|
||||||
|
BKE_mesh_wrapper_ensure_mdata(start_cap_mesh);
|
||||||
|
return BKE_mesh_copy_for_eval(start_cap_mesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,6 +438,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
|
||||||
|
|
||||||
start_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(start_cap_ob);
|
start_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(start_cap_ob);
|
||||||
if (start_cap_mesh) {
|
if (start_cap_mesh) {
|
||||||
|
BKE_mesh_wrapper_ensure_mdata(start_cap_mesh);
|
||||||
start_cap_nverts = start_cap_mesh->totvert;
|
start_cap_nverts = start_cap_mesh->totvert;
|
||||||
start_cap_nedges = start_cap_mesh->totedge;
|
start_cap_nedges = start_cap_mesh->totedge;
|
||||||
start_cap_nloops = start_cap_mesh->totloop;
|
start_cap_nloops = start_cap_mesh->totloop;
|
||||||
|
@ -443,6 +454,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
|
||||||
|
|
||||||
end_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(end_cap_ob);
|
end_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(end_cap_ob);
|
||||||
if (end_cap_mesh) {
|
if (end_cap_mesh) {
|
||||||
|
BKE_mesh_wrapper_ensure_mdata(end_cap_mesh);
|
||||||
end_cap_nverts = end_cap_mesh->totvert;
|
end_cap_nverts = end_cap_mesh->totvert;
|
||||||
end_cap_nedges = end_cap_mesh->totedge;
|
end_cap_nedges = end_cap_mesh->totedge;
|
||||||
end_cap_nloops = end_cap_mesh->totloop;
|
end_cap_nloops = end_cap_mesh->totloop;
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
#include <MaterialXFormat/XmlIo.h>
|
||||||
|
|
||||||
#include "material.h"
|
#include "material.h"
|
||||||
#include "node_parser.h"
|
#include "node_parser.h"
|
||||||
|
|
||||||
#include <MaterialXFormat/XmlIo.h>
|
|
||||||
|
|
||||||
#include "DEG_depsgraph.hh"
|
#include "DEG_depsgraph.hh"
|
||||||
|
|
||||||
#include "DNA_material_types.h"
|
#include "DNA_material_types.h"
|
||||||
|
|
|
@ -2459,7 +2459,10 @@ void RE_RenderAnim(Render *re,
|
||||||
void RE_PreviewRender(Render *re, Main *bmain, Scene *sce)
|
void RE_PreviewRender(Render *re, Main *bmain, Scene *sce)
|
||||||
{
|
{
|
||||||
/* Ensure within GPU render boundary. */
|
/* Ensure within GPU render boundary. */
|
||||||
|
const bool use_gpu = GPU_backend_get_type() != GPU_BACKEND_NONE;
|
||||||
|
if (use_gpu) {
|
||||||
GPU_render_begin();
|
GPU_render_begin();
|
||||||
|
}
|
||||||
|
|
||||||
Object *camera;
|
Object *camera;
|
||||||
int winx, winy;
|
int winx, winy;
|
||||||
|
@ -2483,7 +2486,9 @@ void RE_PreviewRender(Render *re, Main *bmain, Scene *sce)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Close GPU render boundary. */
|
/* Close GPU render boundary. */
|
||||||
|
if (use_gpu) {
|
||||||
GPU_render_end();
|
GPU_render_end();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE: repeated win/disprect calc... solve that nicer, also in compo. */
|
/* NOTE: repeated win/disprect calc... solve that nicer, also in compo. */
|
||||||
|
|
|
@ -692,6 +692,8 @@ static void wm_file_read_post(bContext *C,
|
||||||
CTX_wm_window_set(C, static_cast<wmWindow *>(wm->windows.first));
|
CTX_wm_window_set(C, static_cast<wmWindow *>(wm->windows.first));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WM_cursor_wait(true);
|
||||||
|
|
||||||
#ifdef WITH_PYTHON
|
#ifdef WITH_PYTHON
|
||||||
if (is_startup_file) {
|
if (is_startup_file) {
|
||||||
/* On startup (by default), Python won't have been initialized.
|
/* On startup (by default), Python won't have been initialized.
|
||||||
|
@ -818,6 +820,8 @@ static void wm_file_read_post(bContext *C,
|
||||||
WM_toolsystem_init(C);
|
WM_toolsystem_init(C);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WM_cursor_wait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wm_read_callback_pre_wrapper(bContext *C, const char *filepath)
|
static void wm_read_callback_pre_wrapper(bContext *C, const char *filepath)
|
||||||
|
@ -1067,6 +1071,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
|
||||||
bf_reports.duration.whole = PIL_check_seconds_timer() - bf_reports.duration.whole;
|
bf_reports.duration.whole = PIL_check_seconds_timer() - bf_reports.duration.whole;
|
||||||
file_read_reports_finalize(&bf_reports);
|
file_read_reports_finalize(&bf_reports);
|
||||||
|
|
||||||
|
WM_cursor_wait(true);
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1171,6 +1176,8 @@ void wm_homefile_read_ex(bContext *C,
|
||||||
char filepath_startup[FILE_MAX];
|
char filepath_startup[FILE_MAX];
|
||||||
char filepath_userdef[FILE_MAX];
|
char filepath_userdef[FILE_MAX];
|
||||||
|
|
||||||
|
WM_cursor_wait(true);
|
||||||
|
|
||||||
/* When 'app_template' is set:
|
/* When 'app_template' is set:
|
||||||
* '{BLENDER_USER_CONFIG}/{app_template}' */
|
* '{BLENDER_USER_CONFIG}/{app_template}' */
|
||||||
char app_template_system[FILE_MAX];
|
char app_template_system[FILE_MAX];
|
||||||
|
@ -1488,6 +1495,8 @@ void wm_homefile_read_ex(bContext *C,
|
||||||
CTX_wm_window_set(C, nullptr);
|
CTX_wm_window_set(C, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WM_cursor_wait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_homefile_read(bContext *C,
|
void wm_homefile_read(bContext *C,
|
||||||
|
@ -1871,13 +1880,6 @@ static bool wm_file_write_check_with_report_on_failure(Main *bmain,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if file write permission is ok */
|
|
||||||
if (BLI_exists(filepath) && !BLI_file_is_writable(filepath)) {
|
|
||||||
BKE_reportf(
|
|
||||||
reports, RPT_ERROR, "Cannot save blend file, path \"%s\" is not writable", filepath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
LISTBASE_FOREACH (Library *, li, &bmain->libraries) {
|
LISTBASE_FOREACH (Library *, li, &bmain->libraries) {
|
||||||
if (BLI_path_cmp(li->filepath_abs, filepath) == 0) {
|
if (BLI_path_cmp(li->filepath_abs, filepath) == 0) {
|
||||||
BKE_reportf(reports, RPT_ERROR, "Cannot overwrite used library '%.240s'", filepath);
|
BKE_reportf(reports, RPT_ERROR, "Cannot overwrite used library '%.240s'", filepath);
|
||||||
|
@ -1916,6 +1918,16 @@ static bool wm_file_write(bContext *C,
|
||||||
/* NOTE: either #BKE_CB_EVT_SAVE_POST or #BKE_CB_EVT_SAVE_POST_FAIL must run.
|
/* NOTE: either #BKE_CB_EVT_SAVE_POST or #BKE_CB_EVT_SAVE_POST_FAIL must run.
|
||||||
* Runs at the end of this function, don't return beforehand. */
|
* Runs at the end of this function, don't return beforehand. */
|
||||||
BKE_callback_exec_string(bmain, BKE_CB_EVT_SAVE_PRE, filepath);
|
BKE_callback_exec_string(bmain, BKE_CB_EVT_SAVE_PRE, filepath);
|
||||||
|
|
||||||
|
/* Check if file write permission is OK. */
|
||||||
|
if (BLI_exists(filepath) && !BLI_file_is_writable(filepath)) {
|
||||||
|
BKE_reportf(
|
||||||
|
reports, RPT_ERROR, "Cannot save blend file, path \"%s\" is not writable", filepath);
|
||||||
|
|
||||||
|
BKE_callback_exec_string(bmain, BKE_CB_EVT_SAVE_POST_FAIL, filepath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ED_assets_pre_save(bmain);
|
ED_assets_pre_save(bmain);
|
||||||
|
|
||||||
/* Enforce full override check/generation on file save. */
|
/* Enforce full override check/generation on file save. */
|
||||||
|
|
|
@ -359,7 +359,10 @@ void WM_init(bContext *C, int argc, const char **argv)
|
||||||
ED_render_clear_mtex_copybuf();
|
ED_render_clear_mtex_copybuf();
|
||||||
|
|
||||||
wm_history_file_read();
|
wm_history_file_read();
|
||||||
|
|
||||||
|
if (!G.background) {
|
||||||
blender::ui::string_search::read_recent_searches_file();
|
blender::ui::string_search::read_recent_searches_file();
|
||||||
|
}
|
||||||
|
|
||||||
STRNCPY(G.lib, BKE_main_blendfile_path_from_global());
|
STRNCPY(G.lib, BKE_main_blendfile_path_from_global());
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@ def argparse_create() -> argparse.ArgumentParser:
|
||||||
sort_by_choices = tuple(sorted(SORT_BY_FN.keys()))
|
sort_by_choices = tuple(sorted(SORT_BY_FN.keys()))
|
||||||
|
|
||||||
# When `--help` or no arguments are given, print this help.
|
# When `--help` or no arguments are given, print this help.
|
||||||
epilog = "This is typically used from the output of a stack-trace on Linux/Unix."
|
epilog = "Use to automate loading many blend files in a single Blender instance."
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
formatter_class=argparse.RawTextHelpFormatter,
|
formatter_class=argparse.RawTextHelpFormatter,
|
||||||
|
|
Loading…
Reference in New Issue