Geometry Node: Multi-input socket tooltip #104468

Merged
Jacques Lucke merged 33 commits from mod_moder/blender:multi_input_tooltip into main 2024-04-22 19:49:08 +02:00
46 changed files with 273 additions and 290 deletions
Showing only changes of commit ddaa411f0d - Show all commits

View File

@ -1399,13 +1399,12 @@ endif()
# Test SIMD support, before platform includes to determine if sse2neon is needed. # Test SIMD support, before platform includes to determine if sse2neon is needed.
if(WITH_CPU_SIMD) if(WITH_CPU_SIMD)
set(COMPILER_SSE_FLAG) set(COMPILER_SSE42_FLAG)
set(COMPILER_SSE2_FLAG)
# Test Neon first since macOS Arm can compile and run x86-64 SSE binaries. # Test Neon first since macOS Arm can compile and run x86-64 SSE binaries.
test_neon_support() test_neon_support()
if(NOT SUPPORT_NEON_BUILD) if(NOT SUPPORT_NEON_BUILD)
test_sse_support(COMPILER_SSE_FLAG COMPILER_SSE2_FLAG) test_sse_support(COMPILER_SSE42_FLAG)
endif() endif()
endif() endif()
@ -1445,8 +1444,6 @@ endif()
# Enable SIMD support if detected by `test_sse_support()` or `test_neon_support()`. # Enable SIMD support if detected by `test_sse_support()` or `test_neon_support()`.
# #
# This is done globally, so that all modules can use it if available, and
# because these are used in headers used by many modules.
if(WITH_CPU_SIMD) if(WITH_CPU_SIMD)
if(SUPPORT_NEON_BUILD) if(SUPPORT_NEON_BUILD)
# Neon # Neon
@ -1456,15 +1453,20 @@ if(WITH_CPU_SIMD)
endif() endif()
else() else()
# SSE # SSE
if(SUPPORT_SSE_BUILD) if(SUPPORT_SSE42_BUILD)
string(PREPEND PLATFORM_CFLAGS "${COMPILER_SSE_FLAG} ") string(APPEND CMAKE_CXX_FLAGS " ${COMPILER_SSE42_FLAG}")
add_definitions(-D__SSE__ -D__MMX__) string(APPEND CMAKE_C_FLAGS " ${COMPILER_SSE42_FLAG}")
endif() # MSVC doesn't define any of these and only does the AVX and higher flags.
if(SUPPORT_SSE2_BUILD) # For consistency we define these flags for MSVC.
string(APPEND PLATFORM_CFLAGS " ${COMPILER_SSE2_FLAG}") if(WIN32)
add_definitions(-D__SSE2__) add_compile_definitions(
if(NOT SUPPORT_SSE_BUILD) # don't double up __MMX__
add_definitions(-D__MMX__) __SSE__
__SSE2__
__SSE3__
__SSE4_1__
__SSE4_2__
)
endif() endif()
endif() endif()
endif() endif()
@ -1479,10 +1481,8 @@ if(FIRST_RUN)
else() else()
message(STATUS "Neon SIMD instructions detected but unused, requires sse2neon") message(STATUS "Neon SIMD instructions detected but unused, requires sse2neon")
endif() endif()
elseif(SUPPORT_SSE2_BUILD) elseif(SUPPORT_SSE42_BUILD)
message(STATUS "SSE2 SIMD instructions enabled") message(STATUS "SSE42 SIMD instructions enabled")
elseif(SUPPORT_SSE_BUILD)
message(STATUS "SSE SIMD instructions enabled")
else() else()
message(STATUS "No SIMD instructions detected") message(STATUS "No SIMD instructions detected")
endif() endif()

View File

@ -540,49 +540,37 @@ function(setup_platform_linker_libs
endfunction() endfunction()
macro(TEST_SSE_SUPPORT macro(TEST_SSE_SUPPORT
_sse_flags _sse42_flags)
_sse2_flags)
include(CheckCSourceRuns) include(CheckCSourceRuns)
# message(STATUS "Detecting SSE support") # message(STATUS "Detecting SSE support")
if(CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang")) if(CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang"))
set(${_sse_flags} "-msse") set(${_sse42_flags} "-march=x86-64-v2")
set(${_sse2_flags} "-msse2")
elseif(MSVC) elseif(MSVC)
# x86_64 has this auto enabled # msvc has no specific build flags for SSE42, but when using intrinsics it will
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") # generate the right instructions.
set(${_sse_flags} "") set(${_sse42_flags} "")
set(${_sse2_flags} "")
else()
set(${_sse_flags} "/arch:SSE")
set(${_sse2_flags} "/arch:SSE2")
endif()
elseif(CMAKE_C_COMPILER_ID STREQUAL "Intel") elseif(CMAKE_C_COMPILER_ID STREQUAL "Intel")
set(${_sse_flags} "") # icc defaults to -msse if(WIN32)
set(${_sse2_flags} "") # icc defaults to -msse2 set(${_sse42_flags} "/QxSSE4.2")
else()
set(${_sse42_flags} "-xsse4.2")
endif()
else() else()
message(WARNING "SSE flags for this compiler: '${CMAKE_C_COMPILER_ID}' not known") message(WARNING "SSE flags for this compiler: '${CMAKE_C_COMPILER_ID}' not known")
set(${_sse_flags}) set(${_sse42_flags})
set(${_sse2_flags})
endif() endif()
set(CMAKE_REQUIRED_FLAGS "${${_sse_flags}} ${${_sse2_flags}}") set(CMAKE_REQUIRED_FLAGS "${${_sse42_flags}}")
if(NOT DEFINED SUPPORT_SSE_BUILD) if(NOT DEFINED SUPPORT_SSE42_BUILD)
# result cached
check_c_source_runs("
#include <xmmintrin.h>
int main(void) { __m128 v = _mm_setzero_ps(); return 0; }"
SUPPORT_SSE_BUILD)
endif()
if(NOT DEFINED SUPPORT_SSE2_BUILD)
# result cached # result cached
check_c_source_runs(" check_c_source_runs("
#include <nmmintrin.h>
#include <emmintrin.h> #include <emmintrin.h>
int main(void) { __m128d v = _mm_setzero_pd(); return 0; }" int main(void) { __m128i v = _mm_setzero_si128(); v = _mm_cmpgt_epi64(v,v); return 0; }"
SUPPORT_SSE2_BUILD) SUPPORT_SSE42_BUILD)
endif() endif()
unset(CMAKE_REQUIRED_FLAGS) unset(CMAKE_REQUIRED_FLAGS)

View File

@ -21,4 +21,4 @@ if "Cube" in bpy.data.meshes:
import os import os
with open(os.path.splitext(bpy.data.filepath)[0] + ".txt", 'w') as fs: with open(os.path.splitext(bpy.data.filepath)[0] + ".txt", 'w') as fs:
for image in bpy.data.images: for image in bpy.data.images:
fs.write("%s %d x %d\n" % (image.filepath, image.size[0], image.size[1])) fs.write("{:s} {:d} x {:d}\n".format(image.filepath, image.size[0], image.size[1]))

View File

@ -21,8 +21,9 @@ class OBJECT_OT_property_example(bpy.types.Operator):
def execute(self, context): def execute(self, context):
self.report( self.report(
{'INFO'}, 'F: %.2f B: %s S: %r' % {'INFO'}, "F: {:.2f} B: {:s} S: {!r}".format(
(self.my_float, self.my_bool, self.my_string) self.my_float, self.my_bool, self.my_string,
)
) )
print('My float:', self.my_float) print('My float:', self.my_float)
print('My bool:', self.my_bool) print('My bool:', self.my_bool)

View File

@ -53,9 +53,9 @@ class OBJECT_OT_addon_prefs_example(Operator):
preferences = context.preferences preferences = context.preferences
addon_prefs = preferences.addons[__name__].preferences addon_prefs = preferences.addons[__name__].preferences
info = ("Path: %s, Number: %d, Boolean %r" % info = "Path: {:s}, Number: {:d}, Boolean {!r}".format(
(addon_prefs.filepath, addon_prefs.number, addon_prefs.boolean)) addon_prefs.filepath, addon_prefs.number, addon_prefs.boolean,
)
self.report({'INFO'}, info) self.report({'INFO'}, info)
print(info) print(info)

View File

@ -18,7 +18,7 @@ import bpy
def dump(obj, text): def dump(obj, text):
for attr in dir(obj): for attr in dir(obj):
print("%r.%s = %s" % (obj, attr, getattr(obj, attr))) print("{!r}.{:s} = {:s}".format(obj, attr, getattr(obj, attr)))
class WM_OT_button_context_test(bpy.types.Operator): class WM_OT_button_context_test(bpy.types.Operator):

View File

@ -31,10 +31,10 @@ me = bpy.context.object.data
uv_layer = me.uv_layers.active.data uv_layer = me.uv_layers.active.data
for poly in me.polygons: for poly in me.polygons:
print("Polygon index: %d, length: %d" % (poly.index, poly.loop_total)) print("Polygon index: {:d}, length: {:d}".format(poly.index, poly.loop_total))
# range is used here to show how the polygons reference loops, # range is used here to show how the polygons reference loops,
# for convenience 'poly.loop_indices' can be used instead. # for convenience 'poly.loop_indices' can be used instead.
for loop_index in range(poly.loop_start, poly.loop_start + poly.loop_total): for loop_index in range(poly.loop_start, poly.loop_start + poly.loop_total):
print(" Vertex: %d" % me.loops[loop_index].vertex_index) print(" Vertex: {:d}".format(me.loops[loop_index].vertex_index))
print(" UV: %r" % uv_layer[loop_index].uv) print(" UV: {!r}".format(uv_layer[loop_index].uv))

View File

@ -34,7 +34,7 @@ class SimpleMouseOperator(bpy.types.Operator):
def execute(self, context): def execute(self, context):
# rather than printing, use the report function, # rather than printing, use the report function,
# this way the message appears in the header, # this way the message appears in the header,
self.report({'INFO'}, "Mouse coords are %d %d" % (self.x, self.y)) self.report({'INFO'}, "Mouse coords are {:d} {:d}".format(self.x, self.y))
return {'FINISHED'} return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):

View File

@ -16,9 +16,8 @@ class DialogOperator(bpy.types.Operator):
my_string: bpy.props.StringProperty(name="String Value") my_string: bpy.props.StringProperty(name="String Value")
def execute(self, context): def execute(self, context):
message = ( message = "Popup Values: {:f}, {:d}, '{:s}'".format(
"Popup Values: %f, %d, '%s'" % self.my_float, self.my_bool, self.my_string,
(self.my_float, self.my_bool, self.my_string)
) )
self.report({'INFO'}, message) self.report({'INFO'}, message)
return {'FINISHED'} return {'FINISHED'}

View File

@ -10,21 +10,21 @@ col.s *= 0.5
print("Color R:", col.r) print("Color R:", col.r)
print("Color G:", col[1]) print("Color G:", col[1])
print("Color B:", col[-1]) print("Color B:", col[-1])
print("Color HSV: %.2f, %.2f, %.2f", col[:]) print("Color HSV: {:.2f}, {:.2f}, {:.2f}".format(*col))
# components of an existing color can be set # components of an existing color can be set
col[:] = 0.0, 0.5, 1.0 col[:] = 0.0, 0.5, 1.0
# components of an existing color can use slice notation to get a tuple # components of an existing color can use slice notation to get a tuple
print("Values: %f, %f, %f" % col[:]) print("Values: {:f}, {:f}, {:f}".format(*col))
# colors can be added and subtracted # colors can be added and subtracted
col += mathutils.Color((0.25, 0.0, 0.0)) col += mathutils.Color((0.25, 0.0, 0.0))
# Color can be multiplied, in this example color is scaled to 0-255 # Color can be multiplied, in this example color is scaled to 0-255
# can printed as integers # can printed as integers
print("Color: %d, %d, %d" % (col * 255.0)[:]) print("Color: {:d}, {:d}, {:d}".format(*(int(c) for c in (col * 255.0))))
# This example prints the color as hexadecimal # This example prints the color as hexadecimal
print("Hexadecimal: %.2x%.2x%.2x" % (int(col.r * 255), int(col.g * 255), int(col.b * 255))) print("Hexadecimal: {:02x}{:02x}{:02x}".format(int(col.r * 255), int(col.g * 255), int(col.b * 255)))

View File

@ -16,7 +16,7 @@ print("Euler Z", eul[-1])
eul[:] = 1.0, 2.0, 3.0 eul[:] = 1.0, 2.0, 3.0
# components of an existing euler can use slice notation to get a tuple # components of an existing euler can use slice notation to get a tuple
print("Values: %f, %f, %f" % eul[:]) print("Values: {:f}, {:f}, {:f}".format(*eul))
# the order can be set at any time too # the order can be set at any time too
eul.order = 'ZYX' eul.order = 'ZYX'

View File

@ -18,9 +18,8 @@ quat_out = quat_a @ quat_b
# print the quat, euler degrees for mere mortals and (axis, angle) # print the quat, euler degrees for mere mortals and (axis, angle)
print("Final Rotation:") print("Final Rotation:")
print(quat_out) print(quat_out)
print("%.2f, %.2f, %.2f" % tuple(math.degrees(a) for a in quat_out.to_euler())) print("{:.2f}, {:.2f}, {:.2f}".format(*(math.degrees(a) for a in quat_out.to_euler())))
print("(%.2f, %.2f, %.2f), %.2f" % (quat_out.axis[:] + print("({:.2f}, {:.2f}, {:.2f}), {:.2f}".format(*quat_out.axis, math.degrees(quat_out.angle)))
(math.degrees(quat_out.angle), )))
# multiple rotations can be interpolated using the exponential map # multiple rotations can be interpolated using the exponential map
quat_c = mathutils.Quaternion((1.0, 0.0, 0.0), math.radians(15.0)) quat_c = mathutils.Quaternion((1.0, 0.0, 0.0), math.radians(15.0))

View File

@ -21,7 +21,7 @@ class CyclesPresetPanel(PresetPanel, Panel):
preset_operator = "script.execute_preset" preset_operator = "script.execute_preset"
@staticmethod @staticmethod
def post_cb(context): def post_cb(context, _filepath):
# Modify an arbitrary built-in scene property to force a depsgraph # Modify an arbitrary built-in scene property to force a depsgraph
# update, because add-on properties don't. (see #62325) # update, because add-on properties don't. (see #62325)
render = context.scene.render render = context.scene.render

View File

@ -332,7 +332,7 @@ class InfoPropertyRNA:
self.default_str = "\"%s\"" % self.default self.default_str = "\"%s\"" % self.default
elif self.type == "enum": elif self.type == "enum":
if self.is_enum_flag: if self.is_enum_flag:
# self.default_str = "%r" % self.default # repr or set() # self.default_str = repr(self.default) # repr or set()
self.default_str = "{%s}" % repr(list(sorted(self.default)))[1:-1] self.default_str = "{%s}" % repr(list(sorted(self.default)))[1:-1]
else: else:
self.default_str = "'%s'" % self.default self.default_str = "'%s'" % self.default

View File

@ -818,7 +818,7 @@ class TransformsToDeltasAnim(Operator):
if fcu.array_index in existingFCurves[dpath]: if fcu.array_index in existingFCurves[dpath]:
# conflict # conflict
self.report({'ERROR'}, self.report({'ERROR'},
rpt_("Object '%r' already has '%r' F-Curve(s). " rpt_("Object %r already has %r F-Curve(s). "
"Remove these before trying again") % "Remove these before trying again") %
(obj.name, dpath)) (obj.name, dpath))
return {'CANCELLED'} return {'CANCELLED'}

View File

@ -30,6 +30,25 @@ WindowManager.preset_name = StringProperty(
) )
def _call_preset_cb(fn, context, filepath):
# Allow "None" so the caller doesn't have to assign a variable and check it.
if fn is None:
return
# Support a `filepath` argument, optional for backwards compatibility.
fn_arg_count = getattr(getattr(fn, "__code__", None), "co_argcount", None)
if fn_arg_count == 2:
args = (context, filepath)
else:
print("Deprecated since Blender 4.2, a filepath argument should be included in:", fn)
args = (context, )
try:
fn(*args)
except BaseException as ex:
print("Internal error running", fn, str(ex))
class AddPresetBase: class AddPresetBase:
"""Base preset class, only for subclassing """Base preset class, only for subclassing
subclasses must define subclasses must define
@ -241,8 +260,7 @@ class ExecutePreset(Operator):
self.report({'ERROR'}, rpt_("Unknown file type: %r") % ext) self.report({'ERROR'}, rpt_("Unknown file type: %r") % ext)
return {'CANCELLED'} return {'CANCELLED'}
if hasattr(preset_class, "reset_cb"): _call_preset_cb(getattr(preset_class, "reset_cb", None), context, filepath)
preset_class.reset_cb(context)
if ext == ".py": if ext == ".py":
try: try:
@ -254,8 +272,7 @@ class ExecutePreset(Operator):
import rna_xml import rna_xml
rna_xml.xml_file_run(context, filepath, preset_class.preset_xml_map) rna_xml.xml_file_run(context, filepath, preset_class.preset_xml_map)
if hasattr(preset_class, "post_cb"): _call_preset_cb(getattr(preset_class, "post_cb", None), context, filepath)
preset_class.post_cb(context)
return {'FINISHED'} return {'FINISHED'}
@ -637,6 +654,8 @@ class SavePresetInterfaceTheme(AddPresetBase, Operator):
traceback.print_exc() traceback.print_exc()
return {'CANCELLED'} return {'CANCELLED'}
context.preferences.themes[0].filepath = filepath
return {'FINISHED'} return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):

View File

@ -166,7 +166,7 @@ class PlayRenderedAnim(Operator):
opts = ["-fps", str(rd.fps), "-play"] opts = ["-fps", str(rd.fps), "-play"]
if scene.use_preview_range: if scene.use_preview_range:
opts += [ opts += [
"%s" % file.replace("#", "", file.count('#') - 1), file.replace("#", "", file.count('#') - 1),
"%d-%d" % (frame_start, frame_end), "%d-%d" % (frame_start, frame_end),
] ]
else: else:

View File

@ -66,7 +66,7 @@ class OUTLINER_HT_header(Header):
layout.operator("outliner.collection_new", text="", icon='COLLECTION_NEW').nested = True layout.operator("outliner.collection_new", text="", icon='COLLECTION_NEW').nested = True
elif display_mode == 'ORPHAN_DATA': elif display_mode == 'ORPHAN_DATA':
layout.operator("outliner.orphans_purge", text="Purge").do_recursive = True layout.operator("outliner.orphans_purge", text="Purge")
elif space.display_mode == 'DATA_API': elif space.display_mode == 'DATA_API':
layout.separator() layout.separator()

View File

@ -860,21 +860,37 @@ class USERPREF_MT_interface_theme_presets(Menu):
draw = Menu.draw_preset draw = Menu.draw_preset
@staticmethod @staticmethod
def reset_cb(context): def reset_cb(_context, _filepath):
bpy.ops.preferences.reset_default_theme() bpy.ops.preferences.reset_default_theme()
@staticmethod
def post_cb(context, filepath):
context.preferences.themes[0].filepath = filepath
class USERPREF_PT_theme(ThemePanel, Panel): class USERPREF_PT_theme(ThemePanel, Panel):
bl_label = "Themes" bl_label = "Themes"
bl_options = {'HIDE_HEADER'} bl_options = {'HIDE_HEADER'}
def draw(self, _context): def draw(self, context):
import os
layout = self.layout layout = self.layout
split = layout.split(factor=0.6) split = layout.split(factor=0.6)
row = split.row(align=True) row = split.row(align=True)
row.menu("USERPREF_MT_interface_theme_presets", text=USERPREF_MT_interface_theme_presets.bl_label)
# Unlike most presets (which use the classes bl_label),
# themes store the path, use this when set.
if filepath := context.preferences.themes[0].filepath:
preset_label = bpy.path.display_name(os.path.basename(filepath))
else:
preset_label = USERPREF_MT_interface_theme_presets.bl_label
row.menu("USERPREF_MT_interface_theme_presets", text=preset_label)
del filepath, preset_label
row.operator("wm.interface_theme_preset_add", text="", icon='ADD') row.operator("wm.interface_theme_preset_add", text="", icon='ADD')
row.operator("wm.interface_theme_preset_remove", text="", icon='REMOVE') row.operator("wm.interface_theme_preset_remove", text="", icon='REMOVE')
row.operator("wm.interface_theme_preset_save", text="", icon='FILE_TICK') row.operator("wm.interface_theme_preset_save", text="", icon='FILE_TICK')

View File

@ -108,7 +108,7 @@ class MyCustomShapeWidget(Gizmo):
delta /= 10.0 delta /= 10.0
value = self.init_value - delta value = self.init_value - delta
self.target_set_value("offset", value) self.target_set_value("offset", value)
context.area.header_text_set("My Gizmo: %.4f" % value) context.area.header_text_set("My Gizmo: {:.4f}".format(value))
return {'RUNNING_MODAL'} return {'RUNNING_MODAL'}

View File

@ -4,7 +4,7 @@ import bpy
def write_some_data(context, filepath, use_some_setting): def write_some_data(context, filepath, use_some_setting):
print("running write_some_data...") print("running write_some_data...")
f = open(filepath, 'w', encoding='utf-8') f = open(filepath, 'w', encoding='utf-8')
f.write("Hello World %s" % use_some_setting) f.write("Hello World {:s}".format(use_some_setting))
f.close() f.close()
return {'FINISHED'} return {'FINISHED'}

View File

@ -26,7 +26,7 @@ class ViewOperator(bpy.types.Operator):
if event.type == 'MOUSEMOVE': if event.type == 'MOUSEMOVE':
self.offset = (self._initial_mouse - Vector((event.mouse_x, event.mouse_y, 0.0))) * 0.02 self.offset = (self._initial_mouse - Vector((event.mouse_x, event.mouse_y, 0.0))) * 0.02
self.execute(context) self.execute(context)
context.area.header_text_set("Offset %.4f %.4f %.4f" % tuple(self.offset)) context.area.header_text_set("Offset {:.4f} {:.4f} {:.4f}".format(*self.offset))
elif event.type == 'LEFTMOUSE': elif event.type == 'LEFTMOUSE':
context.area.header_text_set(None) context.area.header_text_set(None)

View File

@ -39,7 +39,7 @@ def enum_previews_from_directory_items(self, context):
if directory == pcoll.my_previews_dir: if directory == pcoll.my_previews_dir:
return pcoll.my_previews return pcoll.my_previews
print("Scanning directory: %s" % directory) print("Scanning directory:", directory)
if directory and os.path.exists(directory): if directory and os.path.exists(directory):
# Scan the directory for `*.png` files # Scan the directory for `*.png` files

View File

@ -181,3 +181,7 @@ endif()
if(WITH_FREESTYLE) if(WITH_FREESTYLE)
add_subdirectory(freestyle) add_subdirectory(freestyle)
endif() endif()
if(WITH_CPU_CHECK)
add_subdirectory(cpucheck)
endif()

View File

@ -29,7 +29,7 @@ extern "C" {
/* Blender file format version. */ /* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION #define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 15 #define BLENDER_FILE_SUBVERSION 16
/* Minimum Blender version that supports reading file written with the current /* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to * version. Older Blender versions will test this and cancel loading the file, showing a warning to

View File

@ -575,14 +575,6 @@ struct SculptSession {
blender::float3 cursor_sampled_normal; blender::float3 cursor_sampled_normal;
blender::float3 cursor_view_normal; blender::float3 cursor_view_normal;
/* For Sculpt trimming gesture tools, initial ray-cast data from the position of the mouse
* when
* the gesture starts (intersection with the surface and if they ray hit the surface or not).
*/
blender::float3 gesture_initial_location;
blender::float3 gesture_initial_normal;
bool gesture_initial_hit;
/* TODO(jbakker): Replace rv3d and v3d with ViewContext */ /* TODO(jbakker): Replace rv3d and v3d with ViewContext */
RegionView3D *rv3d; RegionView3D *rv3d;
View3D *v3d; View3D *v3d;

View File

@ -67,7 +67,7 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
#define FROM_DEFAULT_V4_UCHAR(member) copy_v4_v4_uchar(btheme->member, U_theme_default.member) #define FROM_DEFAULT_V4_UCHAR(member) copy_v4_v4_uchar(btheme->member, U_theme_default.member)
if (!USER_VERSION_ATLEAST(300, 41)) { if (!USER_VERSION_ATLEAST(300, 41)) {
memcpy(btheme, &U_theme_default, sizeof(*btheme)); MEMCPY_STRUCT_AFTER(btheme, &U_theme_default, name);
} }
/* Again reset the theme, but only if stored with an early 3.1 alpha version. Some changes were /* Again reset the theme, but only if stored with an early 3.1 alpha version. Some changes were
@ -76,7 +76,7 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
* don't want to reset theme changes stored in the eventual 3.0 release once opened in a 3.1 * don't want to reset theme changes stored in the eventual 3.0 release once opened in a 3.1
* build. */ * build. */
if (userdef->versionfile > 300 && !USER_VERSION_ATLEAST(301, 1)) { if (userdef->versionfile > 300 && !USER_VERSION_ATLEAST(301, 1)) {
memcpy(btheme, &U_theme_default, sizeof(*btheme)); MEMCPY_STRUCT_AFTER(btheme, &U_theme_default, name);
} }
if (!USER_VERSION_ATLEAST(301, 2)) { if (!USER_VERSION_ATLEAST(301, 2)) {
@ -145,7 +145,7 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
FROM_DEFAULT_V4_UCHAR(space_console.console_cursor); FROM_DEFAULT_V4_UCHAR(space_console.console_cursor);
} }
if (!USER_VERSION_ATLEAST(402, 14)) { if (!USER_VERSION_ATLEAST(402, 16)) {
BLI_uniquename( BLI_uniquename(
&userdef->themes, btheme, "Theme", '.', offsetof(bTheme, name), sizeof(btheme->name)); &userdef->themes, btheme, "Theme", '.', offsetof(bTheme, name), sizeof(btheme->name));
} }
@ -515,7 +515,7 @@ void blo_do_versions_userdef(UserDef *userdef)
/* Reset theme, old themes will not be compatible with minor version updates from now on. */ /* Reset theme, old themes will not be compatible with minor version updates from now on. */
LISTBASE_FOREACH (bTheme *, btheme, &userdef->themes) { LISTBASE_FOREACH (bTheme *, btheme, &userdef->themes) {
memcpy(btheme, &U_theme_default, sizeof(*btheme)); MEMCPY_STRUCT_AFTER(btheme, &U_theme_default, name);
} }
/* Annotations - new layer color /* Annotations - new layer color

View File

@ -0,0 +1,26 @@
# SPDX-FileCopyrightText: 2024 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
# The cpu check module cannot build with sse42 since it will be executed
# by cpus that may not support these instructions
if(COMPILER_SSE42_FLAG)
remove_cc_flag("${COMPILER_SSE42_FLAG}")
endif()
add_library(blender_cpu_check SHARED cpu_check.cc)
target_link_libraries(blender_cpu_check PRIVATE ${PLATFORM_LINKLIBS})
target_compile_definitions(blender_cpu_check PUBLIC WITH_CPU_CHECK)
if(NOT WIN32)
set(_LIB_SUB_FOLDER "lib/")
endif()
set_target_properties(blender_cpu_check
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/${_LIB_SUB_FOLDER}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/${_LIB_SUB_FOLDER}"
)
unset(_LIB_SUB_FOLDER)

View File

@ -580,6 +580,30 @@ bool ANIM_animdata_can_have_greasepencil(const eAnimCont_Types type)
/* ----------- 'Private' Stuff --------------- */ /* ----------- 'Private' Stuff --------------- */
/**
* Set `ale` so that it points to the top-most 'summary' channel of the given `adt`.
* So this is either the Animation or the Action, or empty.
*/
static void key_data_from_adt(bAnimListElem &ale, AnimData *adt)
{
ale.adt = adt;
if (!adt) {
ale.key_data = nullptr;
ale.datatype = ALE_NONE;
return;
}
if (adt->action) {
ale.key_data = adt->action;
ale.datatype = ALE_ACT;
return;
}
ale.key_data = nullptr;
ale.datatype = ALE_NONE;
}
/* this function allocates memory for a new bAnimListElem struct for the /* this function allocates memory for a new bAnimListElem struct for the
* provided animation channel-data. * provided animation channel-data.
*/ */
@ -655,244 +679,125 @@ static bAnimListElem *make_new_animlistelem(void *data,
} }
case ANIMTYPE_DSMAT: { case ANIMTYPE_DSMAT: {
Material *ma = (Material *)data; Material *ma = (Material *)data;
AnimData *adt = ma->adt;
ale->flag = FILTER_MAT_OBJD(ma); ale->flag = FILTER_MAT_OBJD(ma);
key_data_from_adt(*ale, ma->adt);
ale->key_data = (adt) ? adt->action : nullptr;
ale->datatype = ALE_ACT;
ale->adt = BKE_animdata_from_id(static_cast<ID *>(data));
break; break;
} }
case ANIMTYPE_DSLAM: { case ANIMTYPE_DSLAM: {
Light *la = (Light *)data; Light *la = (Light *)data;
AnimData *adt = la->adt;
ale->flag = FILTER_LAM_OBJD(la); ale->flag = FILTER_LAM_OBJD(la);
key_data_from_adt(*ale, la->adt);
ale->key_data = (adt) ? adt->action : nullptr;
ale->datatype = ALE_ACT;
ale->adt = BKE_animdata_from_id(static_cast<ID *>(data));
break; break;
} }
case ANIMTYPE_DSCAM: { case ANIMTYPE_DSCAM: {
Camera *ca = (Camera *)data; Camera *ca = (Camera *)data;
AnimData *adt = ca->adt;
ale->flag = FILTER_CAM_OBJD(ca); ale->flag = FILTER_CAM_OBJD(ca);
key_data_from_adt(*ale, ca->adt);
ale->key_data = (adt) ? adt->action : nullptr;
ale->datatype = ALE_ACT;
ale->adt = BKE_animdata_from_id(static_cast<ID *>(data));
break; break;
} }
case ANIMTYPE_DSCACHEFILE: { case ANIMTYPE_DSCACHEFILE: {
CacheFile *cache_file = (CacheFile *)data; CacheFile *cache_file = (CacheFile *)data;
AnimData *adt = cache_file->adt;
ale->flag = FILTER_CACHEFILE_OBJD(cache_file); ale->flag = FILTER_CACHEFILE_OBJD(cache_file);
key_data_from_adt(*ale, cache_file->adt);
ale->key_data = (adt) ? adt->action : nullptr;
ale->datatype = ALE_ACT;
ale->adt = BKE_animdata_from_id(static_cast<ID *>(data));
break; break;
} }
case ANIMTYPE_DSCUR: { case ANIMTYPE_DSCUR: {
Curve *cu = (Curve *)data; Curve *cu = (Curve *)data;
AnimData *adt = cu->adt;
ale->flag = FILTER_CUR_OBJD(cu); ale->flag = FILTER_CUR_OBJD(cu);
key_data_from_adt(*ale, cu->adt);
ale->key_data = (adt) ? adt->action : nullptr;
ale->datatype = ALE_ACT;
ale->adt = BKE_animdata_from_id(static_cast<ID *>(data));
break; break;
} }
case ANIMTYPE_DSARM: { case ANIMTYPE_DSARM: {
bArmature *arm = (bArmature *)data; bArmature *arm = (bArmature *)data;
AnimData *adt = arm->adt;
ale->flag = FILTER_ARM_OBJD(arm); ale->flag = FILTER_ARM_OBJD(arm);
key_data_from_adt(*ale, arm->adt);
ale->key_data = (adt) ? adt->action : nullptr;
ale->datatype = ALE_ACT;
ale->adt = BKE_animdata_from_id(static_cast<ID *>(data));
break; break;
} }
case ANIMTYPE_DSMESH: { case ANIMTYPE_DSMESH: {
Mesh *mesh = (Mesh *)data; Mesh *mesh = (Mesh *)data;
AnimData *adt = mesh->adt;
ale->flag = FILTER_MESH_OBJD(mesh); ale->flag = FILTER_MESH_OBJD(mesh);
key_data_from_adt(*ale, mesh->adt);
ale->key_data = (adt) ? adt->action : nullptr;
ale->datatype = ALE_ACT;
ale->adt = BKE_animdata_from_id(static_cast<ID *>(data));
break; break;
} }
case ANIMTYPE_DSLAT: { case ANIMTYPE_DSLAT: {
Lattice *lt = (Lattice *)data; Lattice *lt = (Lattice *)data;
AnimData *adt = lt->adt;
ale->flag = FILTER_LATTICE_OBJD(lt); ale->flag = FILTER_LATTICE_OBJD(lt);
key_data_from_adt(*ale, lt->adt);
ale->key_data = (adt) ? adt->action : nullptr;
ale->datatype = ALE_ACT;
ale->adt = BKE_animdata_from_id(static_cast<ID *>(data));
break; break;
} }
case ANIMTYPE_DSSPK: { case ANIMTYPE_DSSPK: {
Speaker *spk = (Speaker *)data; Speaker *spk = (Speaker *)data;
AnimData *adt = spk->adt;
ale->flag = FILTER_SPK_OBJD(spk); ale->flag = FILTER_SPK_OBJD(spk);
key_data_from_adt(*ale, spk->adt);
ale->key_data = (adt) ? adt->action : nullptr;
ale->datatype = ALE_ACT;
ale->adt = BKE_animdata_from_id(static_cast<ID *>(data));
break; break;
} }
case ANIMTYPE_DSHAIR: { case ANIMTYPE_DSHAIR: {
Curves *curves = (Curves *)data; Curves *curves = (Curves *)data;
AnimData *adt = curves->adt;
ale->flag = FILTER_CURVES_OBJD(curves); ale->flag = FILTER_CURVES_OBJD(curves);
key_data_from_adt(*ale, curves->adt);
ale->key_data = (adt) ? adt->action : nullptr;
ale->datatype = ALE_ACT;
ale->adt = BKE_animdata_from_id(static_cast<ID *>(data));
break; break;
} }
case ANIMTYPE_DSPOINTCLOUD: { case ANIMTYPE_DSPOINTCLOUD: {
PointCloud *pointcloud = (PointCloud *)data; PointCloud *pointcloud = (PointCloud *)data;
AnimData *adt = pointcloud->adt;
ale->flag = FILTER_POINTS_OBJD(pointcloud); ale->flag = FILTER_POINTS_OBJD(pointcloud);
key_data_from_adt(*ale, pointcloud->adt);
ale->key_data = (adt) ? adt->action : nullptr;
ale->datatype = ALE_ACT;
ale->adt = BKE_animdata_from_id(static_cast<ID *>(data));
break; break;
} }
case ANIMTYPE_DSVOLUME: { case ANIMTYPE_DSVOLUME: {
Volume *volume = (Volume *)data; Volume *volume = (Volume *)data;
AnimData *adt = volume->adt;
ale->flag = FILTER_VOLUME_OBJD(volume); ale->flag = FILTER_VOLUME_OBJD(volume);
key_data_from_adt(*ale, volume->adt);
ale->key_data = (adt) ? adt->action : nullptr;
ale->datatype = ALE_ACT;
ale->adt = BKE_animdata_from_id(static_cast<ID *>(data));
break; break;
} }
case ANIMTYPE_DSSKEY: { case ANIMTYPE_DSSKEY: {
Key *key = (Key *)data; Key *key = (Key *)data;
AnimData *adt = key->adt;
ale->flag = FILTER_SKE_OBJD(key); ale->flag = FILTER_SKE_OBJD(key);
key_data_from_adt(*ale, key->adt);
ale->key_data = (adt) ? adt->action : nullptr;
ale->datatype = ALE_ACT;
ale->adt = BKE_animdata_from_id(static_cast<ID *>(data));
break; break;
} }
case ANIMTYPE_DSWOR: { case ANIMTYPE_DSWOR: {
World *wo = (World *)data; World *wo = (World *)data;
AnimData *adt = wo->adt;
ale->flag = FILTER_WOR_SCED(wo); ale->flag = FILTER_WOR_SCED(wo);
key_data_from_adt(*ale, wo->adt);
ale->key_data = (adt) ? adt->action : nullptr;
ale->datatype = ALE_ACT;
ale->adt = BKE_animdata_from_id(static_cast<ID *>(data));
break; break;
} }
case ANIMTYPE_DSNTREE: { case ANIMTYPE_DSNTREE: {
bNodeTree *ntree = (bNodeTree *)data; bNodeTree *ntree = (bNodeTree *)data;
AnimData *adt = ntree->adt;
ale->flag = FILTER_NTREE_DATA(ntree); ale->flag = FILTER_NTREE_DATA(ntree);
key_data_from_adt(*ale, ntree->adt);
ale->key_data = (adt) ? adt->action : nullptr;
ale->datatype = ALE_ACT;
ale->adt = BKE_animdata_from_id(static_cast<ID *>(data));
break; break;
} }
case ANIMTYPE_DSLINESTYLE: { case ANIMTYPE_DSLINESTYLE: {
FreestyleLineStyle *linestyle = (FreestyleLineStyle *)data; FreestyleLineStyle *linestyle = (FreestyleLineStyle *)data;
AnimData *adt = linestyle->adt;
ale->flag = FILTER_LS_SCED(linestyle); ale->flag = FILTER_LS_SCED(linestyle);
key_data_from_adt(*ale, linestyle->adt);
ale->key_data = (adt) ? adt->action : nullptr;
ale->datatype = ALE_ACT;
ale->adt = BKE_animdata_from_id(static_cast<ID *>(data));
break; break;
} }
case ANIMTYPE_DSPART: { case ANIMTYPE_DSPART: {
ParticleSettings *part = (ParticleSettings *)ale->data; ParticleSettings *part = (ParticleSettings *)ale->data;
AnimData *adt = part->adt;
ale->flag = FILTER_PART_OBJD(part); ale->flag = FILTER_PART_OBJD(part);
key_data_from_adt(*ale, part->adt);
ale->key_data = (adt) ? adt->action : nullptr;
ale->datatype = ALE_ACT;
ale->adt = BKE_animdata_from_id(static_cast<ID *>(data));
break; break;
} }
case ANIMTYPE_DSTEX: { case ANIMTYPE_DSTEX: {
Tex *tex = (Tex *)data; Tex *tex = (Tex *)data;
AnimData *adt = tex->adt;
ale->flag = FILTER_TEX_DATA(tex); ale->flag = FILTER_TEX_DATA(tex);
key_data_from_adt(*ale, tex->adt);
ale->key_data = (adt) ? adt->action : nullptr;
ale->datatype = ALE_ACT;
ale->adt = BKE_animdata_from_id(static_cast<ID *>(data));
break; break;
} }
case ANIMTYPE_DSGPENCIL: { case ANIMTYPE_DSGPENCIL: {
bGPdata *gpd = (bGPdata *)data; bGPdata *gpd = (bGPdata *)data;
AnimData *adt = gpd->adt;
/* NOTE: we just reuse the same expand filter for this case */ /* NOTE: we just reuse the same expand filter for this case */
ale->flag = EXPANDED_GPD(gpd); ale->flag = EXPANDED_GPD(gpd);
/* XXX: currently, this is only used for access to its animation data */ /* XXX: currently, this is only used for access to its animation data */
ale->key_data = (adt) ? adt->action : nullptr; key_data_from_adt(*ale, gpd->adt);
ale->datatype = ALE_ACT;
ale->adt = BKE_animdata_from_id(static_cast<ID *>(data));
break; break;
} }
case ANIMTYPE_DSMCLIP: { case ANIMTYPE_DSMCLIP: {
MovieClip *clip = (MovieClip *)data; MovieClip *clip = (MovieClip *)data;
AnimData *adt = clip->adt;
ale->flag = EXPANDED_MCLIP(clip); ale->flag = EXPANDED_MCLIP(clip);
key_data_from_adt(*ale, clip->adt);
ale->key_data = (adt) ? adt->action : nullptr;
ale->datatype = ALE_ACT;
ale->adt = BKE_animdata_from_id(static_cast<ID *>(data));
break; break;
} }
case ANIMTYPE_NLACONTROLS: { case ANIMTYPE_NLACONTROLS: {

View File

@ -54,6 +54,8 @@ struct AssetItemTree {
assets_per_path; assets_per_path;
/** Assets not added to a catalog, not part of #assets_per_path. */ /** Assets not added to a catalog, not part of #assets_per_path. */
Vector<asset_system::AssetRepresentation *> unassigned_assets; Vector<asset_system::AssetRepresentation *> unassigned_assets;
/** True if the tree is out of date compared to asset libraries and must be rebuilt. */
bool dirty = true;
}; };
asset_system::AssetCatalogTree build_filtered_catalog_tree( asset_system::AssetCatalogTree build_filtered_catalog_tree(

View File

@ -150,7 +150,8 @@ AssetItemTree build_filtered_all_catalog_tree(
return {std::move(catalogs_with_node_assets), return {std::move(catalogs_with_node_assets),
std::move(assets_per_path), std::move(assets_per_path),
std::move(unassigned_assets)}; std::move(unassigned_assets),
false};
} }
} // namespace blender::ed::asset } // namespace blender::ed::asset

View File

@ -315,7 +315,7 @@ void AssetClearHelper::reportResults(const bContext *C, ReportList &reports) con
&reports, RPT_INFO, "Data-block '%s' is not an asset anymore", stats.last_id->name + 2); &reports, RPT_INFO, "Data-block '%s' is not an asset anymore", stats.last_id->name + 2);
} }
else { else {
BKE_reportf(&reports, RPT_INFO, "%i data-blocks are no assets anymore", stats.tot_cleared); BKE_reportf(&reports, RPT_INFO, "%i data-blocks are not assets anymore", stats.tot_cleared);
} }
} }

View File

@ -787,7 +787,7 @@ void clear_operator_asset_trees()
for (const ObjectType type : {OB_MESH, OB_CURVES, OB_POINTCLOUD}) { for (const ObjectType type : {OB_MESH, OB_CURVES, OB_POINTCLOUD}) {
for (const eObjectMode mode : {OB_MODE_OBJECT, OB_MODE_EDIT, OB_MODE_SCULPT_CURVES}) { for (const eObjectMode mode : {OB_MODE_OBJECT, OB_MODE_EDIT, OB_MODE_SCULPT_CURVES}) {
if (asset::AssetItemTree *tree = get_static_item_tree(type, mode)) { if (asset::AssetItemTree *tree = get_static_item_tree(type, mode)) {
*tree = {}; tree->dirty = true;
} }
} }
} }
@ -1105,7 +1105,7 @@ void ui_template_node_operator_asset_root_items(uiLayout &layout, const bContext
if (!tree) { if (!tree) {
return; return;
} }
if (tree->assets_per_path.size() == 0) { if (tree->dirty) {
*tree = build_catalog_tree(C, *active_object); *tree = build_catalog_tree(C, *active_object);
} }

View File

@ -1071,6 +1071,7 @@ void UI_theme_init_default()
BLI_findstring(&U.themes, U_theme_default.name, offsetof(bTheme, name))); BLI_findstring(&U.themes, U_theme_default.name, offsetof(bTheme, name)));
if (btheme == nullptr) { if (btheme == nullptr) {
btheme = MEM_cnew<bTheme>(__func__); btheme = MEM_cnew<bTheme>(__func__);
STRNCPY(btheme->name, U_theme_default.name);
BLI_addhead(&U.themes, btheme); BLI_addhead(&U.themes, btheme);
} }

View File

@ -38,6 +38,7 @@
#include "sculpt_intern.hh" #include "sculpt_intern.hh"
namespace blender::ed::sculpt_paint::trim { namespace blender::ed::sculpt_paint::trim {
enum class OperationType { enum class OperationType {
Intersect = 0, Intersect = 0,
Difference = 1, Difference = 1,
@ -112,6 +113,10 @@ struct TrimOperation {
/* Operator properties. */ /* Operator properties. */
bool use_cursor_depth; bool use_cursor_depth;
bool initial_hit;
blender::float3 initial_location;
blender::float3 initial_normal;
OperationType mode; OperationType mode;
SolverMode solver_mode; SolverMode solver_mode;
OrientationType orientation; OrientationType orientation;
@ -166,17 +171,17 @@ static void get_origin_and_normal(gesture::GestureData &gesture_data,
case OrientationType::View: case OrientationType::View:
mul_v3_m4v3(r_origin, mul_v3_m4v3(r_origin,
gesture_data.vc.obact->object_to_world().ptr(), gesture_data.vc.obact->object_to_world().ptr(),
gesture_data.ss->gesture_initial_location); trim_operation->initial_location);
copy_v3_v3(r_normal, gesture_data.world_space_view_normal); copy_v3_v3(r_normal, gesture_data.world_space_view_normal);
negate_v3(r_normal); negate_v3(r_normal);
break; break;
case OrientationType::Surface: case OrientationType::Surface:
mul_v3_m4v3(r_origin, mul_v3_m4v3(r_origin,
gesture_data.vc.obact->object_to_world().ptr(), gesture_data.vc.obact->object_to_world().ptr(),
gesture_data.ss->gesture_initial_location); trim_operation->initial_location);
/* Transforming the normal does not take non uniform scaling into account. Sculpt mode is not /* Transforming the normal does not take non uniform scaling into account. Sculpt mode is not
* expected to work on object with non uniform scaling. */ * expected to work on object with non uniform scaling. */
copy_v3_v3(r_normal, gesture_data.ss->gesture_initial_normal); copy_v3_v3(r_normal, trim_operation->initial_normal);
mul_mat3_m4_v3(gesture_data.vc.obact->object_to_world().ptr(), r_normal); mul_mat3_m4_v3(gesture_data.vc.obact->object_to_world().ptr(), r_normal);
break; break;
} }
@ -221,11 +226,11 @@ static void calculate_depth(gesture::GestureData &gesture_data,
float world_space_gesture_initial_location[3]; float world_space_gesture_initial_location[3];
mul_v3_m4v3(world_space_gesture_initial_location, mul_v3_m4v3(world_space_gesture_initial_location,
vc->obact->object_to_world().ptr(), vc->obact->object_to_world().ptr(),
ss->gesture_initial_location); trim_operation->initial_location);
float mid_point_depth; float mid_point_depth;
if (trim_operation->orientation == OrientationType::View) { if (trim_operation->orientation == OrientationType::View) {
mid_point_depth = ss->gesture_initial_hit ? mid_point_depth = trim_operation->initial_hit ?
dist_signed_to_plane_v3(world_space_gesture_initial_location, dist_signed_to_plane_v3(world_space_gesture_initial_location,
shape_plane) : shape_plane) :
(depth_back + depth_front) * 0.5f; (depth_back + depth_front) * 0.5f;
@ -234,12 +239,12 @@ static void calculate_depth(gesture::GestureData &gesture_data,
/* When using normal orientation, if the stroke started over the mesh, position the mid point /* When using normal orientation, if the stroke started over the mesh, position the mid point
* at 0 distance from the shape plane. This positions the trimming shape half inside of the * at 0 distance from the shape plane. This positions the trimming shape half inside of the
* surface. */ * surface. */
mid_point_depth = ss->gesture_initial_hit ? 0.0f : (depth_back + depth_front) * 0.5f; mid_point_depth = trim_operation->initial_hit ? 0.0f : (depth_back + depth_front) * 0.5f;
} }
float depth_radius; float depth_radius;
if (ss->gesture_initial_hit) { if (trim_operation->initial_hit) {
depth_radius = ss->cursor_radius; depth_radius = ss->cursor_radius;
} }
else { else {
@ -254,7 +259,7 @@ static void calculate_depth(gesture::GestureData &gesture_data,
if (!BKE_brush_use_locked_size(scene, brush)) { if (!BKE_brush_use_locked_size(scene, brush)) {
depth_radius = paint_calc_object_space_radius( depth_radius = paint_calc_object_space_radius(
vc, ss->gesture_initial_location, BKE_brush_size_get(scene, brush)); vc, trim_operation->initial_location, BKE_brush_size_get(scene, brush));
} }
else { else {
depth_radius = BKE_brush_unprojected_radius_get(scene, brush); depth_radius = BKE_brush_unprojected_radius_get(scene, brush);
@ -609,13 +614,27 @@ static void init_operation(gesture::GestureData &gesture_data, wmOperator &op)
trim_operation->solver_mode = SolverMode(RNA_enum_get(op.ptr, "trim_solver")); trim_operation->solver_mode = SolverMode(RNA_enum_get(op.ptr, "trim_solver"));
/* If the cursor was not over the mesh, force the orientation to view. */ /* If the cursor was not over the mesh, force the orientation to view. */
if (!gesture_data.ss->gesture_initial_hit) { if (!trim_operation->initial_hit) {
trim_operation->orientation = OrientationType::View; trim_operation->orientation = OrientationType::View;
} }
} }
static void operator_properties(wmOperatorType *ot) static void operator_properties(wmOperatorType *ot)
{ {
PropertyRNA *prop;
prop = RNA_def_int_vector(ot->srna,
"location",
2,
nullptr,
INT_MIN,
INT_MAX,
"Location",
"Mouse location",
INT_MIN,
INT_MAX);
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
RNA_def_enum(ot->srna, RNA_def_enum(ot->srna,
"trim_mode", "trim_mode",
operation_types, operation_types,
@ -672,21 +691,26 @@ static bool can_exec(const bContext &C)
return true; return true;
} }
static void initialize_cursor_info(bContext &C, const wmEvent *event) static void initialize_cursor_info(bContext &C,
const wmOperator &op,
gesture::GestureData &gesture_data)
{ {
const Object &ob = *CTX_data_active_object(&C); const Object &ob = *CTX_data_active_object(&C);
SculptSession &ss = *ob.sculpt; SculptSession &ss = *ob.sculpt;
SCULPT_vertex_random_access_ensure(&ss); SCULPT_vertex_random_access_ensure(&ss);
SculptCursorGeometryInfo sgi; int mval[2];
const float mval_fl[2] = {float(event->mval[0]), float(event->mval[1])}; RNA_int_get_array(op.ptr, "location", mval);
/* TODO: Remove gesture_* properties from SculptSession */ SculptCursorGeometryInfo sgi;
ss.gesture_initial_hit = SCULPT_cursor_geometry_info_update(&C, &sgi, mval_fl, false); const float mval_fl[2] = {float(mval[0]), float(mval[1])};
if (ss.gesture_initial_hit) {
copy_v3_v3(ss.gesture_initial_location, sgi.location); TrimOperation *trim_operation = (TrimOperation *)gesture_data.operation;
copy_v3_v3(ss.gesture_initial_normal, sgi.normal); trim_operation->initial_hit = SCULPT_cursor_geometry_info_update(&C, &sgi, mval_fl, false);
if (trim_operation->initial_hit) {
copy_v3_v3(trim_operation->initial_location, sgi.location);
copy_v3_v3(trim_operation->initial_normal, sgi.normal);
} }
} }
@ -701,7 +725,9 @@ static int gesture_box_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
} }
initialize_cursor_info(*C, *op, *gesture_data);
init_operation(*gesture_data, *op); init_operation(*gesture_data, *op);
gesture::apply(*C, *gesture_data, *op); gesture::apply(*C, *gesture_data, *op);
return OPERATOR_FINISHED; return OPERATOR_FINISHED;
} }
@ -712,7 +738,7 @@ static int gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
} }
initialize_cursor_info(*C, event); RNA_int_set_array(op->ptr, "location", event->mval);
return WM_gesture_box_invoke(C, op, event); return WM_gesture_box_invoke(C, op, event);
} }
@ -727,7 +753,10 @@ static int gesture_lasso_exec(bContext *C, wmOperator *op)
if (!gesture_data) { if (!gesture_data) {
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
} }
initialize_cursor_info(*C, *op, *gesture_data);
init_operation(*gesture_data, *op); init_operation(*gesture_data, *op);
gesture::apply(*C, *gesture_data, *op); gesture::apply(*C, *gesture_data, *op);
return OPERATOR_FINISHED; return OPERATOR_FINISHED;
} }
@ -738,7 +767,7 @@ static int gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *even
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
} }
initialize_cursor_info(*C, event); RNA_int_set_array(op->ptr, "location", event->mval);
return WM_gesture_lasso_invoke(C, op, event); return WM_gesture_lasso_invoke(C, op, event);
} }

View File

@ -242,8 +242,10 @@ static void graph_main_region_draw(const bContext *C, ARegion *region)
graph_draw_curves(&ac, sipo, region, 1); graph_draw_curves(&ac, sipo, region, 1);
/* XXX(ton): the slow way to set tot rect... but for nice sliders needed. */ /* XXX(ton): the slow way to set tot rect... but for nice sliders needed. */
/* Excluding handles from the calculation to save performance. This cuts the time it takes for
* this function to run in half which is a major performance bottleneck on heavy scenes. */
get_graph_keyframe_extents( get_graph_keyframe_extents(
&ac, &v2d->tot.xmin, &v2d->tot.xmax, &v2d->tot.ymin, &v2d->tot.ymax, false, true); &ac, &v2d->tot.xmin, &v2d->tot.xmax, &v2d->tot.ymin, &v2d->tot.ymax, false, false);
/* extra offset so that these items are visible */ /* extra offset so that these items are visible */
v2d->tot.xmin -= 10.0f; v2d->tot.xmin -= 10.0f;
v2d->tot.xmax += 10.0f; v2d->tot.xmax += 10.0f;

View File

@ -2340,7 +2340,7 @@ void OUTLINER_OT_orphans_purge(wmOperatorType *ot)
RNA_def_boolean(ot->srna, RNA_def_boolean(ot->srna,
"do_recursive", "do_recursive",
false, true,
"Recursive Delete", "Recursive Delete",
"Recursively check for indirectly unused data-blocks, ensuring that no orphaned " "Recursively check for indirectly unused data-blocks, ensuring that no orphaned "
"data-blocks remain after execution"); "data-blocks remain after execution");

View File

@ -15,6 +15,7 @@
#include "BKE_report.hh" #include "BKE_report.hh"
#include "BLI_string.h" #include "BLI_string.h"
#include "BLI_string_utils.hh"
#include "DEG_depsgraph_query.hh" #include "DEG_depsgraph_query.hh"
@ -72,14 +73,16 @@ void export_frame(Depsgraph *depsgraph,
/* If exporting in batch, create writer for each iteration over objects. */ /* If exporting in batch, create writer for each iteration over objects. */
if (export_params.use_batch) { if (export_params.use_batch) {
/* Get object name by skipping initial "OB" prefix. */ /* Get object name by skipping initial "OB" prefix. */
std::string object_name = (object->id.name + 2); char object_name[sizeof(object->id.name) - 2];
STRNCPY(object_name, object->id.name + 2);
BLI_path_make_safe_filename(object_name);
/* Replace spaces with underscores. */ /* Replace spaces with underscores. */
std::replace(object_name.begin(), object_name.end(), ' ', '_'); BLI_string_replace_char(object_name, ' ', '_');
/* Include object name in the exported file name. */ /* Include object name in the exported file name. */
char filepath[FILE_MAX]; char filepath[FILE_MAX];
STRNCPY(filepath, export_params.filepath); STRNCPY(filepath, export_params.filepath);
BLI_path_suffix(filepath, FILE_MAX, object_name.c_str(), ""); BLI_path_suffix(filepath, FILE_MAX, object_name, "");
/* Make sure we have .stl extension (case insensitive). */ /* Make sure we have .stl extension (case insensitive). */
if (!BLI_path_extension_check(filepath, ".stl")) { if (!BLI_path_extension_check(filepath, ".stl")) {
BLI_path_extension_ensure(filepath, FILE_MAX, ".stl"); BLI_path_extension_ensure(filepath, FILE_MAX, ".stl");

View File

@ -493,6 +493,16 @@ typedef struct bTheme {
/* NOTE: Values after `name` are copied when resetting the default theme. */ /* NOTE: Values after `name` are copied when resetting the default theme. */
/**
* The file-path for the preset that was loaded into this theme.
*
* This is needed so it's possible to know if updating or removing a theme preset
* should apply changes to the current theme.
*
* #FILE_MAX.
*/
char filepath[1024];
ThemeUI tui; ThemeUI tui;
/** /**

View File

@ -6333,7 +6333,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
{AV_CODEC_ID_MPEG2VIDEO, "MPEG2", 0, "MPEG-2", ""}, {AV_CODEC_ID_MPEG2VIDEO, "MPEG2", 0, "MPEG-2", ""},
{AV_CODEC_ID_MPEG4, "MPEG4", 0, "MPEG-4 (divx)", ""}, {AV_CODEC_ID_MPEG4, "MPEG4", 0, "MPEG-4 (divx)", ""},
{AV_CODEC_ID_PNG, "PNG", 0, "PNG", ""}, {AV_CODEC_ID_PNG, "PNG", 0, "PNG", ""},
{AV_CODEC_ID_QTRLE, "QTRLE", 0, "QT rle / QT Animation", ""}, {AV_CODEC_ID_QTRLE, "QTRLE", 0, "QuickTime Animation", ""},
{AV_CODEC_ID_THEORA, "THEORA", 0, "Theora", ""}, {AV_CODEC_ID_THEORA, "THEORA", 0, "Theora", ""},
{AV_CODEC_ID_VP9, "WEBM", 0, "WebM / VP9", ""}, {AV_CODEC_ID_VP9, "WEBM", 0, "WebM / VP9", ""},
{AV_CODEC_ID_AV1, "AV1", 0, "AV1", ""}, {AV_CODEC_ID_AV1, "AV1", 0, "AV1", ""},

View File

@ -4301,6 +4301,11 @@ static void rna_def_userdef_themes(BlenderRNA *brna)
/* XXX: for now putting this in presets is silly - its just Default */ /* XXX: for now putting this in presets is silly - its just Default */
RNA_def_property_flag(prop, PROP_SKIP_SAVE); RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
RNA_def_property_string_sdna(prop, nullptr, "filepath");
RNA_def_property_ui_text(
prop, "File Path", "The path to the preset loaded into this theme (if any)");
prop = RNA_def_property(srna, "theme_area", PROP_ENUM, PROP_NONE); prop = RNA_def_property(srna, "theme_area", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, nullptr, "active_theme_area"); RNA_def_property_enum_sdna(prop, nullptr, "active_theme_area");
RNA_def_property_flag(prop, PROP_SKIP_SAVE); RNA_def_property_flag(prop, PROP_SKIP_SAVE);

View File

@ -333,29 +333,10 @@ if(WITH_PYTHON_MODULE)
else() else()
add_executable(blender ${EXETYPE} ${SRC}) add_executable(blender ${EXETYPE} ${SRC})
if(WITH_CPU_CHECK) if(WITH_CPU_CHECK)
target_compile_definitions(blender PRIVATE WITH_CPU_CHECK)
# we cannot directly link against any blender libraries for the cpu_check module
# as they may have been build for an ISA that is unsupported by the CPU
# running this code.
add_library(blender_cpu_check SHARED
creator_cpu_check.cc
)
target_link_libraries(blender_cpu_check
PRIVATE ${PLATFORM_LINKLIBS}
)
# blender_cpu_check *NEEDS* to be linked first, there can be no exceptions # blender_cpu_check *NEEDS* to be linked first, there can be no exceptions
# to this, this is to ensure this will be the first code to run once the # to this, this is to ensure this will be the first code to run once the
# blender binary has been loaded by the OS. # blender binary has been loaded by the OS.
target_link_libraries(blender PRIVATE blender_cpu_check) target_link_libraries(blender PRIVATE blender_cpu_check)
if(NOT WIN32)
set(_LIB_SUB_FOLDER "lib/")
endif()
set_target_properties(blender_cpu_check
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/${_LIB_SUB_FOLDER}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/${_LIB_SUB_FOLDER}"
)
unset(_LIB_SUB_FOLDER)
endif() endif()
if(WIN32) if(WIN32)
add_executable(blender-launcher WIN32 add_executable(blender-launcher WIN32

View File

@ -107,7 +107,7 @@ class MeshExportTest4(AbstractColladaTest):
outfile = tempdir / Path("%s_out.dae" % test) outfile = tempdir / Path("%s_out.dae" % test)
bpy.ops.wm.collada_export( bpy.ops.wm.collada_export(
filepath="%s" % str(outfile), filepath=str(outfile),
check_existing=True, check_existing=True,
filemode=8, filemode=8,
display_type='DEFAULT', display_type='DEFAULT',
@ -151,7 +151,7 @@ class MeshExportTest3(AbstractColladaTest):
outfile = tempdir / Path("%s_out.dae" % test) outfile = tempdir / Path("%s_out.dae" % test)
bpy.ops.wm.collada_export( bpy.ops.wm.collada_export(
filepath="%s" % str(outfile), filepath=str(outfile),
check_existing=True, check_existing=True,
filemode=8, filemode=8,
display_type='DEFAULT', display_type='DEFAULT',
@ -195,7 +195,7 @@ class MeshExportTest2(AbstractColladaTest):
outfile = tempdir / Path("%s_out.dae" % test) outfile = tempdir / Path("%s_out.dae" % test)
bpy.ops.wm.collada_export( bpy.ops.wm.collada_export(
filepath="%s" % str(outfile), filepath=str(outfile),
check_existing=True, check_existing=True,
filemode=8, filemode=8,
display_type='DEFAULT', display_type='DEFAULT',
@ -239,7 +239,7 @@ class MeshExportTest1(AbstractColladaTest):
outfile = tempdir / Path("%s_out.dae" % test) outfile = tempdir / Path("%s_out.dae" % test)
bpy.ops.wm.collada_export( bpy.ops.wm.collada_export(
filepath="%s" % str(outfile), filepath=str(outfile),
check_existing=True, check_existing=True,
filemode=8, filemode=8,
display_type='DEFAULT', display_type='DEFAULT',

View File

@ -107,7 +107,7 @@ class MeshExportTest(AbstractColladaTest):
outfile = tempdir / Path("%s_out.dae" % test) outfile = tempdir / Path("%s_out.dae" % test)
bpy.ops.wm.collada_export( bpy.ops.wm.collada_export(
filepath="%s" % str(outfile), filepath=str(outfile),
check_existing=True, check_existing=True,
filemode=8, filemode=8,
display_type="DEFAULT", display_type="DEFAULT",

View File

@ -1638,7 +1638,7 @@ class edit_generators:
): ):
edits.append(Edit( edits.append(Edit(
span=match.span(), span=match.span(),
content='%s' % match.group(2), content=match.group(2),
content_fail='__ALWAYS_FAIL__', content_fail='__ALWAYS_FAIL__',
)) ))