Outliner: Double-click on item icon to select contents/hierarchy #110151
11
GNUmakefile
11
GNUmakefile
|
@ -210,14 +210,17 @@ endif
|
|||
|
||||
# Find the newest Python version bundled in `LIBDIR`.
|
||||
PY_LIB_VERSION:=3.15
|
||||
ifeq (, $(wildcard $(LIBDIR)/python/lib/python$(PY_LIB_VERSION)))
|
||||
ifeq (, $(wildcard $(LIBDIR)/python/bin/python$(PY_LIB_VERSION)))
|
||||
PY_LIB_VERSION:=3.14
|
||||
ifeq (, $(wildcard $(LIBDIR)/python/lib/python$(PY_LIB_VERSION)))
|
||||
ifeq (, $(wildcard $(LIBDIR)/python/bin/python$(PY_LIB_VERSION)))
|
||||
PY_LIB_VERSION:=3.13
|
||||
ifeq (, $(wildcard $(LIBDIR)/python/lib/python$(PY_LIB_VERSION)))
|
||||
ifeq (, $(wildcard $(LIBDIR)/python/bin/python$(PY_LIB_VERSION)))
|
||||
PY_LIB_VERSION:=3.12
|
||||
ifeq (, $(wildcard $(LIBDIR)/python/lib/python$(PY_LIB_VERSION)))
|
||||
ifeq (, $(wildcard $(LIBDIR)/python/bin/python$(PY_LIB_VERSION)))
|
||||
PY_LIB_VERSION:=3.11
|
||||
ifeq (, $(wildcard $(LIBDIR)/python/bin/python$(PY_LIB_VERSION)))
|
||||
PY_LIB_VERSION:=3.10
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
|
|
@ -1247,6 +1247,7 @@ context_type_map = {
|
|||
"soft_body": ("SoftBodyModifier", False),
|
||||
"speaker": ("Speaker", False),
|
||||
"texture": ("Texture", False),
|
||||
"texture_node": ("Node", False),
|
||||
"texture_slot": ("TextureSlot", False),
|
||||
"texture_user": ("ID", False),
|
||||
"texture_user_property": ("Property", False),
|
||||
|
|
|
@ -16,7 +16,7 @@ from bpy.props import (
|
|||
)
|
||||
from bpy.app.translations import (
|
||||
contexts as i18n_contexts,
|
||||
pgettext_iface as iface_
|
||||
pgettext_rpt as rpt_
|
||||
)
|
||||
|
||||
from math import pi
|
||||
|
@ -1602,50 +1602,62 @@ class CyclesPreferences(bpy.types.AddonPreferences):
|
|||
|
||||
if not found_device:
|
||||
col = box.column(align=True)
|
||||
col.label(text="No compatible GPUs found for Cycles", icon='INFO')
|
||||
col.label(text=rpt_("No compatible GPUs found for Cycles"), icon='INFO', translate=False)
|
||||
|
||||
if device_type == 'CUDA':
|
||||
compute_capability = "3.0"
|
||||
col.label(text=iface_("Requires NVIDIA GPU with compute capability %s") % compute_capability,
|
||||
col.label(text=rpt_("Requires NVIDIA GPU with compute capability %s") % compute_capability,
|
||||
icon='BLANK1', translate=False)
|
||||
elif device_type == 'OPTIX':
|
||||
compute_capability = "5.0"
|
||||
driver_version = "470"
|
||||
col.label(text=iface_("Requires NVIDIA GPU with compute capability %s") % compute_capability,
|
||||
col.label(text=rpt_("Requires NVIDIA GPU with compute capability %s") % compute_capability,
|
||||
icon='BLANK1', translate=False)
|
||||
col.label(text=iface_("and NVIDIA driver version %s or newer") % driver_version,
|
||||
col.label(text=rpt_("and NVIDIA driver version %s or newer") % driver_version,
|
||||
icon='BLANK1', translate=False)
|
||||
elif device_type == 'HIP':
|
||||
import sys
|
||||
if sys.platform[:3] == "win":
|
||||
driver_version = "21.Q4"
|
||||
col.label(text="Requires AMD GPU with Vega or RDNA architecture", icon='BLANK1')
|
||||
col.label(text=iface_("and AMD Radeon Pro %s driver or newer") % driver_version,
|
||||
col.label(
|
||||
text=rpt_("Requires AMD GPU with Vega or RDNA architecture"),
|
||||
icon='BLANK1',
|
||||
translate=False)
|
||||
col.label(text=rpt_("and AMD Radeon Pro %s driver or newer") % driver_version,
|
||||
icon='BLANK1', translate=False)
|
||||
elif sys.platform.startswith("linux"):
|
||||
driver_version = "22.10"
|
||||
col.label(text="Requires AMD GPU with Vega or RDNA architecture", icon='BLANK1')
|
||||
col.label(text=iface_("and AMD driver version %s or newer") % driver_version, icon='BLANK1',
|
||||
col.label(
|
||||
text=rpt_("Requires AMD GPU with Vega or RDNA architecture"),
|
||||
icon='BLANK1',
|
||||
translate=False)
|
||||
col.label(text=rpt_("and AMD driver version %s or newer") % driver_version, icon='BLANK1',
|
||||
translate=False)
|
||||
elif device_type == 'ONEAPI':
|
||||
import sys
|
||||
if sys.platform.startswith("win"):
|
||||
driver_version = "XX.X.101.4824"
|
||||
col.label(text="Requires Intel GPU with Xe-HPG architecture", icon='BLANK1')
|
||||
col.label(text=iface_("and Windows driver version %s or newer") % driver_version,
|
||||
col.label(text=rpt_("Requires Intel GPU with Xe-HPG architecture"), icon='BLANK1', translate=False)
|
||||
col.label(text=rpt_("and Windows driver version %s or newer") % driver_version,
|
||||
icon='BLANK1', translate=False)
|
||||
elif sys.platform.startswith("linux"):
|
||||
driver_version = "XX.XX.25812.14"
|
||||
col.label(text="Requires Intel GPU with Xe-HPG architecture and", icon='BLANK1')
|
||||
col.label(text=" - intel-level-zero-gpu or intel-compute-runtime version", icon='BLANK1')
|
||||
col.label(text=iface_(" %s or newer") % driver_version, icon='BLANK1', translate=False)
|
||||
col.label(text=" - oneAPI Level-Zero Loader", icon='BLANK1')
|
||||
col.label(
|
||||
text=rpt_("Requires Intel GPU with Xe-HPG architecture and"),
|
||||
icon='BLANK1',
|
||||
translate=False)
|
||||
col.label(
|
||||
text=rpt_(" - intel-level-zero-gpu or intel-compute-runtime version"),
|
||||
icon='BLANK1',
|
||||
translate=False)
|
||||
col.label(text=rpt_(" %s or newer") % driver_version, icon='BLANK1', translate=False)
|
||||
col.label(text=rpt_(" - oneAPI Level-Zero Loader"), icon='BLANK1', translate=False)
|
||||
elif device_type == 'METAL':
|
||||
silicon_mac_version = "12.2"
|
||||
amd_mac_version = "12.3"
|
||||
col.label(text=iface_("Requires Apple Silicon with macOS %s or newer") % silicon_mac_version,
|
||||
col.label(text=rpt_("Requires Apple Silicon with macOS %s or newer") % silicon_mac_version,
|
||||
icon='BLANK1', translate=False)
|
||||
col.label(text=iface_("or AMD with macOS %s or newer") % amd_mac_version, icon='BLANK1',
|
||||
col.label(text=rpt_("or AMD with macOS %s or newer") % amd_mac_version, icon='BLANK1',
|
||||
translate=False)
|
||||
return
|
||||
|
||||
|
|
|
@ -2086,6 +2086,13 @@ static int memfd_create_sealed(const char *name)
|
|||
#endif /* !HAVE_MEMFD_CREATE */
|
||||
}
|
||||
|
||||
#if defined(WITH_GHOST_WAYLAND_LIBDECOR) && defined(WITH_VULKAN_BACKEND)
|
||||
int memfd_create_sealed_for_vulkan_hack(const char *name)
|
||||
{
|
||||
return memfd_create_sealed(name);
|
||||
}
|
||||
#endif
|
||||
|
||||
enum {
|
||||
GWL_IOR_READ = 1 << 0,
|
||||
GWL_IOR_WRITE = 1 << 1,
|
||||
|
|
|
@ -88,6 +88,13 @@ bool ghost_wl_dynload_libraries_init();
|
|||
void ghost_wl_dynload_libraries_exit();
|
||||
#endif
|
||||
|
||||
#if defined(WITH_GHOST_WAYLAND_LIBDECOR) && defined(WITH_VULKAN_BACKEND)
|
||||
/**
|
||||
* Needed for temporary buffer creation.
|
||||
*/
|
||||
int memfd_create_sealed_for_vulkan_hack(const char *name);
|
||||
#endif
|
||||
|
||||
struct GWL_Output {
|
||||
|
||||
/** Wayland core types. */
|
||||
|
|
|
@ -38,6 +38,10 @@
|
|||
# include <wayland_dynload_libdecor.h>
|
||||
# endif
|
||||
# include <libdecor.h>
|
||||
|
||||
# ifdef WITH_VULKAN_BACKEND
|
||||
# include <unistd.h> /* For `ftruncate`. */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Generated by `wayland-scanner`. */
|
||||
|
@ -1769,11 +1773,47 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
|
|||
|
||||
/* NOTE: LIBDECOR requires the window to be created & configured before the state can be set.
|
||||
* Workaround this by using the underlying `xdg_toplevel` */
|
||||
|
||||
# ifdef WITH_VULKAN_BACKEND
|
||||
/* A dummy buffer is needed for VULKAN & LIBDECOR,
|
||||
* otherwise `decor.initial_configure_seen` and startup locks up. */
|
||||
wl_buffer *dummy_buffer = nullptr;
|
||||
if (window_->ghost_context_type == GHOST_kDrawingContextTypeVulkan) {
|
||||
const uint32_t format = WL_SHM_FORMAT_ARGB8888;
|
||||
const int format_size = 4;
|
||||
const int buffer_size = (window_->frame.size[0] * window_->frame.size[1]) * format_size;
|
||||
const int fd = memfd_create_sealed_for_vulkan_hack("ghost-wl-dummy-buffer");
|
||||
ftruncate(fd, buffer_size);
|
||||
wl_shm *shm = system_->wl_shm_get();
|
||||
wl_shm_pool *pool = wl_shm_create_pool(shm, fd, buffer_size);
|
||||
dummy_buffer = wl_shm_pool_create_buffer(pool,
|
||||
0,
|
||||
window_->frame.size[0],
|
||||
window_->frame.size[1],
|
||||
window_->frame.size[0] * format_size,
|
||||
format);
|
||||
wl_shm_pool_destroy(pool);
|
||||
|
||||
wl_surface_attach(window_->wl.surface, dummy_buffer, 0, 0);
|
||||
wl_surface_damage(window_->wl.surface, 0, 0, window_->frame.size[0], window_->frame.size[1]);
|
||||
wl_surface_commit(window_->wl.surface);
|
||||
::close(fd);
|
||||
}
|
||||
# endif /* WITH_GHOST_WAYLAND_LIBDECOR */
|
||||
|
||||
while (!decor.initial_configure_seen) {
|
||||
wl_display_flush(system->wl_display_get());
|
||||
wl_display_dispatch(system->wl_display_get());
|
||||
}
|
||||
|
||||
# ifdef WITH_VULKAN_BACKEND
|
||||
if (window_->ghost_context_type == GHOST_kDrawingContextTypeVulkan) {
|
||||
wl_surface_attach(window_->wl.surface, nullptr, 0, 0);
|
||||
wl_surface_commit(window_->wl.surface);
|
||||
wl_buffer_destroy(dummy_buffer);
|
||||
}
|
||||
# endif /* WITH_GHOST_WAYLAND_LIBDECOR */
|
||||
|
||||
xdg_toplevel *toplevel = libdecor_frame_get_xdg_toplevel(decor.frame);
|
||||
gwl_window_state_set_for_xdg(toplevel, state, gwl_window_state_get(window_));
|
||||
}
|
||||
|
|
|
@ -573,6 +573,7 @@ def dump_py_messages_from_files(msgs, reports, files, settings):
|
|||
("pgettext", ("_",)),
|
||||
("pgettext_iface", ("iface_",)),
|
||||
("pgettext_tip", ("tip_",)),
|
||||
("pgettext_rpt", ("rpt_",)),
|
||||
("pgettext_data", ("data_",)),
|
||||
)
|
||||
pgettext_variants_args = {"msgid": (0, {"msgctxt": 1})}
|
||||
|
|
|
@ -243,14 +243,15 @@ _ctxt_re = _ctxt_re_gen("")
|
|||
_msg_re = r"(?P<msg_raw>" + _str_whole_re.format(_="_msg") + r")"
|
||||
PYGETTEXT_KEYWORDS = (() +
|
||||
tuple((r"{}\(\s*" + _msg_re + r"\s*\)").format(it)
|
||||
for it in ("IFACE_", "TIP_", "DATA_", "N_")) +
|
||||
for it in ("IFACE_", "TIP_", "RPT_", "DATA_", "N_")) +
|
||||
|
||||
tuple((r"{}\(\s*" + _ctxt_re + r"\s*,\s*" + _msg_re + r"\s*\)").format(it)
|
||||
for it in ("CTX_IFACE_", "CTX_TIP_", "CTX_DATA_", "CTX_N_")) +
|
||||
for it in ("CTX_IFACE_", "CTX_TIP_", "CTX_RPT_", "CTX_DATA_", "CTX_N_")) +
|
||||
|
||||
tuple(("{}\\((?:[^\"',]+,){{1,2}}\\s*" + _msg_re + r"\s*(?:\)|,)").format(it)
|
||||
for it in ("BKE_report", "BKE_reportf", "BKE_reports_prepend", "BKE_reports_prependf",
|
||||
"CTX_wm_operator_poll_msg_set", "WM_report", "WM_reportf")) +
|
||||
"CTX_wm_operator_poll_msg_set", "WM_report", "WM_reportf",
|
||||
"UI_but_disable")) +
|
||||
|
||||
# bmesh operator errors
|
||||
tuple(("{}\\((?:[^\"',]+,){{3}}\\s*" + _msg_re + r"\s*\)").format(it)
|
||||
|
|
|
@ -4594,6 +4594,8 @@ def km_grease_pencil_paint(_params):
|
|||
|
||||
# Show/hide
|
||||
*_template_items_hide_reveal_actions("grease_pencil.layer_hide", "grease_pencil.layer_reveal"),
|
||||
|
||||
("paint.sample_color", {"type": 'X', "value": 'PRESS', "shift": True}, None),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
|
|
@ -14,7 +14,7 @@ from bpy.props import (
|
|||
StringProperty,
|
||||
)
|
||||
from bpy.app.translations import (
|
||||
pgettext_tip as tip_,
|
||||
pgettext_rpt as rpt_,
|
||||
contexts as i18n_contexts,
|
||||
)
|
||||
|
||||
|
@ -114,7 +114,7 @@ class ANIM_OT_keying_set_export(Operator):
|
|||
if not found:
|
||||
self.report(
|
||||
{'WARN'},
|
||||
tip_("Could not find material or light using Shader Node Tree - %s") %
|
||||
rpt_("Could not find material or light using Shader Node Tree - %s") %
|
||||
(ksp.id))
|
||||
elif ksp.id.bl_rna.identifier.startswith("CompositorNodeTree"):
|
||||
# Find compositor node-tree using this node tree.
|
||||
|
@ -123,7 +123,7 @@ class ANIM_OT_keying_set_export(Operator):
|
|||
id_bpy_path = "bpy.data.scenes[\"%s\"].node_tree" % (scene.name)
|
||||
break
|
||||
else:
|
||||
self.report({'WARN'}, tip_("Could not find scene using Compositor Node Tree - %s") % (ksp.id))
|
||||
self.report({'WARN'}, rpt_("Could not find scene using Compositor Node Tree - %s") % (ksp.id))
|
||||
elif ksp.id.bl_rna.name == "Key":
|
||||
# "keys" conflicts with a Python keyword, hence the simple solution won't work
|
||||
id_bpy_path = "bpy.data.shape_keys[\"%s\"]" % (ksp.id.name)
|
||||
|
@ -358,7 +358,7 @@ class ClearUselessActions(Operator):
|
|||
action.user_clear()
|
||||
removed += 1
|
||||
|
||||
self.report({'INFO'}, tip_("Removed %d empty and/or fake-user only Actions")
|
||||
self.report({'INFO'}, rpt_("Removed %d empty and/or fake-user only Actions")
|
||||
% removed)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
@ -443,7 +443,7 @@ class UpdateAnimatedTransformConstraint(Operator):
|
|||
print(log)
|
||||
text = bpy.data.texts.new("UpdateAnimatedTransformConstraint Report")
|
||||
text.from_string(log)
|
||||
self.report({'INFO'}, tip_("Complete report available on '%s' text datablock") % text.name)
|
||||
self.report({'INFO'}, rpt_("Complete report available on '%s' text datablock") % text.name)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import bpy
|
|||
from bpy.types import Operator
|
||||
from bpy.app.translations import (
|
||||
pgettext_data as data_,
|
||||
pgettext_tip as tip_,
|
||||
pgettext_rpt as rpt_,
|
||||
)
|
||||
|
||||
|
||||
|
@ -125,7 +125,7 @@ class ASSET_OT_open_containing_blend_file(Operator):
|
|||
return {'RUNNING_MODAL'}
|
||||
|
||||
if returncode:
|
||||
self.report({'WARNING'}, tip_("Blender sub-process exited with error code %d") % returncode)
|
||||
self.report({'WARNING'}, rpt_("Blender sub-process exited with error code %d") % returncode)
|
||||
|
||||
if bpy.ops.asset.library_refresh.poll():
|
||||
bpy.ops.asset.library_refresh()
|
||||
|
|
|
@ -9,7 +9,7 @@ from mathutils import (
|
|||
Vector,
|
||||
Matrix,
|
||||
)
|
||||
from bpy.app.translations import pgettext_tip as tip_
|
||||
from bpy.app.translations import pgettext_rpt as rpt_
|
||||
|
||||
|
||||
def CLIP_spaces_walk(context, all_screens, tarea, tspace, callback, *args):
|
||||
|
@ -197,7 +197,7 @@ class CLIP_OT_filter_tracks(Operator):
|
|||
|
||||
def execute(self, context):
|
||||
num_tracks = self._filter_values(context, self.track_threshold)
|
||||
self.report({'INFO'}, tip_("Identified %d problematic tracks") % num_tracks)
|
||||
self.report({'INFO'}, rpt_("Identified %d problematic tracks") % num_tracks)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ from bpy.props import (
|
|||
CollectionProperty,
|
||||
StringProperty,
|
||||
)
|
||||
from bpy.app.translations import pgettext_tip as tip_
|
||||
from bpy.app.translations import pgettext_rpt as rpt_
|
||||
|
||||
# ########## Datablock previews... ##########
|
||||
|
||||
|
@ -126,7 +126,7 @@ class WM_OT_previews_batch_generate(Operator):
|
|||
if not self.use_backups:
|
||||
cmd.append("--no_backups")
|
||||
if subprocess.call(cmd):
|
||||
self.report({'ERROR'}, tip_("Previews generation process failed for file '%s'!") % blen_path)
|
||||
self.report({'ERROR'}, rpt_("Previews generation process failed for file '%s'!") % blen_path)
|
||||
context.window_manager.progress_end()
|
||||
return {'CANCELLED'}
|
||||
context.window_manager.progress_update(i + 1)
|
||||
|
@ -237,7 +237,7 @@ class WM_OT_previews_batch_clear(Operator):
|
|||
if not self.use_backups:
|
||||
cmd.append("--no_backups")
|
||||
if subprocess.call(cmd):
|
||||
self.report({'ERROR'}, tip_("Previews clear process failed for file '%s'!") % blen_path)
|
||||
self.report({'ERROR'}, rpt_("Previews clear process failed for file '%s'!") % blen_path)
|
||||
context.window_manager.progress_end()
|
||||
return {'CANCELLED'}
|
||||
context.window_manager.progress_update(i + 1)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
import bpy
|
||||
from bpy.types import Operator
|
||||
from bpy.props import StringProperty
|
||||
from bpy.app.translations import pgettext_tip as tip_
|
||||
from bpy.app.translations import pgettext_rpt as rpt_
|
||||
|
||||
|
||||
class EditExternally(Operator):
|
||||
|
@ -55,7 +55,7 @@ class EditExternally(Operator):
|
|||
|
||||
if not os.path.exists(filepath) or not os.path.isfile(filepath):
|
||||
self.report({'ERROR'},
|
||||
tip_("Image path %r not found, image may be packed or "
|
||||
rpt_("Image path %r not found, image may be packed or "
|
||||
"unsaved") % filepath)
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
@ -182,7 +182,7 @@ class ProjectApply(Operator):
|
|||
image_name = ProjectEdit._proj_hack[0] # TODO, deal with this nicer
|
||||
image = bpy.data.images.get((image_name, None))
|
||||
if image is None:
|
||||
self.report({'ERROR'}, tip_("Could not find image '%s'") % image_name)
|
||||
self.report({'ERROR'}, rpt_("Could not find image '%s'") % image_name)
|
||||
return {'CANCELLED'}
|
||||
|
||||
image.reload()
|
||||
|
|
|
@ -9,7 +9,7 @@ from bpy.props import (
|
|||
EnumProperty,
|
||||
IntProperty,
|
||||
)
|
||||
from bpy.app.translations import pgettext_tip as tip_
|
||||
from bpy.app.translations import pgettext_rpt as rpt_
|
||||
|
||||
|
||||
class MeshMirrorUV(Operator):
|
||||
|
@ -169,18 +169,18 @@ class MeshMirrorUV(Operator):
|
|||
|
||||
if total_duplicates and total_no_active_UV:
|
||||
self.report({'WARNING'},
|
||||
tip_("%d mesh(es) with no active UV layer, "
|
||||
rpt_("%d mesh(es) with no active UV layer, "
|
||||
"%d duplicates found in %d mesh(es), mirror may be incomplete")
|
||||
% (total_no_active_UV,
|
||||
total_duplicates,
|
||||
meshes_with_duplicates))
|
||||
elif total_no_active_UV:
|
||||
self.report({'WARNING'},
|
||||
tip_("%d mesh(es) with no active UV layer")
|
||||
rpt_("%d mesh(es) with no active UV layer")
|
||||
% (total_no_active_UV,))
|
||||
elif total_duplicates:
|
||||
self.report({'WARNING'},
|
||||
tip_("%d duplicates found in %d mesh(es), mirror may be incomplete")
|
||||
rpt_("%d duplicates found in %d mesh(es), mirror may be incomplete")
|
||||
% (total_duplicates, meshes_with_duplicates))
|
||||
|
||||
return {'FINISHED'}
|
||||
|
|
|
@ -20,7 +20,10 @@ from mathutils import (
|
|||
Vector,
|
||||
)
|
||||
|
||||
from bpy.app.translations import pgettext_tip as tip_
|
||||
from bpy.app.translations import (
|
||||
pgettext_tip as tip_,
|
||||
pgettext_rpt as rpt_,
|
||||
)
|
||||
|
||||
|
||||
class NodeSetting(PropertyGroup):
|
||||
|
@ -94,7 +97,7 @@ class NodeAddOperator:
|
|||
except AttributeError as ex:
|
||||
self.report(
|
||||
{'ERROR_INVALID_INPUT'},
|
||||
tip_("Node has no attribute %s") % setting.name)
|
||||
rpt_("Node has no attribute %s") % setting.name)
|
||||
print(str(ex))
|
||||
# Continue despite invalid attribute
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ from bpy.props import (
|
|||
IntProperty,
|
||||
StringProperty,
|
||||
)
|
||||
from bpy.app.translations import pgettext_tip as tip_
|
||||
from bpy.app.translations import pgettext_rpt as rpt_
|
||||
|
||||
|
||||
class SelectPattern(Operator):
|
||||
|
@ -367,12 +367,12 @@ class ShapeTransfer(Operator):
|
|||
for ob_other in objects:
|
||||
if ob_other.type != 'MESH':
|
||||
self.report({'WARNING'},
|
||||
tip_("Skipping '%s', not a mesh") % ob_other.name)
|
||||
rpt_("Skipping '%s', not a mesh") % ob_other.name)
|
||||
continue
|
||||
me_other = ob_other.data
|
||||
if len(me_other.vertices) != len(me.vertices):
|
||||
self.report({'WARNING'},
|
||||
tip_("Skipping '%s', vertex count differs") % ob_other.name)
|
||||
rpt_("Skipping '%s', vertex count differs") % ob_other.name)
|
||||
continue
|
||||
|
||||
target_normals = me_nos(me_other.vertices)
|
||||
|
@ -511,7 +511,7 @@ class JoinUVs(Operator):
|
|||
|
||||
if not mesh.uv_layers:
|
||||
self.report({'WARNING'},
|
||||
tip_("Object: %s, Mesh: '%s' has no UVs")
|
||||
rpt_("Object: %s, Mesh: '%s' has no UVs")
|
||||
% (obj.name, mesh.name))
|
||||
else:
|
||||
nbr_loops = len(mesh.loops)
|
||||
|
@ -535,7 +535,7 @@ class JoinUVs(Operator):
|
|||
|
||||
if len(mesh_other.loops) != nbr_loops:
|
||||
self.report({'WARNING'},
|
||||
tip_("Object: %s, Mesh: "
|
||||
rpt_("Object: %s, Mesh: "
|
||||
"'%s' has %d loops (for %d faces),"
|
||||
" expected %d\n")
|
||||
% (obj_other.name,
|
||||
|
@ -552,7 +552,7 @@ class JoinUVs(Operator):
|
|||
uv_other = mesh_other.uv_layers.active
|
||||
if not uv_other:
|
||||
self.report({'ERROR'},
|
||||
tip_("Could not add "
|
||||
rpt_("Could not add "
|
||||
"a new UV map to object "
|
||||
"'%s' (Mesh '%s')\n")
|
||||
% (obj_other.name,
|
||||
|
@ -795,7 +795,7 @@ class TransformsToDeltasAnim(Operator):
|
|||
adt = obj.animation_data
|
||||
if (adt is None) or (adt.action is None):
|
||||
self.report({'WARNING'},
|
||||
tip_("No animation data to convert on object: %r")
|
||||
rpt_("No animation data to convert on object: %r")
|
||||
% obj.name)
|
||||
continue
|
||||
|
||||
|
@ -822,7 +822,7 @@ class TransformsToDeltasAnim(Operator):
|
|||
if fcu.array_index in existingFCurves[dpath]:
|
||||
# conflict
|
||||
self.report({'ERROR'},
|
||||
tip_("Object '%r' already has '%r' F-Curve(s). "
|
||||
rpt_("Object '%r' already has '%r' F-Curve(s). "
|
||||
"Remove these before trying again") %
|
||||
(obj.name, dpath))
|
||||
return {'CANCELLED'}
|
||||
|
|
|
@ -12,7 +12,7 @@ from bpy.props import (
|
|||
IntProperty,
|
||||
)
|
||||
from bpy.app.translations import (
|
||||
pgettext_tip as tip_,
|
||||
pgettext_rpt as rpt_,
|
||||
pgettext_data as data_,
|
||||
)
|
||||
|
||||
|
@ -282,7 +282,7 @@ class QuickExplode(ObjectModeOperator, Operator):
|
|||
for obj in mesh_objects:
|
||||
if obj.particle_systems:
|
||||
self.report({'ERROR'},
|
||||
tip_("Object %r already has a "
|
||||
rpt_("Object %r already has a "
|
||||
"particle system") % obj.name)
|
||||
|
||||
return {'CANCELLED'}
|
||||
|
|
|
@ -13,7 +13,7 @@ from bpy.props import (
|
|||
StringProperty,
|
||||
)
|
||||
from bpy.app.translations import (
|
||||
pgettext_tip as tip_,
|
||||
pgettext_rpt as rpt_,
|
||||
pgettext_data as data_,
|
||||
)
|
||||
|
||||
|
@ -191,7 +191,7 @@ class AddPresetBase:
|
|||
else:
|
||||
os.remove(filepath)
|
||||
except BaseException as ex:
|
||||
self.report({'ERROR'}, tip_("Unable to remove preset: %r") % ex)
|
||||
self.report({'ERROR'}, rpt_("Unable to remove preset: %r") % ex)
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return {'CANCELLED'}
|
||||
|
@ -241,7 +241,7 @@ class ExecutePreset(Operator):
|
|||
ext = splitext(filepath)[1].lower()
|
||||
|
||||
if ext not in {".py", ".xml"}:
|
||||
self.report({'ERROR'}, tip_("Unknown file type: %r") % ext)
|
||||
self.report({'ERROR'}, rpt_("Unknown file type: %r") % ext)
|
||||
return {'CANCELLED'}
|
||||
|
||||
if hasattr(preset_class, "reset_cb"):
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import bpy
|
||||
from bpy.types import Operator
|
||||
from bpy.app.translations import pgettext_tip as tip_
|
||||
from bpy.app.translations import pgettext_rpt as rpt_
|
||||
|
||||
|
||||
def guess_player_path(preset):
|
||||
|
@ -119,7 +119,7 @@ class PlayRenderedAnim(Operator):
|
|||
file = rd.frame_path(frame=scene.frame_start, preview=scene.use_preview_range, view=view_suffix)
|
||||
file = bpy.path.abspath(file) # expand '//'
|
||||
if not os.path.exists(file):
|
||||
err_msg = tip_("File %r not found") % file
|
||||
err_msg = rpt_("File %r not found") % file
|
||||
self.report({'WARNING'}, err_msg)
|
||||
path_valid = False
|
||||
|
||||
|
@ -127,7 +127,7 @@ class PlayRenderedAnim(Operator):
|
|||
if scene.use_preview_range and not path_valid:
|
||||
file = rd.frame_path(frame=scene.frame_start, preview=False, view=view_suffix)
|
||||
file = bpy.path.abspath(file) # expand '//'
|
||||
err_msg = tip_("File %r not found") % file
|
||||
err_msg = rpt_("File %r not found") % file
|
||||
if not os.path.exists(file):
|
||||
self.report({'WARNING'}, err_msg)
|
||||
|
||||
|
@ -195,7 +195,7 @@ class PlayRenderedAnim(Operator):
|
|||
try:
|
||||
subprocess.Popen(cmd)
|
||||
except BaseException as ex:
|
||||
err_msg = tip_("Couldn't run external animation player with command %r\n%s") % (cmd, ex)
|
||||
err_msg = rpt_("Couldn't run external animation player with command %r\n%s") % (cmd, ex)
|
||||
self.report(
|
||||
{'ERROR'},
|
||||
err_msg,
|
||||
|
|
|
@ -10,7 +10,7 @@ from bpy.props import (
|
|||
FloatProperty,
|
||||
IntProperty,
|
||||
)
|
||||
from bpy.app.translations import pgettext_tip as tip_
|
||||
from bpy.app.translations import pgettext_rpt as rpt_
|
||||
|
||||
|
||||
class SequencerCrossfadeSounds(Operator):
|
||||
|
@ -236,7 +236,7 @@ class SequencerFadesAdd(Operator):
|
|||
sequence.invalidate_cache('COMPOSITE')
|
||||
|
||||
sequence_string = "sequence" if len(faded_sequences) == 1 else "sequences"
|
||||
self.report({'INFO'}, tip_("Added fade animation to %d %s") % (len(faded_sequences), sequence_string))
|
||||
self.report({'INFO'}, rpt_("Added fade animation to %d %s") % (len(faded_sequences), sequence_string))
|
||||
return {'FINISHED'}
|
||||
|
||||
def calculate_fade_duration(self, context, sequence):
|
||||
|
|
|
@ -16,7 +16,7 @@ from bpy.props import (
|
|||
)
|
||||
from bpy.app.translations import (
|
||||
pgettext_iface as iface_,
|
||||
pgettext_tip as tip_,
|
||||
pgettext_tip as rpt_,
|
||||
)
|
||||
|
||||
|
||||
|
@ -229,7 +229,7 @@ class PREFERENCES_OT_keyconfig_import(Operator):
|
|||
else:
|
||||
shutil.move(self.filepath, path)
|
||||
except BaseException as ex:
|
||||
self.report({'ERROR'}, tip_("Installing keymap failed: %s") % ex)
|
||||
self.report({'ERROR'}, rpt_("Installing keymap failed: %s") % ex)
|
||||
return {'CANCELLED'}
|
||||
|
||||
# sneaky way to check we're actually running the code.
|
||||
|
@ -455,7 +455,7 @@ class PREFERENCES_OT_addon_enable(Operator):
|
|||
if info_ver > bpy.app.version:
|
||||
self.report(
|
||||
{'WARNING'},
|
||||
tip_("This script was written Blender "
|
||||
rpt_("This script was written Blender "
|
||||
"version %d.%d.%d and might not "
|
||||
"function (correctly), "
|
||||
"though it is enabled")
|
||||
|
@ -543,7 +543,7 @@ class PREFERENCES_OT_theme_install(Operator):
|
|||
|
||||
if not self.overwrite:
|
||||
if os.path.exists(path_dest):
|
||||
self.report({'WARNING'}, tip_("File already installed to %r\n") % path_dest)
|
||||
self.report({'WARNING'}, rpt_("File already installed to %r\n") % path_dest)
|
||||
return {'CANCELLED'}
|
||||
|
||||
try:
|
||||
|
@ -657,7 +657,7 @@ class PREFERENCES_OT_addon_install(Operator):
|
|||
pyfile_dir = os.path.dirname(pyfile)
|
||||
for addon_path in addon_utils.paths():
|
||||
if os.path.samefile(pyfile_dir, addon_path):
|
||||
self.report({'ERROR'}, tip_("Source file is in the add-on search path: %r") % addon_path)
|
||||
self.report({'ERROR'}, rpt_("Source file is in the add-on search path: %r") % addon_path)
|
||||
return {'CANCELLED'}
|
||||
del addon_path
|
||||
del pyfile_dir
|
||||
|
@ -681,7 +681,7 @@ class PREFERENCES_OT_addon_install(Operator):
|
|||
for f in file_to_extract_root:
|
||||
path_dest = os.path.join(path_addons, os.path.basename(f))
|
||||
if os.path.exists(path_dest):
|
||||
self.report({'WARNING'}, tip_("File already installed to %r\n") % path_dest)
|
||||
self.report({'WARNING'}, rpt_("File already installed to %r\n") % path_dest)
|
||||
return {'CANCELLED'}
|
||||
|
||||
try: # extract the file to "addons"
|
||||
|
@ -696,7 +696,7 @@ class PREFERENCES_OT_addon_install(Operator):
|
|||
if self.overwrite:
|
||||
_module_filesystem_remove(path_addons, os.path.basename(pyfile))
|
||||
elif os.path.exists(path_dest):
|
||||
self.report({'WARNING'}, tip_("File already installed to %r\n") % path_dest)
|
||||
self.report({'WARNING'}, rpt_("File already installed to %r\n") % path_dest)
|
||||
return {'CANCELLED'}
|
||||
|
||||
# if not compressed file just copy into the addon path
|
||||
|
@ -731,7 +731,7 @@ class PREFERENCES_OT_addon_install(Operator):
|
|||
|
||||
# print message
|
||||
msg = (
|
||||
tip_("Modules Installed (%s) from %r into %r") %
|
||||
rpt_("Modules Installed (%s) from %r into %r") %
|
||||
(", ".join(sorted(addons_new)), pyfile, path_addons)
|
||||
)
|
||||
print(msg)
|
||||
|
@ -776,7 +776,7 @@ class PREFERENCES_OT_addon_remove(Operator):
|
|||
|
||||
path, isdir = PREFERENCES_OT_addon_remove.path_from_addon(self.module)
|
||||
if path is None:
|
||||
self.report({'WARNING'}, tip_("Add-on path %r could not be found") % path)
|
||||
self.report({'WARNING'}, rpt_("Add-on path %r could not be found") % path)
|
||||
return {'CANCELLED'}
|
||||
|
||||
# in case its enabled
|
||||
|
@ -926,7 +926,7 @@ class PREFERENCES_OT_app_template_install(Operator):
|
|||
for f in file_to_extract_root:
|
||||
path_dest = os.path.join(path_app_templates, os.path.basename(f))
|
||||
if os.path.exists(path_dest):
|
||||
self.report({'WARNING'}, tip_("File already installed to %r\n") % path_dest)
|
||||
self.report({'WARNING'}, rpt_("File already installed to %r\n") % path_dest)
|
||||
return {'CANCELLED'}
|
||||
|
||||
try: # extract the file to "bl_app_templates_user"
|
||||
|
@ -937,7 +937,7 @@ class PREFERENCES_OT_app_template_install(Operator):
|
|||
|
||||
else:
|
||||
# Only support installing zip-files.
|
||||
self.report({'WARNING'}, tip_("Expected a zip-file %r\n") % filepath)
|
||||
self.report({'WARNING'}, rpt_("Expected a zip-file %r\n") % filepath)
|
||||
return {'CANCELLED'}
|
||||
|
||||
app_templates_new = set(os.listdir(path_app_templates)) - app_templates_old
|
||||
|
@ -947,7 +947,7 @@ class PREFERENCES_OT_app_template_install(Operator):
|
|||
|
||||
# print message
|
||||
msg = (
|
||||
tip_("Template Installed (%s) from %r into %r") %
|
||||
rpt_("Template Installed (%s) from %r into %r") %
|
||||
(", ".join(sorted(app_templates_new)), filepath, path_app_templates)
|
||||
)
|
||||
print(msg)
|
||||
|
@ -1011,7 +1011,7 @@ class PREFERENCES_OT_studiolight_install(Operator):
|
|||
|
||||
# print message
|
||||
msg = (
|
||||
tip_("StudioLight Installed %r into %r") %
|
||||
rpt_("StudioLight Installed %r into %r") %
|
||||
(", ".join(e.name for e in self.files), path_studiolights)
|
||||
)
|
||||
print(msg)
|
||||
|
@ -1069,7 +1069,7 @@ class PREFERENCES_OT_studiolight_new(Operator):
|
|||
|
||||
# print message
|
||||
msg = (
|
||||
tip_("StudioLight Installed %r into %r") %
|
||||
rpt_("StudioLight Installed %r into %r") %
|
||||
(self.filename, str(path_studiolights))
|
||||
)
|
||||
print(msg)
|
||||
|
|
|
@ -23,6 +23,7 @@ from bpy.props import (
|
|||
from bpy.app.translations import (
|
||||
pgettext_iface as iface_,
|
||||
pgettext_tip as tip_,
|
||||
pgettext_rpt as rpt_,
|
||||
contexts as i18n_contexts,
|
||||
)
|
||||
|
||||
|
@ -778,7 +779,7 @@ class WM_OT_operator_pie_enum(Operator):
|
|||
try:
|
||||
op_rna = op.get_rna_type()
|
||||
except KeyError:
|
||||
self.report({'ERROR'}, tip_("Operator not found: bpy.ops.%s") % data_path)
|
||||
self.report({'ERROR'}, rpt_("Operator not found: bpy.ops.%s") % data_path)
|
||||
return {'CANCELLED'}
|
||||
|
||||
def draw_cb(self, context):
|
||||
|
@ -878,7 +879,7 @@ class WM_OT_context_collection_boolean_set(Operator):
|
|||
elif value_orig is False:
|
||||
pass
|
||||
else:
|
||||
self.report({'WARNING'}, tip_("Non boolean value found: %s[ ].%s") %
|
||||
self.report({'WARNING'}, rpt_("Non boolean value found: %s[ ].%s") %
|
||||
(data_path_iter, data_path_item))
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
@ -981,7 +982,7 @@ class WM_OT_context_modal_mouse(Operator):
|
|||
(item, ) = self._values.keys()
|
||||
header_text = header_text % eval("item.%s" % self.data_path_item)
|
||||
else:
|
||||
header_text = (self.header_text % delta) + tip_(" (delta)")
|
||||
header_text = (self.header_text % delta) + rpt_(" (delta)")
|
||||
context.area.header_text_set(header_text)
|
||||
|
||||
elif 'LEFTMOUSE' == event_type:
|
||||
|
@ -1001,7 +1002,7 @@ class WM_OT_context_modal_mouse(Operator):
|
|||
self._values_store(context)
|
||||
|
||||
if not self._values:
|
||||
self.report({'WARNING'}, tip_("Nothing to operate on: %s[ ].%s") %
|
||||
self.report({'WARNING'}, rpt_("Nothing to operate on: %s[ ].%s") %
|
||||
(self.data_path_iter, self.data_path_item))
|
||||
|
||||
return {'CANCELLED'}
|
||||
|
@ -1168,7 +1169,7 @@ class WM_OT_path_open(Operator):
|
|||
filepath = os.path.normpath(filepath)
|
||||
|
||||
if not os.path.exists(filepath):
|
||||
self.report({'ERROR'}, tip_("File '%s' not found") % filepath)
|
||||
self.report({'ERROR'}, rpt_("File '%s' not found") % filepath)
|
||||
return {'CANCELLED'}
|
||||
|
||||
if sys.platform[:3] == "win":
|
||||
|
@ -1239,7 +1240,7 @@ def _wm_doc_get_id(doc_id, *, do_url=True, url_prefix="", report=None):
|
|||
|
||||
if rna_class is None:
|
||||
if report is not None:
|
||||
report({'ERROR'}, tip_("Type \"%s\" can not be found") % class_name)
|
||||
report({'ERROR'}, rpt_("Type \"%s\" can not be found") % class_name)
|
||||
return None
|
||||
|
||||
# Detect if this is a inherited member and use that name instead.
|
||||
|
@ -1334,7 +1335,7 @@ class WM_OT_doc_view_manual(Operator):
|
|||
if url is None:
|
||||
self.report(
|
||||
{'WARNING'},
|
||||
tip_("No reference available %r, "
|
||||
rpt_("No reference available %r, "
|
||||
"Update info in 'rna_manual_reference.py' "
|
||||
"or callback to bpy.utils.manual_map()") %
|
||||
self.doc_id
|
||||
|
@ -2317,7 +2318,7 @@ class WM_OT_tool_set_by_id(Operator):
|
|||
tool_settings.workspace_tool_type = 'FALLBACK'
|
||||
return {'FINISHED'}
|
||||
else:
|
||||
self.report({'WARNING'}, tip_("Tool %r not found for space %r") % (self.name, space_type))
|
||||
self.report({'WARNING'}, rpt_("Tool %r not found for space %r") % (self.name, space_type))
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
||||
|
@ -3188,7 +3189,7 @@ class WM_OT_batch_rename(Operator):
|
|||
change_len += 1
|
||||
total_len += 1
|
||||
|
||||
self.report({'INFO'}, tip_("Renamed %d of %d %s") % (change_len, total_len, descr))
|
||||
self.report({'INFO'}, rpt_("Renamed %d of %d %s") % (change_len, total_len, descr))
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
|
|
@ -215,6 +215,7 @@ class NODE_MT_geometry_node_GEO_GEOMETRY_OPERATIONS(Menu):
|
|||
node_add_menu.add_node_type(layout, "GeometryNodeDeleteGeometry")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeDuplicateElements")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeMergeByDistance")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeSortElements")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeTransform")
|
||||
layout.separator()
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeSeparateComponents")
|
||||
|
|
|
@ -8,7 +8,7 @@ from rna_prop_ui import PropertyPanel
|
|||
|
||||
from bpy.app.translations import (
|
||||
pgettext_iface as iface_,
|
||||
pgettext_tip as tip_,
|
||||
pgettext_tip as rpt_,
|
||||
)
|
||||
|
||||
|
||||
|
@ -581,7 +581,7 @@ def draw_attribute_warnings(context, layout):
|
|||
if not colliding_names:
|
||||
return
|
||||
|
||||
layout.label(text=tip_("Name collisions: ") + ", ".join(set(colliding_names)),
|
||||
layout.label(text=rpt_("Name collisions: ") + ", ".join(set(colliding_names)),
|
||||
icon='ERROR', translate=False)
|
||||
|
||||
|
||||
|
|
|
@ -27,6 +27,15 @@ class GPENCIL_MT_material_context_menu(Menu):
|
|||
layout.operator("grease_pencil.material_unlock_all", icon='UNLOCKED', text="Unlock All")
|
||||
layout.operator("grease_pencil.material_lock_unselected", text="Lock Unselected")
|
||||
layout.operator("grease_pencil.material_lock_unused", text="Lock Unused")
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator(
|
||||
"grease_pencil.material_copy_to_object",
|
||||
text="Copy Material to Selected").only_active = True
|
||||
layout.operator("grease_pencil.material_copy_to_object",
|
||||
text="Copy All Materials to Selected").only_active = False
|
||||
|
||||
else:
|
||||
layout.operator("gpencil.material_reveal", icon='RESTRICT_VIEW_OFF', text="Show All")
|
||||
layout.operator("gpencil.material_hide", icon='RESTRICT_VIEW_ON', text="Hide Others").unselected = True
|
||||
|
|
|
@ -8,7 +8,7 @@ from bl_ui.utils import PresetPanel
|
|||
|
||||
from bpy.app.translations import (
|
||||
contexts as i18n_contexts,
|
||||
pgettext_tip as tip_,
|
||||
pgettext_iface as iface_,
|
||||
)
|
||||
|
||||
|
||||
|
@ -75,10 +75,10 @@ class RENDER_PT_format(RenderOutputButtonsPanel, Panel):
|
|||
custom_framerate = (fps_rate not in {23.98, 24, 25, 29.97, 30, 50, 59.94, 60, 120, 240})
|
||||
|
||||
if custom_framerate is True:
|
||||
fps_label_text = tip_("Custom (%.4g fps)") % fps_rate
|
||||
fps_label_text = iface_("Custom (%.4g fps)") % fps_rate
|
||||
show_framerate = True
|
||||
else:
|
||||
fps_label_text = tip_("%.4g fps") % fps_rate
|
||||
fps_label_text = iface_("%.4g fps") % fps_rate
|
||||
show_framerate = (preset_label == "Custom")
|
||||
|
||||
RENDER_PT_format._frame_rate_args_prev = args
|
||||
|
|
|
@ -8,6 +8,7 @@ from rna_prop_ui import PropertyPanel
|
|||
from bpy.app.translations import (
|
||||
contexts as i18n_contexts,
|
||||
pgettext_iface as iface_,
|
||||
pgettext_rpt as rpt_,
|
||||
)
|
||||
from bl_ui.utils import PresetPanel
|
||||
|
||||
|
@ -221,7 +222,7 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel):
|
|||
row.template_ID(psys, "settings", new="particle.new")
|
||||
|
||||
if part.is_fluid:
|
||||
layout.label(text=iface_("%d fluid particles for this frame") % part.count, translate=False)
|
||||
layout.label(text=rpt_("%d fluid particles for this frame") % part.count, translate=False)
|
||||
return
|
||||
|
||||
row = layout.row()
|
||||
|
@ -432,10 +433,10 @@ class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel, Panel):
|
|||
label = "ERROR"
|
||||
icon = 'ERROR'
|
||||
box.label(text=label, icon=icon)
|
||||
box.label(text=iface_("Iterations: %d .. %d (avg. %d)") %
|
||||
box.label(text=rpt_("Iterations: %d .. %d (avg. %d)") %
|
||||
(result.min_iterations, result.max_iterations, result.avg_iterations),
|
||||
translate=False)
|
||||
box.label(text=iface_("Error: %.5f .. %.5f (avg. %.5f)")
|
||||
box.label(text=rpt_("Error: %.5f .. %.5f (avg. %.5f)")
|
||||
% (result.min_error, result.max_error, result.avg_error),
|
||||
translate=False)
|
||||
|
||||
|
|
|
@ -1055,51 +1055,6 @@ class PHYSICS_PT_particles(PhysicButtonsPanel, Panel):
|
|||
split.operator("fluid.free_particles", text="Free Particles")
|
||||
|
||||
|
||||
class PHYSICS_PT_viscosity(PhysicButtonsPanel, Panel):
|
||||
bl_label = "Viscosity"
|
||||
bl_parent_id = "PHYSICS_PT_liquid"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
COMPAT_ENGINES = {
|
||||
'BLENDER_RENDER',
|
||||
'BLENDER_EEVEE',
|
||||
'BLENDER_EEVEE_NEXT',
|
||||
'BLENDER_WORKBENCH',
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
# Fluid viscosity only enabled for liquids
|
||||
if not PhysicButtonsPanel.poll_liquid_domain(context):
|
||||
return False
|
||||
|
||||
return (context.engine in cls.COMPAT_ENGINES)
|
||||
|
||||
def draw_header(self, context):
|
||||
md = context.fluid.domain_settings
|
||||
domain = context.fluid.domain_settings
|
||||
is_baking_any = domain.is_cache_baking_any
|
||||
has_baked_any = domain.has_cache_baked_any
|
||||
self.layout.enabled = not is_baking_any and not has_baked_any
|
||||
self.layout.prop(md, "use_viscosity", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
|
||||
domain = context.fluid.domain_settings
|
||||
layout.active = domain.use_viscosity
|
||||
|
||||
is_baking_any = domain.is_cache_baking_any
|
||||
has_baked_any = domain.has_cache_baked_any
|
||||
has_baked_data = domain.has_cache_baked_data
|
||||
|
||||
flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
|
||||
flow.enabled = not is_baking_any and not has_baked_any and not has_baked_data
|
||||
|
||||
col = flow.column(align=True)
|
||||
col.prop(domain, "viscosity_value", text="Strength")
|
||||
|
||||
|
||||
class PHYSICS_PT_diffusion(PhysicButtonsPanel, Panel):
|
||||
bl_label = "Diffusion"
|
||||
bl_parent_id = "PHYSICS_PT_liquid"
|
||||
|
@ -1152,6 +1107,51 @@ class PHYSICS_PT_diffusion(PhysicButtonsPanel, Panel):
|
|||
col.prop(domain, "surface_tension", text="Surface Tension")
|
||||
|
||||
|
||||
class PHYSICS_PT_viscosity(PhysicButtonsPanel, Panel):
|
||||
bl_label = "High Viscosity Solver"
|
||||
bl_parent_id = "PHYSICS_PT_diffusion"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
COMPAT_ENGINES = {
|
||||
'BLENDER_RENDER',
|
||||
'BLENDER_EEVEE',
|
||||
'BLENDER_EEVEE_NEXT',
|
||||
'BLENDER_WORKBENCH',
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
# Fluid viscosity only enabled for liquids
|
||||
if not PhysicButtonsPanel.poll_liquid_domain(context):
|
||||
return False
|
||||
|
||||
return (context.engine in cls.COMPAT_ENGINES)
|
||||
|
||||
def draw_header(self, context):
|
||||
md = context.fluid.domain_settings
|
||||
domain = context.fluid.domain_settings
|
||||
is_baking_any = domain.is_cache_baking_any
|
||||
has_baked_any = domain.has_cache_baked_any
|
||||
self.layout.enabled = not is_baking_any and not has_baked_any
|
||||
self.layout.prop(md, "use_viscosity", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
|
||||
domain = context.fluid.domain_settings
|
||||
layout.active = domain.use_viscosity
|
||||
|
||||
is_baking_any = domain.is_cache_baking_any
|
||||
has_baked_any = domain.has_cache_baked_any
|
||||
has_baked_data = domain.has_cache_baked_data
|
||||
|
||||
flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
|
||||
flow.enabled = not is_baking_any and not has_baked_any and not has_baked_data
|
||||
|
||||
col = flow.column(align=True)
|
||||
col.prop(domain, "viscosity_value", text="Strength")
|
||||
|
||||
|
||||
class PHYSICS_PT_guide(PhysicButtonsPanel, Panel):
|
||||
bl_label = "Guides"
|
||||
bl_parent_id = "PHYSICS_PT_fluid"
|
||||
|
@ -1625,8 +1625,8 @@ classes = (
|
|||
PHYSICS_PT_noise,
|
||||
PHYSICS_PT_fire,
|
||||
PHYSICS_PT_liquid,
|
||||
PHYSICS_PT_viscosity,
|
||||
PHYSICS_PT_diffusion,
|
||||
PHYSICS_PT_viscosity,
|
||||
PHYSICS_PT_particles,
|
||||
PHYSICS_PT_mesh,
|
||||
PHYSICS_PT_guide,
|
||||
|
|
|
@ -10,6 +10,7 @@ from bl_ui.space_view3d import (
|
|||
VIEW3D_PT_shading_options,
|
||||
)
|
||||
from bl_ui.utils import PresetPanel
|
||||
from bpy.app.translations import pgettext_rpt as rpt_
|
||||
|
||||
|
||||
class RenderButtonsPanel:
|
||||
|
@ -829,7 +830,7 @@ class RENDER_PT_eevee_indirect_lighting(RenderButtonsPanel, Panel):
|
|||
|
||||
cache_info = scene.eevee.gi_cache_info
|
||||
if cache_info:
|
||||
col.label(text=cache_info)
|
||||
col.label(text=rpt_(cache_info), translate=False)
|
||||
|
||||
col.prop(props, "gi_auto_bake")
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import bpy
|
|||
from bpy.types import Panel, Header, Menu, UIList
|
||||
from bpy.app.translations import (
|
||||
pgettext_iface as iface_,
|
||||
pgettext_rpt as rpt_,
|
||||
contexts as i18n_contexts,
|
||||
)
|
||||
from bl_ui.utils import PresetPanel
|
||||
|
@ -170,7 +171,7 @@ class CLIP_HT_header(Header):
|
|||
r = active_object.reconstruction
|
||||
|
||||
if r.is_valid and sc.view == 'CLIP':
|
||||
layout.label(text=iface_("Solve error: %.2f px") %
|
||||
layout.label(text=rpt_("Solve error: %.2f px") %
|
||||
(r.average_error),
|
||||
translate=False)
|
||||
|
||||
|
@ -769,7 +770,7 @@ class CLIP_PT_track(CLIP_PT_tracking_panel, Panel):
|
|||
layout.prop(act_track, "weight_stab")
|
||||
|
||||
if act_track.has_bundle:
|
||||
label_text = iface_("Average Error: %.2f px") % (act_track.average_error)
|
||||
label_text = rpt_("Average Error: %.2f px") % (act_track.average_error)
|
||||
layout.label(text=label_text, translate=False)
|
||||
|
||||
layout.use_property_split = False
|
||||
|
|
|
@ -11,6 +11,7 @@ from bpy.types import (
|
|||
from bpy.app.translations import (
|
||||
contexts as i18n_contexts,
|
||||
pgettext_iface as iface_,
|
||||
pgettext_rpt as rpt_,
|
||||
)
|
||||
from bl_ui.properties_grease_pencil_common import (
|
||||
AnnotationDataPanel,
|
||||
|
@ -1905,7 +1906,7 @@ class SEQUENCER_PT_mask(SequencerButtonsPanel, Panel):
|
|||
if mask:
|
||||
sta = mask.frame_start
|
||||
end = mask.frame_end
|
||||
layout.label(text=iface_("Original frame range: %d-%d (%d)") % (sta, end, end - sta + 1), translate=False)
|
||||
layout.label(text=rpt_("Original frame range: %d-%d (%d)") % (sta, end, end - sta + 1), translate=False)
|
||||
|
||||
|
||||
class SEQUENCER_PT_time(SequencerButtonsPanel, Panel):
|
||||
|
|
|
@ -11,7 +11,7 @@ from bpy.types import (
|
|||
from bpy.app.translations import (
|
||||
contexts as i18n_contexts,
|
||||
pgettext_iface as iface_,
|
||||
pgettext_tip as tip_,
|
||||
pgettext_rpt as rpt_,
|
||||
)
|
||||
from bl_ui.utils import PresetPanel
|
||||
|
||||
|
@ -260,6 +260,7 @@ class USERPREF_PT_interface_translation(InterfacePanel, CenterAlignMixIn, Panel)
|
|||
col.active = (bpy.app.translations.locale != "en_US")
|
||||
col.prop(view, "use_translate_tooltips", text="Tooltips")
|
||||
col.prop(view, "use_translate_interface", text="Interface")
|
||||
col.prop(view, "use_translate_reports", text="Reports")
|
||||
col.prop(view, "use_translate_new_dataname", text="New Data")
|
||||
|
||||
|
||||
|
@ -2239,11 +2240,11 @@ class USERPREF_PT_addons(AddOnPanel, Panel):
|
|||
if info["description"]:
|
||||
split = colsub.row().split(factor=0.15)
|
||||
split.label(text="Description:")
|
||||
split.label(text=tip_(info["description"]))
|
||||
split.label(text=iface_(info["description"]))
|
||||
if info["location"]:
|
||||
split = colsub.row().split(factor=0.15)
|
||||
split.label(text="Location:")
|
||||
split.label(text=tip_(info["location"]))
|
||||
split.label(text=iface_(info["location"]))
|
||||
if mod:
|
||||
split = colsub.row().split(factor=0.15)
|
||||
split.label(text="File:")
|
||||
|
@ -2259,7 +2260,7 @@ class USERPREF_PT_addons(AddOnPanel, Panel):
|
|||
if info["warning"]:
|
||||
split = colsub.row().split(factor=0.15)
|
||||
split.label(text="Warning:")
|
||||
split.label(text=" " + info["warning"], icon='ERROR')
|
||||
split.label(text=" " + iface_(info["warning"]), icon='ERROR')
|
||||
|
||||
user_addon = USERPREF_PT_addons.is_user_addon(mod, user_addon_paths)
|
||||
if info["doc_url"] or info.get("tracker_url"):
|
||||
|
@ -2370,7 +2371,7 @@ class StudioLightPanelMixin:
|
|||
layout.label(text=self.get_error_message())
|
||||
|
||||
def get_error_message(self):
|
||||
return tip_("No custom %s configured") % self.bl_label
|
||||
return rpt_("No custom %s configured") % self.bl_label
|
||||
|
||||
def draw_studio_light(self, layout, studio_light):
|
||||
box = layout.box()
|
||||
|
@ -2398,7 +2399,7 @@ class USERPREF_PT_studiolight_matcaps(StudioLightPanel, StudioLightPanelMixin, P
|
|||
layout.separator()
|
||||
|
||||
def get_error_message(self):
|
||||
return tip_("No custom MatCaps configured")
|
||||
return rpt_("No custom MatCaps configured")
|
||||
|
||||
|
||||
class USERPREF_PT_studiolight_world(StudioLightPanel, StudioLightPanelMixin, Panel):
|
||||
|
@ -2411,7 +2412,7 @@ class USERPREF_PT_studiolight_world(StudioLightPanel, StudioLightPanelMixin, Pan
|
|||
layout.separator()
|
||||
|
||||
def get_error_message(self):
|
||||
return tip_("No custom HDRIs configured")
|
||||
return rpt_("No custom HDRIs configured")
|
||||
|
||||
|
||||
class USERPREF_PT_studiolight_lights(StudioLightPanel, StudioLightPanelMixin, Panel):
|
||||
|
@ -2426,7 +2427,7 @@ class USERPREF_PT_studiolight_lights(StudioLightPanel, StudioLightPanelMixin, Pa
|
|||
layout.separator()
|
||||
|
||||
def get_error_message(self):
|
||||
return tip_("No custom Studio Lights configured")
|
||||
return rpt_("No custom Studio Lights configured")
|
||||
|
||||
|
||||
class USERPREF_PT_studiolight_light_editor(StudioLightPanel, Panel):
|
||||
|
|
|
@ -24,7 +24,7 @@ from bl_ui.space_toolsystem_common import (
|
|||
)
|
||||
from bpy.app.translations import (
|
||||
pgettext_iface as iface_,
|
||||
pgettext_tip as tip_,
|
||||
pgettext_rpt as rpt_,
|
||||
contexts as i18n_contexts,
|
||||
)
|
||||
|
||||
|
@ -2180,6 +2180,10 @@ class VIEW3D_MT_paint_grease_pencil(Menu):
|
|||
|
||||
layout.menu("VIEW3D_MT_edit_greasepencil_showhide")
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("paint.sample_color")
|
||||
|
||||
|
||||
class VIEW3D_MT_paint_gpencil(Menu):
|
||||
bl_label = "Paint"
|
||||
|
@ -2861,16 +2865,16 @@ class VIEW3D_MT_object_context_menu(Menu):
|
|||
props.data_path_item = "data.lens"
|
||||
props.input_scale = 0.1
|
||||
if obj.data.lens_unit == 'MILLIMETERS':
|
||||
props.header_text = tip_("Camera Focal Length: %.1fmm")
|
||||
props.header_text = rpt_("Camera Focal Length: %.1fmm")
|
||||
else:
|
||||
props.header_text = tip_("Camera Focal Length: %.1f\u00B0")
|
||||
props.header_text = rpt_("Camera Focal Length: %.1f\u00B0")
|
||||
|
||||
else:
|
||||
props = layout.operator("wm.context_modal_mouse", text="Camera Lens Scale")
|
||||
props.data_path_iter = "selected_editable_objects"
|
||||
props.data_path_item = "data.ortho_scale"
|
||||
props.input_scale = 0.01
|
||||
props.header_text = tip_("Camera Lens Scale: %.3f")
|
||||
props.header_text = rpt_("Camera Lens Scale: %.3f")
|
||||
|
||||
if not obj.data.dof.focus_object:
|
||||
if view and view.camera == obj and view.region_3d.view_perspective == 'CAMERA':
|
||||
|
@ -2880,7 +2884,7 @@ class VIEW3D_MT_object_context_menu(Menu):
|
|||
props.data_path_iter = "selected_editable_objects"
|
||||
props.data_path_item = "data.dof.focus_distance"
|
||||
props.input_scale = 0.02
|
||||
props.header_text = tip_("Focus Distance: %.3f")
|
||||
props.header_text = rpt_("Focus Distance: %.3f")
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
@ -2891,13 +2895,13 @@ class VIEW3D_MT_object_context_menu(Menu):
|
|||
props.data_path_iter = "selected_editable_objects"
|
||||
props.data_path_item = "data.extrude"
|
||||
props.input_scale = 0.01
|
||||
props.header_text = tip_("Extrude: %.3f")
|
||||
props.header_text = rpt_("Extrude: %.3f")
|
||||
|
||||
props = layout.operator("wm.context_modal_mouse", text="Adjust Offset")
|
||||
props.data_path_iter = "selected_editable_objects"
|
||||
props.data_path_item = "data.offset"
|
||||
props.input_scale = 0.01
|
||||
props.header_text = tip_("Offset: %.3f")
|
||||
props.header_text = rpt_("Offset: %.3f")
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
@ -2908,7 +2912,7 @@ class VIEW3D_MT_object_context_menu(Menu):
|
|||
props.data_path_iter = "selected_editable_objects"
|
||||
props.data_path_item = "empty_display_size"
|
||||
props.input_scale = 0.01
|
||||
props.header_text = tip_("Empty Display Size: %.3f")
|
||||
props.header_text = rpt_("Empty Display Size: %.3f")
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
@ -2926,36 +2930,36 @@ class VIEW3D_MT_object_context_menu(Menu):
|
|||
props.data_path_iter = "selected_editable_objects"
|
||||
props.data_path_item = "data.energy"
|
||||
props.input_scale = 1.0
|
||||
props.header_text = tip_("Light Power: %.3f")
|
||||
props.header_text = rpt_("Light Power: %.3f")
|
||||
|
||||
if light.type == 'AREA':
|
||||
if light.shape in {'RECTANGLE', 'ELLIPSE'}:
|
||||
props = layout.operator("wm.context_modal_mouse", text="Adjust Area Light X Size")
|
||||
props.data_path_iter = "selected_editable_objects"
|
||||
props.data_path_item = "data.size"
|
||||
props.header_text = tip_("Light Size X: %.3f")
|
||||
props.header_text = rpt_("Light Size X: %.3f")
|
||||
|
||||
props = layout.operator("wm.context_modal_mouse", text="Adjust Area Light Y Size")
|
||||
props.data_path_iter = "selected_editable_objects"
|
||||
props.data_path_item = "data.size_y"
|
||||
props.header_text = tip_("Light Size Y: %.3f")
|
||||
props.header_text = rpt_("Light Size Y: %.3f")
|
||||
else:
|
||||
props = layout.operator("wm.context_modal_mouse", text="Adjust Area Light Size")
|
||||
props.data_path_iter = "selected_editable_objects"
|
||||
props.data_path_item = "data.size"
|
||||
props.header_text = tip_("Light Size: %.3f")
|
||||
props.header_text = rpt_("Light Size: %.3f")
|
||||
|
||||
elif light.type in {'SPOT', 'POINT'}:
|
||||
props = layout.operator("wm.context_modal_mouse", text="Adjust Light Radius")
|
||||
props.data_path_iter = "selected_editable_objects"
|
||||
props.data_path_item = "data.shadow_soft_size"
|
||||
props.header_text = tip_("Light Radius: %.3f")
|
||||
props.header_text = rpt_("Light Radius: %.3f")
|
||||
|
||||
elif light.type == 'SUN':
|
||||
props = layout.operator("wm.context_modal_mouse", text="Adjust Sun Light Angle")
|
||||
props.data_path_iter = "selected_editable_objects"
|
||||
props.data_path_item = "data.angle"
|
||||
props.header_text = tip_("Light Angle: %.3f")
|
||||
props.header_text = rpt_("Light Angle: %.3f")
|
||||
|
||||
if light.type == 'SPOT':
|
||||
layout.separator()
|
||||
|
@ -2964,13 +2968,13 @@ class VIEW3D_MT_object_context_menu(Menu):
|
|||
props.data_path_iter = "selected_editable_objects"
|
||||
props.data_path_item = "data.spot_size"
|
||||
props.input_scale = 0.01
|
||||
props.header_text = tip_("Spot Size: %.2f")
|
||||
props.header_text = rpt_("Spot Size: %.2f")
|
||||
|
||||
props = layout.operator("wm.context_modal_mouse", text="Adjust Spot Light Blend")
|
||||
props.data_path_iter = "selected_editable_objects"
|
||||
props.data_path_item = "data.spot_blend"
|
||||
props.input_scale = -0.01
|
||||
props.header_text = tip_("Spot Blend: %.2f")
|
||||
props.header_text = rpt_("Spot Blend: %.2f")
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
@ -5827,6 +5831,7 @@ class VIEW3D_MT_edit_greasepencil_stroke(Menu):
|
|||
|
||||
layout.separator()
|
||||
|
||||
layout.menu("VIEW3D_MT_grease_pencil_assign_material")
|
||||
layout.operator("grease_pencil.set_active_material")
|
||||
|
||||
layout.separator()
|
||||
|
@ -8135,6 +8140,27 @@ class VIEW3D_MT_greasepencil_material_active(Menu):
|
|||
layout.operator("grease_pencil.set_material", text=mat.name, icon_value=icon).slot = mat.name
|
||||
|
||||
|
||||
class VIEW3D_MT_grease_pencil_assign_material(Menu):
|
||||
bl_label = "Assign Material"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
ob = context.active_object
|
||||
mat_active = ob.active_material
|
||||
|
||||
if len(ob.material_slots) == 0:
|
||||
row = layout.row()
|
||||
row.label(text="No Materials")
|
||||
row.enabled = False
|
||||
return
|
||||
|
||||
for slot in ob.material_slots:
|
||||
mat = slot.material
|
||||
if mat:
|
||||
layout.operator("grease_pencil.stroke_material_set", text=mat.name,
|
||||
icon='LAYER_ACTIVE' if mat == mat_active else 'BLANK1').material = mat.name
|
||||
|
||||
|
||||
class VIEW3D_MT_greasepencil_edit_context_menu(Menu):
|
||||
bl_label = ""
|
||||
|
||||
|
@ -8194,6 +8220,11 @@ class VIEW3D_MT_greasepencil_edit_context_menu(Menu):
|
|||
|
||||
col.separator()
|
||||
|
||||
col.menu("VIEW3D_MT_grease_pencil_assign_material")
|
||||
col.operator("grease_pencil.set_active_material", text="Set as Active Material")
|
||||
|
||||
col.separator()
|
||||
|
||||
col.menu("VIEW3D_MT_mirror")
|
||||
|
||||
|
||||
|
@ -8890,6 +8921,7 @@ classes = (
|
|||
VIEW3D_MT_gpencil_autoweights,
|
||||
VIEW3D_MT_gpencil_edit_context_menu,
|
||||
VIEW3D_MT_greasepencil_edit_context_menu,
|
||||
VIEW3D_MT_grease_pencil_assign_material,
|
||||
VIEW3D_MT_edit_greasepencil,
|
||||
VIEW3D_MT_edit_greasepencil_delete,
|
||||
VIEW3D_MT_edit_greasepencil_stroke,
|
||||
|
|
|
@ -375,7 +375,7 @@ bool insert_keyframe_direct(ReportList *reports,
|
|||
PointerRNA tmp_ptr;
|
||||
|
||||
if (RNA_path_resolve_property(&ptr, fcu->rna_path, &tmp_ptr, &prop) == false) {
|
||||
const char *idname = (ptr.owner_id) ? ptr.owner_id->name : TIP_("<No ID pointer>");
|
||||
const char *idname = (ptr.owner_id) ? ptr.owner_id->name : RPT_("<No ID pointer>");
|
||||
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
|
@ -529,7 +529,7 @@ int insert_keyframe(Main *bmain,
|
|||
reports,
|
||||
RPT_ERROR,
|
||||
"Could not insert keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)",
|
||||
(id) ? id->name : TIP_("<Missing ID block>"),
|
||||
(id) ? id->name : RPT_("<Missing ID block>"),
|
||||
rna_path);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -304,6 +304,10 @@ bool autokeyframe_property(bContext *C,
|
|||
return changed;
|
||||
}
|
||||
|
||||
if (driven) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (special) {
|
||||
/* NLA Strip property. */
|
||||
if (is_autokey_on(scene)) {
|
||||
|
@ -321,25 +325,6 @@ bool autokeyframe_property(bContext *C,
|
|||
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, nullptr);
|
||||
}
|
||||
}
|
||||
else if (driven) {
|
||||
/* Driver - Try to insert keyframe using the driver's input as the frame,
|
||||
* making it easier to set up corrective drivers.
|
||||
*/
|
||||
if (is_autokey_on(scene)) {
|
||||
ReportList *reports = CTX_wm_reports(C);
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
|
||||
changed = insert_keyframe_direct(reports,
|
||||
*ptr,
|
||||
prop,
|
||||
fcu,
|
||||
&anim_eval_context,
|
||||
eBezTriple_KeyframeType(ts->keyframe_type),
|
||||
nullptr,
|
||||
INSERTKEY_DRIVER);
|
||||
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, nullptr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ID *id = ptr->owner_id;
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
|
|
@ -218,8 +218,16 @@ bool BKE_collection_object_cyclic_check(struct Main *bmain,
|
|||
|
||||
struct ListBase BKE_collection_object_cache_get(struct Collection *collection);
|
||||
ListBase BKE_collection_object_cache_instanced_get(struct Collection *collection);
|
||||
/** Free the object cache of given `collection` and all of its ancestors (recursively). */
|
||||
void BKE_collection_object_cache_free(struct Collection *collection);
|
||||
/** Free the object cache of given `collection` and all of its ancestors (recursively).
|
||||
*
|
||||
* \param bmain: The Main database owning the collection. May be `nullptr`, only used if doing
|
||||
* depsgraph tagging.
|
||||
* \param id_create_flag: Flags controlling ID creation, used here to enable or
|
||||
* not depsgraph tagging of affected IDs (e.g. #LIB_ID_CREATE_NO_DEG_TAG would prevent depsgraph
|
||||
* tagging). */
|
||||
void BKE_collection_object_cache_free(const struct Main *bmain,
|
||||
struct Collection *collection,
|
||||
const int id_create_flag);
|
||||
/**
|
||||
* Free the object cache of all collections in given `bmain`, including master collections of
|
||||
* scenes.
|
||||
|
@ -261,7 +269,9 @@ bool BKE_collection_child_add(struct Main *bmain,
|
|||
struct Collection *parent,
|
||||
struct Collection *child);
|
||||
|
||||
bool BKE_collection_child_add_no_sync(struct Collection *parent, struct Collection *child);
|
||||
bool BKE_collection_child_add_no_sync(struct Main *bmain,
|
||||
struct Collection *parent,
|
||||
struct Collection *child);
|
||||
|
||||
bool BKE_collection_child_remove(struct Main *bmain,
|
||||
struct Collection *parent,
|
||||
|
|
|
@ -447,6 +447,7 @@ class MeshComponent : public GeometryComponent {
|
|||
|
||||
public:
|
||||
MeshComponent();
|
||||
MeshComponent(Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
|
||||
~MeshComponent();
|
||||
GeometryComponentPtr copy() const override;
|
||||
|
||||
|
@ -501,6 +502,8 @@ class PointCloudComponent : public GeometryComponent {
|
|||
|
||||
public:
|
||||
PointCloudComponent();
|
||||
PointCloudComponent(PointCloud *pointcloud,
|
||||
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
|
||||
~PointCloudComponent();
|
||||
GeometryComponentPtr copy() const override;
|
||||
|
||||
|
@ -561,6 +564,7 @@ class CurveComponent : public GeometryComponent {
|
|||
|
||||
public:
|
||||
CurveComponent();
|
||||
CurveComponent(Curves *curve, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
|
||||
~CurveComponent();
|
||||
GeometryComponentPtr copy() const override;
|
||||
|
||||
|
@ -602,6 +606,8 @@ class InstancesComponent : public GeometryComponent {
|
|||
|
||||
public:
|
||||
InstancesComponent();
|
||||
InstancesComponent(Instances *instances,
|
||||
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
|
||||
~InstancesComponent();
|
||||
GeometryComponentPtr copy() const override;
|
||||
|
||||
|
|
|
@ -818,7 +818,6 @@ void BKE_grease_pencil_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
|
|||
void BKE_grease_pencil_duplicate_drawing_array(const GreasePencil *grease_pencil_src,
|
||||
GreasePencil *grease_pencil_dst);
|
||||
|
||||
int BKE_grease_pencil_object_material_index_get(Object *ob, Material *ma);
|
||||
int BKE_grease_pencil_object_material_index_get_by_name(Object *ob, const char *name);
|
||||
Material *BKE_grease_pencil_object_material_new(Main *bmain,
|
||||
Object *ob,
|
||||
|
|
|
@ -114,6 +114,9 @@ bool BKE_object_material_slot_add(struct Main *bmain, struct Object *ob);
|
|||
bool BKE_object_material_slot_remove(struct Main *bmain, struct Object *ob);
|
||||
bool BKE_object_material_slot_used(struct Object *object, short actcol);
|
||||
|
||||
int BKE_object_material_index_get(Object *ob, Material *ma);
|
||||
int BKE_object_material_ensure(Main *bmain, Object *ob, Material *material);
|
||||
|
||||
struct Material *BKE_gpencil_material(struct Object *ob, short act);
|
||||
struct MaterialGPencilStyle *BKE_gpencil_material_settings(struct Object *ob, short act);
|
||||
|
||||
|
|
|
@ -1327,6 +1327,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
|
|||
#define GEO_NODE_BAKE 2120
|
||||
#define GEO_NODE_GET_NAMED_GRID 2121
|
||||
#define GEO_NODE_STORE_NAMED_GRID 2122
|
||||
#define GEO_NODE_SORT_ELEMENTS 2123
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
#include "DNA_node_types.h"
|
||||
|
||||
#include "BLI_vector.hh"
|
||||
|
@ -42,6 +44,8 @@ class bNodeTreeZone {
|
|||
|
||||
bool contains_node_recursively(const bNode &node) const;
|
||||
bool contains_zone_recursively(const bNodeTreeZone &other_zone) const;
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &stream, const bNodeTreeZone &zone);
|
||||
};
|
||||
|
||||
class bNodeTreeZones {
|
||||
|
@ -72,6 +76,8 @@ class bNodeTreeZones {
|
|||
* nested zone. For nodes that are at the root level, the returned list is empty.
|
||||
*/
|
||||
Vector<const bNodeTreeZone *> get_zone_stack_for_node(const int32_t node_id) const;
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &stream, const bNodeTreeZones &zones);
|
||||
};
|
||||
|
||||
const bNodeTreeZones *get_tree_zones(const bNodeTree &tree);
|
||||
|
|
|
@ -27,6 +27,7 @@ struct BlendWriter;
|
|||
struct Header;
|
||||
struct ID;
|
||||
struct IDRemapper;
|
||||
struct LayoutPanelState;
|
||||
struct LibraryForeachIDData;
|
||||
struct ListBase;
|
||||
struct Menu;
|
||||
|
@ -606,6 +607,14 @@ void BKE_screen_area_free(ScrArea *area);
|
|||
void BKE_region_callback_free_gizmomap_set(void (*callback)(wmGizmoMap *));
|
||||
void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(wmGizmoMap *));
|
||||
|
||||
/**
|
||||
* Get the layout panel state for the given idname. If it does not exist yet, initialize a new
|
||||
* panel state with the given default value.
|
||||
*/
|
||||
LayoutPanelState *BKE_panel_layout_panel_state_ensure(Panel *panel,
|
||||
const char *idname,
|
||||
bool default_closed);
|
||||
|
||||
/**
|
||||
* Find a region of type \a region_type in provided \a regionbase.
|
||||
*
|
||||
|
|
|
@ -3235,7 +3235,7 @@ static void animsys_create_action_track_strip(const AnimData *adt,
|
|||
/* Must set NLASTRIP_FLAG_USR_INFLUENCE, or else the default setting overrides, and influence
|
||||
* doesn't work.
|
||||
*/
|
||||
r_action_strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
|
||||
r_action_strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE | NLASTRIP_FLAG_NO_TIME_MAP;
|
||||
|
||||
const bool tweaking = (adt->flag & ADT_NLA_EDIT_ON) != 0;
|
||||
const bool soloing = (adt->flag & ADT_NLA_SOLO_TRACK) != 0;
|
||||
|
|
|
@ -137,7 +137,7 @@ bMotionPath *animviz_verify_motionpaths(ReportList *reports,
|
|||
(pchan) ? pchan->name : ob->id.name,
|
||||
avs->path_sf,
|
||||
avs->path_ef,
|
||||
(avs->path_sf == avs->path_ef) ? TIP_(", cannot have single-frame paths") : "");
|
||||
(avs->path_sf == avs->path_ef) ? RPT_(", cannot have single-frame paths") : "");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -936,29 +936,6 @@ void gather_attributes(const AttributeAccessor src_attributes,
|
|||
});
|
||||
}
|
||||
|
||||
static bool indices_are_range(const Span<int> indices, const IndexRange range)
|
||||
{
|
||||
if (indices.size() != range.size()) {
|
||||
return false;
|
||||
}
|
||||
return threading::parallel_reduce(
|
||||
range,
|
||||
4096,
|
||||
true,
|
||||
[&](const IndexRange range, const bool init) {
|
||||
if (!init) {
|
||||
return false;
|
||||
}
|
||||
for (const int i : range) {
|
||||
if (indices[i] != i) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
std::logical_and());
|
||||
}
|
||||
|
||||
void gather_attributes(const AttributeAccessor src_attributes,
|
||||
const AttrDomain domain,
|
||||
const AnonymousAttributePropagationInfo &propagation_info,
|
||||
|
@ -966,7 +943,7 @@ void gather_attributes(const AttributeAccessor src_attributes,
|
|||
const Span<int> indices,
|
||||
MutableAttributeAccessor dst_attributes)
|
||||
{
|
||||
if (indices_are_range(indices, IndexRange(src_attributes.domain_size(domain)))) {
|
||||
if (array_utils::indices_are_range(indices, IndexRange(src_attributes.domain_size(domain)))) {
|
||||
copy_attributes(src_attributes, domain, propagation_info, skip, dst_attributes);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -61,27 +61,35 @@ static CLG_LogRef LOG = {"bke.collection"};
|
|||
/** \name Prototypes
|
||||
* \{ */
|
||||
|
||||
static bool collection_child_add(Collection *parent,
|
||||
/** \param id_create_flag: Creation/Copy ID management flags, e.g. #LIB_ID_CREATE_NO_MAIN. */
|
||||
static bool collection_child_add(Main *bmain,
|
||||
Collection *parent,
|
||||
Collection *collection,
|
||||
CollectionLightLinking *light_linking,
|
||||
const int flag,
|
||||
const int id_create_flag,
|
||||
const bool add_us);
|
||||
static bool collection_child_remove(Collection *parent, Collection *collection);
|
||||
/** \param id_create_flag: Creation/Copy ID management flags, e.g. #LIB_ID_CREATE_NO_MAIN. */
|
||||
static bool collection_child_remove(Main *bmain,
|
||||
Collection *parent,
|
||||
Collection *collection,
|
||||
const int id_create_flag);
|
||||
/** \param id_create_flag: Creation/Copy ID management flags, e.g. #LIB_ID_CREATE_NO_MAIN. */
|
||||
static bool collection_object_add(Main *bmain,
|
||||
Collection *collection,
|
||||
Object *ob,
|
||||
CollectionLightLinking *light_linking,
|
||||
int flag,
|
||||
const int id_create_flag,
|
||||
const bool add_us);
|
||||
|
||||
/** \param id_create_flag: Creation/Copy ID management flags, e.g. #LIB_ID_CREATE_NO_MAIN. */
|
||||
static void collection_object_remove_no_gobject_hash(Main *bmain,
|
||||
Collection *collection,
|
||||
CollectionObject *cob,
|
||||
const int id_create_flag,
|
||||
const bool free_us);
|
||||
static bool collection_object_remove(Main *bmain,
|
||||
Collection *collection,
|
||||
Object *ob,
|
||||
const bool free_us);
|
||||
/** \param id_create_flag: Creation/Copy ID management flags, e.g. #LIB_ID_CREATE_NO_MAIN. */
|
||||
static bool collection_object_remove(
|
||||
Main *bmain, Collection *collection, Object *ob, const int id_create_flag, const bool free_us);
|
||||
|
||||
static CollectionChild *collection_find_child(Collection *parent, Collection *collection);
|
||||
static CollectionParent *collection_find_parent(Collection *child, Collection *collection);
|
||||
|
@ -89,7 +97,11 @@ static CollectionParent *collection_find_parent(Collection *child, Collection *c
|
|||
static bool collection_find_child_recursive(const Collection *parent,
|
||||
const Collection *collection);
|
||||
|
||||
static void collection_object_cache_free(Collection *collection);
|
||||
/** \param id_create_flag: Creation/Copy ID management flags, e.g. #LIB_ID_CREATE_NO_MAIN. */
|
||||
static void collection_object_cache_free(const Main *bmain,
|
||||
Collection *collection,
|
||||
const int id_create_flag,
|
||||
const uint id_recalc_flag);
|
||||
|
||||
static void collection_gobject_hash_ensure(Collection *collection);
|
||||
static void collection_gobject_hash_update_object(Collection *collection,
|
||||
|
@ -146,7 +158,8 @@ static void collection_copy_data(Main *bmain, ID *id_dst, const ID *id_src, cons
|
|||
collection_dst->runtime.gobject_hash = nullptr;
|
||||
|
||||
LISTBASE_FOREACH (CollectionChild *, child, &collection_src->children) {
|
||||
collection_child_add(collection_dst, child->collection, &child->light_linking, flag, false);
|
||||
collection_child_add(
|
||||
bmain, collection_dst, child->collection, &child->light_linking, flag, false);
|
||||
}
|
||||
LISTBASE_FOREACH (CollectionObject *, cob, &collection_src->gobject) {
|
||||
collection_object_add(bmain, collection_dst, cob->ob, &cob->light_linking, flag, false);
|
||||
|
@ -169,7 +182,8 @@ static void collection_free_data(ID *id)
|
|||
BLI_freelistN(&collection->children);
|
||||
BLI_freelistN(&collection->runtime.parents);
|
||||
|
||||
collection_object_cache_free(collection);
|
||||
/* No need for depsgraph taging here, since the data is being deleted. */
|
||||
collection_object_cache_free(nullptr, collection, LIB_ID_CREATE_NO_DEG_TAG, 0);
|
||||
}
|
||||
|
||||
static void collection_foreach_id(ID *id, LibraryForeachIDData *data)
|
||||
|
@ -393,7 +407,7 @@ static Collection *collection_add(Main *bmain,
|
|||
|
||||
/* Optionally add to parent collection. */
|
||||
if (collection_parent) {
|
||||
collection_child_add(collection_parent, collection, nullptr, 0, true);
|
||||
collection_child_add(bmain, collection_parent, collection, nullptr, 0, true);
|
||||
}
|
||||
|
||||
return collection;
|
||||
|
@ -417,14 +431,14 @@ void BKE_collection_add_from_object(Main *bmain,
|
|||
if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDABLE_LIBRARY(collection) &&
|
||||
BKE_collection_has_object(collection, ob_src))
|
||||
{
|
||||
collection_child_add(collection, collection_dst, nullptr, 0, true);
|
||||
collection_child_add(bmain, collection, collection_dst, nullptr, 0, true);
|
||||
is_instantiated = true;
|
||||
}
|
||||
}
|
||||
FOREACH_SCENE_COLLECTION_END;
|
||||
|
||||
if (!is_instantiated) {
|
||||
collection_child_add(scene->master_collection, collection_dst, nullptr, 0, true);
|
||||
collection_child_add(bmain, scene->master_collection, collection_dst, nullptr, 0, true);
|
||||
}
|
||||
|
||||
BKE_main_collection_sync(bmain);
|
||||
|
@ -441,7 +455,7 @@ void BKE_collection_add_from_collection(Main *bmain,
|
|||
if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY(collection) &&
|
||||
collection_find_child(collection, collection_src))
|
||||
{
|
||||
collection_child_add(collection, collection_dst, nullptr, 0, true);
|
||||
collection_child_add(bmain, collection, collection_dst, nullptr, 0, true);
|
||||
is_instantiated = true;
|
||||
}
|
||||
else if (!is_instantiated && collection_find_child(collection, collection_dst)) {
|
||||
|
@ -453,7 +467,7 @@ void BKE_collection_add_from_collection(Main *bmain,
|
|||
FOREACH_SCENE_COLLECTION_END;
|
||||
|
||||
if (!is_instantiated) {
|
||||
collection_child_add(scene->master_collection, collection_dst, nullptr, 0, true);
|
||||
collection_child_add(bmain, scene->master_collection, collection_dst, nullptr, 0, true);
|
||||
}
|
||||
|
||||
BKE_main_collection_sync(bmain);
|
||||
|
@ -492,7 +506,8 @@ bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
|
|||
/* Remove child objects. */
|
||||
CollectionObject *cob = static_cast<CollectionObject *>(collection->gobject.first);
|
||||
while (cob != nullptr) {
|
||||
collection_object_remove_no_gobject_hash(bmain, collection, cob, true);
|
||||
collection_object_remove_no_gobject_hash(
|
||||
bmain, collection, cob, LIB_ID_CREATE_NO_DEG_TAG, true);
|
||||
cob = static_cast<CollectionObject *>(collection->gobject.first);
|
||||
}
|
||||
|
||||
|
@ -508,7 +523,7 @@ bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
|
|||
LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
|
||||
LISTBASE_FOREACH (CollectionParent *, cparent, &collection->runtime.parents) {
|
||||
Collection *parent = cparent->collection;
|
||||
collection_child_add(parent, child->collection, nullptr, 0, true);
|
||||
collection_child_add(bmain, parent, child->collection, nullptr, 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -521,7 +536,8 @@ bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
|
|||
}
|
||||
|
||||
/* Remove child object. */
|
||||
collection_object_remove_no_gobject_hash(bmain, collection, cob, true);
|
||||
collection_object_remove_no_gobject_hash(
|
||||
bmain, collection, cob, LIB_ID_CREATE_NO_DEG_TAG, true);
|
||||
cob = static_cast<CollectionObject *>(collection->gobject.first);
|
||||
}
|
||||
}
|
||||
|
@ -542,6 +558,7 @@ bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
|
|||
static Collection *collection_duplicate_recursive(Main *bmain,
|
||||
Collection *parent,
|
||||
Collection *collection_old,
|
||||
const int id_create_flag,
|
||||
const eDupli_ID_Flags duplicate_flags,
|
||||
const eLibIDDuplicateFlags duplicate_options)
|
||||
{
|
||||
|
@ -560,7 +577,7 @@ static Collection *collection_duplicate_recursive(Main *bmain,
|
|||
}
|
||||
else if (collection_old->id.newid == nullptr) {
|
||||
collection_new = (Collection *)BKE_id_copy_for_duplicate(
|
||||
bmain, (ID *)collection_old, duplicate_flags, LIB_ID_COPY_DEFAULT);
|
||||
bmain, (ID *)collection_old, duplicate_flags, id_create_flag);
|
||||
|
||||
if (collection_new == collection_old) {
|
||||
return collection_new;
|
||||
|
@ -576,7 +593,9 @@ static Collection *collection_duplicate_recursive(Main *bmain,
|
|||
* even if collection_old had already been duplicated). */
|
||||
if (parent != nullptr) {
|
||||
CollectionChild *child = collection_find_child(parent, collection_old);
|
||||
if (collection_child_add(parent, collection_new, &child->light_linking, 0, true)) {
|
||||
if (collection_child_add(
|
||||
bmain, parent, collection_new, &child->light_linking, id_create_flag, true))
|
||||
{
|
||||
/* Put collection right after existing one. */
|
||||
CollectionChild *child_new = collection_find_child(parent, collection_new);
|
||||
|
||||
|
@ -620,8 +639,9 @@ static Collection *collection_duplicate_recursive(Main *bmain,
|
|||
continue;
|
||||
}
|
||||
|
||||
collection_object_add(bmain, collection_new, ob_new, &cob->light_linking, 0, true);
|
||||
collection_object_remove(bmain, collection_new, ob_old, false);
|
||||
collection_object_add(
|
||||
bmain, collection_new, ob_new, &cob->light_linking, id_create_flag, true);
|
||||
collection_object_remove(bmain, collection_new, ob_old, id_create_flag, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -630,10 +650,14 @@ static Collection *collection_duplicate_recursive(Main *bmain,
|
|||
LISTBASE_FOREACH_MUTABLE (CollectionChild *, child, &collection_old->children) {
|
||||
Collection *child_collection_old = child->collection;
|
||||
|
||||
Collection *child_collection_new = collection_duplicate_recursive(
|
||||
bmain, collection_new, child_collection_old, duplicate_flags, duplicate_options);
|
||||
Collection *child_collection_new = collection_duplicate_recursive(bmain,
|
||||
collection_new,
|
||||
child_collection_old,
|
||||
id_create_flag,
|
||||
duplicate_flags,
|
||||
duplicate_options);
|
||||
if (child_collection_new != child_collection_old) {
|
||||
collection_child_remove(collection_new, child_collection_old);
|
||||
collection_child_remove(bmain, collection_new, child_collection_old, id_create_flag);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -648,6 +672,7 @@ Collection *BKE_collection_duplicate(Main *bmain,
|
|||
{
|
||||
const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0;
|
||||
const bool is_root_id = (duplicate_options & LIB_ID_DUPLICATE_IS_ROOT_ID) != 0;
|
||||
const int id_create_flag = (collection->id.tag & LIB_TAG_NO_MAIN) ? LIB_ID_CREATE_NO_MAIN : 0;
|
||||
|
||||
if (!is_subprocess) {
|
||||
BKE_main_id_newptr_and_tag_clear(bmain);
|
||||
|
@ -665,6 +690,7 @@ Collection *BKE_collection_duplicate(Main *bmain,
|
|||
bmain,
|
||||
parent,
|
||||
collection,
|
||||
id_create_flag,
|
||||
eDupli_ID_Flags(duplicate_flags),
|
||||
eLibIDDuplicateFlags(duplicate_options));
|
||||
|
||||
|
@ -809,16 +835,38 @@ ListBase BKE_collection_object_cache_instanced_get(Collection *collection)
|
|||
return collection->runtime.object_cache_instanced;
|
||||
}
|
||||
|
||||
static void collection_object_cache_free(Collection *collection)
|
||||
static void collection_object_cache_free(const Main *bmain,
|
||||
Collection *collection,
|
||||
const int id_create_flag,
|
||||
const uint id_recalc_flag)
|
||||
{
|
||||
collection->flag &= ~(COLLECTION_HAS_OBJECT_CACHE | COLLECTION_HAS_OBJECT_CACHE_INSTANCED);
|
||||
BLI_freelistN(&collection->runtime.object_cache);
|
||||
BLI_freelistN(&collection->runtime.object_cache_instanced);
|
||||
|
||||
/* Although it may seem abusive to call depsgraph updates from this util function, it is called
|
||||
* from any codepath modifying the collections hierarchy and/or their objects. Including the
|
||||
* reversed-hierarchy walked by #collection_object_cache_free_parent_recursive.
|
||||
*
|
||||
* Plus, the main reason to tag the hierarchy of parents for deg update is because their object
|
||||
* caches are being freed.
|
||||
*
|
||||
* Having this code here avoids the need for another util tagging function processing the parent
|
||||
* hierarchy as well. */
|
||||
if (id_recalc_flag && (id_create_flag & (LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_DEG_TAG)) == 0)
|
||||
{
|
||||
BLI_assert(bmain != nullptr);
|
||||
DEG_id_tag_update_ex(const_cast<Main *>(bmain), &collection->id, id_recalc_flag);
|
||||
}
|
||||
}
|
||||
|
||||
static void collection_object_cache_free_parent_recursive(Collection *collection)
|
||||
/** Utils to recursively tag the parent hierarchy of a collection, matching the */
|
||||
static void collection_object_cache_free_parent_recursive(const Main *bmain,
|
||||
Collection *collection,
|
||||
const int id_create_flag,
|
||||
const uint id_recalc_flag)
|
||||
{
|
||||
collection_object_cache_free(collection);
|
||||
collection_object_cache_free(bmain, collection, id_create_flag, id_recalc_flag);
|
||||
|
||||
/* Clear cache in all parents recursively, since those are affected by changes as well. */
|
||||
LISTBASE_FOREACH (CollectionParent *, parent, &collection->runtime.parents) {
|
||||
|
@ -828,14 +876,18 @@ static void collection_object_cache_free_parent_recursive(Collection *collection
|
|||
if (parent->collection == nullptr) {
|
||||
continue;
|
||||
}
|
||||
collection_object_cache_free_parent_recursive(parent->collection);
|
||||
collection_object_cache_free_parent_recursive(
|
||||
bmain, parent->collection, id_create_flag, id_recalc_flag);
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_collection_object_cache_free(Collection *collection)
|
||||
void BKE_collection_object_cache_free(const Main *bmain,
|
||||
Collection *collection,
|
||||
const int id_create_flag)
|
||||
{
|
||||
BLI_assert(collection != nullptr);
|
||||
collection_object_cache_free_parent_recursive(collection);
|
||||
collection_object_cache_free_parent_recursive(
|
||||
bmain, collection, id_create_flag, ID_RECALC_HIERARCHY | ID_RECALC_GEOMETRY);
|
||||
}
|
||||
|
||||
void BKE_main_collections_object_cache_free(const Main *bmain)
|
||||
|
@ -843,14 +895,15 @@ void BKE_main_collections_object_cache_free(const Main *bmain)
|
|||
for (Scene *scene = static_cast<Scene *>(bmain->scenes.first); scene != nullptr;
|
||||
scene = static_cast<Scene *>(scene->id.next))
|
||||
{
|
||||
collection_object_cache_free(scene->master_collection);
|
||||
collection_object_cache_free(
|
||||
bmain, scene->master_collection, 0, ID_RECALC_HIERARCHY | ID_RECALC_GEOMETRY);
|
||||
}
|
||||
|
||||
for (Collection *collection = static_cast<Collection *>(bmain->collections.first);
|
||||
collection != nullptr;
|
||||
collection = static_cast<Collection *>(collection->id.next))
|
||||
{
|
||||
collection_object_cache_free(collection);
|
||||
collection_object_cache_free(bmain, collection, 0, ID_RECALC_HIERARCHY | ID_RECALC_GEOMETRY);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1054,7 +1107,7 @@ static void collection_gobject_hash_ensure(Collection *collection)
|
|||
* Similar to #collection_gobject_hash_ensure/#collection_gobject_hash_create, but does fix
|
||||
* inconsistencies in the collection objects list.
|
||||
*/
|
||||
static void collection_gobject_hash_ensure_fix(Collection *collection)
|
||||
static void collection_gobject_hash_ensure_fix(Main *bmain, Collection *collection)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
|
@ -1089,7 +1142,7 @@ static void collection_gobject_hash_ensure_fix(Collection *collection)
|
|||
}
|
||||
|
||||
if (changed) {
|
||||
BKE_collection_object_cache_free(collection);
|
||||
BKE_collection_object_cache_free(bmain, collection, 0);
|
||||
}
|
||||
|
||||
collection->runtime.tag &= ~COLLECTION_TAG_COLLECTION_OBJECT_DIRTY;
|
||||
|
@ -1179,25 +1232,6 @@ static void collection_gobject_assert_internal_consistency(Collection *collectio
|
|||
}
|
||||
}
|
||||
|
||||
static void collection_tag_update_parent_recursive(Main *bmain,
|
||||
Collection *collection,
|
||||
const int flag)
|
||||
{
|
||||
if (collection->flag & COLLECTION_IS_MASTER) {
|
||||
return;
|
||||
}
|
||||
|
||||
DEG_id_tag_update_ex(bmain, &collection->id, flag);
|
||||
|
||||
LISTBASE_FOREACH (CollectionParent *, collection_parent, &collection->runtime.parents) {
|
||||
if (collection_parent->collection->flag & COLLECTION_IS_MASTER) {
|
||||
/* We don't care about scene/master collection here. */
|
||||
continue;
|
||||
}
|
||||
collection_tag_update_parent_recursive(bmain, collection_parent->collection, flag);
|
||||
}
|
||||
}
|
||||
|
||||
static Collection *collection_parent_editable_find_recursive(const ViewLayer *view_layer,
|
||||
Collection *collection)
|
||||
{
|
||||
|
@ -1238,7 +1272,7 @@ static bool collection_object_add(Main *bmain,
|
|||
Collection *collection,
|
||||
Object *ob,
|
||||
CollectionLightLinking *light_linking,
|
||||
int flag,
|
||||
const int id_create_flag,
|
||||
const bool add_us)
|
||||
{
|
||||
/* Cyclic dependency check. */
|
||||
|
@ -1264,17 +1298,13 @@ static bool collection_object_add(Main *bmain,
|
|||
}
|
||||
*cob_p = cob;
|
||||
BLI_addtail(&collection->gobject, cob);
|
||||
BKE_collection_object_cache_free(collection);
|
||||
BKE_collection_object_cache_free(bmain, collection, id_create_flag);
|
||||
|
||||
if (add_us && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
|
||||
if (add_us && (id_create_flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
|
||||
id_us_plus(&ob->id);
|
||||
}
|
||||
|
||||
if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
|
||||
collection_tag_update_parent_recursive(bmain, collection, ID_RECALC_COPY_ON_WRITE);
|
||||
}
|
||||
|
||||
if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
|
||||
if ((id_create_flag & LIB_ID_CREATE_NO_MAIN) == 0) {
|
||||
BKE_rigidbody_main_collection_object_add(bmain, collection, ob);
|
||||
}
|
||||
|
||||
|
@ -1288,11 +1318,12 @@ static bool collection_object_add(Main *bmain,
|
|||
static void collection_object_remove_no_gobject_hash(Main *bmain,
|
||||
Collection *collection,
|
||||
CollectionObject *cob,
|
||||
const int id_create_flag,
|
||||
const bool free_us)
|
||||
{
|
||||
Object *ob = cob->ob;
|
||||
BLI_freelinkN(&collection->gobject, cob);
|
||||
BKE_collection_object_cache_free(collection);
|
||||
BKE_collection_object_cache_free(bmain, collection, id_create_flag);
|
||||
|
||||
if (free_us) {
|
||||
BKE_id_free_us(bmain, ob);
|
||||
|
@ -1300,15 +1331,10 @@ static void collection_object_remove_no_gobject_hash(Main *bmain,
|
|||
else {
|
||||
id_us_min(&ob->id);
|
||||
}
|
||||
|
||||
collection_tag_update_parent_recursive(
|
||||
bmain, collection, ID_RECALC_COPY_ON_WRITE | ID_RECALC_GEOMETRY);
|
||||
}
|
||||
|
||||
static bool collection_object_remove(Main *bmain,
|
||||
Collection *collection,
|
||||
Object *ob,
|
||||
const bool free_us)
|
||||
static bool collection_object_remove(
|
||||
Main *bmain, Collection *collection, Object *ob, const int id_create_flag, const bool free_us)
|
||||
{
|
||||
collection_gobject_hash_ensure(collection);
|
||||
CollectionObject *cob = static_cast<CollectionObject *>(
|
||||
|
@ -1316,7 +1342,7 @@ static bool collection_object_remove(Main *bmain,
|
|||
if (cob == nullptr) {
|
||||
return false;
|
||||
}
|
||||
collection_object_remove_no_gobject_hash(bmain, collection, cob, free_us);
|
||||
collection_object_remove_no_gobject_hash(bmain, collection, cob, id_create_flag, free_us);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1326,6 +1352,8 @@ bool BKE_collection_object_add_notest(Main *bmain, Collection *collection, Objec
|
|||
return false;
|
||||
}
|
||||
|
||||
const int id_create_flag = (collection->id.tag & LIB_TAG_NO_MAIN) ? LIB_ID_CREATE_NO_MAIN : 0;
|
||||
|
||||
/* Only case where this pointer can be nullptr is when scene itself is linked, this case should
|
||||
* never be reached. */
|
||||
BLI_assert(collection != nullptr);
|
||||
|
@ -1333,7 +1361,7 @@ bool BKE_collection_object_add_notest(Main *bmain, Collection *collection, Objec
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!collection_object_add(bmain, collection, ob, nullptr, 0, true)) {
|
||||
if (!collection_object_add(bmain, collection, ob, nullptr, id_create_flag, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1341,8 +1369,6 @@ bool BKE_collection_object_add_notest(Main *bmain, Collection *collection, Objec
|
|||
BKE_main_collection_sync(bmain);
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&collection->id, ID_RECALC_GEOMETRY | ID_RECALC_HIERARCHY);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1401,7 +1427,8 @@ bool BKE_collection_object_remove(Main *bmain,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!collection_object_remove(bmain, collection, ob, free_us)) {
|
||||
const int id_create_flag = (collection->id.tag & LIB_TAG_NO_MAIN) ? LIB_ID_CREATE_NO_MAIN : 0;
|
||||
if (!collection_object_remove(bmain, collection, ob, id_create_flag, free_us)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1409,8 +1436,6 @@ bool BKE_collection_object_remove(Main *bmain,
|
|||
BKE_main_collection_sync(bmain);
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&collection->id, ID_RECALC_GEOMETRY | ID_RECALC_HIERARCHY);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1435,7 +1460,7 @@ bool BKE_collection_object_replace(Main *bmain,
|
|||
BLI_ghash_insert(collection->runtime.gobject_hash, cob->ob, cob);
|
||||
}
|
||||
else {
|
||||
collection_object_remove_no_gobject_hash(bmain, collection, cob, false);
|
||||
collection_object_remove_no_gobject_hash(bmain, collection, cob, 0, false);
|
||||
}
|
||||
|
||||
if (BKE_collection_is_in_scene(collection)) {
|
||||
|
@ -1453,6 +1478,7 @@ static bool scene_collections_object_remove(
|
|||
Main *bmain, Scene *scene, Object *ob, const bool free_us, Collection *collection_skip)
|
||||
{
|
||||
bool removed = false;
|
||||
const int id_create_flag = (scene->id.tag & LIB_TAG_NO_MAIN) ? LIB_ID_CREATE_NO_MAIN : 0;
|
||||
|
||||
/* If given object is removed from all collections in given scene, then it can also be safely
|
||||
* removed from rigidbody world for given scene. */
|
||||
|
@ -1468,7 +1494,7 @@ static bool scene_collections_object_remove(
|
|||
continue;
|
||||
}
|
||||
|
||||
removed |= collection_object_remove(bmain, collection, ob, free_us);
|
||||
removed |= collection_object_remove(bmain, collection, ob, id_create_flag, free_us);
|
||||
}
|
||||
FOREACH_SCENE_COLLECTION_END;
|
||||
|
||||
|
@ -1485,11 +1511,11 @@ bool BKE_scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob,
|
|||
void BKE_collections_object_remove_invalids(Main *bmain)
|
||||
{
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
collection_gobject_hash_ensure_fix(scene->master_collection);
|
||||
collection_gobject_hash_ensure_fix(bmain, scene->master_collection);
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
|
||||
collection_gobject_hash_ensure_fix(collection);
|
||||
collection_gobject_hash_ensure_fix(bmain, collection);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1729,10 +1755,11 @@ static CollectionParent *collection_find_parent(Collection *child, Collection *c
|
|||
BLI_findptr(&child->runtime.parents, collection, offsetof(CollectionParent, collection)));
|
||||
}
|
||||
|
||||
static bool collection_child_add(Collection *parent,
|
||||
static bool collection_child_add(Main *bmain,
|
||||
Collection *parent,
|
||||
Collection *collection,
|
||||
CollectionLightLinking *light_linking,
|
||||
const int flag,
|
||||
const int id_create_flag,
|
||||
const bool add_us)
|
||||
{
|
||||
CollectionChild *child = collection_find_child(parent, collection);
|
||||
|
@ -1751,7 +1778,7 @@ static bool collection_child_add(Collection *parent,
|
|||
BLI_addtail(&parent->children, child);
|
||||
|
||||
/* Don't add parent links for depsgraph datablocks, these are not kept in sync. */
|
||||
if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
|
||||
if ((id_create_flag & LIB_ID_CREATE_NO_MAIN) == 0) {
|
||||
CollectionParent *cparent = static_cast<CollectionParent *>(
|
||||
MEM_callocN(sizeof(CollectionParent), "CollectionParent"));
|
||||
cparent->collection = parent;
|
||||
|
@ -1762,12 +1789,15 @@ static bool collection_child_add(Collection *parent,
|
|||
id_us_plus(&collection->id);
|
||||
}
|
||||
|
||||
BKE_collection_object_cache_free(parent);
|
||||
BKE_collection_object_cache_free(bmain, parent, id_create_flag);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool collection_child_remove(Collection *parent, Collection *collection)
|
||||
static bool collection_child_remove(Main *bmain,
|
||||
Collection *parent,
|
||||
Collection *collection,
|
||||
const int id_create_flag)
|
||||
{
|
||||
CollectionChild *child = collection_find_child(parent, collection);
|
||||
if (child == nullptr) {
|
||||
|
@ -1780,14 +1810,14 @@ static bool collection_child_remove(Collection *parent, Collection *collection)
|
|||
|
||||
id_us_min(&collection->id);
|
||||
|
||||
BKE_collection_object_cache_free(parent);
|
||||
BKE_collection_object_cache_free(bmain, parent, id_create_flag);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BKE_collection_child_add(Main *bmain, Collection *parent, Collection *child)
|
||||
{
|
||||
if (!collection_child_add(parent, child, nullptr, 0, true)) {
|
||||
if (!collection_child_add(bmain, parent, child, nullptr, 0, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1795,14 +1825,14 @@ bool BKE_collection_child_add(Main *bmain, Collection *parent, Collection *child
|
|||
return true;
|
||||
}
|
||||
|
||||
bool BKE_collection_child_add_no_sync(Collection *parent, Collection *child)
|
||||
bool BKE_collection_child_add_no_sync(Main *bmain, Collection *parent, Collection *child)
|
||||
{
|
||||
return collection_child_add(parent, child, nullptr, 0, true);
|
||||
return collection_child_add(bmain, parent, child, nullptr, 0, true);
|
||||
}
|
||||
|
||||
bool BKE_collection_child_remove(Main *bmain, Collection *parent, Collection *child)
|
||||
{
|
||||
if (!collection_child_remove(parent, child)) {
|
||||
if (!collection_child_remove(bmain, parent, child, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2044,10 +2074,10 @@ bool BKE_collection_move(Main *bmain,
|
|||
|
||||
/* Move to new parent collection */
|
||||
if (from_parent) {
|
||||
collection_child_remove(from_parent, collection);
|
||||
collection_child_remove(bmain, from_parent, collection, 0);
|
||||
}
|
||||
|
||||
collection_child_add(to_parent, collection, nullptr, 0, true);
|
||||
collection_child_add(bmain, to_parent, collection, nullptr, 0, true);
|
||||
|
||||
/* Move to specified location under parent. */
|
||||
if (relative) {
|
||||
|
@ -2064,7 +2094,7 @@ bool BKE_collection_move(Main *bmain,
|
|||
BLI_insertlinkbefore(&to_parent->children, relative_child, child);
|
||||
}
|
||||
|
||||
BKE_collection_object_cache_free(to_parent);
|
||||
BKE_collection_object_cache_free(bmain, to_parent, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4761,16 +4761,16 @@ bool BKE_nurb_valid_message(const int pnts,
|
|||
message_dst[0] = 0;
|
||||
return false;
|
||||
}
|
||||
msg_template = TIP_("At least two points required");
|
||||
msg_template = RPT_("At least two points required");
|
||||
break;
|
||||
case NURBSValidationStatus::MorePointsThanOrderRequired:
|
||||
msg_template = TIP_("Must have more control points than Order");
|
||||
msg_template = RPT_("Must have more control points than Order");
|
||||
break;
|
||||
case NURBSValidationStatus::MoreRowsForBezierRequired:
|
||||
msg_template = TIP_("%d more %s row(s) needed for Bezier");
|
||||
msg_template = RPT_("%d more %s row(s) needed for Bezier");
|
||||
break;
|
||||
case NURBSValidationStatus::MorePointsForBezierRequired:
|
||||
msg_template = TIP_("%d more point(s) needed for Bezier");
|
||||
msg_template = RPT_("%d more point(s) needed for Bezier");
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,11 @@ namespace blender::bke {
|
|||
|
||||
CurveComponent::CurveComponent() : GeometryComponent(Type::Curve) {}
|
||||
|
||||
CurveComponent::CurveComponent(Curves *curve, GeometryOwnershipType ownership)
|
||||
: GeometryComponent(Type::Curve), curves_(curve), ownership_(ownership)
|
||||
{
|
||||
}
|
||||
|
||||
CurveComponent::~CurveComponent()
|
||||
{
|
||||
this->clear();
|
||||
|
|
|
@ -32,6 +32,11 @@ namespace blender::bke {
|
|||
|
||||
InstancesComponent::InstancesComponent() : GeometryComponent(Type::Instance) {}
|
||||
|
||||
InstancesComponent::InstancesComponent(Instances *instances, GeometryOwnershipType ownership)
|
||||
: GeometryComponent(Type::Instance), instances_(instances), ownership_(ownership)
|
||||
{
|
||||
}
|
||||
|
||||
InstancesComponent::~InstancesComponent()
|
||||
{
|
||||
this->clear();
|
||||
|
|
|
@ -28,6 +28,11 @@ namespace blender::bke {
|
|||
|
||||
MeshComponent::MeshComponent() : GeometryComponent(Type::Mesh) {}
|
||||
|
||||
MeshComponent::MeshComponent(Mesh *mesh, GeometryOwnershipType ownership)
|
||||
: GeometryComponent(Type::Mesh), mesh_(mesh), ownership_(ownership)
|
||||
{
|
||||
}
|
||||
|
||||
MeshComponent::~MeshComponent()
|
||||
{
|
||||
this->clear();
|
||||
|
|
|
@ -18,6 +18,11 @@ namespace blender::bke {
|
|||
|
||||
PointCloudComponent::PointCloudComponent() : GeometryComponent(Type::PointCloud) {}
|
||||
|
||||
PointCloudComponent::PointCloudComponent(PointCloud *pointcloud, GeometryOwnershipType ownership)
|
||||
: GeometryComponent(Type::PointCloud), pointcloud_(pointcloud), ownership_(ownership)
|
||||
{
|
||||
}
|
||||
|
||||
PointCloudComponent::~PointCloudComponent()
|
||||
{
|
||||
this->clear();
|
||||
|
|
|
@ -542,7 +542,7 @@ void BKE_gpencil_modifier_set_error(GpencilModifierData *md, const char *format,
|
|||
{
|
||||
char buffer[512];
|
||||
va_list ap;
|
||||
const char *format_tip = TIP_(format);
|
||||
const char *format_tip = RPT_(format);
|
||||
|
||||
va_start(ap, format);
|
||||
vsnprintf(buffer, sizeof(buffer), format_tip, ap);
|
||||
|
|
|
@ -1223,19 +1223,6 @@ void BKE_grease_pencil_duplicate_drawing_array(const GreasePencil *grease_pencil
|
|||
/** \name Grease Pencil material functions
|
||||
* \{ */
|
||||
|
||||
int BKE_grease_pencil_object_material_index_get(Object *ob, Material *ma)
|
||||
{
|
||||
short *totcol = BKE_object_material_len_p(ob);
|
||||
Material *read_ma = nullptr;
|
||||
for (short i = 0; i < *totcol; i++) {
|
||||
read_ma = BKE_object_material_get(ob, i + 1);
|
||||
if (ma == read_ma) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int BKE_grease_pencil_object_material_index_get_by_name(Object *ob, const char *name)
|
||||
{
|
||||
short *totcol = BKE_object_material_len_p(ob);
|
||||
|
@ -1311,7 +1298,7 @@ Material *BKE_grease_pencil_object_material_ensure_from_brush(Main *bmain,
|
|||
Material *ma = BKE_grease_pencil_brush_material_get(brush);
|
||||
|
||||
/* check if the material is already on object material slots and add it if missing */
|
||||
if (ma && BKE_grease_pencil_object_material_index_get(ob, ma) < 0) {
|
||||
if (ma && BKE_object_material_index_get(ob, ma) < 0) {
|
||||
BKE_object_material_slot_add(bmain, ob);
|
||||
BKE_object_material_assign(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_USERPREF);
|
||||
}
|
||||
|
|
|
@ -823,6 +823,33 @@ void BKE_id_material_eval_ensure_default_slot(ID *id)
|
|||
}
|
||||
}
|
||||
|
||||
int BKE_object_material_index_get(Object *ob, Material *ma)
|
||||
{
|
||||
short *totcol = BKE_object_material_len_p(ob);
|
||||
Material *read_ma = nullptr;
|
||||
for (short i = 0; i < *totcol; i++) {
|
||||
read_ma = BKE_object_material_get(ob, i + 1);
|
||||
if (ma == read_ma) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int BKE_object_material_ensure(Main *bmain, Object *ob, Material *material)
|
||||
{
|
||||
if (!material) {
|
||||
return -1;
|
||||
}
|
||||
int index = BKE_object_material_index_get(ob, material);
|
||||
if (index < 0) {
|
||||
BKE_object_material_slot_add(bmain, ob);
|
||||
BKE_object_material_assign(bmain, ob, material, ob->totcol, BKE_MAT_ASSIGN_USERPREF);
|
||||
return ob->totcol - 1;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
Material *BKE_gpencil_material(Object *ob, short act)
|
||||
{
|
||||
Material *ma = BKE_object_material_get(ob, act);
|
||||
|
|
|
@ -74,9 +74,9 @@ MeshRuntime::~MeshRuntime()
|
|||
static int reset_bits_and_count(MutableBitSpan bits, const Span<int> indices_to_reset)
|
||||
{
|
||||
int count = bits.size();
|
||||
for (const int vert : indices_to_reset) {
|
||||
if (bits[vert]) {
|
||||
bits[vert].reset();
|
||||
for (const int i : indices_to_reset) {
|
||||
if (bits[i]) {
|
||||
bits[i].reset();
|
||||
count--;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -419,7 +419,7 @@ void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *_for
|
|||
{
|
||||
char buffer[512];
|
||||
va_list ap;
|
||||
const char *format = TIP_(_format);
|
||||
const char *format = RPT_(_format);
|
||||
|
||||
va_start(ap, _format);
|
||||
vsnprintf(buffer, sizeof(buffer), format, ap);
|
||||
|
@ -446,7 +446,7 @@ void BKE_modifier_set_warning(const Object *ob, ModifierData *md, const char *_f
|
|||
{
|
||||
char buffer[512];
|
||||
va_list ap;
|
||||
const char *format = TIP_(_format);
|
||||
const char *format = RPT_(_format);
|
||||
|
||||
va_start(ap, _format);
|
||||
vsnprintf(buffer, sizeof(buffer), format, ap);
|
||||
|
@ -1263,7 +1263,7 @@ void BKE_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb, Object
|
|||
BLO_reportf_wrap(
|
||||
BLO_read_data_reports(reader),
|
||||
RPT_WARNING,
|
||||
TIP_("Possible data loss when saving this file! %s modifier is deprecated (Object: %s)"),
|
||||
RPT_("Possible data loss when saving this file! %s modifier is deprecated (Object: %s)"),
|
||||
md->name,
|
||||
ob->id.name + 2);
|
||||
md = modifier_replace_with_fluid(reader, ob, lb, md);
|
||||
|
@ -1273,7 +1273,7 @@ void BKE_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb, Object
|
|||
BLO_reportf_wrap(
|
||||
BLO_read_data_reports(reader),
|
||||
RPT_WARNING,
|
||||
TIP_("Possible data loss when saving this file! %s modifier is deprecated (Object: %s)"),
|
||||
RPT_("Possible data loss when saving this file! %s modifier is deprecated (Object: %s)"),
|
||||
md->name,
|
||||
ob->id.name + 2);
|
||||
md = modifier_replace_with_fluid(reader, ob, lb, md);
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "BKE_node.hh"
|
||||
#include "BKE_node_runtime.hh"
|
||||
#include "BKE_node_tree_zones.hh"
|
||||
|
@ -351,6 +353,7 @@ static std::unique_ptr<bNodeTreeZones> discover_tree_zones(const bNodeTree &tree
|
|||
|
||||
update_zone_border_links(tree, *tree_zones);
|
||||
|
||||
// std::cout << *tree_zones << std::endl;
|
||||
return tree_zones;
|
||||
}
|
||||
|
||||
|
@ -522,4 +525,37 @@ const bNodeZoneType *zone_type_by_node_type(const int node_type)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &stream, const bNodeTreeZones &zones)
|
||||
{
|
||||
for (const std::unique_ptr<bNodeTreeZone> &zone : zones.zones) {
|
||||
stream << *zone;
|
||||
if (zones.zones.last().get() != zone.get()) {
|
||||
stream << "\n";
|
||||
}
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &stream, const bNodeTreeZone &zone)
|
||||
{
|
||||
stream << zone.index << ": Parent index: ";
|
||||
if (zone.parent_zone != nullptr) {
|
||||
stream << zone.parent_zone->index;
|
||||
}
|
||||
else {
|
||||
stream << "*";
|
||||
}
|
||||
|
||||
stream << "; Input: " << (zone.input_node ? zone.input_node->name : "null");
|
||||
stream << ", Output: " << (zone.output_node ? zone.output_node->name : "null");
|
||||
|
||||
stream << "; Border Links: {\n";
|
||||
for (const bNodeLink *border_link : zone.border_links) {
|
||||
stream << " " << border_link->fromnode->name << ": " << border_link->fromsock->name << " -> ";
|
||||
stream << border_link->tonode->name << ": " << border_link->tosock->name << ";\n";
|
||||
}
|
||||
stream << "}.";
|
||||
return stream;
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
|
|
@ -915,12 +915,12 @@ static void object_blend_read_after_liblink(BlendLibReader *reader, ID *id)
|
|||
if (ob->id.lib) {
|
||||
BLO_reportf_wrap(reports,
|
||||
RPT_INFO,
|
||||
TIP_("Can't find object data of %s lib %s"),
|
||||
RPT_("Can't find object data of %s lib %s"),
|
||||
ob->id.name + 2,
|
||||
ob->id.lib->filepath);
|
||||
}
|
||||
else {
|
||||
BLO_reportf_wrap(reports, RPT_INFO, TIP_("Object %s lost data"), ob->id.name + 2);
|
||||
BLO_reportf_wrap(reports, RPT_INFO, RPT_("Object %s lost data"), ob->id.name + 2);
|
||||
}
|
||||
reports->count.missing_obdata++;
|
||||
}
|
||||
|
|
|
@ -3691,13 +3691,13 @@ void BKE_ptcache_update_info(PTCacheID *pid)
|
|||
|
||||
/* smoke doesn't use frame 0 as info frame so can't check based on totpoint */
|
||||
if (pid->type == PTCACHE_TYPE_SMOKE_DOMAIN && totframes) {
|
||||
SNPRINTF(cache->info, TIP_("%i frames found!"), totframes);
|
||||
SNPRINTF(cache->info, RPT_("%i frames found!"), totframes);
|
||||
}
|
||||
else if (totframes && cache->totpoint) {
|
||||
SNPRINTF(cache->info, TIP_("%i points found!"), cache->totpoint);
|
||||
SNPRINTF(cache->info, RPT_("%i points found!"), cache->totpoint);
|
||||
}
|
||||
else {
|
||||
STRNCPY(cache->info, TIP_("No valid data to read!"));
|
||||
STRNCPY(cache->info, RPT_("No valid data to read!"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -3707,10 +3707,10 @@ void BKE_ptcache_update_info(PTCacheID *pid)
|
|||
int totpoint = pid->totpoint(pid->calldata, 0);
|
||||
|
||||
if (cache->totpoint > totpoint) {
|
||||
SNPRINTF(mem_info, TIP_("%i cells + High Resolution cached"), totpoint);
|
||||
SNPRINTF(mem_info, RPT_("%i cells + High Resolution cached"), totpoint);
|
||||
}
|
||||
else {
|
||||
SNPRINTF(mem_info, TIP_("%i cells cached"), totpoint);
|
||||
SNPRINTF(mem_info, RPT_("%i cells cached"), totpoint);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -3722,7 +3722,7 @@ void BKE_ptcache_update_info(PTCacheID *pid)
|
|||
}
|
||||
}
|
||||
|
||||
SNPRINTF(mem_info, TIP_("%i frames on disk"), totframes);
|
||||
SNPRINTF(mem_info, RPT_("%i frames on disk"), totframes);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -3750,14 +3750,14 @@ void BKE_ptcache_update_info(PTCacheID *pid)
|
|||
BLI_str_format_int_grouped(formatted_tot, totframes);
|
||||
BLI_str_format_byte_unit(formatted_mem, bytes, false);
|
||||
|
||||
SNPRINTF(mem_info, TIP_("%s frames in memory (%s)"), formatted_tot, formatted_mem);
|
||||
SNPRINTF(mem_info, RPT_("%s frames in memory (%s)"), formatted_tot, formatted_mem);
|
||||
}
|
||||
|
||||
if (cache->flag & PTCACHE_OUTDATED) {
|
||||
SNPRINTF(cache->info, TIP_("%s, cache is outdated!"), mem_info);
|
||||
SNPRINTF(cache->info, RPT_("%s, cache is outdated!"), mem_info);
|
||||
}
|
||||
else if (cache->flag & PTCACHE_FRAMES_SKIPPED) {
|
||||
SNPRINTF(cache->info, TIP_("%s, not exact since frame %i"), mem_info, cache->last_exact);
|
||||
SNPRINTF(cache->info, RPT_("%s, not exact since frame %i"), mem_info, cache->last_exact);
|
||||
}
|
||||
else {
|
||||
SNPRINTF(cache->info, "%s.", mem_info);
|
||||
|
|
|
@ -29,25 +29,25 @@ const char *BKE_report_type_str(eReportType type)
|
|||
{
|
||||
switch (type) {
|
||||
case RPT_DEBUG:
|
||||
return TIP_("Debug");
|
||||
return RPT_("Debug");
|
||||
case RPT_INFO:
|
||||
return TIP_("Info");
|
||||
return RPT_("Info");
|
||||
case RPT_OPERATOR:
|
||||
return TIP_("Operator");
|
||||
return RPT_("Operator");
|
||||
case RPT_PROPERTY:
|
||||
return TIP_("Property");
|
||||
return RPT_("Property");
|
||||
case RPT_WARNING:
|
||||
return TIP_("Warning");
|
||||
return RPT_("Warning");
|
||||
case RPT_ERROR:
|
||||
return TIP_("Error");
|
||||
return RPT_("Error");
|
||||
case RPT_ERROR_INVALID_INPUT:
|
||||
return TIP_("Invalid Input Error");
|
||||
return RPT_("Invalid Input Error");
|
||||
case RPT_ERROR_INVALID_CONTEXT:
|
||||
return TIP_("Invalid Context Error");
|
||||
return RPT_("Invalid Context Error");
|
||||
case RPT_ERROR_OUT_OF_MEMORY:
|
||||
return TIP_("Out Of Memory Error");
|
||||
return RPT_("Out Of Memory Error");
|
||||
default:
|
||||
return TIP_("Undefined Type");
|
||||
return RPT_("Undefined Type");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,7 +126,7 @@ void BKE_report(ReportList *reports, eReportType type, const char *_message)
|
|||
{
|
||||
Report *report;
|
||||
int len;
|
||||
const char *message = TIP_(_message);
|
||||
const char *message = RPT_(_message);
|
||||
|
||||
if (BKE_reports_print_test(reports, type)) {
|
||||
printf("%s: %s\n", BKE_report_type_str(type), message);
|
||||
|
@ -154,7 +154,7 @@ void BKE_reportf(ReportList *reports, eReportType type, const char *_format, ...
|
|||
{
|
||||
Report *report;
|
||||
va_list args;
|
||||
const char *format = TIP_(_format);
|
||||
const char *format = RPT_(_format);
|
||||
|
||||
if (BKE_reports_print_test(reports, type)) {
|
||||
printf("%s: ", BKE_report_type_str(type));
|
||||
|
@ -207,7 +207,7 @@ void BKE_reports_prepend(ReportList *reports, const char *prepend)
|
|||
if (!reports || !reports->list.first) {
|
||||
return;
|
||||
}
|
||||
reports_prepend_impl(reports, TIP_(prepend));
|
||||
reports_prepend_impl(reports, RPT_(prepend));
|
||||
}
|
||||
|
||||
void BKE_reports_prependf(ReportList *reports, const char *prepend_format, ...)
|
||||
|
@ -217,7 +217,7 @@ void BKE_reports_prependf(ReportList *reports, const char *prepend_format, ...)
|
|||
}
|
||||
va_list args;
|
||||
va_start(args, prepend_format);
|
||||
char *prepend = BLI_vsprintfN(TIP_(prepend_format), args);
|
||||
char *prepend = BLI_vsprintfN(RPT_(prepend_format), args);
|
||||
va_end(args);
|
||||
|
||||
reports_prepend_impl(reports, prepend);
|
||||
|
|
|
@ -502,7 +502,11 @@ static void scene_foreach_toolsettings_id_pointer_process(
|
|||
ID *id_old_new = id_old != nullptr ? BLO_read_get_new_id_address_from_session_uuid(
|
||||
reader, id_old->session_uuid) :
|
||||
nullptr;
|
||||
if (!ELEM(id_old_new, id_old, nullptr)) {
|
||||
/* The new address may be the same as the old one, in which case there is nothing to do. */
|
||||
if (id_old_new == id_old) {
|
||||
break;
|
||||
}
|
||||
if (id_old_new != nullptr) {
|
||||
BLI_assert(id_old == id_old_new->orig_id);
|
||||
*id_old_p = id_old_new;
|
||||
if (cb_flag & IDWALK_CB_USER) {
|
||||
|
@ -518,7 +522,7 @@ static void scene_foreach_toolsettings_id_pointer_process(
|
|||
* There is a nasty twist here though: a previous call to 'undo_preserve' on the Scene ID may
|
||||
* have modified it, even though the undo step detected it as unmodified. In such case, the
|
||||
* value of `*id_p` may end up also pointing to an invalid (no more in newly read Main) ID,
|
||||
* se it also needs to be checked from its `session_uuid`. */
|
||||
* so it also needs to be checked from its `session_uuid`. */
|
||||
ID *id = *id_p;
|
||||
ID *id_new = id != nullptr ?
|
||||
BLO_read_get_new_id_address_from_session_uuid(reader, id->session_uuid) :
|
||||
|
@ -1543,7 +1547,7 @@ static void scene_blend_read_after_liblink(BlendLibReader *reader, ID *id)
|
|||
if (base_legacy->object == nullptr) {
|
||||
BLO_reportf_wrap(BLO_read_lib_reports(reader),
|
||||
RPT_WARNING,
|
||||
TIP_("LIB: object lost from scene: '%s'"),
|
||||
RPT_("LIB: object lost from scene: '%s'"),
|
||||
sce->id.name + 2);
|
||||
BLI_remlink(&sce->base, base_legacy);
|
||||
if (base_legacy == sce->basact) {
|
||||
|
|
|
@ -323,6 +323,14 @@ static void panel_list_copy(ListBase *newlb, const ListBase *lb)
|
|||
new_panel->runtime = new_runtime;
|
||||
new_panel->activedata = nullptr;
|
||||
new_panel->drawname = nullptr;
|
||||
|
||||
BLI_listbase_clear(&new_panel->layout_panel_states);
|
||||
LISTBASE_FOREACH (LayoutPanelState *, src_state, &old_panel->layout_panel_states) {
|
||||
LayoutPanelState *new_state = MEM_new<LayoutPanelState>(__func__, *src_state);
|
||||
new_state->idname = BLI_strdup(src_state->idname);
|
||||
BLI_addtail(&new_panel->layout_panel_states, new_state);
|
||||
}
|
||||
|
||||
BLI_addtail(newlb, new_panel);
|
||||
panel_list_copy(&new_panel->children, &old_panel->children);
|
||||
}
|
||||
|
@ -487,6 +495,22 @@ void BKE_region_callback_free_gizmomap_set(void (*callback)(wmGizmoMap *))
|
|||
region_free_gizmomap_callback = callback;
|
||||
}
|
||||
|
||||
LayoutPanelState *BKE_panel_layout_panel_state_ensure(Panel *panel,
|
||||
const char *idname,
|
||||
const bool default_closed)
|
||||
{
|
||||
LISTBASE_FOREACH (LayoutPanelState *, state, &panel->layout_panel_states) {
|
||||
if (STREQ(state->idname, idname)) {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
LayoutPanelState *state = MEM_cnew<LayoutPanelState>(__func__);
|
||||
state->idname = BLI_strdup(idname);
|
||||
SET_FLAG_FROM_TEST(state->flag, !default_closed, LAYOUT_PANEL_STATE_FLAG_OPEN);
|
||||
BLI_addtail(&panel->layout_panel_states, state);
|
||||
return state;
|
||||
}
|
||||
|
||||
Panel *BKE_panel_new(PanelType *panel_type)
|
||||
{
|
||||
Panel *panel = MEM_cnew<Panel>(__func__);
|
||||
|
@ -502,6 +526,12 @@ void BKE_panel_free(Panel *panel)
|
|||
{
|
||||
MEM_SAFE_FREE(panel->activedata);
|
||||
MEM_SAFE_FREE(panel->drawname);
|
||||
|
||||
LISTBASE_FOREACH (LayoutPanelState *, state, &panel->layout_panel_states) {
|
||||
MEM_freeN(state->idname);
|
||||
}
|
||||
BLI_freelistN(&panel->layout_panel_states);
|
||||
|
||||
MEM_delete(panel->runtime);
|
||||
MEM_freeN(panel);
|
||||
}
|
||||
|
@ -1054,6 +1084,10 @@ static void write_panel_list(BlendWriter *writer, ListBase *lb)
|
|||
{
|
||||
LISTBASE_FOREACH (Panel *, panel, lb) {
|
||||
BLO_write_struct(writer, Panel, panel);
|
||||
BLO_write_struct_list(writer, LayoutPanelState, &panel->layout_panel_states);
|
||||
LISTBASE_FOREACH (LayoutPanelState *, state, &panel->layout_panel_states) {
|
||||
BLO_write_string(writer, state->idname);
|
||||
}
|
||||
write_panel_list(writer, &panel->children);
|
||||
}
|
||||
}
|
||||
|
@ -1116,6 +1150,10 @@ static void direct_link_panel_list(BlendDataReader *reader, ListBase *lb)
|
|||
panel->activedata = nullptr;
|
||||
panel->type = nullptr;
|
||||
panel->drawname = nullptr;
|
||||
BLO_read_list(reader, &panel->layout_panel_states);
|
||||
LISTBASE_FOREACH (LayoutPanelState *, state, &panel->layout_panel_states) {
|
||||
BLO_read_data_address(reader, &state->idname);
|
||||
}
|
||||
direct_link_panel_list(reader, &panel->children);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,6 +83,19 @@ inline void scatter(const Span<T> src,
|
|||
});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void scatter(const Span<T> src,
|
||||
const IndexMask &indices,
|
||||
MutableSpan<T> dst,
|
||||
const int64_t grain_size = 4096)
|
||||
{
|
||||
BLI_assert(indices.size() == src.size());
|
||||
BLI_assert(indices.min_array_size() <= dst.size());
|
||||
indices.foreach_index_optimized<int64_t>(
|
||||
GrainSize(grain_size),
|
||||
[&](const int64_t index, const int64_t pos) { dst[index] = src[pos]; });
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the destination span by gathering indexed values from the `src` array.
|
||||
*/
|
||||
|
@ -281,4 +294,6 @@ bool indexed_data_equal(const Span<T> all_values, const Span<int> indices, const
|
|||
return false;
|
||||
}
|
||||
|
||||
bool indices_are_range(Span<int> indices, IndexRange range);
|
||||
|
||||
} // namespace blender::array_utils
|
||||
|
|
|
@ -155,6 +155,8 @@ void copy_group_sizes(OffsetIndices<int> offsets, const IndexMask &mask, Mutable
|
|||
/** Gather the number of indices in each indexed group to sizes. */
|
||||
void gather_group_sizes(OffsetIndices<int> offsets, const IndexMask &mask, MutableSpan<int> sizes);
|
||||
|
||||
void gather_group_sizes(OffsetIndices<int> offsets, Span<int> indices, MutableSpan<int> sizes);
|
||||
|
||||
/** Build new offsets that contains only the groups chosen by \a selection. */
|
||||
OffsetIndices<int> gather_selected_offsets(OffsetIndices<int> src_offsets,
|
||||
const IndexMask &selection,
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "BLI_array_utils.hh"
|
||||
#include "BLI_threads.h"
|
||||
|
||||
|
@ -196,4 +198,22 @@ int64_t count_booleans(const VArray<bool> &varray)
|
|||
return count_booleans(varray, IndexMask(varray.size()));
|
||||
}
|
||||
|
||||
bool indices_are_range(Span<int> indices, IndexRange range)
|
||||
{
|
||||
if (indices.size() != range.size()) {
|
||||
return false;
|
||||
}
|
||||
return threading::parallel_reduce(
|
||||
range.index_range(),
|
||||
4096,
|
||||
true,
|
||||
[&](const IndexRange part, const bool is_range) {
|
||||
const Span<int> local_indices = indices.slice(part);
|
||||
const IndexRange local_range = range.slice(part);
|
||||
return is_range &&
|
||||
std::equal(local_indices.begin(), local_indices.end(), local_range.begin());
|
||||
},
|
||||
std::logical_and<bool>());
|
||||
}
|
||||
|
||||
} // namespace blender::array_utils
|
||||
|
|
|
@ -48,6 +48,17 @@ void gather_group_sizes(const OffsetIndices<int> offsets,
|
|||
});
|
||||
}
|
||||
|
||||
void gather_group_sizes(const OffsetIndices<int> offsets,
|
||||
const Span<int> indices,
|
||||
MutableSpan<int> sizes)
|
||||
{
|
||||
threading::parallel_for(indices.index_range(), 4096, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
sizes[i] = offsets[indices[i]].size();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
OffsetIndices<int> gather_selected_offsets(const OffsetIndices<int> src_offsets,
|
||||
const IndexMask &selection,
|
||||
const int start_offset,
|
||||
|
|
|
@ -1113,7 +1113,7 @@ static bool is_minversion_older_than_blender(FileData *fd, ReportList *reports)
|
|||
}
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
TIP_("The file was saved by a newer version, open it with Blender %s or later"),
|
||||
"The file was saved by a newer version, open it with Blender %s or later",
|
||||
min_reader_ver_str);
|
||||
CLOG_WARN(&LOG,
|
||||
"%s: File saved by a newer version of Blender (%s), Blender %s or later is "
|
||||
|
@ -1172,7 +1172,7 @@ static FileData *blo_filedata_from_file_descriptor(const char *filepath,
|
|||
RPT_WARNING,
|
||||
"Unable to read '%s': %s",
|
||||
filepath,
|
||||
errno ? strerror(errno) : TIP_("insufficient content"));
|
||||
errno ? strerror(errno) : RPT_("insufficient content"));
|
||||
if (rawfile) {
|
||||
rawfile->close(rawfile);
|
||||
}
|
||||
|
@ -1232,7 +1232,7 @@ static FileData *blo_filedata_from_file_open(const char *filepath, BlendFileRead
|
|||
RPT_WARNING,
|
||||
"Unable to open '%s': %s",
|
||||
filepath,
|
||||
errno ? strerror(errno) : TIP_("unknown error reading file"));
|
||||
errno ? strerror(errno) : RPT_("unknown error reading file"));
|
||||
return nullptr;
|
||||
}
|
||||
return blo_filedata_from_file_descriptor(filepath, reports, file);
|
||||
|
@ -1272,7 +1272,7 @@ FileData *blo_filedata_from_memory(const void *mem, int memsize, BlendFileReadRe
|
|||
{
|
||||
if (!mem || memsize < SIZEOFBLENDERHEADER) {
|
||||
BKE_report(
|
||||
reports->reports, RPT_WARNING, (mem) ? TIP_("Unable to read") : TIP_("Unable to open"));
|
||||
reports->reports, RPT_WARNING, (mem) ? RPT_("Unable to read") : RPT_("Unable to open"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -2275,7 +2275,7 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main)
|
|||
if (BLI_path_cmp(newmain->curlib->filepath_abs, lib->filepath_abs) == 0) {
|
||||
BLO_reportf_wrap(fd->reports,
|
||||
RPT_WARNING,
|
||||
TIP_("Library '%s', '%s' had multiple instances, save and reload!"),
|
||||
RPT_("Library '%s', '%s' had multiple instances, save and reload!"),
|
||||
lib->filepath,
|
||||
lib->filepath_abs);
|
||||
|
||||
|
@ -4032,7 +4032,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
|
|||
|
||||
BLO_reportf_wrap(fd->reports,
|
||||
RPT_WARNING,
|
||||
TIP_("LIB: Data refers to main .blend file: '%s' from %s"),
|
||||
RPT_("LIB: Data refers to main .blend file: '%s' from %s"),
|
||||
idname,
|
||||
mainvar->curlib->filepath_abs);
|
||||
return;
|
||||
|
@ -4546,7 +4546,7 @@ static void read_library_linked_id(
|
|||
if (!is_valid) {
|
||||
BLO_reportf_wrap(basefd->reports,
|
||||
RPT_ERROR,
|
||||
TIP_("LIB: %s: '%s' is directly linked from '%s' (parent '%s'), but is a "
|
||||
RPT_("LIB: %s: '%s' is directly linked from '%s' (parent '%s'), but is a "
|
||||
"non-linkable data type"),
|
||||
BKE_idtype_idcode_to_name(GS(id->name)),
|
||||
id->name + 2,
|
||||
|
@ -4565,7 +4565,7 @@ static void read_library_linked_id(
|
|||
else {
|
||||
BLO_reportf_wrap(basefd->reports,
|
||||
RPT_INFO,
|
||||
TIP_("LIB: %s: '%s' missing from '%s', parent '%s'"),
|
||||
RPT_("LIB: %s: '%s' missing from '%s', parent '%s'"),
|
||||
BKE_idtype_idcode_to_name(GS(id->name)),
|
||||
id->name + 2,
|
||||
mainvar->curlib->filepath_abs,
|
||||
|
@ -4679,7 +4679,7 @@ static FileData *read_library_file_data(FileData *basefd,
|
|||
|
||||
BLO_reportf_wrap(basefd->reports,
|
||||
RPT_INFO,
|
||||
TIP_("Read packed library: '%s', parent '%s'"),
|
||||
RPT_("Read packed library: '%s', parent '%s'"),
|
||||
mainptr->curlib->filepath,
|
||||
library_parent_filepath(mainptr->curlib));
|
||||
fd = blo_filedata_from_memory(pf->data, pf->size, basefd->reports);
|
||||
|
@ -4691,7 +4691,7 @@ static FileData *read_library_file_data(FileData *basefd,
|
|||
/* Read file on disk. */
|
||||
BLO_reportf_wrap(basefd->reports,
|
||||
RPT_INFO,
|
||||
TIP_("Read library: '%s', '%s', parent '%s'"),
|
||||
RPT_("Read library: '%s', '%s', parent '%s'"),
|
||||
mainptr->curlib->filepath_abs,
|
||||
mainptr->curlib->filepath,
|
||||
library_parent_filepath(mainptr->curlib));
|
||||
|
@ -4732,7 +4732,7 @@ static FileData *read_library_file_data(FileData *basefd,
|
|||
|
||||
if (fd == nullptr) {
|
||||
BLO_reportf_wrap(
|
||||
basefd->reports, RPT_INFO, TIP_("Cannot find lib '%s'"), mainptr->curlib->filepath_abs);
|
||||
basefd->reports, RPT_INFO, RPT_("Cannot find lib '%s'"), mainptr->curlib->filepath_abs);
|
||||
basefd->reports->count.missing_libraries++;
|
||||
}
|
||||
|
||||
|
|
|
@ -2961,7 +2961,7 @@ void do_versions_after_linking_280(FileData *fd, Main *bmain)
|
|||
if (ob->type != OB_EMPTY && ob->instance_collection != nullptr) {
|
||||
BLO_reportf_wrap(fd->reports,
|
||||
RPT_INFO,
|
||||
TIP_("Non-Empty object '%s' cannot duplicate collection '%s' "
|
||||
RPT_("Non-Empty object '%s' cannot duplicate collection '%s' "
|
||||
"anymore in Blender 2.80 and later, removed instancing"),
|
||||
ob->id.name + 2,
|
||||
ob->instance_collection->id.name + 2);
|
||||
|
|
|
@ -393,14 +393,14 @@ void do_versions_after_linking_400(FileData *fd, Main *bmain)
|
|||
if (ob->id.lib) {
|
||||
BLO_reportf_wrap(fd->reports,
|
||||
RPT_INFO,
|
||||
TIP_("Proxy lost from object %s lib %s\n"),
|
||||
RPT_("Proxy lost from object %s lib %s\n"),
|
||||
ob->id.name + 2,
|
||||
ob->id.lib->filepath);
|
||||
}
|
||||
else {
|
||||
BLO_reportf_wrap(fd->reports,
|
||||
RPT_INFO,
|
||||
TIP_("Proxy lost from object %s lib <NONE>\n"),
|
||||
RPT_("Proxy lost from object %s lib <NONE>\n"),
|
||||
ob->id.name + 2);
|
||||
}
|
||||
fd->reports->count.missing_obproxies++;
|
||||
|
|
|
@ -494,8 +494,8 @@ void blo_do_versions_userdef(UserDef *userdef)
|
|||
USER_FLAG_UNUSED_6 | USER_FLAG_UNUSED_7 | USER_FLAG_UNUSED_9 |
|
||||
USER_DEVELOPER_UI);
|
||||
userdef->uiflag &= ~(USER_HEADER_BOTTOM);
|
||||
userdef->transopts &= ~(USER_TR_UNUSED_2 | USER_TR_UNUSED_3 | USER_TR_UNUSED_4 |
|
||||
USER_TR_UNUSED_6 | USER_TR_UNUSED_7);
|
||||
userdef->transopts &= ~(USER_TR_UNUSED_3 | USER_TR_UNUSED_4 | USER_TR_UNUSED_6 |
|
||||
USER_TR_UNUSED_7);
|
||||
|
||||
userdef->uiflag |= USER_LOCK_CURSOR_ADJUST;
|
||||
}
|
||||
|
|
|
@ -19,14 +19,21 @@ extern "C" {
|
|||
bool BLT_is_default_context(const char *msgctxt);
|
||||
const char *BLT_pgettext(const char *msgctxt, const char *msgid);
|
||||
|
||||
/* translation */
|
||||
/* Translation */
|
||||
/* - iface includes buttons in the user interface: short labels displayed in windows, panels,
|
||||
* menus.
|
||||
* - tooltips only include the popup tooltips when hovering a button.
|
||||
* - report is for longer, additional information displayed in the UI, such as error messages.
|
||||
* - new_dataname is the actual user-created data such as objects, meshes, etc. */
|
||||
bool BLT_translate(void);
|
||||
bool BLT_translate_iface(void);
|
||||
bool BLT_translate_tooltips(void);
|
||||
bool BLT_translate_reports(void);
|
||||
bool BLT_translate_new_dataname(void);
|
||||
const char *BLT_translate_do(const char *msgctxt, const char *msgid);
|
||||
const char *BLT_translate_do_iface(const char *msgctxt, const char *msgid);
|
||||
const char *BLT_translate_do_tooltip(const char *msgctxt, const char *msgid);
|
||||
const char *BLT_translate_do_report(const char *msgctxt, const char *msgid);
|
||||
const char *BLT_translate_do_new_dataname(const char *msgctxt, const char *msgid);
|
||||
|
||||
/* The "translation-marker" macro. */
|
||||
|
@ -37,9 +44,11 @@ const char *BLT_translate_do_new_dataname(const char *msgctxt, const char *msgid
|
|||
/*# define _(msgid) BLT_gettext(msgid) */
|
||||
#define IFACE_(msgid) BLT_translate_do_iface(NULL, msgid)
|
||||
#define TIP_(msgid) BLT_translate_do_tooltip(NULL, msgid)
|
||||
#define RPT_(msgid) BLT_translate_do_report(NULL, msgid)
|
||||
#define DATA_(msgid) BLT_translate_do_new_dataname(NULL, msgid)
|
||||
#define CTX_IFACE_(context, msgid) BLT_translate_do_iface(context, msgid)
|
||||
#define CTX_TIP_(context, msgid) BLT_translate_do_tooltip(context, msgid)
|
||||
#define CTX_RPT_(context, msgid) BLT_translate_do_report(context, msgid)
|
||||
#define CTX_DATA_(context, msgid) BLT_translate_do_new_dataname(context, msgid)
|
||||
|
||||
/* Helper macro, when we want to define a same msgid for multiple msgctxt...
|
||||
|
|
|
@ -90,6 +90,15 @@ bool BLT_translate_tooltips()
|
|||
#endif
|
||||
}
|
||||
|
||||
bool BLT_translate_reports()
|
||||
{
|
||||
#ifdef WITH_INTERNATIONAL
|
||||
return BLT_translate() && (U.transopts & USER_TR_REPORTS);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool BLT_translate_new_dataname()
|
||||
{
|
||||
#ifdef WITH_INTERNATIONAL
|
||||
|
@ -144,6 +153,21 @@ const char *BLT_translate_do_tooltip(const char *msgctxt, const char *msgid)
|
|||
#endif
|
||||
}
|
||||
|
||||
const char *BLT_translate_do_report(const char *msgctxt, const char *msgid)
|
||||
{
|
||||
#ifdef WITH_INTERNATIONAL
|
||||
if (BLT_translate_reports()) {
|
||||
return BLT_pgettext(msgctxt, msgid);
|
||||
}
|
||||
|
||||
return msgid;
|
||||
|
||||
#else
|
||||
(void)msgctxt;
|
||||
return msgid;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *BLT_translate_do_new_dataname(const char *msgctxt, const char *msgid)
|
||||
{
|
||||
#ifdef WITH_INTERNATIONAL
|
||||
|
|
|
@ -421,7 +421,7 @@ void ExecutionGroup::finalize_chunk_execution(int chunk_number, MemoryBuffer **m
|
|||
bTree_->runtime->progress(bTree_->runtime->prh, progress);
|
||||
|
||||
char buf[128];
|
||||
SNPRINTF(buf, TIP_("Compositing | Tile %u-%u"), chunks_finished_, chunks_len_);
|
||||
SNPRINTF(buf, RPT_("Compositing | Tile %u-%u"), chunks_finished_, chunks_len_);
|
||||
bTree_->runtime->stats_draw(bTree_->runtime->sdh, buf);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ void FullFrameExecutionModel::execute(ExecutionSystem &exec_system)
|
|||
{
|
||||
const bNodeTree *node_tree = this->context_.get_bnodetree();
|
||||
node_tree->runtime->stats_draw(node_tree->runtime->sdh,
|
||||
TIP_("Compositing | Initializing execution"));
|
||||
RPT_("Compositing | Initializing execution"));
|
||||
|
||||
DebugInfo::graphviz(&exec_system, "compositor_prior_rendering");
|
||||
|
||||
|
@ -281,7 +281,7 @@ void FullFrameExecutionModel::update_progress_bar()
|
|||
|
||||
char buf[128];
|
||||
SNPRINTF(buf,
|
||||
TIP_("Compositing | Operation %i-%li"),
|
||||
RPT_("Compositing | Operation %i-%li"),
|
||||
num_operations_finished_ + 1,
|
||||
operations_.size());
|
||||
tree->runtime->stats_draw(tree->runtime->sdh, buf);
|
||||
|
|
|
@ -23,7 +23,7 @@ TiledExecutionModel::TiledExecutionModel(CompositorContext &context,
|
|||
{
|
||||
const bNodeTree *node_tree = context.get_bnodetree();
|
||||
node_tree->runtime->stats_draw(node_tree->runtime->sdh,
|
||||
TIP_("Compositing | Determining resolution"));
|
||||
RPT_("Compositing | Determining resolution"));
|
||||
|
||||
uint resolution[2];
|
||||
for (ExecutionGroup *group : groups_) {
|
||||
|
@ -103,7 +103,7 @@ void TiledExecutionModel::execute(ExecutionSystem &exec_system)
|
|||
const bNodeTree *editingtree = this->context_.get_bnodetree();
|
||||
|
||||
editingtree->runtime->stats_draw(editingtree->runtime->sdh,
|
||||
TIP_("Compositing | Initializing execution"));
|
||||
RPT_("Compositing | Initializing execution"));
|
||||
|
||||
update_read_buffer_offset(operations_);
|
||||
|
||||
|
@ -122,7 +122,7 @@ void TiledExecutionModel::execute(ExecutionSystem &exec_system)
|
|||
WorkScheduler::stop();
|
||||
|
||||
editingtree->runtime->stats_draw(editingtree->runtime->sdh,
|
||||
TIP_("Compositing | De-initializing execution"));
|
||||
RPT_("Compositing | De-initializing execution"));
|
||||
|
||||
for (NodeOperation *operation : operations_) {
|
||||
operation->deinit_execution();
|
||||
|
|
|
@ -183,6 +183,8 @@ set(GLSL_SRC
|
|||
shaders/compositor_morphological_distance_feather.glsl
|
||||
shaders/compositor_morphological_distance_threshold.glsl
|
||||
shaders/compositor_morphological_step.glsl
|
||||
shaders/compositor_motion_blur.glsl
|
||||
shaders/compositor_motion_blur_max_velocity_dilate.glsl
|
||||
shaders/compositor_movie_distortion.glsl
|
||||
shaders/compositor_normalize.glsl
|
||||
shaders/compositor_parallel_reduction.glsl
|
||||
|
@ -235,6 +237,7 @@ set(GLSL_SRC
|
|||
shaders/library/gpu_shader_compositor_luminance_matte.glsl
|
||||
shaders/library/gpu_shader_compositor_main.glsl
|
||||
shaders/library/gpu_shader_compositor_map_value.glsl
|
||||
shaders/library/gpu_shader_compositor_motion_blur_lib.glsl
|
||||
shaders/library/gpu_shader_compositor_normal.glsl
|
||||
shaders/library/gpu_shader_compositor_ocio_processor.glsl
|
||||
shaders/library/gpu_shader_compositor_posterize.glsl
|
||||
|
@ -304,6 +307,7 @@ set(SRC_SHADER_CREATE_INFOS
|
|||
shaders/infos/compositor_morphological_distance_info.hh
|
||||
shaders/infos/compositor_morphological_distance_threshold_info.hh
|
||||
shaders/infos/compositor_morphological_step_info.hh
|
||||
shaders/infos/compositor_motion_blur_info.hh
|
||||
shaders/infos/compositor_movie_distortion_info.hh
|
||||
shaders/infos/compositor_normalize_info.hh
|
||||
shaders/infos/compositor_parallel_reduction_info.hh
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/* This is identical to the EEVEE implementation in eevee_motion_blur_gather_comp.glsl with the
|
||||
* necessary adjustments to make it work for the compositor:
|
||||
*
|
||||
* - depth_compare() uses an inverted sign since the depth texture stores linear depth.
|
||||
* - The next velocities are inverted since the velocity textures stores the previous and next
|
||||
* velocities in the same direction.
|
||||
* - The samples count is a variable uniform and not fixed to 8 samples.
|
||||
* - The depth scale is constant and set to 100.
|
||||
* - The motion scale is defined by the shutter_speed. */
|
||||
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_compositor_motion_blur_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
|
||||
|
||||
const float g_depth_scale = 100.0;
|
||||
|
||||
/* Interleaved gradient noise by Jorge Jimenez
|
||||
* http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare. */
|
||||
float interleaved_gradient_noise(ivec2 p)
|
||||
{
|
||||
return fract(52.9829189 * fract(0.06711056 * p.x + 0.00583715 * p.y));
|
||||
}
|
||||
|
||||
vec2 spread_compare(float center_motion_length, float sample_motion_length, float offset_length)
|
||||
{
|
||||
return clamp(vec2(center_motion_length, sample_motion_length) - offset_length + 1.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
vec2 depth_compare(float center_depth, float sample_depth)
|
||||
{
|
||||
vec2 depth_scale = vec2(g_depth_scale, -g_depth_scale);
|
||||
return clamp(0.5 + depth_scale * (sample_depth - center_depth), 0.0, 1.0);
|
||||
}
|
||||
|
||||
/* Kill contribution if not going the same direction. */
|
||||
float dir_compare(vec2 offset, vec2 sample_motion, float sample_motion_length)
|
||||
{
|
||||
if (sample_motion_length < 0.5) {
|
||||
return 1.0;
|
||||
}
|
||||
return (dot(offset, sample_motion) > 0.0) ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
/* Return background (x) and foreground (y) weights. */
|
||||
vec2 sample_weights(float center_depth,
|
||||
float sample_depth,
|
||||
float center_motion_length,
|
||||
float sample_motion_length,
|
||||
float offset_length)
|
||||
{
|
||||
/* Classify foreground/background. */
|
||||
vec2 depth_weight = depth_compare(center_depth, sample_depth);
|
||||
/* Weight if sample is overlapping or under the center pixel. */
|
||||
vec2 spread_weight = spread_compare(center_motion_length, sample_motion_length, offset_length);
|
||||
return depth_weight * spread_weight;
|
||||
}
|
||||
|
||||
struct Accumulator {
|
||||
vec4 fg;
|
||||
vec4 bg;
|
||||
/** x: Background, y: Foreground, z: dir. */
|
||||
vec3 weight;
|
||||
};
|
||||
|
||||
void gather_sample(vec2 screen_uv,
|
||||
float center_depth,
|
||||
float center_motion_len,
|
||||
vec2 offset,
|
||||
float offset_len,
|
||||
const bool next,
|
||||
inout Accumulator accum)
|
||||
{
|
||||
vec2 sample_uv = screen_uv - offset / vec2(texture_size(input_tx));
|
||||
vec4 sample_vectors = texture(velocity_tx, sample_uv) *
|
||||
vec4(vec2(shutter_speed), vec2(-shutter_speed));
|
||||
vec2 sample_motion = (next) ? sample_vectors.zw : sample_vectors.xy;
|
||||
float sample_motion_len = length(sample_motion);
|
||||
float sample_depth = texture(depth_tx, sample_uv).r;
|
||||
vec4 sample_color = texture(input_tx, sample_uv);
|
||||
|
||||
vec3 weights;
|
||||
weights.xy = sample_weights(
|
||||
center_depth, sample_depth, center_motion_len, sample_motion_len, offset_len);
|
||||
weights.z = dir_compare(offset, sample_motion, sample_motion_len);
|
||||
weights.xy *= weights.z;
|
||||
|
||||
accum.fg += sample_color * weights.y;
|
||||
accum.bg += sample_color * weights.x;
|
||||
accum.weight += weights;
|
||||
}
|
||||
|
||||
void gather_blur(vec2 screen_uv,
|
||||
vec2 center_motion,
|
||||
float center_depth,
|
||||
vec2 max_motion,
|
||||
float ofs,
|
||||
const bool next,
|
||||
inout Accumulator accum)
|
||||
{
|
||||
float center_motion_len = length(center_motion);
|
||||
float max_motion_len = length(max_motion);
|
||||
|
||||
/* Tile boundaries randomization can fetch a tile where there is less motion than this pixel.
|
||||
* Fix this by overriding the max_motion. */
|
||||
if (max_motion_len < center_motion_len) {
|
||||
max_motion_len = center_motion_len;
|
||||
max_motion = center_motion;
|
||||
}
|
||||
|
||||
if (max_motion_len < 0.5) {
|
||||
return;
|
||||
}
|
||||
|
||||
int i;
|
||||
float t, inc = 1.0 / float(samples_count);
|
||||
for (i = 0, t = ofs * inc; i < samples_count; i++, t += inc) {
|
||||
gather_sample(screen_uv,
|
||||
center_depth,
|
||||
center_motion_len,
|
||||
max_motion * t,
|
||||
max_motion_len * t,
|
||||
next,
|
||||
accum);
|
||||
}
|
||||
|
||||
if (center_motion_len < 0.5) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0, t = ofs * inc; i < samples_count; i++, t += inc) {
|
||||
/* Also sample in center motion direction.
|
||||
* Allow recovering motion where there is conflicting
|
||||
* motion between foreground and background. */
|
||||
gather_sample(screen_uv,
|
||||
center_depth,
|
||||
center_motion_len,
|
||||
center_motion * t,
|
||||
center_motion_len * t,
|
||||
next,
|
||||
accum);
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
|
||||
vec2 uv = (vec2(texel) + 0.5) / vec2(texture_size(input_tx));
|
||||
|
||||
/* Data of the center pixel of the gather (target). */
|
||||
float center_depth = texture_load(depth_tx, texel).x;
|
||||
vec4 center_motion = texture(velocity_tx, uv) * vec4(vec2(shutter_speed), vec2(-shutter_speed));
|
||||
vec4 center_color = textureLod(input_tx, uv, 0.0);
|
||||
|
||||
/* Randomize tile boundary to avoid ugly discontinuities. Randomize 1/4th of the tile.
|
||||
* Note this randomize only in one direction but in practice it's enough. */
|
||||
float rand = interleaved_gradient_noise(texel);
|
||||
ivec2 tile = (texel + ivec2(rand * 2.0 - 1.0 * float(MOTION_BLUR_TILE_SIZE) * 0.25)) /
|
||||
MOTION_BLUR_TILE_SIZE;
|
||||
|
||||
vec4 max_motion;
|
||||
/* Load dilation result from the indirection table. */
|
||||
ivec2 tile_prev;
|
||||
motion_blur_tile_indirection_load(tile_indirection_buf, MOTION_PREV, uvec2(tile), tile_prev);
|
||||
max_motion.xy = texture_load(max_velocity_tx, tile_prev).xy;
|
||||
ivec2 tile_next;
|
||||
motion_blur_tile_indirection_load(tile_indirection_buf, MOTION_NEXT, uvec2(tile), tile_next);
|
||||
max_motion.zw = texture_load(max_velocity_tx, tile_next).zw;
|
||||
|
||||
max_motion *= vec4(vec2(shutter_speed), vec2(-shutter_speed));
|
||||
|
||||
Accumulator accum;
|
||||
accum.weight = vec3(0.0, 0.0, 1.0);
|
||||
accum.bg = vec4(0.0);
|
||||
accum.fg = vec4(0.0);
|
||||
/* First linear gather. time = [T - delta, T] */
|
||||
gather_blur(uv, center_motion.xy, center_depth, max_motion.xy, rand, false, accum);
|
||||
/* Second linear gather. time = [T, T + delta] */
|
||||
gather_blur(uv, center_motion.zw, center_depth, max_motion.zw, rand, true, accum);
|
||||
|
||||
#if 1 /* Own addition. Not present in reference implementation. */
|
||||
/* Avoid division by 0.0. */
|
||||
float w = 1.0 / (50.0 * float(samples_count) * 4.0);
|
||||
accum.bg += center_color * w;
|
||||
accum.weight.x += w;
|
||||
/* NOTE: In Jimenez's presentation, they used center sample.
|
||||
* We use background color as it contains more information for foreground
|
||||
* elements that have not enough weights.
|
||||
* Yield better blur in complex motion. */
|
||||
center_color = accum.bg / accum.weight.x;
|
||||
#endif
|
||||
/* Merge background. */
|
||||
accum.fg += accum.bg;
|
||||
accum.weight.y += accum.weight.x;
|
||||
/* Balance accumulation for failed samples.
|
||||
* We replace the missing foreground by the background. */
|
||||
float blend_fac = clamp(1.0 - accum.weight.y / accum.weight.z, 0.0, 1.0);
|
||||
vec4 out_color = (accum.fg / accum.weight.z) + center_color * blend_fac;
|
||||
|
||||
imageStore(output_img, texel, out_color);
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/* Identical to eevee_motion_blur_dilate_comp.glsl but with minor adjustments to work with the
|
||||
* compositor. */
|
||||
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_base_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_compositor_motion_blur_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
|
||||
|
||||
struct MotionRect {
|
||||
ivec2 bottom_left;
|
||||
ivec2 extent;
|
||||
};
|
||||
|
||||
MotionRect compute_motion_rect(ivec2 tile, vec2 motion)
|
||||
{
|
||||
/* `ceil()` to number of tile touched. */
|
||||
ivec2 point1 = tile + ivec2(sign(motion) * ceil(abs(motion) / float(MOTION_BLUR_TILE_SIZE)));
|
||||
ivec2 point2 = tile;
|
||||
|
||||
ivec2 max_point = max(point1, point2);
|
||||
ivec2 min_point = min(point1, point2);
|
||||
/* Clamp to bounds. */
|
||||
max_point = min(max_point, texture_size(input_tx) - 1);
|
||||
min_point = max(min_point, ivec2(0));
|
||||
|
||||
MotionRect rect;
|
||||
rect.bottom_left = min_point;
|
||||
rect.extent = 1 + max_point - min_point;
|
||||
return rect;
|
||||
}
|
||||
|
||||
struct MotionLine {
|
||||
/** Origin of the line. */
|
||||
vec2 origin;
|
||||
/** Normal to the line direction. */
|
||||
vec2 normal;
|
||||
};
|
||||
|
||||
MotionLine compute_motion_line(ivec2 tile, vec2 motion)
|
||||
{
|
||||
float magnitude = length(motion);
|
||||
vec2 dir = magnitude != 0.0 ? motion / magnitude : motion;
|
||||
|
||||
MotionLine line;
|
||||
line.origin = vec2(tile);
|
||||
/* Rotate 90 degrees counter-clockwise. */
|
||||
line.normal = vec2(-dir.y, dir.x);
|
||||
return line;
|
||||
}
|
||||
|
||||
bool is_inside_motion_line(ivec2 tile, MotionLine motion_line)
|
||||
{
|
||||
/* NOTE: Everything in is tile unit. */
|
||||
float distance_to_line = dot(motion_line.normal, motion_line.origin - vec2(tile));
|
||||
/* In order to be conservative and for simplicity, we use the tiles bounding circles.
|
||||
* Consider that both the tile and the line have bounding radius of M_SQRT1_2. */
|
||||
return abs(distance_to_line) < M_SQRT2;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 src_tile = ivec2(gl_GlobalInvocationID.xy);
|
||||
if (any(greaterThanEqual(src_tile, texture_size(input_tx)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 max_motion = texture_load(input_tx, src_tile) *
|
||||
vec4(vec2(shutter_speed), vec2(-shutter_speed));
|
||||
|
||||
MotionPayload payload_prv = motion_blur_tile_indirection_pack_payload(max_motion.xy,
|
||||
uvec2(src_tile));
|
||||
MotionPayload payload_nxt = motion_blur_tile_indirection_pack_payload(max_motion.zw,
|
||||
uvec2(src_tile));
|
||||
if (true) {
|
||||
/* Rectangular area (in tiles) where the motion vector spreads. */
|
||||
MotionRect motion_rect = compute_motion_rect(src_tile, max_motion.xy);
|
||||
MotionLine motion_line = compute_motion_line(src_tile, max_motion.xy);
|
||||
/* Do a conservative rasterization of the line of the motion vector line. */
|
||||
for (int x = 0; x < motion_rect.extent.x; x++) {
|
||||
for (int y = 0; y < motion_rect.extent.y; y++) {
|
||||
ivec2 tile = motion_rect.bottom_left + ivec2(x, y);
|
||||
if (is_inside_motion_line(tile, motion_line)) {
|
||||
motion_blur_tile_indirection_store(
|
||||
tile_indirection_buf, MOTION_PREV, uvec2(tile), payload_prv);
|
||||
/* FIXME: This is a bit weird, but for some reason, we need the store the same vector in
|
||||
* the motion next so that weighting in gather pass is better. */
|
||||
motion_blur_tile_indirection_store(
|
||||
tile_indirection_buf, MOTION_NEXT, uvec2(tile), payload_nxt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (true) {
|
||||
MotionPayload payload = motion_blur_tile_indirection_pack_payload(max_motion.zw,
|
||||
uvec2(src_tile));
|
||||
/* Rectangular area (in tiles) where the motion vector spreads. */
|
||||
MotionRect motion_rect = compute_motion_rect(src_tile, max_motion.zw);
|
||||
MotionLine motion_line = compute_motion_line(src_tile, max_motion.zw);
|
||||
/* Do a conservative rasterization of the line of the motion vector line. */
|
||||
for (int x = 0; x < motion_rect.extent.x; x++) {
|
||||
for (int y = 0; y < motion_rect.extent.y; y++) {
|
||||
ivec2 tile = motion_rect.bottom_left + ivec2(x, y);
|
||||
if (is_inside_motion_line(tile, motion_line)) {
|
||||
motion_blur_tile_indirection_store(
|
||||
tile_indirection_buf, MOTION_NEXT, uvec2(tile), payload_nxt);
|
||||
/* FIXME: This is a bit weird, but for some reason, we need the store the same vector in
|
||||
* the motion next so that weighting in gather pass is better. */
|
||||
motion_blur_tile_indirection_store(
|
||||
tile_indirection_buf, MOTION_PREV, uvec2(tile), payload_prv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
GPU_SHADER_CREATE_INFO(compositor_motion_blur_max_velocity_dilate)
|
||||
.local_group_size(16, 16)
|
||||
.push_constant(Type::FLOAT, "shutter_speed")
|
||||
.sampler(0, ImageType::FLOAT_2D, "input_tx")
|
||||
.storage_buf(0, Qualifier::READ_WRITE, "uint", "tile_indirection_buf[]")
|
||||
.compute_source("compositor_motion_blur_max_velocity_dilate.glsl")
|
||||
.do_static_compilation(true);
|
||||
|
||||
GPU_SHADER_CREATE_INFO(compositor_motion_blur)
|
||||
.local_group_size(16, 16)
|
||||
.push_constant(Type::INT, "samples_count")
|
||||
.push_constant(Type::FLOAT, "shutter_speed")
|
||||
.sampler(0, ImageType::FLOAT_2D, "input_tx")
|
||||
.sampler(1, ImageType::FLOAT_2D, "depth_tx")
|
||||
.sampler(2, ImageType::FLOAT_2D, "velocity_tx")
|
||||
.sampler(3, ImageType::FLOAT_2D, "max_velocity_tx")
|
||||
.storage_buf(0, Qualifier::READ, "uint", "tile_indirection_buf[]")
|
||||
.image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
|
||||
.compute_source("compositor_motion_blur.glsl")
|
||||
.do_static_compilation(true);
|
|
@ -149,3 +149,22 @@ GPU_SHADER_CREATE_INFO(compositor_minimum_float_in_range)
|
|||
.define("LOAD(value)", "value.x")
|
||||
.define("REDUCE(lhs, rhs)", "((rhs < lhs) && (rhs >= lower_bound)) ? rhs : lhs")
|
||||
.do_static_compilation(true);
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Velocity Reductions.
|
||||
*/
|
||||
|
||||
GPU_SHADER_CREATE_INFO(compositor_max_velocity)
|
||||
.local_group_size(32, 32)
|
||||
.push_constant(Type::BOOL, "is_initial_reduction")
|
||||
.sampler(0, ImageType::FLOAT_2D, "input_tx")
|
||||
.image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
|
||||
.define("TYPE", "vec4")
|
||||
.define("IDENTITY", "vec4(0.0)")
|
||||
.define("INITIALIZE(value)", "value")
|
||||
.define("LOAD(value)", "value")
|
||||
.define("REDUCE(lhs, rhs)",
|
||||
"vec4(dot(lhs.xy, lhs.xy) > dot(rhs.xy, rhs.xy) ? lhs.xy : rhs.xy,"
|
||||
" dot(lhs.zw, lhs.zw) > dot(rhs.zw, rhs.zw) ? lhs.zw : rhs.zw)")
|
||||
.compute_source("compositor_parallel_reduction.glsl")
|
||||
.do_static_compilation(true);
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/* Identical copy to eevee_motion_blur_lib.glsl, but with the needed macros defined inline. */
|
||||
|
||||
#define MOTION_BLUR_TILE_SIZE 32
|
||||
#define MOTION_BLUR_MAX_TILE 512 /* 16384 / MOTION_BLUR_TILE_SIZE */
|
||||
#define MotionPayload uint
|
||||
|
||||
/* Store velocity magnitude in the MSB to be able to use it with atomicMax operations. */
|
||||
MotionPayload motion_blur_tile_indirection_pack_payload(vec2 motion, uvec2 payload)
|
||||
{
|
||||
/* NOTE: Clamp to 16383 pixel velocity. After that, it is tile position that determine the tile
|
||||
* to dilate over. */
|
||||
uint velocity = min(uint(ceil(length(motion))), 0x3FFFu);
|
||||
/* Designed for 512x512 tiles max. */
|
||||
return (velocity << 18u) | ((payload.x & 0x1FFu) << 9u) | (payload.y & 0x1FFu);
|
||||
}
|
||||
|
||||
/* Return thread index. */
|
||||
ivec2 motion_blur_tile_indirection_pack_payload(uint data)
|
||||
{
|
||||
return ivec2((data >> 9u) & 0x1FFu, data & 0x1FFu);
|
||||
}
|
||||
|
||||
uint motion_blur_tile_indirection_index(uint motion_step, uvec2 tile)
|
||||
{
|
||||
uint index = tile.x;
|
||||
index += tile.y * MOTION_BLUR_MAX_TILE;
|
||||
index += motion_step * MOTION_BLUR_MAX_TILE * MOTION_BLUR_MAX_TILE;
|
||||
return index;
|
||||
}
|
||||
|
||||
#define MOTION_PREV 0u
|
||||
#define MOTION_NEXT 1u
|
||||
|
||||
#define motion_blur_tile_indirection_store(table_, step_, tile, payload_) \
|
||||
if (true) { \
|
||||
uint index = motion_blur_tile_indirection_index(step_, tile); \
|
||||
atomicMax(table_[index], payload_); \
|
||||
}
|
||||
|
||||
#define motion_blur_tile_indirection_load(table_, step_, tile_, result_) \
|
||||
if (true) { \
|
||||
uint index = motion_blur_tile_indirection_index(step_, tile_); \
|
||||
result_ = motion_blur_tile_indirection_pack_payload(table_[index]); \
|
||||
}
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_collection.h"
|
||||
#include "BKE_lib_id.h"
|
||||
|
||||
#include "RNA_prototypes.h"
|
||||
|
||||
|
@ -210,7 +211,8 @@ void deg_graph_build_finalize(Main *bmain, Depsgraph *graph)
|
|||
* removed from the graph based on their inclusion and visibility flags). */
|
||||
const ID_Type id_type = GS(id_node->id_cow->name);
|
||||
if (id_type == ID_GR) {
|
||||
BKE_collection_object_cache_free(reinterpret_cast<Collection *>(id_node->id_cow));
|
||||
BKE_collection_object_cache_free(
|
||||
nullptr, reinterpret_cast<Collection *>(id_node->id_cow), LIB_ID_CREATE_NO_DEG_TAG);
|
||||
}
|
||||
}
|
||||
/* Restore recalc flags from original ID, which could possibly contain recalc flags set by
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "BLI_listbase.h"
|
||||
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_mesh_types.hh"
|
||||
#include "BKE_object.hh"
|
||||
#include "BKE_object_types.hh"
|
||||
|
||||
|
@ -161,6 +162,15 @@ void ObjectRuntimeBackup::restore_modifier_runtime_data(Object *object)
|
|||
const ModifierTypeInfo *modifier_type_info = BKE_modifier_get_info(backup.type);
|
||||
BLI_assert(modifier_type_info != nullptr);
|
||||
modifier_type_info->free_runtime_data(backup.runtime);
|
||||
|
||||
if (backup.type == eModifierType_Subsurf) {
|
||||
if (object->type == OB_MESH) {
|
||||
Mesh *mesh = (Mesh *)object->data;
|
||||
if (mesh->runtime->subsurf_runtime_data == backup.runtime) {
|
||||
mesh->runtime->subsurf_runtime_data = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -183,11 +183,11 @@ static void eevee_cache_finish(void *vedata)
|
|||
}
|
||||
|
||||
if (g_data->queued_shaders_count > 0) {
|
||||
SNPRINTF(ved->info, TIP_("Compiling Shaders (%d remaining)"), g_data->queued_shaders_count);
|
||||
SNPRINTF(ved->info, RPT_("Compiling Shaders (%d remaining)"), g_data->queued_shaders_count);
|
||||
}
|
||||
else if (g_data->queued_optimise_shaders_count > 0) {
|
||||
SNPRINTF(ved->info,
|
||||
TIP_("Optimizing Shaders (%d remaining)"),
|
||||
RPT_("Optimizing Shaders (%d remaining)"),
|
||||
g_data->queued_optimise_shaders_count);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -225,31 +225,31 @@ void EEVEE_lightcache_info_update(SceneEEVEE *eevee)
|
|||
if (lcache != nullptr) {
|
||||
if (!eevee_lightcache_version_check(lcache)) {
|
||||
BLI_strncpy(eevee->light_cache_info,
|
||||
TIP_("Incompatible Light cache version, please bake again"),
|
||||
N_("Incompatible Light cache version, please bake again"),
|
||||
sizeof(eevee->light_cache_info));
|
||||
return;
|
||||
}
|
||||
|
||||
if (lcache->cube_tx.tex_size[2] > GPU_max_texture_layers()) {
|
||||
STRNCPY(eevee->light_cache_info,
|
||||
TIP_("Error: Light cache is too big for the GPU to be loaded"));
|
||||
N_("Error: Light cache is too big for the GPU to be loaded"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (lcache->flag & LIGHTCACHE_INVALID) {
|
||||
STRNCPY(eevee->light_cache_info,
|
||||
TIP_("Error: Light cache dimensions not supported by the GPU"));
|
||||
N_("Error: Light cache dimensions not supported by the GPU"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (lcache->flag & LIGHTCACHE_BAKING) {
|
||||
STRNCPY(eevee->light_cache_info, TIP_("Baking light cache"));
|
||||
STRNCPY(eevee->light_cache_info, N_("Baking light cache"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!eevee_lightcache_can_be_saved(lcache)) {
|
||||
STRNCPY(eevee->light_cache_info,
|
||||
TIP_("Error: LightCache is too large and will not be saved to disk"));
|
||||
N_("Error: LightCache is too large and will not be saved to disk"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -258,14 +258,16 @@ void EEVEE_lightcache_info_update(SceneEEVEE *eevee)
|
|||
|
||||
int irr_samples = eevee_lightcache_irradiance_sample_count(lcache);
|
||||
|
||||
/* This message needs to be translated here instead of the UI code, otherwise it would already
|
||||
* be formatted and translation would not work. */
|
||||
SNPRINTF(eevee->light_cache_info,
|
||||
TIP_("%d Ref. Cubemaps, %d Irr. Samples (%s in memory)"),
|
||||
RPT_("%d Ref. Cubemaps, %d Irr. Samples (%s in memory)"),
|
||||
lcache->cube_len - 1,
|
||||
irr_samples,
|
||||
formatted_mem);
|
||||
}
|
||||
else {
|
||||
STRNCPY(eevee->light_cache_info, TIP_("No light cache in this scene"));
|
||||
STRNCPY(eevee->light_cache_info, N_("No light cache in this scene"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -420,6 +420,7 @@ void DeferredLayerBase::gbuffer_pass_sync(Instance &inst)
|
|||
gbuffer_ps_.init();
|
||||
gbuffer_ps_.subpass_transition(GPU_ATTACHEMENT_WRITE,
|
||||
{GPU_ATTACHEMENT_WRITE,
|
||||
GPU_ATTACHEMENT_WRITE,
|
||||
GPU_ATTACHEMENT_WRITE,
|
||||
GPU_ATTACHEMENT_WRITE,
|
||||
GPU_ATTACHEMENT_WRITE});
|
||||
|
@ -519,6 +520,7 @@ void DeferredLayer::end_sync()
|
|||
{GPU_ATTACHEMENT_IGNORE,
|
||||
GPU_ATTACHEMENT_READ, /* Header. */
|
||||
GPU_ATTACHEMENT_IGNORE,
|
||||
GPU_ATTACHEMENT_IGNORE,
|
||||
GPU_ATTACHEMENT_IGNORE});
|
||||
sub.shader_set(sh);
|
||||
sub.state_set(DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS);
|
||||
|
|
|
@ -15,16 +15,6 @@
|
|||
|
||||
#define GGX_USE_VISIBLE_NORMAL 1
|
||||
|
||||
float sample_pdf_ggx_reflect(float NH, float NV, float VH, float G1_V, float alpha)
|
||||
{
|
||||
float a2 = square(alpha);
|
||||
#if GGX_USE_VISIBLE_NORMAL
|
||||
return 0.25 * bxdf_ggx_D(NH, a2) * G1_V / NV;
|
||||
#else
|
||||
return NH * bxdf_ggx_D(NH, a2);
|
||||
#endif
|
||||
}
|
||||
|
||||
float sample_pdf_ggx_refract(
|
||||
float NH, float NV, float VH, float LH, float G1_V, float alpha, float eta)
|
||||
{
|
||||
|
@ -39,35 +29,33 @@ float sample_pdf_ggx_refract(
|
|||
*
|
||||
* \param rand: random point on the unit cylinder (result of sample_cylinder).
|
||||
* \param alpha: roughness parameter.
|
||||
* \param tV: tangent space view vector.
|
||||
* \param Vt: tangent space view vector.
|
||||
* \param G1_V: output G1_V factor to be reused.
|
||||
*/
|
||||
vec3 sample_ggx(vec3 rand, float alpha, vec3 Vt, out float G1_V)
|
||||
{
|
||||
#if GGX_USE_VISIBLE_NORMAL
|
||||
/* From:
|
||||
* "A Simpler and Exact Sampling Routine for the GGXDistribution of Visible Normals"
|
||||
* by Eric Heitz.
|
||||
* http://jcgt.org/published/0007/04/01/slides.pdf
|
||||
/* Sampling Visible GGX Normals with Spherical Caps.
|
||||
* Jonathan Dupuy and Anis Benyoub, HPG Vol. 42, No. 8, 2023.
|
||||
* https://diglib.eg.org/bitstream/handle/10.1111/cgf14867/v42i8_03_14867.pdf
|
||||
* View vector is expected to be in tangent space. */
|
||||
|
||||
/* Stretch view. */
|
||||
vec3 Th, Bh, Vh = normalize(vec3(alpha * Vt.xy, Vt.z));
|
||||
make_orthonormal_basis(Vh, Th, Bh);
|
||||
/* Sample point with polar coordinates (r, phi). */
|
||||
float r = sqrt(rand.x);
|
||||
float x = r * rand.y;
|
||||
float y = r * rand.z;
|
||||
float s = 0.5 * (1.0 + Vh.z);
|
||||
G1_V = Vh.z / s;
|
||||
y = (1.0 - s) * sqrt(1.0 - x * x) + s * y;
|
||||
float z = sqrt(saturate(1.0 - x * x - y * y));
|
||||
/* Compute normal. */
|
||||
vec3 Hh = x * Th + y * Bh + z * Vh;
|
||||
/* Unstretch. */
|
||||
vec3 Ht = normalize(vec3(alpha * Hh.xy, saturate(Hh.z)));
|
||||
/* Microfacet Normal. */
|
||||
return Ht;
|
||||
/* Transforming the view direction to the hemisphere configuration. */
|
||||
vec3 Vh = normalize(vec3(alpha * Vt.xy, Vt.z));
|
||||
|
||||
/* Visibility term. */
|
||||
G1_V = 2.0 * Vh.z / (1.0 + Vh.z);
|
||||
|
||||
/* Sample a spherical cap in (-Vh.z, 1]. */
|
||||
float cos_theta = mix(-Vh.z, 1.0, 1.0 - rand.x);
|
||||
float sin_theta = sqrt(saturate(1.0 - square(cos_theta)));
|
||||
vec3 Lh = vec3(sin_theta * rand.yz, cos_theta);
|
||||
|
||||
/* Compute unnormalized halfway direction. */
|
||||
vec3 Hh = Vh + Lh;
|
||||
|
||||
/* Transforming the normal back to the ellipsoid configuration. */
|
||||
return normalize(vec3(alpha * Hh.xy, max(0.0, Hh.z)));
|
||||
#else
|
||||
/* Theta is the cone angle. */
|
||||
float z = sqrt((1.0 - rand.x) / (1.0 + square(alpha) * rand.x - rand.x)); /* cos theta */
|
||||
|
@ -85,6 +73,41 @@ vec3 sample_ggx(vec3 rand, float alpha, vec3 Vt)
|
|||
return sample_ggx(rand, alpha, Vt, G1_unused);
|
||||
}
|
||||
|
||||
/* Similar as `sample_ggx()`, but reduces the number or rejected samples due to reflection in the
|
||||
* lower hemisphere, and returns `pdf` instead of `G1_V`. Only used for reflection.
|
||||
*
|
||||
* Sampling visible GGX normals with bounded spherical caps.
|
||||
* Eto, Kenta, and Yusuke Tokuyoshi. "Bounded VNDF Sampling for Smith-GGX Reflections."
|
||||
* SIGGRAPH Asia 2023 Technical Communications. 2023. 1-4.
|
||||
* https://gpuopen.com/download/publications/Bounded_VNDF_Sampling_for_Smith-GGX_Reflections.pdf */
|
||||
vec3 sample_ggx_bounded(vec3 rand, float alpha, vec3 Vt, out float pdf)
|
||||
{
|
||||
/* Transforming the view direction to the hemisphere configuration. */
|
||||
vec3 Vh = vec3(alpha * Vt.xy, Vt.z);
|
||||
float norm = length(Vh);
|
||||
Vh = Vh / norm;
|
||||
|
||||
/* Compute the bounded cap. */
|
||||
float a2 = square(alpha);
|
||||
float s2 = square(1.0 + length(Vt.xy));
|
||||
float k = (1.0 - a2) * s2 / (s2 + a2 * square(Vt.z));
|
||||
|
||||
/* Sample a spherical cap in (-Vh.z * k, 1]. */
|
||||
float cos_theta = mix(-Vh.z * k, 1.0, 1.0 - rand.x);
|
||||
float sin_theta = sqrt(saturate(1.0 - square(cos_theta)));
|
||||
vec3 Lh = vec3(sin_theta * rand.yz, cos_theta);
|
||||
|
||||
/* Compute unnormalized halfway direction. */
|
||||
vec3 Hh = Vh + Lh;
|
||||
|
||||
/* Transforming the normal back to the ellipsoid configuration. */
|
||||
vec3 Ht = normalize(vec3(alpha * Hh.xy, max(0.0, Hh.z)));
|
||||
|
||||
pdf = 0.5 * bxdf_ggx_D(saturate(Ht.z), a2) / (k * Vt.z + norm);
|
||||
|
||||
return Ht;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reflected ray direction following the GGX distribution.
|
||||
*
|
||||
|
@ -99,17 +122,12 @@ vec3 sample_ggx(vec3 rand, float alpha, vec3 Vt)
|
|||
*/
|
||||
vec3 sample_ggx_reflect(vec3 rand, float alpha, vec3 V, vec3 N, vec3 T, vec3 B, out float pdf)
|
||||
{
|
||||
float G1_V;
|
||||
vec3 tV = world_to_tangent(V, N, T, B);
|
||||
vec3 tH = sample_ggx(rand, alpha, tV, G1_V);
|
||||
float NH = saturate(tH.z);
|
||||
float NV = saturate(tV.z);
|
||||
float VH = dot(tV, tH);
|
||||
vec3 H = tangent_to_world(tH, N, T, B);
|
||||
vec3 Vt = world_to_tangent(V, N, T, B);
|
||||
vec3 Ht = sample_ggx_bounded(rand, alpha, Vt, pdf);
|
||||
vec3 H = tangent_to_world(Ht, N, T, B);
|
||||
|
||||
if (VH > 0.0) {
|
||||
if (dot(V, H) > 0.0) {
|
||||
vec3 L = reflect(-V, H);
|
||||
pdf = sample_pdf_ggx_reflect(NH, NV, VH, G1_V, alpha);
|
||||
return L;
|
||||
}
|
||||
pdf = 0.0;
|
||||
|
|
|
@ -492,11 +492,13 @@ static void grease_pencil_geom_batch_ensure(Object &object,
|
|||
const VArray<float> selection_float = *attributes.lookup_or_default<float>(
|
||||
".selection", bke::AttrDomain::Point, true);
|
||||
const VArray<int8_t> start_caps = *attributes.lookup_or_default<int8_t>(
|
||||
"start_cap", bke::AttrDomain::Curve, 0);
|
||||
"start_cap", bke::AttrDomain::Curve, GP_STROKE_CAP_TYPE_ROUND);
|
||||
const VArray<int8_t> end_caps = *attributes.lookup_or_default<int8_t>(
|
||||
"end_cap", bke::AttrDomain::Curve, 0);
|
||||
"end_cap", bke::AttrDomain::Curve, GP_STROKE_CAP_TYPE_ROUND);
|
||||
const VArray<int> materials = *attributes.lookup_or_default<int>(
|
||||
"material_index", bke::AttrDomain::Curve, 0);
|
||||
const VArray<float> hardness = *attributes.lookup_or_default<float>(
|
||||
"hardness", bke::AttrDomain::Curve, 1.0f);
|
||||
const Span<uint3> triangles = info.drawing.triangles();
|
||||
const Span<int> verts_start_offsets = verts_start_offsets_per_visible_drawing[drawing_i];
|
||||
const Span<int> tris_start_offsets = tris_start_offsets_per_visible_drawing[drawing_i];
|
||||
|
@ -520,8 +522,8 @@ static void grease_pencil_geom_batch_ensure(Object &object,
|
|||
s_vert.stroke_id = verts_range.first();
|
||||
s_vert.mat = materials[curve_i] % GPENCIL_MATERIAL_BUFFER_LEN;
|
||||
|
||||
/* TODO: Populate rotation, aspect and hardness. */
|
||||
s_vert.packed_asp_hard_rot = pack_rotation_aspect_hardness(0.0f, 1.0f, 1.0f);
|
||||
/* TODO: Populate rotation and aspect. */
|
||||
s_vert.packed_asp_hard_rot = pack_rotation_aspect_hardness(0.0f, 1.0f, hardness[curve_i]);
|
||||
/* TODO: Populate stroke UVs. */
|
||||
s_vert.u_stroke = 0;
|
||||
/* TODO: Populate fill UVs. */
|
||||
|
|
|
@ -5430,7 +5430,7 @@ static void draw_setting_widget(bAnimContext *ac,
|
|||
!BKE_id_is_editable(ac->bmain, ale->id)))
|
||||
{
|
||||
if (setting != ACHANNEL_SETTING_EXPAND) {
|
||||
UI_but_disable(but, TIP_("Can't edit this property from a linked data-block"));
|
||||
UI_but_disable(but, "Can't edit this property from a linked data-block");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,10 +46,10 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
|
|||
|
||||
if (ELEM(nullptr, id, fcu, fcu->rna_path)) {
|
||||
if (fcu == nullptr) {
|
||||
BLI_strncpy(name, TIP_("<invalid>"), name_maxncpy);
|
||||
BLI_strncpy(name, RPT_("<invalid>"), name_maxncpy);
|
||||
}
|
||||
else if (fcu->rna_path == nullptr) {
|
||||
BLI_strncpy(name, TIP_("<no path>"), name_maxncpy);
|
||||
BLI_strncpy(name, RPT_("<no path>"), name_maxncpy);
|
||||
}
|
||||
else { /* id == nullptr */
|
||||
BLI_snprintf(name, name_maxncpy, "%s[%d]", fcu->rna_path, fcu->array_index);
|
||||
|
|
|
@ -866,14 +866,14 @@ static void ed_marker_move_update_header(bContext *C, wmOperator *op)
|
|||
if (totmark == 1 && selmarker) {
|
||||
/* we print current marker value */
|
||||
if (use_time) {
|
||||
SNPRINTF(str, TIP_("Marker %.2f offset %s"), FRA2TIME(selmarker->frame), str_ofs);
|
||||
SNPRINTF(str, RPT_("Marker %.2f offset %s"), FRA2TIME(selmarker->frame), str_ofs);
|
||||
}
|
||||
else {
|
||||
SNPRINTF(str, TIP_("Marker %d offset %s"), selmarker->frame, str_ofs);
|
||||
SNPRINTF(str, RPT_("Marker %d offset %s"), selmarker->frame, str_ofs);
|
||||
}
|
||||
}
|
||||
else {
|
||||
SNPRINTF(str, TIP_("Marker offset %s"), str_ofs);
|
||||
SNPRINTF(str, RPT_("Marker offset %s"), str_ofs);
|
||||
}
|
||||
|
||||
ED_area_status_text(CTX_wm_area(C), str);
|
||||
|
|
|
@ -129,7 +129,7 @@ void update_autoflags_fcurve(FCurve *fcu, bContext *C, ReportList *reports, Poin
|
|||
/* try to get property we should be affecting */
|
||||
if (RNA_path_resolve_property(ptr, fcu->rna_path, &tmp_ptr, &prop) == false) {
|
||||
/* property not found... */
|
||||
const char *idname = (ptr->owner_id) ? ptr->owner_id->name : TIP_("<No ID pointer>");
|
||||
const char *idname = (ptr->owner_id) ? ptr->owner_id->name : RPT_("<No ID pointer>");
|
||||
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -321,7 +321,7 @@ static bool poselib_blend_init_data(bContext *C, wmOperator *op, const wmEvent *
|
|||
/* check if valid poselib */
|
||||
Object *ob = get_poselib_object(C);
|
||||
if (ELEM(nullptr, ob, ob->pose, ob->data)) {
|
||||
BKE_report(op->reports, RPT_ERROR, TIP_("Pose lib is only for armatures in pose mode"));
|
||||
BKE_report(op->reports, RPT_ERROR, "Pose lib is only for armatures in pose mode");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -500,10 +500,10 @@ static int poselib_blend_modal(bContext *C, wmOperator *op, const wmEvent *event
|
|||
ED_slider_status_string_get(pbd->slider, slider_string, sizeof(slider_string));
|
||||
|
||||
if (pbd->state == POSE_BLEND_BLENDING) {
|
||||
STRNCPY(tab_string, TIP_("[Tab] - Show original pose"));
|
||||
STRNCPY(tab_string, RPT_("[Tab] - Show original pose"));
|
||||
}
|
||||
else {
|
||||
STRNCPY(tab_string, TIP_("[Tab] - Show blended pose"));
|
||||
STRNCPY(tab_string, RPT_("[Tab] - Show blended pose"));
|
||||
}
|
||||
|
||||
SNPRINTF(status_string, "%s | %s | [Ctrl] - Flip Pose", tab_string, slider_string);
|
||||
|
|
|
@ -922,38 +922,38 @@ static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso)
|
|||
|
||||
switch (pso->mode) {
|
||||
case POSESLIDE_PUSH:
|
||||
STRNCPY(mode_str, TIP_("Push Pose"));
|
||||
STRNCPY(mode_str, RPT_("Push Pose"));
|
||||
break;
|
||||
case POSESLIDE_RELAX:
|
||||
STRNCPY(mode_str, TIP_("Relax Pose"));
|
||||
STRNCPY(mode_str, RPT_("Relax Pose"));
|
||||
break;
|
||||
case POSESLIDE_BREAKDOWN:
|
||||
STRNCPY(mode_str, TIP_("Breakdown"));
|
||||
STRNCPY(mode_str, RPT_("Breakdown"));
|
||||
break;
|
||||
case POSESLIDE_BLEND:
|
||||
STRNCPY(mode_str, TIP_("Blend to Neighbor"));
|
||||
STRNCPY(mode_str, RPT_("Blend to Neighbor"));
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Unknown. */
|
||||
STRNCPY(mode_str, TIP_("Sliding-Tool"));
|
||||
STRNCPY(mode_str, RPT_("Sliding-Tool"));
|
||||
break;
|
||||
}
|
||||
|
||||
switch (pso->axislock) {
|
||||
case PS_LOCK_X:
|
||||
STRNCPY(axis_str, TIP_("[X]/Y/Z axis only (X to clear)"));
|
||||
STRNCPY(axis_str, RPT_("[X]/Y/Z axis only (X to clear)"));
|
||||
break;
|
||||
case PS_LOCK_Y:
|
||||
STRNCPY(axis_str, TIP_("X/[Y]/Z axis only (Y to clear)"));
|
||||
STRNCPY(axis_str, RPT_("X/[Y]/Z axis only (Y to clear)"));
|
||||
break;
|
||||
case PS_LOCK_Z:
|
||||
STRNCPY(axis_str, TIP_("X/Y/[Z] axis only (Z to clear)"));
|
||||
STRNCPY(axis_str, RPT_("X/Y/[Z] axis only (Z to clear)"));
|
||||
break;
|
||||
|
||||
default:
|
||||
if (ELEM(pso->channels, PS_TFM_LOC, PS_TFM_ROT, PS_TFM_SIZE)) {
|
||||
STRNCPY(axis_str, TIP_("X/Y/Z = Axis Constraint"));
|
||||
STRNCPY(axis_str, RPT_("X/Y/Z = Axis Constraint"));
|
||||
}
|
||||
else {
|
||||
axis_str[0] = '\0';
|
||||
|
@ -963,26 +963,26 @@ static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso)
|
|||
|
||||
switch (pso->channels) {
|
||||
case PS_TFM_LOC:
|
||||
SNPRINTF(limits_str, TIP_("[G]/R/S/B/C - Location only (G to clear) | %s"), axis_str);
|
||||
SNPRINTF(limits_str, RPT_("[G]/R/S/B/C - Location only (G to clear) | %s"), axis_str);
|
||||
break;
|
||||
case PS_TFM_ROT:
|
||||
SNPRINTF(limits_str, TIP_("G/[R]/S/B/C - Rotation only (R to clear) | %s"), axis_str);
|
||||
SNPRINTF(limits_str, RPT_("G/[R]/S/B/C - Rotation only (R to clear) | %s"), axis_str);
|
||||
break;
|
||||
case PS_TFM_SIZE:
|
||||
SNPRINTF(limits_str, TIP_("G/R/[S]/B/C - Scale only (S to clear) | %s"), axis_str);
|
||||
SNPRINTF(limits_str, RPT_("G/R/[S]/B/C - Scale only (S to clear) | %s"), axis_str);
|
||||
break;
|
||||
case PS_TFM_BBONE_SHAPE:
|
||||
STRNCPY(limits_str, TIP_("G/R/S/[B]/C - Bendy Bone properties only (B to clear) | %s"));
|
||||
STRNCPY(limits_str, RPT_("G/R/S/[B]/C - Bendy Bone properties only (B to clear) | %s"));
|
||||
break;
|
||||
case PS_TFM_PROPS:
|
||||
STRNCPY(limits_str, TIP_("G/R/S/B/[C] - Custom Properties only (C to clear) | %s"));
|
||||
STRNCPY(limits_str, RPT_("G/R/S/B/[C] - Custom Properties only (C to clear) | %s"));
|
||||
break;
|
||||
default:
|
||||
STRNCPY(limits_str, TIP_("G/R/S/B/C - Limit to Transform/Property Set"));
|
||||
STRNCPY(limits_str, RPT_("G/R/S/B/C - Limit to Transform/Property Set"));
|
||||
break;
|
||||
}
|
||||
|
||||
STRNCPY(bone_vis_str, TIP_("[H] - Toggle bone visibility"));
|
||||
STRNCPY(bone_vis_str, RPT_("[H] - Toggle bone visibility"));
|
||||
|
||||
ED_slider_status_string_get(pso->slider, slider_str, sizeof(slider_str));
|
||||
|
||||
|
|
|
@ -110,7 +110,6 @@ AssetItemTree build_filtered_all_catalog_tree(
|
|||
Vector<asset_system::AssetRepresentation *> unassigned_assets;
|
||||
|
||||
ED_assetlist_storage_fetch(&library_ref, &C);
|
||||
ED_assetlist_ensure_previews_job(&library_ref, &C);
|
||||
asset_system::AssetLibrary *library = ED_assetlist_library_get_once_available(library_ref);
|
||||
if (!library) {
|
||||
return {};
|
||||
|
|
|
@ -71,7 +71,6 @@ static const asset_system::AssetRepresentation *get_local_asset_from_relative_id
|
|||
AssetLibraryReference library_ref{};
|
||||
library_ref.type = ASSET_LIBRARY_LOCAL;
|
||||
ED_assetlist_storage_fetch(&library_ref, &C);
|
||||
ED_assetlist_ensure_previews_job(&library_ref, &C);
|
||||
|
||||
const asset_system::AssetRepresentation *matching_asset = nullptr;
|
||||
ED_assetlist_iterate(library_ref, [&](asset_system::AssetRepresentation &asset) {
|
||||
|
@ -104,7 +103,6 @@ static const asset_system::AssetRepresentation *find_asset_from_weak_ref(
|
|||
|
||||
const AssetLibraryReference library_ref = asset_system::all_library_reference();
|
||||
ED_assetlist_storage_fetch(&library_ref, &C);
|
||||
ED_assetlist_ensure_previews_job(&library_ref, &C);
|
||||
asset_system::AssetLibrary *all_library = ED_assetlist_library_get_once_available(
|
||||
asset_system::all_library_reference());
|
||||
if (!all_library) {
|
||||
|
|
|
@ -363,8 +363,8 @@ static bool asset_clear_poll(bContext *C, const PointerRNAVec &ids)
|
|||
IDVecStats ctx_stats = asset_operation_get_id_vec_stats_from_ids(ids);
|
||||
|
||||
if (!ctx_stats.has_asset) {
|
||||
const char *msg_single = TIP_("Data-block is not marked as asset");
|
||||
const char *msg_multiple = TIP_("No data-block selected that is marked as asset");
|
||||
const char *msg_single = N_("Data-block is not marked as asset");
|
||||
const char *msg_multiple = N_("No data-block selected that is marked as asset");
|
||||
CTX_wm_operator_poll_msg_set(C, ctx_stats.is_single ? msg_single : msg_multiple);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ class AssetCatalogSelectorTree : public ui::AbstractTreeView {
|
|||
void build_tree() override
|
||||
{
|
||||
if (catalog_tree_.is_empty()) {
|
||||
auto &item = add_tree_item<ui::BasicTreeViewItem>(TIP_("No applicable assets found"),
|
||||
auto &item = add_tree_item<ui::BasicTreeViewItem>(RPT_("No applicable assets found"),
|
||||
ICON_INFO);
|
||||
item.disable_interaction();
|
||||
return;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue