UI: Asset Shelf (Experimental Feature) #104831
|
@ -689,7 +689,7 @@ PACKAGES_ALL = (
|
|||
DISTRO_ID_ARCH: "clang", # clang-format is part of the main clang package.
|
||||
},
|
||||
),
|
||||
Package(name="Python", is_mandatory=True, version="3.10.9", version_short="3.10", version_min="3.10", version_mex="3.12",
|
||||
Package(name="Python", is_mandatory=True, version="3.10.11", version_short="3.10", version_min="3.10", version_mex="3.12",
|
||||
sub_packages=PYTHON_SUBPACKAGES,
|
||||
distro_package_names={DISTRO_ID_DEBIAN: "python3-dev",
|
||||
DISTRO_ID_FEDORA: "python3-devel",
|
||||
|
@ -721,7 +721,7 @@ PACKAGES_ALL = (
|
|||
DISTRO_ID_ARCH: "opencolorio",
|
||||
},
|
||||
),
|
||||
Package(name="IMath Library", is_mandatory=False, version="3.1.5", version_short="3.1", version_min="3.0", version_mex="4.0",
|
||||
Package(name="IMath Library", is_mandatory=False, version="3.1.7", version_short="3.1", version_min="3.0", version_mex="4.0",
|
||||
sub_packages=(),
|
||||
distro_package_names={DISTRO_ID_DEBIAN: "libimath-dev",
|
||||
DISTRO_ID_FEDORA: "imath-devel",
|
||||
|
@ -729,7 +729,7 @@ PACKAGES_ALL = (
|
|||
DISTRO_ID_ARCH: "imath",
|
||||
},
|
||||
),
|
||||
Package(name="OpenEXR Library", is_mandatory=False, version="3.1.5", version_short="3.1", version_min="3.0", version_mex="4.0",
|
||||
Package(name="OpenEXR Library", is_mandatory=False, version="3.1.7", version_short="3.1", version_min="3.0", version_mex="4.0",
|
||||
sub_packages=(),
|
||||
distro_package_names={DISTRO_ID_DEBIAN: "libopenexr-dev",
|
||||
DISTRO_ID_FEDORA: "openexr-devel",
|
||||
|
@ -737,7 +737,7 @@ PACKAGES_ALL = (
|
|||
DISTRO_ID_ARCH: "openexr",
|
||||
},
|
||||
),
|
||||
Package(name="OpenImageIO Library", is_mandatory=True, version="2.4.9.0", version_short="2.4", version_min="2.2.0", version_mex="2.5.0",
|
||||
Package(name="OpenImageIO Library", is_mandatory=True, version="2.4.11.0", version_short="2.4", version_min="2.2.0", version_mex="2.5.0",
|
||||
sub_packages=(
|
||||
Package(name="OpenImageIO Tools", is_mandatory=False,
|
||||
distro_package_names={DISTRO_ID_DEBIAN: "openimageio-tools",
|
||||
|
@ -836,7 +836,7 @@ PACKAGES_ALL = (
|
|||
DISTRO_ID_ARCH: "materialx-git",
|
||||
},
|
||||
),
|
||||
Package(name="USD Library", is_mandatory=False, version="22.11", version_short="22.11", version_min="20.05", version_mex="23.00",
|
||||
Package(name="USD Library", is_mandatory=False, version="23.05", version_short="23.05", version_min="20.05", version_mex="24.00",
|
||||
sub_packages=(),
|
||||
distro_package_names={DISTRO_ID_DEBIAN: None,
|
||||
DISTRO_ID_FEDORA: "usd-devel",
|
||||
|
@ -851,7 +851,7 @@ PACKAGES_ALL = (
|
|||
DISTRO_ID_ARCH: "opencollada",
|
||||
},
|
||||
),
|
||||
Package(name="Embree Library", is_mandatory=False, version="3.13.4", version_short="3.13", version_min="3.13", version_mex="5.0",
|
||||
Package(name="Embree Library", is_mandatory=False, version="4.1.0", version_short="4.1", version_min="3.13", version_mex="5.0",
|
||||
sub_packages=(),
|
||||
distro_package_names={DISTRO_ID_DEBIAN: "libembree-dev",
|
||||
DISTRO_ID_FEDORA: "embree-devel",
|
||||
|
@ -867,7 +867,7 @@ PACKAGES_ALL = (
|
|||
DISTRO_ID_ARCH: "openimagedenoise",
|
||||
},
|
||||
),
|
||||
Package(name="Level Zero Library", is_mandatory=False, version="1.7.15", version_short="1.7", version_min="1.7", version_mex="2.0",
|
||||
Package(name="Level Zero Library", is_mandatory=False, version="1.8.8", version_short="1.8", version_min="1.7", version_mex="2.0",
|
||||
sub_packages=(),
|
||||
distro_package_names={DISTRO_ID_DEBIAN: None,
|
||||
DISTRO_ID_FEDORA: "oneapi-level-zero-devel",
|
||||
|
@ -875,7 +875,7 @@ PACKAGES_ALL = (
|
|||
DISTRO_ID_ARCH: "level-zero-headers", # ???
|
||||
},
|
||||
),
|
||||
Package(name="OpenPGL Library", is_mandatory=False, version="0.4.1", version_short="0.4", version_min="0.4.1", version_mex="0.5",
|
||||
Package(name="OpenPGL Library", is_mandatory=False, version="0.5.0", version_short="0.5", version_min="0.5.0", version_mex="0.6",
|
||||
sub_packages=(),
|
||||
distro_package_names={DISTRO_ID_DEBIAN: None,
|
||||
DISTRO_ID_FEDORA: "openpgl-devel",
|
||||
|
@ -891,7 +891,7 @@ PACKAGES_ALL = (
|
|||
DISTRO_ID_ARCH: "openxr",
|
||||
},
|
||||
),
|
||||
Package(name="FFMPEG Library", is_mandatory=False, version="5.1.2", version_short="5.1", version_min="4.0", version_mex="7.0",
|
||||
Package(name="FFMPEG Library", is_mandatory=False, version="6.0", version_short="6.0", version_min="4.0", version_mex="7.0",
|
||||
sub_packages=(
|
||||
Package(name="AVDevice FFMPEG Library", is_mandatory=False,
|
||||
distro_package_names={DISTRO_ID_DEBIAN: "libavdevice-dev",
|
||||
|
|
|
@ -209,6 +209,21 @@ enum_guiding_distribution = (
|
|||
('VMM', "VMM", "Use von Mises-Fisher models as directional distribution", 2),
|
||||
)
|
||||
|
||||
enum_guiding_directional_sampling_types = (
|
||||
('MIS',
|
||||
"Diffuse Product MIS",
|
||||
"Guided diffuse BSDF component based on the incoming light distribution and the cosine product (closed form product)",
|
||||
0),
|
||||
('RIS',
|
||||
"Re-sampled Importance Sampling",
|
||||
"Perform RIS sampling to guided based on the product of the incoming light distribution and the BSDF",
|
||||
1),
|
||||
('ROUGHNESS',
|
||||
"Roughness-based",
|
||||
"Adjust the guiding probability based on the roughness of the material components",
|
||||
2),
|
||||
)
|
||||
|
||||
|
||||
def enum_openimagedenoise_denoiser(self, context):
|
||||
import _cycles
|
||||
|
@ -568,6 +583,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
|||
default='PARALLAX_AWARE_VMM',
|
||||
)
|
||||
|
||||
guiding_directional_sampling_type: EnumProperty(
|
||||
name="Directional Sampling Type",
|
||||
description="Type of the directional sampling used for guiding",
|
||||
items=enum_guiding_directional_sampling_types,
|
||||
default='RIS',
|
||||
)
|
||||
|
||||
use_surface_guiding: BoolProperty(
|
||||
name="Surface Guiding",
|
||||
description="Use guiding when sampling directions on a surface",
|
||||
|
@ -617,6 +639,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
|||
default=True,
|
||||
)
|
||||
|
||||
guiding_roughness_threshold: FloatProperty(
|
||||
name="Guiding Roughness Threshold",
|
||||
description="The minimal roughness value of a material to apply guiding",
|
||||
min=0.0, max=1.0,
|
||||
default=0.05,
|
||||
)
|
||||
|
||||
max_bounces: IntProperty(
|
||||
name="Max Bounces",
|
||||
description="Total maximum number of bounces",
|
||||
|
|
|
@ -337,6 +337,8 @@ class CYCLES_RENDER_PT_sampling_path_guiding_debug(CyclesDebugButtonsPanel, Pane
|
|||
layout.active = cscene.use_guiding
|
||||
|
||||
layout.prop(cscene, "guiding_distribution_type", text="Distribution Type")
|
||||
layout.prop(cscene, "guiding_roughness_threshold")
|
||||
layout.prop(cscene, "guiding_directional_sampling_type", text="Directional Sampling Type")
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(cscene, "surface_guiding_probability")
|
||||
|
|
|
@ -30,6 +30,25 @@ int blender_device_threads(BL::Scene &b_scene)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void adjust_device_info_from_preferences(DeviceInfo &info, PointerRNA cpreferences)
|
||||
{
|
||||
if (!get_boolean(cpreferences, "peer_memory")) {
|
||||
info.has_peer_memory = false;
|
||||
}
|
||||
|
||||
if (info.type == DEVICE_METAL && !get_boolean(cpreferences, "use_metalrt")) {
|
||||
info.use_hardware_raytracing = false;
|
||||
}
|
||||
|
||||
if (info.type == DEVICE_ONEAPI && !get_boolean(cpreferences, "use_oneapirt")) {
|
||||
info.use_hardware_raytracing = false;
|
||||
}
|
||||
|
||||
if (info.type == DEVICE_HIP && !get_boolean(cpreferences, "use_hiprt")) {
|
||||
info.use_hardware_raytracing = false;
|
||||
}
|
||||
}
|
||||
|
||||
DeviceInfo blender_device_info(BL::Preferences &b_preferences,
|
||||
BL::Scene &b_scene,
|
||||
bool background,
|
||||
|
@ -108,35 +127,17 @@ DeviceInfo blender_device_info(BL::Preferences &b_preferences,
|
|||
}
|
||||
}
|
||||
|
||||
if (!get_boolean(cpreferences, "peer_memory")) {
|
||||
device.has_peer_memory = false;
|
||||
}
|
||||
adjust_device_info_from_preferences(device, cpreferences);
|
||||
foreach (DeviceInfo &info, device.multi_devices) {
|
||||
adjust_device_info_from_preferences(info, cpreferences);
|
||||
|
||||
bool accumulated_use_hardware_raytracing = false;
|
||||
foreach (
|
||||
DeviceInfo &info,
|
||||
(device.multi_devices.size() != 0 ? device.multi_devices : vector<DeviceInfo>({device})))
|
||||
{
|
||||
if (info.type == DEVICE_METAL && !get_boolean(cpreferences, "use_metalrt")) {
|
||||
info.use_hardware_raytracing = false;
|
||||
}
|
||||
|
||||
if (info.type == DEVICE_ONEAPI && !get_boolean(cpreferences, "use_oneapirt")) {
|
||||
info.use_hardware_raytracing = false;
|
||||
}
|
||||
|
||||
if (info.type == DEVICE_HIP && !get_boolean(cpreferences, "use_hiprt")) {
|
||||
info.use_hardware_raytracing = false;
|
||||
}
|
||||
|
||||
/* There is an accumulative logic here, because Multi-devices are support only for
|
||||
/* There is an accumulative logic here, because Multi-devices are supported only for
|
||||
* the same backend + CPU in Blender right now, and both oneAPI and Metal have a
|
||||
* global boolean backend setting (see above) for enabling/disabling HW RT,
|
||||
* so all sub-devices in the multi-device should enable (or disable) HW RT
|
||||
* simultaneously (and CPU device are expected to ignore `use_hardware_raytracing` setting). */
|
||||
accumulated_use_hardware_raytracing |= info.use_hardware_raytracing;
|
||||
* global boolean backend setting for enabling/disabling Hardware Ray Tracing,
|
||||
* so all sub-devices in the multi-device should enable (or disable) Hardware Ray Tracing
|
||||
* simultaneously (and CPU device is expected to ignore `use_hardware_raytracing` setting). */
|
||||
device.use_hardware_raytracing |= info.use_hardware_raytracing;
|
||||
}
|
||||
device.use_hardware_raytracing = accumulated_use_hardware_raytracing;
|
||||
|
||||
if (preview) {
|
||||
/* Disable specialization for preview renders. */
|
||||
|
|
|
@ -440,6 +440,13 @@ void BlenderSync::sync_integrator(BL::ViewLayer &b_view_layer, bool background)
|
|||
GuidingDistributionType guiding_distribution_type = (GuidingDistributionType)get_enum(
|
||||
cscene, "guiding_distribution_type", GUIDING_NUM_TYPES, GUIDING_TYPE_PARALLAX_AWARE_VMM);
|
||||
integrator->set_guiding_distribution_type(guiding_distribution_type);
|
||||
GuidingDirectionalSamplingType guiding_directional_sampling_type =
|
||||
(GuidingDirectionalSamplingType)get_enum(cscene,
|
||||
"guiding_directional_sampling_type",
|
||||
GUIDING_DIRECTIONAL_SAMPLING_NUM_TYPES,
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS);
|
||||
integrator->set_guiding_directional_sampling_type(guiding_directional_sampling_type);
|
||||
integrator->set_guiding_roughness_threshold(get_float(cscene, "guiding_roughness_threshold"));
|
||||
}
|
||||
|
||||
DenoiseParams denoise_params = get_denoise_params(b_scene, b_view_layer, background);
|
||||
|
|
|
@ -33,12 +33,16 @@ const char *bvh_layout_name(BVHLayout layout)
|
|||
return "METAL";
|
||||
case BVH_LAYOUT_HIPRT:
|
||||
return "HIPRT";
|
||||
case BVH_LAYOUT_EMBREEGPU:
|
||||
return "EMBREEGPU";
|
||||
case BVH_LAYOUT_MULTI_OPTIX:
|
||||
case BVH_LAYOUT_MULTI_METAL:
|
||||
case BVH_LAYOUT_MULTI_HIPRT:
|
||||
case BVH_LAYOUT_MULTI_EMBREEGPU:
|
||||
case BVH_LAYOUT_MULTI_OPTIX_EMBREE:
|
||||
case BVH_LAYOUT_MULTI_METAL_EMBREE:
|
||||
case BVH_LAYOUT_MULTI_HIPRT_EMBREE:
|
||||
case BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE:
|
||||
return "MULTI";
|
||||
case BVH_LAYOUT_ALL:
|
||||
return "ALL";
|
||||
|
@ -88,6 +92,7 @@ BVH *BVH::create(const BVHParams ¶ms,
|
|||
case BVH_LAYOUT_BVH2:
|
||||
return new BVH2(params, geometry, objects);
|
||||
case BVH_LAYOUT_EMBREE:
|
||||
case BVH_LAYOUT_EMBREEGPU:
|
||||
#ifdef WITH_EMBREE
|
||||
return new BVHEmbree(params, geometry, objects);
|
||||
#else
|
||||
|
@ -117,9 +122,11 @@ BVH *BVH::create(const BVHParams ¶ms,
|
|||
case BVH_LAYOUT_MULTI_OPTIX:
|
||||
case BVH_LAYOUT_MULTI_METAL:
|
||||
case BVH_LAYOUT_MULTI_HIPRT:
|
||||
case BVH_LAYOUT_MULTI_EMBREEGPU:
|
||||
case BVH_LAYOUT_MULTI_OPTIX_EMBREE:
|
||||
case BVH_LAYOUT_MULTI_METAL_EMBREE:
|
||||
case BVH_LAYOUT_MULTI_HIPRT_EMBREE:
|
||||
case BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE:
|
||||
return new BVHMulti(params, geometry, objects);
|
||||
case BVH_LAYOUT_NONE:
|
||||
case BVH_LAYOUT_ALL:
|
||||
|
|
|
@ -265,7 +265,8 @@ void CPUDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
|
|||
#ifdef WITH_EMBREE
|
||||
if (bvh->params.bvh_layout == BVH_LAYOUT_EMBREE ||
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE ||
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL_EMBREE)
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL_EMBREE ||
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE)
|
||||
{
|
||||
BVHEmbree *const bvh_embree = static_cast<BVHEmbree *>(bvh);
|
||||
if (refit) {
|
||||
|
|
|
@ -122,6 +122,11 @@ class MultiDevice : public Device {
|
|||
return BVH_LAYOUT_MULTI_HIPRT;
|
||||
}
|
||||
|
||||
/* With multiple oneAPI devices, every device needs its own acceleration structure */
|
||||
if (bvh_layout_mask == BVH_LAYOUT_EMBREEGPU) {
|
||||
return BVH_LAYOUT_MULTI_EMBREEGPU;
|
||||
}
|
||||
|
||||
/* When devices do not share a common BVH layout, fall back to creating one for each */
|
||||
const BVHLayoutMask BVH_LAYOUT_OPTIX_EMBREE = (BVH_LAYOUT_OPTIX | BVH_LAYOUT_EMBREE);
|
||||
if ((bvh_layout_mask_all & BVH_LAYOUT_OPTIX_EMBREE) == BVH_LAYOUT_OPTIX_EMBREE) {
|
||||
|
@ -131,6 +136,10 @@ class MultiDevice : public Device {
|
|||
if ((bvh_layout_mask_all & BVH_LAYOUT_METAL_EMBREE) == BVH_LAYOUT_METAL_EMBREE) {
|
||||
return BVH_LAYOUT_MULTI_METAL_EMBREE;
|
||||
}
|
||||
const BVHLayoutMask BVH_LAYOUT_EMBREEGPU_EMBREE = (BVH_LAYOUT_EMBREEGPU | BVH_LAYOUT_EMBREE);
|
||||
if ((bvh_layout_mask_all & BVH_LAYOUT_EMBREEGPU_EMBREE) == BVH_LAYOUT_EMBREEGPU_EMBREE) {
|
||||
return BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE;
|
||||
}
|
||||
|
||||
return bvh_layout_mask;
|
||||
}
|
||||
|
@ -164,9 +173,11 @@ class MultiDevice : public Device {
|
|||
assert(bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX ||
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL ||
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_HIPRT ||
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_EMBREEGPU ||
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE ||
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL_EMBREE ||
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_HIPRT_EMBREE);
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_HIPRT_EMBREE ||
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE);
|
||||
|
||||
BVHMulti *const bvh_multi = static_cast<BVHMulti *>(bvh);
|
||||
bvh_multi->sub_bvhs.resize(devices.size());
|
||||
|
@ -193,6 +204,8 @@ class MultiDevice : public Device {
|
|||
params.bvh_layout = BVH_LAYOUT_METAL;
|
||||
else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_HIPRT)
|
||||
params.bvh_layout = BVH_LAYOUT_HIPRT;
|
||||
else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_EMBREEGPU)
|
||||
params.bvh_layout = BVH_LAYOUT_EMBREEGPU;
|
||||
else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE)
|
||||
params.bvh_layout = sub.device->info.type == DEVICE_OPTIX ? BVH_LAYOUT_OPTIX :
|
||||
BVH_LAYOUT_EMBREE;
|
||||
|
@ -202,7 +215,9 @@ class MultiDevice : public Device {
|
|||
else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_HIPRT_EMBREE)
|
||||
params.bvh_layout = sub.device->info.type == DEVICE_HIPRT ? BVH_LAYOUT_HIPRT :
|
||||
BVH_LAYOUT_EMBREE;
|
||||
|
||||
else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE)
|
||||
params.bvh_layout = sub.device->info.type == DEVICE_ONEAPI ? BVH_LAYOUT_EMBREEGPU :
|
||||
BVH_LAYOUT_EMBREE;
|
||||
/* Skip building a bottom level acceleration structure for non-instanced geometry on Embree
|
||||
* (since they are put into the top level directly, see bvh_embree.cpp) */
|
||||
if (!params.top_level && params.bvh_layout == BVH_LAYOUT_EMBREE &&
|
||||
|
|
|
@ -122,7 +122,8 @@ bool OneapiDevice::check_peer_access(Device * /*peer_device*/)
|
|||
|
||||
bool OneapiDevice::can_use_hardware_raytracing_for_features(uint requested_features) const
|
||||
{
|
||||
/* MNEE and Raytrace kernels work correctly with Hardware Raytracing starting with Embree 4.1. */
|
||||
/* MNEE and Ray-trace kernels work correctly with Hardware Ray-tracing starting with Embree 4.1.
|
||||
*/
|
||||
# if defined(RTC_VERSION) && RTC_VERSION < 40100
|
||||
return !(requested_features & (KERNEL_FEATURE_MNEE | KERNEL_FEATURE_NODE_RAYTRACE));
|
||||
# else
|
||||
|
@ -135,14 +136,14 @@ BVHLayoutMask OneapiDevice::get_bvh_layout_mask(uint requested_features) const
|
|||
{
|
||||
return (use_hardware_raytracing &&
|
||||
can_use_hardware_raytracing_for_features(requested_features)) ?
|
||||
BVH_LAYOUT_EMBREE :
|
||||
BVH_LAYOUT_EMBREEGPU :
|
||||
BVH_LAYOUT_BVH2;
|
||||
}
|
||||
|
||||
# ifdef WITH_EMBREE_GPU
|
||||
void OneapiDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
|
||||
{
|
||||
if (embree_device && bvh->params.bvh_layout == BVH_LAYOUT_EMBREE) {
|
||||
if (embree_device && bvh->params.bvh_layout == BVH_LAYOUT_EMBREEGPU) {
|
||||
BVHEmbree *const bvh_embree = static_cast<BVHEmbree *>(bvh);
|
||||
if (refit) {
|
||||
bvh_embree->refit(progress);
|
||||
|
@ -435,7 +436,7 @@ void OneapiDevice::const_copy_to(const char *name, void *host, size_t size)
|
|||
<< string_human_readable_size(size) << ")";
|
||||
|
||||
# ifdef WITH_EMBREE_GPU
|
||||
if (strcmp(name, "data") == 0) {
|
||||
if (embree_scene != nullptr && strcmp(name, "data") == 0) {
|
||||
assert(size <= sizeof(KernelData));
|
||||
|
||||
/* Update scene handle(since it is different for each device on multi devices) */
|
||||
|
|
|
@ -15,6 +15,8 @@ struct GuidingParams {
|
|||
bool use_volume_guiding = false;
|
||||
|
||||
GuidingDistributionType type = GUIDING_TYPE_PARALLAX_AWARE_VMM;
|
||||
GuidingDirectionalSamplingType sampling_type = GUIDING_DIRECTIONAL_SAMPLING_TYPE_PRODUCT_MIS;
|
||||
float roughness_threshold = 0.05f;
|
||||
int training_samples = 128;
|
||||
bool deterministic = false;
|
||||
|
||||
|
@ -24,7 +26,9 @@ struct GuidingParams {
|
|||
{
|
||||
return !((use == other.use) && (use_surface_guiding == other.use_surface_guiding) &&
|
||||
(use_volume_guiding == other.use_volume_guiding) && (type == other.type) &&
|
||||
(sampling_type == other.sampling_type) &&
|
||||
(training_samples == other.training_samples) &&
|
||||
(roughness_threshold == other.roughness_threshold) &&
|
||||
(deterministic == other.deterministic));
|
||||
}
|
||||
};
|
||||
|
|
|
@ -207,6 +207,8 @@ KERNEL_STRUCT_MEMBER(integrator, int, direct_light_sampling_type)
|
|||
KERNEL_STRUCT_MEMBER(integrator, float, surface_guiding_probability)
|
||||
KERNEL_STRUCT_MEMBER(integrator, float, volume_guiding_probability)
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, guiding_distribution_type)
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, guiding_directional_sampling_type)
|
||||
KERNEL_STRUCT_MEMBER(integrator, float, guiding_roughness_threshold)
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, use_guiding)
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, train_guiding)
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, use_surface_guiding)
|
||||
|
@ -216,6 +218,8 @@ KERNEL_STRUCT_MEMBER(integrator, int, use_guiding_mis_weights)
|
|||
|
||||
/* Padding. */
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, pad1)
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, pad2)
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, pad3)
|
||||
KERNEL_STRUCT_END(KernelIntegrator)
|
||||
|
||||
/* SVM. For shader specialization. */
|
||||
|
|
|
@ -432,7 +432,7 @@ ccl_gpu_kernel_threads(GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE)
|
|||
}
|
||||
ccl_gpu_kernel_postfix
|
||||
|
||||
/* oneAPI verion needs the local_mem accessor in the arguments. */
|
||||
/* oneAPI Verizon needs the local_mem accessor in the arguments. */
|
||||
#ifdef __KERNEL_ONEAPI__
|
||||
ccl_gpu_kernel_threads(GPU_PARALLEL_SORT_BLOCK_SIZE)
|
||||
ccl_gpu_kernel_signature(integrator_sort_bucket_pass,
|
||||
|
@ -489,7 +489,7 @@ ccl_gpu_kernel_threads(GPU_PARALLEL_SORT_BLOCK_SIZE)
|
|||
}
|
||||
ccl_gpu_kernel_postfix
|
||||
|
||||
/* oneAPI verion needs the local_mem accessor in the arguments. */
|
||||
/* oneAPI version needs the local_mem accessor in the arguments. */
|
||||
#ifdef __KERNEL_ONEAPI__
|
||||
ccl_gpu_kernel_threads(GPU_PARALLEL_SORT_BLOCK_SIZE)
|
||||
ccl_gpu_kernel_signature(integrator_sort_write_pass,
|
||||
|
|
|
@ -109,7 +109,7 @@ size_t oneapi_kernel_preferred_local_size(SyclQueue *queue,
|
|||
assert(queue);
|
||||
(void)kernel_global_size;
|
||||
const static size_t preferred_work_group_size_intersect_shading = 32;
|
||||
/* Shader evalutation kernels seems to use some amount of shared memory, so better
|
||||
/* Shader evaluation kernels seems to use some amount of shared memory, so better
|
||||
* to avoid usage of maximum work group sizes for them. */
|
||||
const static size_t preferred_work_group_size_shader_evaluation = 256;
|
||||
const static size_t preferred_work_group_size_default = 1024;
|
||||
|
@ -196,7 +196,7 @@ bool oneapi_kernel_is_required_for_features(const std::string &kernel_name,
|
|||
|
||||
bool oneapi_kernel_is_compatible_with_hardware_raytracing(const std::string &kernel_name)
|
||||
{
|
||||
/* MNEE and Raytrace kernels work correctly with Hardware Raytracing starting with Embree 4.1.
|
||||
/* MNEE and Ray-trace kernels work correctly with Hardware Ray-tracing starting with Embree 4.1.
|
||||
*/
|
||||
# if defined(RTC_VERSION) && RTC_VERSION < 40100
|
||||
return (kernel_name.find(device_kernel_as_string(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE)) ==
|
||||
|
|
|
@ -7,10 +7,66 @@
|
|||
#include "kernel/closure/bsdf.h"
|
||||
#include "kernel/film/write.h"
|
||||
|
||||
#if OPENPGL_VERSION_MINOR >= 5
|
||||
# define RIS_INCOMING_RADIANCE
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Utilities. */
|
||||
|
||||
struct GuidingRISSample {
|
||||
float3 rand;
|
||||
float2 sampled_roughness;
|
||||
float eta{1.0f};
|
||||
int label;
|
||||
float3 wo;
|
||||
float bsdf_pdf{0.0f};
|
||||
float guide_pdf{0.0f};
|
||||
float ris_target{0.0f};
|
||||
float ris_pdf{0.0f};
|
||||
float ris_weight{0.0f};
|
||||
|
||||
#ifdef RIS_INCOMING_RADIANCE
|
||||
float incoming_radiance_pdf{0.0f};
|
||||
#else
|
||||
float cosine{0.0f};
|
||||
#endif
|
||||
BsdfEval bsdf_eval;
|
||||
float avg_bsdf_eval{0.0f};
|
||||
Spectrum eval{zero_spectrum()};
|
||||
};
|
||||
|
||||
ccl_device_forceinline bool calculate_ris_target(ccl_private GuidingRISSample *ris_sample,
|
||||
ccl_private const float guiding_sampling_prob)
|
||||
{
|
||||
#if defined(__PATH_GUIDING__)
|
||||
const float pi_factor = 2.0f;
|
||||
if (ris_sample->avg_bsdf_eval > 0.0f && ris_sample->bsdf_pdf > 1e-10f &&
|
||||
ris_sample->guide_pdf > 0.0f)
|
||||
{
|
||||
|
||||
# ifdef RIS_INCOMING_RADIANCE
|
||||
ris_sample->ris_target = (ris_sample->avg_bsdf_eval *
|
||||
((((1.0f - guiding_sampling_prob) * (1.0f / (pi_factor * M_PI_F))) +
|
||||
(guiding_sampling_prob * ris_sample->incoming_radiance_pdf))));
|
||||
# else
|
||||
ris_sample->ris_target = (ris_sample->avg_bsdf_eval / ris_sample->cosine *
|
||||
((((1.0f - guiding_sampling_prob) * (1.0f / (pi_factor * M_PI_F))) +
|
||||
(guiding_sampling_prob * ris_sample->guide_pdf))));
|
||||
# endif
|
||||
ris_sample->ris_pdf = (0.5f * (ris_sample->bsdf_pdf + ris_sample->guide_pdf));
|
||||
ris_sample->ris_weight = ris_sample->ris_target / ris_sample->ris_pdf;
|
||||
return true;
|
||||
}
|
||||
ris_sample->ris_target = 0.0f;
|
||||
ris_sample->ris_pdf = 0.0f;
|
||||
return false;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__PATH_GUIDING__)
|
||||
static pgl_vec3f guiding_vec3f(const float3 v)
|
||||
{
|
||||
|
@ -241,7 +297,7 @@ ccl_device_forceinline void guiding_record_volume_bounce(KernelGlobals kg,
|
|||
openpgl::cpp::SetPDFDirectionIn(state->guiding.path_segment, pdf);
|
||||
openpgl::cpp::SetScatteringWeight(state->guiding.path_segment, guiding_vec3f(weight_rgb));
|
||||
openpgl::cpp::SetIsDelta(state->guiding.path_segment, false);
|
||||
openpgl::cpp::SetEta(state->guiding.path_segment, 1.f);
|
||||
openpgl::cpp::SetEta(state->guiding.path_segment, 1.0f);
|
||||
openpgl::cpp::SetRoughness(state->guiding.path_segment, roughness);
|
||||
#endif
|
||||
}
|
||||
|
@ -259,11 +315,11 @@ ccl_device_forceinline void guiding_record_volume_transmission(KernelGlobals kg,
|
|||
|
||||
if (state->guiding.path_segment) {
|
||||
// TODO (sherholz): need to find a better way to avoid this check
|
||||
if ((transmittance_weight[0] < 0.f || !std::isfinite(transmittance_weight[0]) ||
|
||||
if ((transmittance_weight[0] < 0.0f || !std::isfinite(transmittance_weight[0]) ||
|
||||
std::isnan(transmittance_weight[0])) ||
|
||||
(transmittance_weight[1] < 0.f || !std::isfinite(transmittance_weight[1]) ||
|
||||
(transmittance_weight[1] < 0.0f || !std::isfinite(transmittance_weight[1]) ||
|
||||
std::isnan(transmittance_weight[1])) ||
|
||||
(transmittance_weight[2] < 0.f || !std::isfinite(transmittance_weight[2]) ||
|
||||
(transmittance_weight[2] < 0.0f || !std::isfinite(transmittance_weight[2]) ||
|
||||
std::isnan(transmittance_weight[2])))
|
||||
{
|
||||
}
|
||||
|
@ -438,7 +494,7 @@ ccl_device_forceinline void guiding_write_debug_passes(KernelGlobals kg,
|
|||
sum_sample_weight += sc->sample_weight;
|
||||
}
|
||||
|
||||
avg_roughness = avg_roughness > 0.f ? avg_roughness / sum_sample_weight : 0.f;
|
||||
avg_roughness = avg_roughness > 0.0f ? avg_roughness / sum_sample_weight : 0.0f;
|
||||
|
||||
film_write_pass_float(buffer + kernel_data.film.pass_guiding_avg_roughness, avg_roughness);
|
||||
}
|
||||
|
@ -498,6 +554,17 @@ ccl_device_forceinline float guiding_bsdf_pdf(KernelGlobals kg,
|
|||
#endif
|
||||
}
|
||||
|
||||
ccl_device_forceinline float guiding_surface_incoming_radiance_pdf(KernelGlobals kg,
|
||||
IntegratorState state,
|
||||
const float3 wo)
|
||||
{
|
||||
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4 && OPENPGL_VERSION_MINOR >= 5
|
||||
return kg->opgl_surface_sampling_distribution->IncomingRadiancePDF(guiding_vec3f(wo));
|
||||
#else
|
||||
return 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Guided Volume Phases */
|
||||
|
||||
ccl_device_forceinline bool guiding_phase_init(KernelGlobals kg,
|
||||
|
|
|
@ -372,6 +372,7 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(
|
|||
|
||||
float2 bsdf_sampled_roughness = make_float2(1.0f, 1.0f);
|
||||
float bsdf_eta = 1.0f;
|
||||
float mis_pdf = 1.0f;
|
||||
|
||||
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
|
||||
if (kernel_data.integrator.use_surface_guiding) {
|
||||
|
@ -383,9 +384,11 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(
|
|||
&bsdf_eval,
|
||||
&bsdf_wo,
|
||||
&bsdf_pdf,
|
||||
&mis_pdf,
|
||||
&unguided_bsdf_pdf,
|
||||
&bsdf_sampled_roughness,
|
||||
&bsdf_eta);
|
||||
&bsdf_eta,
|
||||
rng_state);
|
||||
|
||||
if (bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval)) {
|
||||
return LABEL_NONE;
|
||||
|
@ -410,7 +413,7 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(
|
|||
if (bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval)) {
|
||||
return LABEL_NONE;
|
||||
}
|
||||
|
||||
mis_pdf = bsdf_pdf;
|
||||
unguided_bsdf_pdf = bsdf_pdf;
|
||||
}
|
||||
|
||||
|
@ -445,7 +448,7 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(
|
|||
|
||||
/* Update path state */
|
||||
if (!(label & LABEL_TRANSPARENT)) {
|
||||
INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = bsdf_pdf;
|
||||
INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = mis_pdf;
|
||||
INTEGRATOR_STATE_WRITE(state, path, mis_origin_n) = sd->N;
|
||||
INTEGRATOR_STATE_WRITE(state, path, min_ray_pdf) = fminf(
|
||||
unguided_bsdf_pdf, INTEGRATOR_STATE(state, path, min_ray_pdf));
|
||||
|
|
|
@ -24,6 +24,28 @@ CCL_NAMESPACE_BEGIN
|
|||
/* Guiding */
|
||||
|
||||
#ifdef __PATH_GUIDING__
|
||||
|
||||
ccl_device float surface_shader_average_sample_weight_squared_roughness(
|
||||
ccl_private const ShaderData *sd)
|
||||
{
|
||||
float avg_squared_roughness = 0.0f;
|
||||
float sum_sample_weight = 0.0f;
|
||||
for (int i = 0; i < sd->num_closure; i++) {
|
||||
ccl_private const ShaderClosure *sc = &sd->closure[i];
|
||||
|
||||
if (!CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
|
||||
continue;
|
||||
}
|
||||
avg_squared_roughness += sc->sample_weight * bsdf_get_specular_roughness_squared(sc);
|
||||
sum_sample_weight += sc->sample_weight;
|
||||
}
|
||||
|
||||
avg_squared_roughness = avg_squared_roughness > 0.0f ?
|
||||
avg_squared_roughness / sum_sample_weight :
|
||||
0.0f;
|
||||
return avg_squared_roughness;
|
||||
}
|
||||
|
||||
ccl_device_inline void surface_shader_prepare_guiding(KernelGlobals kg,
|
||||
IntegratorState state,
|
||||
ccl_private ShaderData *sd,
|
||||
|
@ -36,6 +58,9 @@ ccl_device_inline void surface_shader_prepare_guiding(KernelGlobals kg,
|
|||
}
|
||||
|
||||
const float surface_guiding_probability = kernel_data.integrator.surface_guiding_probability;
|
||||
const int guiding_directional_sampling_type =
|
||||
kernel_data.integrator.guiding_directional_sampling_type;
|
||||
const float guiding_roughness_threshold = kernel_data.integrator.guiding_roughness_threshold;
|
||||
float rand_bsdf_guiding = path_state_rng_1D(kg, rng_state, PRNG_SURFACE_BSDF_GUIDING);
|
||||
|
||||
/* Compute proportion of diffuse BSDF and BSSRDFs. */
|
||||
|
@ -43,6 +68,8 @@ ccl_device_inline void surface_shader_prepare_guiding(KernelGlobals kg,
|
|||
float bssrdf_sampling_fraction = 0.0f;
|
||||
float bsdf_bssrdf_sampling_sum = 0.0f;
|
||||
|
||||
bool fully_opaque = true;
|
||||
|
||||
for (int i = 0; i < sd->num_closure; i++) {
|
||||
ShaderClosure *sc = &sd->closure[i];
|
||||
if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
|
||||
|
@ -56,6 +83,10 @@ ccl_device_inline void surface_shader_prepare_guiding(KernelGlobals kg,
|
|||
if (CLOSURE_IS_BSSRDF(sc->type)) {
|
||||
bssrdf_sampling_fraction += sweight;
|
||||
}
|
||||
|
||||
if (CLOSURE_IS_BSDF_TRANSPARENT(sc->type) || CLOSURE_IS_BSDF_TRANSMISSION(sc->type)) {
|
||||
fully_opaque = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,17 +95,36 @@ ccl_device_inline void surface_shader_prepare_guiding(KernelGlobals kg,
|
|||
bssrdf_sampling_fraction /= bsdf_bssrdf_sampling_sum;
|
||||
}
|
||||
|
||||
/* Init guiding (diffuse BSDFs only for now). */
|
||||
if (!(diffuse_sampling_fraction > 0.0f &&
|
||||
guiding_bsdf_init(kg, state, sd->P, sd->N, rand_bsdf_guiding)))
|
||||
/* Init guiding */
|
||||
/* The the roughness because the function returns alpha.x * alpha.y. In addition alpha is squared
|
||||
* again */
|
||||
float avg_roughness = surface_shader_average_sample_weight_squared_roughness(sd);
|
||||
avg_roughness = safe_sqrtf(avg_roughness);
|
||||
if (!fully_opaque || avg_roughness < guiding_roughness_threshold ||
|
||||
((guiding_directional_sampling_type == GUIDING_DIRECTIONAL_SAMPLING_TYPE_PRODUCT_MIS) &&
|
||||
(diffuse_sampling_fraction <= 0.0f)) ||
|
||||
!guiding_bsdf_init(kg, state, sd->P, sd->N, rand_bsdf_guiding))
|
||||
{
|
||||
state->guiding.use_surface_guiding = false;
|
||||
state->guiding.surface_guiding_sampling_prob = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
state->guiding.use_surface_guiding = true;
|
||||
state->guiding.surface_guiding_sampling_prob = surface_guiding_probability *
|
||||
diffuse_sampling_fraction;
|
||||
if (kernel_data.integrator.guiding_directional_sampling_type ==
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_PRODUCT_MIS)
|
||||
{
|
||||
state->guiding.surface_guiding_sampling_prob = surface_guiding_probability *
|
||||
diffuse_sampling_fraction;
|
||||
}
|
||||
else if (kernel_data.integrator.guiding_directional_sampling_type ==
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS)
|
||||
{
|
||||
state->guiding.surface_guiding_sampling_prob = surface_guiding_probability;
|
||||
}
|
||||
else { // GUIDING_DIRECTIONAL_SAMPLING_TYPE_ROUGHNESS
|
||||
state->guiding.surface_guiding_sampling_prob = surface_guiding_probability * avg_roughness;
|
||||
}
|
||||
state->guiding.bssrdf_sampling_prob = bssrdf_sampling_fraction;
|
||||
state->guiding.sample_surface_guiding_rand = rand_bsdf_guiding;
|
||||
|
||||
|
@ -325,12 +375,20 @@ ccl_device_inline
|
|||
kg, sd, wo, NULL, bsdf_eval, 0.0f, 0.0f, light_shader_flags);
|
||||
|
||||
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
|
||||
if (state->guiding.use_surface_guiding) {
|
||||
if (pdf > 0.0f && state->guiding.use_surface_guiding) {
|
||||
const float guiding_sampling_prob = state->guiding.surface_guiding_sampling_prob;
|
||||
const float bssrdf_sampling_prob = state->guiding.bssrdf_sampling_prob;
|
||||
const float guide_pdf = guiding_bsdf_pdf(kg, state, wo);
|
||||
pdf = (guiding_sampling_prob * guide_pdf * (1.0f - bssrdf_sampling_prob)) +
|
||||
(1.0f - guiding_sampling_prob) * pdf;
|
||||
|
||||
if (kernel_data.integrator.guiding_directional_sampling_type ==
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS)
|
||||
{
|
||||
pdf = (0.5f * guide_pdf * (1.0f - bssrdf_sampling_prob)) + 0.5f * pdf;
|
||||
}
|
||||
else {
|
||||
pdf = (guiding_sampling_prob * guide_pdf * (1.0f - bssrdf_sampling_prob)) +
|
||||
(1.0f - guiding_sampling_prob) * pdf;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -406,17 +464,17 @@ surface_shader_bssrdf_sample_weight(ccl_private const ShaderData *ccl_restrict s
|
|||
/* Sample direction for picked BSDF, and return evaluation and pdf for all
|
||||
* BSDFs combined using MIS. */
|
||||
|
||||
ccl_device int surface_shader_bsdf_guided_sample_closure(KernelGlobals kg,
|
||||
IntegratorState state,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private const ShaderClosure *sc,
|
||||
const float3 rand_bsdf,
|
||||
ccl_private BsdfEval *bsdf_eval,
|
||||
ccl_private float3 *wo,
|
||||
ccl_private float *bsdf_pdf,
|
||||
ccl_private float *unguided_bsdf_pdf,
|
||||
ccl_private float2 *sampled_rougness,
|
||||
ccl_private float *eta)
|
||||
ccl_device int surface_shader_bsdf_guided_sample_closure_mis(KernelGlobals kg,
|
||||
IntegratorState state,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private const ShaderClosure *sc,
|
||||
const float3 rand_bsdf,
|
||||
ccl_private BsdfEval *bsdf_eval,
|
||||
ccl_private float3 *wo,
|
||||
ccl_private float *bsdf_pdf,
|
||||
ccl_private float *unguided_bsdf_pdf,
|
||||
ccl_private float2 *sampled_rougness,
|
||||
ccl_private float *eta)
|
||||
{
|
||||
/* BSSRDF should already have been handled elsewhere. */
|
||||
kernel_assert(CLOSURE_IS_BSDF(sc->type));
|
||||
|
@ -478,6 +536,10 @@ ccl_device int surface_shader_bsdf_guided_sample_closure(KernelGlobals kg,
|
|||
|
||||
label = bsdf_label(kg, &sd->closure[idx], *wo);
|
||||
}
|
||||
else {
|
||||
*bsdf_pdf = 0.0f;
|
||||
*unguided_bsdf_pdf = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
kernel_assert(reduce_min(bsdf_eval_sum(bsdf_eval)) >= 0.0f);
|
||||
|
@ -499,6 +561,9 @@ ccl_device int surface_shader_bsdf_guided_sample_closure(KernelGlobals kg,
|
|||
sampled_rougness,
|
||||
eta);
|
||||
# if 0
|
||||
// Code path to validate the estimation of the label, sampled roughness and eta
|
||||
// This should be activated from time to time when the BSDFs change to check if everything
|
||||
// is still working correctly.
|
||||
if (*unguided_bsdf_pdf > 0.0f) {
|
||||
surface_shader_validate_bsdf_sample(kg, sc, *wo, label, sampled_roughness, eta);
|
||||
}
|
||||
|
@ -529,6 +594,309 @@ ccl_device int surface_shader_bsdf_guided_sample_closure(KernelGlobals kg,
|
|||
|
||||
return label;
|
||||
}
|
||||
|
||||
ccl_device int surface_shader_bsdf_guided_sample_closure_ris(KernelGlobals kg,
|
||||
IntegratorState state,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private const ShaderClosure *sc,
|
||||
const float3 rand_bsdf,
|
||||
ccl_private const RNGState *rng_state,
|
||||
ccl_private BsdfEval *bsdf_eval,
|
||||
ccl_private float3 *wo,
|
||||
ccl_private float *bsdf_pdf,
|
||||
ccl_private float *mis_pdf,
|
||||
ccl_private float *unguided_bsdf_pdf,
|
||||
ccl_private float2 *sampled_roughness,
|
||||
ccl_private float *eta)
|
||||
{
|
||||
/* BSSRDF should already have been handled elsewhere. */
|
||||
kernel_assert(CLOSURE_IS_BSDF(sc->type));
|
||||
|
||||
const bool use_surface_guiding = state->guiding.use_surface_guiding;
|
||||
const float guiding_sampling_prob = state->guiding.surface_guiding_sampling_prob;
|
||||
const float bssrdf_sampling_prob = state->guiding.bssrdf_sampling_prob;
|
||||
|
||||
/* Decide between sampling guiding distribution and BSDF. */
|
||||
float rand_bsdf_guiding = state->guiding.sample_surface_guiding_rand;
|
||||
|
||||
/* Initialize to zero. */
|
||||
int label = LABEL_NONE;
|
||||
Spectrum eval = zero_spectrum();
|
||||
bsdf_eval_init(bsdf_eval, CLOSURE_NONE_ID, eval);
|
||||
|
||||
*unguided_bsdf_pdf = 0.0f;
|
||||
float guide_pdf = 0.0f;
|
||||
|
||||
if (use_surface_guiding && guiding_sampling_prob > 0.0f) {
|
||||
/* Performing guided sampling using RIS */
|
||||
|
||||
// selected RIS candidate
|
||||
int ris_idx = 0;
|
||||
|
||||
// meta data for the two RIS candidates
|
||||
GuidingRISSample ris_samples[2];
|
||||
ris_samples[0].rand = rand_bsdf;
|
||||
ris_samples[1].rand = path_state_rng_3D(kg, rng_state, PRNG_SURFACE_RIS_GUIDING_0);
|
||||
|
||||
// ----------------------------------------------------
|
||||
// generate the first RIS candidate using a BSDF sample
|
||||
// ----------------------------------------------------
|
||||
ris_samples[0].label = bsdf_sample(kg,
|
||||
sd,
|
||||
sc,
|
||||
INTEGRATOR_STATE(state, path, flag),
|
||||
ris_samples[0].rand,
|
||||
&ris_samples[0].eval,
|
||||
&ris_samples[0].wo,
|
||||
&ris_samples[0].bsdf_pdf,
|
||||
&ris_samples[0].sampled_roughness,
|
||||
&ris_samples[0].eta);
|
||||
|
||||
bsdf_eval_init(&ris_samples[0].bsdf_eval, sc->type, ris_samples[0].eval * sc->weight);
|
||||
if (ris_samples[0].bsdf_pdf > 0.0f) {
|
||||
if (sd->num_closure > 1) {
|
||||
float sweight = sc->sample_weight;
|
||||
ris_samples[0].bsdf_pdf = _surface_shader_bsdf_eval_mis(kg,
|
||||
sd,
|
||||
ris_samples[0].wo,
|
||||
sc,
|
||||
&ris_samples[0].bsdf_eval,
|
||||
(ris_samples[0].bsdf_pdf) *
|
||||
sweight,
|
||||
sweight,
|
||||
0);
|
||||
kernel_assert(reduce_min(bsdf_eval_sum(&ris_samples[0].bsdf_eval)) >= 0.0f);
|
||||
}
|
||||
ris_samples[0].avg_bsdf_eval = average(ris_samples[0].bsdf_eval.sum);
|
||||
ris_samples[0].guide_pdf = guiding_bsdf_pdf(kg, state, ris_samples[0].wo);
|
||||
ris_samples[0].guide_pdf *= (1.0f - bssrdf_sampling_prob);
|
||||
# ifdef RIS_INCOMING_RADIANCE
|
||||
ris_samples[0].incoming_radiance_pdf = guiding_surface_incoming_radiance_pdf(
|
||||
kg, state, ris_samples[0].wo);
|
||||
# else
|
||||
ris_samples[0].cosine = max(0.01f, fabsf(dot(sd->N, ris_samples[0].wo)));
|
||||
# endif
|
||||
ris_samples[0].bsdf_pdf = max(0.0f, ris_samples[0].bsdf_pdf);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// generate the second RIS candidate using a sample from the guiding distribution
|
||||
// ------------------------------------------------------------------------------
|
||||
float unguided_bsdf_pdfs[MAX_CLOSURE];
|
||||
bsdf_eval_init(&ris_samples[1].bsdf_eval, CLOSURE_NONE_ID, eval);
|
||||
ris_samples[1].guide_pdf = guiding_bsdf_sample(
|
||||
kg, state, float3_to_float2(ris_samples[1].rand), &ris_samples[1].wo);
|
||||
ris_samples[1].guide_pdf *= (1.0f - bssrdf_sampling_prob);
|
||||
# ifdef RIS_INCOMING_RADIANCE
|
||||
ris_samples[1].incoming_radiance_pdf = guiding_surface_incoming_radiance_pdf(
|
||||
kg, state, ris_samples[1].wo);
|
||||
# else
|
||||
ris_samples[1].cosine = max(0.01f, fabsf(dot(sd->N, ris_samples[1].wo)));
|
||||
# endif
|
||||
ris_samples[1].bsdf_pdf = surface_shader_bsdf_eval_pdfs(
|
||||
kg, sd, ris_samples[1].wo, &ris_samples[1].bsdf_eval, unguided_bsdf_pdfs, 0);
|
||||
ris_samples[1].label = ris_samples[0].label;
|
||||
ris_samples[1].avg_bsdf_eval = average(ris_samples[1].bsdf_eval.sum);
|
||||
ris_samples[1].bsdf_pdf = max(0.0f, ris_samples[1].bsdf_pdf);
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// calculate the RIS target functions for each RIS candidate
|
||||
// ------------------------------------------------------------------------------
|
||||
int num_ris_candidates = 0;
|
||||
float sum_ris_weights = 0.0f;
|
||||
if (calculate_ris_target(&ris_samples[0], guiding_sampling_prob)) {
|
||||
sum_ris_weights += ris_samples[0].ris_weight;
|
||||
num_ris_candidates++;
|
||||
}
|
||||
kernel_assert(ris_samples[0].ris_weight >= 0.0f);
|
||||
kernel_assert(sum_ris_weights >= 0.0f);
|
||||
|
||||
if (calculate_ris_target(&ris_samples[1], guiding_sampling_prob)) {
|
||||
sum_ris_weights += ris_samples[1].ris_weight;
|
||||
num_ris_candidates++;
|
||||
}
|
||||
kernel_assert(ris_samples[1].ris_weight >= 0.0f);
|
||||
kernel_assert(sum_ris_weights >= 0.0f);
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Sample/Select a sample from the RIS candidates proportional to the target
|
||||
// ------------------------------------------------------------------------------
|
||||
if (num_ris_candidates == 0 || !(sum_ris_weights > 1e-10f)) {
|
||||
*bsdf_pdf = 0.0f;
|
||||
*mis_pdf = 0.0f;
|
||||
return label;
|
||||
}
|
||||
|
||||
float rand_ris_select = rand_bsdf_guiding * sum_ris_weights;
|
||||
|
||||
float sum_ris = 0.0f;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
sum_ris += ris_samples[i].ris_weight;
|
||||
if (rand_ris_select <= sum_ris) {
|
||||
ris_idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
kernel_assert(sum_ris >= 0.0f);
|
||||
kernel_assert(ris_idx < 2);
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Fill in the sample data for the selected RIS candidate
|
||||
// ------------------------------------------------------------------------------
|
||||
guide_pdf = ris_samples[ris_idx].ris_target * (2.0f / sum_ris_weights);
|
||||
*unguided_bsdf_pdf = ris_samples[ris_idx].bsdf_pdf;
|
||||
*mis_pdf = 0.5f * (ris_samples[ris_idx].bsdf_pdf + ris_samples[ris_idx].guide_pdf);
|
||||
*bsdf_pdf = guide_pdf;
|
||||
|
||||
*wo = ris_samples[ris_idx].wo;
|
||||
label = ris_samples[ris_idx].label;
|
||||
|
||||
*sampled_roughness = ris_samples[ris_idx].sampled_roughness;
|
||||
*eta = ris_samples[ris_idx].eta;
|
||||
*bsdf_eval = ris_samples[ris_idx].bsdf_eval;
|
||||
|
||||
kernel_assert(isfinite_safe(guide_pdf));
|
||||
kernel_assert(isfinite_safe(*bsdf_pdf));
|
||||
|
||||
if (!(*bsdf_pdf > 1e-10f)) {
|
||||
*bsdf_pdf = 0.0f;
|
||||
*mis_pdf = 0.0f;
|
||||
return label;
|
||||
}
|
||||
|
||||
kernel_assert(*bsdf_pdf > 0.0f);
|
||||
kernel_assert(*bsdf_pdf >= 1e-20f);
|
||||
kernel_assert(guide_pdf >= 0.0f);
|
||||
|
||||
/// select label sampled_roughness and eta
|
||||
if (ris_idx == 1 && ris_samples[1].bsdf_pdf > 0.0f) {
|
||||
|
||||
float rnd = path_state_rng_1D(kg, rng_state, PRNG_SURFACE_RIS_GUIDING_1);
|
||||
|
||||
float sum_pdfs = 0.0f;
|
||||
int idx = -1;
|
||||
for (int i = 0; i < sd->num_closure; i++) {
|
||||
sum_pdfs += unguided_bsdf_pdfs[i];
|
||||
if (rnd <= sum_pdfs) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// kernel_assert(idx >= 0);
|
||||
/* Set the default idx to the last in the list.
|
||||
* in case of numerical problems and rand_bsdf_guiding is just >=1.0f and
|
||||
* the sum of all unguided_bsdf_pdfs is just < 1.0f. */
|
||||
idx = (rnd > sum_pdfs) ? sd->num_closure - 1 : idx;
|
||||
|
||||
label = bsdf_label(kg, &sd->closure[idx], *wo);
|
||||
bsdf_roughness_eta(kg, &sd->closure[idx], sampled_roughness, eta);
|
||||
}
|
||||
|
||||
kernel_assert(isfinite_safe(*bsdf_pdf));
|
||||
kernel_assert(*bsdf_pdf >= 0.0f);
|
||||
kernel_assert(reduce_min(bsdf_eval_sum(bsdf_eval)) >= 0.0f);
|
||||
}
|
||||
else {
|
||||
/* Sample BSDF. */
|
||||
*bsdf_pdf = 0.0f;
|
||||
label = bsdf_sample(kg,
|
||||
sd,
|
||||
sc,
|
||||
INTEGRATOR_STATE(state, path, flag),
|
||||
rand_bsdf,
|
||||
&eval,
|
||||
wo,
|
||||
unguided_bsdf_pdf,
|
||||
sampled_roughness,
|
||||
eta);
|
||||
# if 0
|
||||
// Code path to validate the estimation of the label, sampled roughness and eta
|
||||
// This should be activated from time to time when the BSDFs change to check if everything
|
||||
// is still working correctly.
|
||||
if (*unguided_bsdf_pdf > 0.0f) {
|
||||
surface_shader_validate_bsdf_sample(kg, sc, *wo, label, sampled_roughness, eta);
|
||||
}
|
||||
# endif
|
||||
|
||||
if (*unguided_bsdf_pdf != 0.0f) {
|
||||
bsdf_eval_init(bsdf_eval, sc->type, eval * sc->weight);
|
||||
|
||||
kernel_assert(reduce_min(bsdf_eval_sum(bsdf_eval)) >= 0.0f);
|
||||
|
||||
if (sd->num_closure > 1) {
|
||||
float sweight = sc->sample_weight;
|
||||
*unguided_bsdf_pdf = _surface_shader_bsdf_eval_mis(
|
||||
kg, sd, *wo, sc, bsdf_eval, (*unguided_bsdf_pdf) * sweight, sweight, 0);
|
||||
kernel_assert(reduce_min(bsdf_eval_sum(bsdf_eval)) >= 0.0f);
|
||||
}
|
||||
*bsdf_pdf = *unguided_bsdf_pdf;
|
||||
*mis_pdf = *bsdf_pdf;
|
||||
}
|
||||
|
||||
kernel_assert(reduce_min(bsdf_eval_sum(bsdf_eval)) >= 0.0f);
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
ccl_device int surface_shader_bsdf_guided_sample_closure(KernelGlobals kg,
|
||||
IntegratorState state,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private const ShaderClosure *sc,
|
||||
const float3 rand_bsdf,
|
||||
ccl_private BsdfEval *bsdf_eval,
|
||||
ccl_private float3 *wo,
|
||||
ccl_private float *bsdf_pdf,
|
||||
ccl_private float *mis_pdf,
|
||||
ccl_private float *unguided_bsdf_pdf,
|
||||
ccl_private float2 *sampled_roughness,
|
||||
ccl_private float *eta,
|
||||
ccl_private const RNGState *rng_state)
|
||||
{
|
||||
int label;
|
||||
if (kernel_data.integrator.guiding_directional_sampling_type ==
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_PRODUCT_MIS ||
|
||||
kernel_data.integrator.guiding_directional_sampling_type ==
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_ROUGHNESS)
|
||||
{
|
||||
label = surface_shader_bsdf_guided_sample_closure_mis(kg,
|
||||
state,
|
||||
sd,
|
||||
sc,
|
||||
rand_bsdf,
|
||||
bsdf_eval,
|
||||
wo,
|
||||
bsdf_pdf,
|
||||
unguided_bsdf_pdf,
|
||||
sampled_roughness,
|
||||
eta);
|
||||
*mis_pdf = (*unguided_bsdf_pdf > 0.0f) ? *bsdf_pdf : 0.0f;
|
||||
}
|
||||
else if (kernel_data.integrator.guiding_directional_sampling_type ==
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS)
|
||||
{
|
||||
label = surface_shader_bsdf_guided_sample_closure_ris(kg,
|
||||
state,
|
||||
sd,
|
||||
sc,
|
||||
rand_bsdf,
|
||||
rng_state,
|
||||
bsdf_eval,
|
||||
wo,
|
||||
bsdf_pdf,
|
||||
mis_pdf,
|
||||
unguided_bsdf_pdf,
|
||||
sampled_roughness,
|
||||
eta);
|
||||
}
|
||||
if (!(*unguided_bsdf_pdf > 0.0f)) {
|
||||
*bsdf_pdf = 0.0f;
|
||||
*mis_pdf = 0.0f;
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Sample direction for picked BSDF, and return evaluation and pdf for all
|
||||
|
|
|
@ -163,6 +163,11 @@ enum PathTraceDimension {
|
|||
PRNG_SURFACE_AO = 4,
|
||||
PRNG_SURFACE_BEVEL = 5,
|
||||
PRNG_SURFACE_BSDF_GUIDING = 6,
|
||||
|
||||
/* Guiding RIS */
|
||||
PRNG_SURFACE_RIS_GUIDING_0 = 10,
|
||||
PRNG_SURFACE_RIS_GUIDING_1 = 11,
|
||||
|
||||
/* Volume */
|
||||
PRNG_VOLUME_PHASE = 3,
|
||||
PRNG_VOLUME_PHASE_CHANNEL = 4,
|
||||
|
@ -506,6 +511,16 @@ typedef enum GuidingDistributionType {
|
|||
GUIDING_NUM_TYPES,
|
||||
} GuidingDistributionType;
|
||||
|
||||
/* Guiding Directional Sampling Type */
|
||||
|
||||
typedef enum GuidingDirectionalSamplingType {
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_PRODUCT_MIS = 0,
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS = 1,
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_ROUGHNESS = 2,
|
||||
|
||||
GUIDING_DIRECTIONAL_SAMPLING_NUM_TYPES,
|
||||
} GuidingDirectionalSamplingType;
|
||||
|
||||
/* Camera Type */
|
||||
|
||||
enum CameraType { CAMERA_PERSPECTIVE, CAMERA_ORTHOGRAPHIC, CAMERA_PANORAMA };
|
||||
|
@ -1172,11 +1187,16 @@ typedef enum KernelBVHLayout {
|
|||
BVH_LAYOUT_HIPRT = (1 << 8),
|
||||
BVH_LAYOUT_MULTI_HIPRT = (1 << 9),
|
||||
BVH_LAYOUT_MULTI_HIPRT_EMBREE = (1 << 10),
|
||||
BVH_LAYOUT_EMBREEGPU = (1 << 11),
|
||||
BVH_LAYOUT_MULTI_EMBREEGPU = (1 << 12),
|
||||
BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE = (1 << 13),
|
||||
|
||||
/* Default BVH layout to use for CPU. */
|
||||
BVH_LAYOUT_AUTO = BVH_LAYOUT_EMBREE,
|
||||
BVH_LAYOUT_ALL = BVH_LAYOUT_BVH2 | BVH_LAYOUT_EMBREE | BVH_LAYOUT_OPTIX | BVH_LAYOUT_METAL |
|
||||
BVH_LAYOUT_HIPRT | BVH_LAYOUT_MULTI_HIPRT | BVH_LAYOUT_MULTI_HIPRT_EMBREE,
|
||||
BVH_LAYOUT_HIPRT | BVH_LAYOUT_MULTI_HIPRT | BVH_LAYOUT_MULTI_HIPRT_EMBREE |
|
||||
BVH_LAYOUT_EMBREEGPU | BVH_LAYOUT_MULTI_EMBREEGPU |
|
||||
BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE,
|
||||
} KernelBVHLayout;
|
||||
|
||||
/* Specialized struct that can become constants in dynamic compilation. */
|
||||
|
|
|
@ -116,7 +116,8 @@ bool Geometry::need_build_bvh(BVHLayout layout) const
|
|||
layout == BVH_LAYOUT_METAL || layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE ||
|
||||
layout == BVH_LAYOUT_MULTI_METAL || layout == BVH_LAYOUT_MULTI_METAL_EMBREE ||
|
||||
layout == BVH_LAYOUT_HIPRT || layout == BVH_LAYOUT_MULTI_HIPRT ||
|
||||
layout == BVH_LAYOUT_MULTI_HIPRT_EMBREE;
|
||||
layout == BVH_LAYOUT_MULTI_HIPRT_EMBREE || layout == BVH_LAYOUT_EMBREEGPU ||
|
||||
layout == BVH_LAYOUT_MULTI_EMBREEGPU || layout == BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE;
|
||||
}
|
||||
|
||||
bool Geometry::is_instanced() const
|
||||
|
|
|
@ -60,10 +60,17 @@ NODE_DEFINE(Integrator)
|
|||
SOCKET_INT(volume_max_steps, "Volume Max Steps", 1024);
|
||||
SOCKET_FLOAT(volume_step_rate, "Volume Step Rate", 1.0f);
|
||||
|
||||
static NodeEnum guiding_ditribution_enum;
|
||||
guiding_ditribution_enum.insert("PARALLAX_AWARE_VMM", GUIDING_TYPE_PARALLAX_AWARE_VMM);
|
||||
guiding_ditribution_enum.insert("DIRECTIONAL_QUAD_TREE", GUIDING_TYPE_DIRECTIONAL_QUAD_TREE);
|
||||
guiding_ditribution_enum.insert("VMM", GUIDING_TYPE_VMM);
|
||||
static NodeEnum guiding_distribution_enum;
|
||||
guiding_distribution_enum.insert("PARALLAX_AWARE_VMM", GUIDING_TYPE_PARALLAX_AWARE_VMM);
|
||||
guiding_distribution_enum.insert("DIRECTIONAL_QUAD_TREE", GUIDING_TYPE_DIRECTIONAL_QUAD_TREE);
|
||||
guiding_distribution_enum.insert("VMM", GUIDING_TYPE_VMM);
|
||||
|
||||
static NodeEnum guiding_directional_sampling_type_enum;
|
||||
guiding_directional_sampling_type_enum.insert("MIS",
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_PRODUCT_MIS);
|
||||
guiding_directional_sampling_type_enum.insert("RIS", GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS);
|
||||
guiding_directional_sampling_type_enum.insert("ROUGHNESS",
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_ROUGHNESS);
|
||||
|
||||
SOCKET_BOOLEAN(use_guiding, "Guiding", false);
|
||||
SOCKET_BOOLEAN(deterministic_guiding, "Deterministic Guiding", true);
|
||||
|
@ -76,8 +83,13 @@ NODE_DEFINE(Integrator)
|
|||
SOCKET_BOOLEAN(use_guiding_mis_weights, "Use MIS Weights", true);
|
||||
SOCKET_ENUM(guiding_distribution_type,
|
||||
"Guiding Distribution Type",
|
||||
guiding_ditribution_enum,
|
||||
guiding_distribution_enum,
|
||||
GUIDING_TYPE_PARALLAX_AWARE_VMM);
|
||||
SOCKET_ENUM(guiding_directional_sampling_type,
|
||||
"Guiding Directional Sampling Type",
|
||||
guiding_directional_sampling_type_enum,
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS);
|
||||
SOCKET_FLOAT(guiding_roughness_threshold, "Guiding Roughness Threshold", 0.05f);
|
||||
|
||||
SOCKET_BOOLEAN(caustics_reflective, "Reflective Caustics", true);
|
||||
SOCKET_BOOLEAN(caustics_refractive, "Refractive Caustics", true);
|
||||
|
@ -239,6 +251,8 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
|
|||
kintegrator->use_guiding_direct_light = use_guiding_direct_light;
|
||||
kintegrator->use_guiding_mis_weights = use_guiding_mis_weights;
|
||||
kintegrator->guiding_distribution_type = guiding_params.type;
|
||||
kintegrator->guiding_directional_sampling_type = guiding_params.sampling_type;
|
||||
kintegrator->guiding_roughness_threshold = guiding_params.roughness_threshold;
|
||||
|
||||
kintegrator->seed = seed;
|
||||
|
||||
|
@ -409,7 +423,9 @@ GuidingParams Integrator::get_guiding_params(const Device *device) const
|
|||
guiding_params.type = guiding_distribution_type;
|
||||
guiding_params.training_samples = guiding_training_samples;
|
||||
guiding_params.deterministic = deterministic_guiding;
|
||||
|
||||
guiding_params.sampling_type = guiding_directional_sampling_type;
|
||||
// In Blender/Cycles the user set roughness is squared to behave more linear.
|
||||
guiding_params.roughness_threshold = guiding_roughness_threshold * guiding_roughness_threshold;
|
||||
return guiding_params;
|
||||
}
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
@ -54,6 +54,8 @@ class Integrator : public Node {
|
|||
NODE_SOCKET_API(bool, use_guiding_direct_light);
|
||||
NODE_SOCKET_API(bool, use_guiding_mis_weights);
|
||||
NODE_SOCKET_API(GuidingDistributionType, guiding_distribution_type);
|
||||
NODE_SOCKET_API(GuidingDirectionalSamplingType, guiding_directional_sampling_type);
|
||||
NODE_SOCKET_API(float, guiding_roughness_threshold);
|
||||
|
||||
NODE_SOCKET_API(bool, caustics_reflective)
|
||||
NODE_SOCKET_API(bool, caustics_refractive)
|
||||
|
|
|
@ -73,6 +73,17 @@ struct WGL_XDG_Decor_Window {
|
|||
struct zxdg_toplevel_decoration_v1 *toplevel_decor = nullptr;
|
||||
struct xdg_toplevel *toplevel = nullptr;
|
||||
enum zxdg_toplevel_decoration_v1_mode mode = (enum zxdg_toplevel_decoration_v1_mode)0;
|
||||
|
||||
/**
|
||||
* Defer calling #xdg_surface_ack_configure.
|
||||
* \note Accessing the members must lock on `win->frame_pending_mutex`.
|
||||
*/
|
||||
struct {
|
||||
/** When set, ACK configure is expected. */
|
||||
bool ack_configure = false;
|
||||
/** The serial to pass to ACK configure. */
|
||||
uint32_t ack_configure_serial = 0;
|
||||
} pending;
|
||||
};
|
||||
|
||||
static void gwl_xdg_decor_window_destroy(WGL_XDG_Decor_Window *decor)
|
||||
|
@ -745,6 +756,18 @@ static void gwl_window_frame_update_from_pending_no_lock(GWL_Window *win)
|
|||
wl_surface_set_buffer_scale(win->wl_surface, win->frame.buffer_scale);
|
||||
}
|
||||
|
||||
if (win->xdg_decor) {
|
||||
WGL_XDG_Decor_Window &decor = *win->xdg_decor;
|
||||
if (decor.pending.ack_configure) {
|
||||
xdg_surface_ack_configure(decor.surface, decor.pending.ack_configure_serial);
|
||||
/* The XDG spec states a commit event is required after ACK configure. */
|
||||
surface_needs_commit = true;
|
||||
|
||||
decor.pending.ack_configure = false;
|
||||
decor.pending.ack_configure_serial = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (surface_needs_commit) {
|
||||
#ifdef USE_EVENT_BACKGROUND_THREAD
|
||||
/* Postponing the commit avoids flickering when moving between monitors of different scale. */
|
||||
|
@ -1179,6 +1202,12 @@ static void xdg_surface_handle_configure(void *data,
|
|||
}
|
||||
CLOG_INFO(LOG, 2, "configure");
|
||||
|
||||
#ifdef USE_EVENT_BACKGROUND_THREAD
|
||||
std::lock_guard lock_frame_guard{static_cast<GWL_Window *>(data)->frame_pending_mutex};
|
||||
#endif
|
||||
win->xdg_decor->pending.ack_configure = true;
|
||||
win->xdg_decor->pending.ack_configure_serial = serial;
|
||||
|
||||
#ifdef USE_EVENT_BACKGROUND_THREAD
|
||||
GHOST_SystemWayland *system = win->ghost_system;
|
||||
const bool is_main_thread = system->main_thread_id == std::this_thread::get_id();
|
||||
|
@ -1190,10 +1219,8 @@ static void xdg_surface_handle_configure(void *data,
|
|||
else
|
||||
#endif
|
||||
{
|
||||
gwl_window_frame_update_from_pending(win);
|
||||
gwl_window_frame_update_from_pending_no_lock(win);
|
||||
}
|
||||
|
||||
xdg_surface_ack_configure(xdg_surface, serial);
|
||||
}
|
||||
|
||||
static const xdg_surface_listener xdg_surface_listener = {
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
# Skipped (see IMPORT_LANGUAGES_SKIP in settings.py). #23:Greek (Ελληνικά):el_GR
|
||||
35:Esperanto (Esperanto):eo
|
||||
# Skipped (see IMPORT_LANGUAGES_SKIP in settings.py). #36:Spanish from Spain (Español de España):es_ES
|
||||
# Skipped (see IMPORT_LANGUAGES_SKIP in settings.py). #34:Estonian (Eestlane):et_EE
|
||||
# Skipped (see IMPORT_LANGUAGES_SKIP in settings.py). #34:Estonian (Eesti keel):et_EE
|
||||
42:Basque (Euskara):eu_EU
|
||||
26:Persian (ﯽﺳﺭﺎﻓ):fa_IR
|
||||
6:Finnish (Suomi):fi_FI
|
||||
|
|
|
@ -68,7 +68,7 @@ LANGUAGES = (
|
|||
(32, "Brazilian Portuguese (Português do Brasil)", "pt_BR"),
|
||||
# Using the utf8 flipped form of Hebrew (עִבְרִית)).
|
||||
(33, "Hebrew (תירִבְעִ)", "he_IL"),
|
||||
(34, "Estonian (Eestlane)", "et_EE"),
|
||||
(34, "Estonian (Eesti keel)", "et_EE"),
|
||||
(35, "Esperanto (Esperanto)", "eo"),
|
||||
(36, "Spanish from Spain (Español de España)", "es_ES"),
|
||||
(37, "Amharic (አማርኛ)", "am_ET"),
|
||||
|
@ -206,7 +206,7 @@ _str_base = (
|
|||
r"(?:(?!<\\)(?:\\\\)*\\(?=(?P={_}2)))|"
|
||||
# The most common case.
|
||||
".(?!(?P={_}2))"
|
||||
")+.)" # Don't forget the last char!
|
||||
")*.)" # Don't forget the last char!
|
||||
"(?P={_}2)" # And closing quote.
|
||||
)
|
||||
str_clean_re = _str_base.format(_="g", capt="P<clean>")
|
||||
|
@ -257,7 +257,8 @@ PYGETTEXT_KEYWORDS = (() +
|
|||
for it in ("modifier_subpanel_register", "gpencil_modifier_subpanel_register")) +
|
||||
|
||||
# Node socket declarations: contextless names
|
||||
tuple((r"\.{}<decl::.*?>\(\s*" + _msg_re + r"(?:,[^),]+)*\s*\)").format(it)
|
||||
tuple((r"\.{}<decl::.*?>\(\s*" + _msg_re + r"(?:,[^),]+)*\s*\)"
|
||||
r"(?![^;]*\.translation_context\()").format(it)
|
||||
for it in ("add_input", "add_output")) +
|
||||
|
||||
# Node socket declarations: names with contexts
|
||||
|
|
|
@ -250,6 +250,15 @@ class Prefs(bpy.types.KeyConfigPreferences):
|
|||
update=update_fn,
|
||||
)
|
||||
|
||||
use_transform_navigation: BoolProperty(
|
||||
name="Navigate during Transform",
|
||||
description=(
|
||||
"Enable view navigation while using transform operators. "
|
||||
"Proportional Influence, Automatic Constraints and Auto IK Chain Length shortcuts will require holding Alt key"),
|
||||
default=False,
|
||||
update=update_fn,
|
||||
)
|
||||
|
||||
def draw(self, layout):
|
||||
from bpy import context
|
||||
|
||||
|
@ -313,6 +322,7 @@ class Prefs(bpy.types.KeyConfigPreferences):
|
|||
sub.prop(self, "use_v3d_tab_menu")
|
||||
sub.prop(self, "use_pie_click_drag")
|
||||
sub.prop(self, "use_v3d_shade_ex_pie")
|
||||
sub.prop(self, "use_transform_navigation")
|
||||
|
||||
# File Browser settings.
|
||||
col = layout.column()
|
||||
|
@ -365,6 +375,7 @@ def load():
|
|||
use_alt_click_leader=kc_prefs.use_alt_click_leader,
|
||||
use_pie_click_drag=kc_prefs.use_pie_click_drag,
|
||||
use_file_single_click=kc_prefs.use_file_single_click,
|
||||
use_transform_navigation=kc_prefs.use_transform_navigation,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
@ -93,6 +93,8 @@ class Params:
|
|||
# Since this means with RMB select enabled in edit-mode for e.g.
|
||||
# `Ctrl-LMB` would be caught by box-select instead of add/extrude.
|
||||
"tool_maybe_tweak_event",
|
||||
# Changes some transformers modal key-map items to avoid conflicts with navigation operations
|
||||
"use_transform_navigation",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
|
@ -119,6 +121,7 @@ class Params:
|
|||
use_file_single_click=False,
|
||||
v3d_tilde_action='VIEW',
|
||||
v3d_alt_mmb_drag_action='RELATIVE',
|
||||
use_transform_navigation=False,
|
||||
):
|
||||
from sys import platform
|
||||
self.apple = (platform == 'darwin')
|
||||
|
@ -209,6 +212,7 @@ class Params:
|
|||
self.pie_value = 'CLICK_DRAG' if use_pie_click_drag else 'PRESS'
|
||||
self.tool_tweak_event = {"type": self.tool_mouse, "value": 'CLICK_DRAG'}
|
||||
self.tool_maybe_tweak_event = {"type": self.tool_mouse, "value": self.tool_maybe_tweak_value}
|
||||
self.use_transform_navigation = use_transform_navigation
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
@ -1312,7 +1316,7 @@ def km_uv_editor(params):
|
|||
{"properties": [("extend", True)]}),
|
||||
])
|
||||
|
||||
# 3D cursor
|
||||
# 2D cursor
|
||||
if params.cursor_tweak_event:
|
||||
items.extend([
|
||||
("uv.cursor_set", params.cursor_set_event, None),
|
||||
|
@ -1581,13 +1585,16 @@ def km_view3d(params):
|
|||
# Transform.
|
||||
("transform.translate", {"type": params.select_mouse, "value": 'CLICK_DRAG'}, None),
|
||||
op_tool_optional(
|
||||
("transform.translate", {"type": 'G', "value": 'PRESS'}, None),
|
||||
("transform.translate", {"type": 'G', "value": 'PRESS'},
|
||||
{"properties": [("allow_navigation", params.use_transform_navigation)]}),
|
||||
(op_tool_cycle, "builtin.move"), params),
|
||||
op_tool_optional(
|
||||
("transform.rotate", {"type": 'R', "value": 'PRESS'}, None),
|
||||
("transform.rotate", {"type": 'R', "value": 'PRESS'},
|
||||
{"properties": [("allow_navigation", params.use_transform_navigation)]}),
|
||||
(op_tool_cycle, "builtin.rotate"), params),
|
||||
op_tool_optional(
|
||||
("transform.resize", {"type": 'S', "value": 'PRESS'}, None),
|
||||
("transform.resize", {"type": 'S', "value": 'PRESS'},
|
||||
{"properties": [("allow_navigation", params.use_transform_navigation)]}),
|
||||
(op_tool_cycle, "builtin.scale"), params),
|
||||
op_tool_optional(
|
||||
("transform.tosphere", {"type": 'S', "value": 'PRESS', "shift": True, "alt": True}, None),
|
||||
|
@ -2497,7 +2504,7 @@ def km_nla_generic(_params):
|
|||
sidebar_key={"type": 'N', "value": 'PRESS'},
|
||||
),
|
||||
("nla.tweakmode_enter", {"type": 'TAB', "value": 'PRESS'},
|
||||
{"properties": [("use_upper_stack_evaluation", True)]}),
|
||||
{"properties": [("use_upper_stack_evaluation", False)]}),
|
||||
("nla.tweakmode_exit", {"type": 'TAB', "value": 'PRESS'}, None),
|
||||
("nla.tweakmode_enter", {"type": 'TAB', "value": 'PRESS', "shift": True},
|
||||
{"properties": [("isolate_action", True)]}),
|
||||
|
@ -3470,7 +3477,6 @@ def km_animation_channels(params):
|
|||
("anim.channels_click", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True},
|
||||
{"properties": [("children_only", True)]}),
|
||||
# Rename.
|
||||
("anim.channels_rename", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, None),
|
||||
("anim.channels_rename", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
|
||||
# Select keys.
|
||||
("anim.channel_select_keys", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
|
||||
|
@ -4681,10 +4687,13 @@ def km_paint_curve(params):
|
|||
("paintcurve.delete_point", {"type": 'DEL', "value": 'PRESS'}, None),
|
||||
("paintcurve.draw", {"type": 'RET', "value": 'PRESS'}, None),
|
||||
("paintcurve.draw", {"type": 'NUMPAD_ENTER', "value": 'PRESS'}, None),
|
||||
("transform.translate", {"type": 'G', "value": 'PRESS'}, None),
|
||||
("transform.translate", {"type": 'G', "value": 'PRESS'},
|
||||
{"properties": [("allow_navigation", params.use_transform_navigation)]}),
|
||||
("transform.translate", {"type": params.select_mouse, "value": 'CLICK_DRAG'}, None),
|
||||
("transform.rotate", {"type": 'R', "value": 'PRESS'}, None),
|
||||
("transform.resize", {"type": 'S', "value": 'PRESS'}, None),
|
||||
("transform.rotate", {"type": 'R', "value": 'PRESS'},
|
||||
{"properties": [("allow_navigation", params.use_transform_navigation)]}),
|
||||
("transform.resize", {"type": 'S', "value": 'PRESS'},
|
||||
{"properties": [("allow_navigation", params.use_transform_navigation)]}),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
@ -5844,7 +5853,7 @@ def km_eyedropper_colorramp_pointsampling_map(_params):
|
|||
return keymap
|
||||
|
||||
|
||||
def km_transform_modal_map(_params):
|
||||
def km_transform_modal_map(params):
|
||||
items = []
|
||||
keymap = (
|
||||
"Transform Modal Map",
|
||||
|
@ -5884,24 +5893,24 @@ def km_transform_modal_map(_params):
|
|||
("PROPORTIONAL_SIZE_DOWN", {"type": 'PAGE_DOWN', "value": 'PRESS', "repeat": True}, None),
|
||||
("PROPORTIONAL_SIZE_UP", {"type": 'PAGE_UP', "value": 'PRESS', "shift": True, "repeat": True}, None),
|
||||
("PROPORTIONAL_SIZE_DOWN", {"type": 'PAGE_DOWN', "value": 'PRESS', "shift": True, "repeat": True}, None),
|
||||
("PROPORTIONAL_SIZE_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS'}, None),
|
||||
("PROPORTIONAL_SIZE_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS'}, None),
|
||||
("PROPORTIONAL_SIZE_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "alt": params.use_transform_navigation}, None),
|
||||
("PROPORTIONAL_SIZE_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "alt": params.use_transform_navigation}, None),
|
||||
("PROPORTIONAL_SIZE_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "shift": True}, None),
|
||||
("PROPORTIONAL_SIZE_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "shift": True}, None),
|
||||
("PROPORTIONAL_SIZE", {"type": 'TRACKPADPAN', "value": 'ANY'}, None),
|
||||
("PROPORTIONAL_SIZE", {"type": 'TRACKPADPAN', "value": 'ANY', "alt": params.use_transform_navigation}, None),
|
||||
("AUTOIK_CHAIN_LEN_UP", {"type": 'PAGE_UP', "value": 'PRESS', "repeat": True}, None),
|
||||
("AUTOIK_CHAIN_LEN_DOWN", {"type": 'PAGE_DOWN', "value": 'PRESS', "repeat": True}, None),
|
||||
("AUTOIK_CHAIN_LEN_UP", {"type": 'PAGE_UP', "value": 'PRESS', "shift": True, "repeat": True}, None),
|
||||
("AUTOIK_CHAIN_LEN_DOWN", {"type": 'PAGE_DOWN', "value": 'PRESS', "shift": True, "repeat": True}, None),
|
||||
("AUTOIK_CHAIN_LEN_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS'}, None),
|
||||
("AUTOIK_CHAIN_LEN_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS'}, None),
|
||||
("AUTOIK_CHAIN_LEN_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "alt": params.use_transform_navigation}, None),
|
||||
("AUTOIK_CHAIN_LEN_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "alt": params.use_transform_navigation}, None),
|
||||
("AUTOIK_CHAIN_LEN_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "shift": True}, None),
|
||||
("AUTOIK_CHAIN_LEN_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "shift": True}, None),
|
||||
("INSERTOFS_TOGGLE_DIR", {"type": 'T', "value": 'PRESS'}, None),
|
||||
("NODE_ATTACH_ON", {"type": 'LEFT_ALT', "value": 'RELEASE', "any": True}, None),
|
||||
("NODE_ATTACH_OFF", {"type": 'LEFT_ALT', "value": 'PRESS', "any": True}, None),
|
||||
("AUTOCONSTRAIN", {"type": 'MIDDLEMOUSE', "value": 'ANY'}, None),
|
||||
("AUTOCONSTRAINPLANE", {"type": 'MIDDLEMOUSE', "value": 'ANY', "shift": True}, None),
|
||||
("AUTOCONSTRAIN", {"type": 'MIDDLEMOUSE', "value": 'ANY', "alt": params.use_transform_navigation}, None),
|
||||
("AUTOCONSTRAINPLANE", {"type": 'MIDDLEMOUSE', "value": 'ANY', "shift": True, "alt": params.use_transform_navigation}, None),
|
||||
("PRECISION", {"type": 'LEFT_SHIFT', "value": 'ANY', "any": True}, None),
|
||||
("PRECISION", {"type": 'RIGHT_SHIFT', "value": 'ANY', "any": True}, None),
|
||||
])
|
||||
|
|
|
@ -257,6 +257,7 @@ class TIME_PT_playback(TimelinePanelButtons, Panel):
|
|||
col.prop(screen, "use_play_clip_editors", text="Movie Clip Editor")
|
||||
col.prop(screen, "use_play_node_editors", text="Node Editors")
|
||||
col.prop(screen, "use_play_sequence_editors", text="Video Sequencer")
|
||||
col.prop(screen, "use_play_spreadsheet_editors")
|
||||
|
||||
col = layout.column(heading="Show")
|
||||
col.prop(scene, "show_subframe", text="Subframes")
|
||||
|
|
|
@ -1038,10 +1038,22 @@ class VIEW3D_MT_transform_base:
|
|||
# TODO: get rid of the custom text strings?
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
allow_navigation = getattr(
|
||||
context.window_manager.keyconfigs.active.preferences,
|
||||
"use_transform_navigation",
|
||||
False)
|
||||
|
||||
layout.operator("transform.translate")
|
||||
layout.operator("transform.rotate")
|
||||
layout.operator("transform.resize", text="Scale")
|
||||
props = layout.operator("transform.translate")
|
||||
props.release_confirm = False
|
||||
props.allow_navigation = allow_navigation
|
||||
|
||||
props = layout.operator("transform.rotate")
|
||||
props.release_confirm = False
|
||||
props.allow_navigation = allow_navigation
|
||||
|
||||
props = layout.operator("transform.resize", text="Scale")
|
||||
props.release_confirm = False
|
||||
props.allow_navigation = allow_navigation
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
|
|
@ -155,6 +155,17 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
|
|||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_ui_units_x = 12
|
||||
|
||||
def draw(self, _context):
|
||||
# layout = self.layout
|
||||
pass
|
||||
|
||||
|
||||
class VIEW3D_PT_tools_meshedit_options_transform(View3DPanel, Panel):
|
||||
bl_category = "Tool"
|
||||
bl_context = ".mesh_edit" # dot on purpose (access from topbar)
|
||||
bl_label = "Transform"
|
||||
bl_parent_id = "VIEW3D_PT_tools_meshedit_options"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.active_object
|
||||
|
@ -169,56 +180,47 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
|
|||
ob = context.active_object
|
||||
mesh = ob.data
|
||||
|
||||
row = layout.row(align=True, heading="Transform")
|
||||
row.prop(tool_settings, "use_transform_correct_face_attributes")
|
||||
col = layout.column(align=True)
|
||||
col.prop(tool_settings, "use_transform_correct_face_attributes")
|
||||
sub = col.column(align=True)
|
||||
sub.active = tool_settings.use_transform_correct_face_attributes
|
||||
sub.prop(tool_settings, "use_transform_correct_keep_connected")
|
||||
col.separator()
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.active = tool_settings.use_transform_correct_face_attributes
|
||||
row.prop(tool_settings, "use_transform_correct_keep_connected")
|
||||
|
||||
row = layout.row(align=True, heading="UVs")
|
||||
row.prop(tool_settings, "use_edge_path_live_unwrap")
|
||||
|
||||
row = layout.row(heading="Mirror")
|
||||
sub = row.row(align=True)
|
||||
col = layout.column(heading="Mirror")
|
||||
sub = col.row(align=True)
|
||||
sub.prop(mesh, "use_mirror_x", text="X", toggle=True)
|
||||
sub.prop(mesh, "use_mirror_y", text="Y", toggle=True)
|
||||
sub.prop(mesh, "use_mirror_z", text="Z", toggle=True)
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.active = ob.data.use_mirror_x or ob.data.use_mirror_y or ob.data.use_mirror_z
|
||||
row.prop(mesh, "use_mirror_topology")
|
||||
col = layout.column(align=True)
|
||||
col.active = mesh.use_mirror_x or mesh.use_mirror_y or mesh.use_mirror_z
|
||||
col.prop(mesh, "use_mirror_topology")
|
||||
col.separator()
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(tool_settings, "use_mesh_automerge", text="Auto Merge", toggle=False)
|
||||
sub = col.column(align=True)
|
||||
sub.active = tool_settings.use_mesh_automerge
|
||||
sub.prop(tool_settings, "use_mesh_automerge_and_split", toggle=False)
|
||||
sub.prop(tool_settings, "double_threshold", text="Threshold")
|
||||
|
||||
|
||||
class VIEW3D_PT_tools_meshedit_options_automerge(View3DPanel, Panel):
|
||||
class VIEW3D_PT_tools_meshedit_options_uvs(View3DPanel, Panel):
|
||||
bl_category = "Tool"
|
||||
bl_context = ".mesh_edit" # dot on purpose (access from topbar)
|
||||
bl_label = "Auto Merge"
|
||||
bl_label = "UVs"
|
||||
bl_parent_id = "VIEW3D_PT_tools_meshedit_options"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.active_object
|
||||
|
||||
def draw_header(self, context):
|
||||
tool_settings = context.tool_settings
|
||||
self.layout.use_property_split = False
|
||||
self.layout.prop(tool_settings, "use_mesh_automerge",
|
||||
text=self.bl_label if self.is_popover else "", toggle=False)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.use_property_decorate = False
|
||||
layout.use_property_split = True
|
||||
|
||||
tool_settings = context.tool_settings
|
||||
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.active = tool_settings.use_mesh_automerge
|
||||
col.prop(tool_settings, "use_mesh_automerge_and_split", toggle=False)
|
||||
col.prop(tool_settings, "double_threshold", text="Threshold")
|
||||
layout.prop(tool_settings, "use_edge_path_live_unwrap")
|
||||
|
||||
|
||||
# ********** default tools for editmode_armature ****************
|
||||
|
@ -2368,7 +2370,8 @@ classes = (
|
|||
VIEW3D_PT_tools_object_options,
|
||||
VIEW3D_PT_tools_object_options_transform,
|
||||
VIEW3D_PT_tools_meshedit_options,
|
||||
VIEW3D_PT_tools_meshedit_options_automerge,
|
||||
VIEW3D_PT_tools_meshedit_options_transform,
|
||||
VIEW3D_PT_tools_meshedit_options_uvs,
|
||||
VIEW3D_PT_tools_armatureedit_options,
|
||||
VIEW3D_PT_tools_posemode_options,
|
||||
|
||||
|
|
|
@ -480,7 +480,7 @@ bool BKE_fcurve_bezt_subdivide_handles(struct BezTriple *bezt,
|
|||
/**
|
||||
* Resize the FCurve 'bezt' array to fit the given length.
|
||||
*
|
||||
* \param new_totvert new number of elements in the FCurve's `bezt` array.
|
||||
* \param new_totvert: new number of elements in the FCurve's `bezt` array.
|
||||
* Constraint: `0 <= new_totvert <= fcu->totvert`
|
||||
*/
|
||||
void BKE_fcurve_bezt_shrink(struct FCurve *fcu, int new_totvert);
|
||||
|
|
|
@ -311,10 +311,11 @@ void BKE_id_delete(struct Main *bmain, void *idv) ATTR_NONNULL();
|
|||
/**
|
||||
* Like BKE_id_delete, but with extra corner-case options.
|
||||
*
|
||||
* \param extra_remapping_flags Additional `ID_REMAP_` flags to pass to remapping code when
|
||||
* \param extra_remapping_flags: Additional `ID_REMAP_` flags to pass to remapping code when
|
||||
* ensuring that deleted IDs are not used by any other ID in given `bmain`. Typical example would
|
||||
* be e.g. `ID_REMAP_FORCE_UI_POINTERS`, required when default UI-handling callbacks of remapping
|
||||
* code won't be working (e.g. from readfile code). */
|
||||
* code won't be working (e.g. from readfile code).
|
||||
*/
|
||||
void BKE_id_delete_ex(struct Main *bmain, void *idv, const int extra_remapping_flags)
|
||||
ATTR_NONNULL(1, 2);
|
||||
/**
|
||||
|
|
|
@ -303,6 +303,27 @@ struct IDOverrideLibraryProperty *BKE_lib_override_library_property_get(
|
|||
*/
|
||||
void BKE_lib_override_library_property_delete(struct IDOverrideLibrary *override,
|
||||
struct IDOverrideLibraryProperty *override_property);
|
||||
/**
|
||||
* Delete a property override from the given ID \a override, if it exists.
|
||||
*
|
||||
* \return True when the property was found (and thus deleted), false if it wasn't found.
|
||||
*/
|
||||
bool BKE_lib_override_library_property_search_and_delete(struct IDOverrideLibrary *override,
|
||||
const char *rna_path);
|
||||
|
||||
/** Change the RNA path of a library override on a property.
|
||||
*
|
||||
* No-op if the property override cannot be found.
|
||||
*
|
||||
* \param from_rna_path The RNA path of the property to change.
|
||||
* \param to_rna_path The new RNA path. The library override system will copy the string to its own
|
||||
* memory; the caller will retain ownership of the passed pointer.
|
||||
* \return True if the property was found (and thus changed), false if it wasn't found.
|
||||
*/
|
||||
bool BKE_lib_override_library_property_rna_path_change(IDOverrideLibrary *liboverride,
|
||||
const char *old_rna_path,
|
||||
const char *new_rna_path);
|
||||
|
||||
/**
|
||||
* Get the RNA-property matching the \a library_prop override property. Used for UI to query
|
||||
* additional data about the overridden property (e.g. UI name).
|
||||
|
|
|
@ -86,7 +86,7 @@ void normals_calc_poly_vert(Span<float3> vert_positions,
|
|||
* \{ */
|
||||
|
||||
/**
|
||||
* Combined with the automatically calculated face corner normal, this gives a dimentional
|
||||
* Combined with the automatically calculated face corner normal, this gives a dimensional
|
||||
* coordinate space used to convert normals between the "custom normal" #short2 representation and
|
||||
* a regular #float3 format.
|
||||
*/
|
||||
|
|
|
@ -19,7 +19,7 @@ struct CustomData_MeshMasks;
|
|||
struct MemArena;
|
||||
struct Mesh;
|
||||
|
||||
/* Generic ways to map some geometry elements from a source mesh to a dest one. */
|
||||
/* Generic ways to map some geometry elements from a source mesh to a destination one. */
|
||||
|
||||
typedef struct MeshPairRemapItem {
|
||||
int sources_num;
|
||||
|
@ -33,7 +33,7 @@ typedef struct MeshPairRemapItem {
|
|||
/* All mapping computing func return this. */
|
||||
typedef struct MeshPairRemap {
|
||||
int items_num;
|
||||
MeshPairRemapItem *items; /* array, one item per dest element. */
|
||||
MeshPairRemapItem *items; /* Array, one item per destination element. */
|
||||
|
||||
struct MemArena *mem; /* memory arena, internal use only. */
|
||||
} MeshPairRemap;
|
||||
|
@ -89,7 +89,7 @@ enum {
|
|||
/* ***** Target's edges ***** */
|
||||
MREMAP_MODE_EDGE = 1 << 25,
|
||||
|
||||
/* Source edge which both vertices are nearest of dest ones. */
|
||||
/* Source edge which both vertices are nearest of destination ones. */
|
||||
MREMAP_MODE_EDGE_VERT_NEAREST = MREMAP_MODE_EDGE | MREMAP_USE_VERT | MREMAP_USE_NEAREST,
|
||||
|
||||
/* Nearest source edge (using mid-point). */
|
||||
|
@ -98,7 +98,7 @@ enum {
|
|||
/* Nearest edge of nearest poly (using mid-point). */
|
||||
MREMAP_MODE_EDGE_POLY_NEAREST = MREMAP_MODE_EDGE | MREMAP_USE_POLY | MREMAP_USE_NEAREST,
|
||||
|
||||
/* Cast a set of rays from along dest edge,
|
||||
/* Cast a set of rays from along destination edge,
|
||||
* interpolating its vertices' normals, and use hit source edges. */
|
||||
MREMAP_MODE_EDGE_EDGEINTERP_VNORPROJ = MREMAP_MODE_EDGE | MREMAP_USE_VERT | MREMAP_USE_NORPROJ |
|
||||
MREMAP_USE_INTERP,
|
||||
|
@ -131,10 +131,10 @@ enum {
|
|||
|
||||
/* Nearest source poly. */
|
||||
MREMAP_MODE_POLY_NEAREST = MREMAP_MODE_POLY | MREMAP_USE_POLY | MREMAP_USE_NEAREST,
|
||||
/* Source poly from best normal-matching dest poly. */
|
||||
/* Source poly from best normal-matching destination poly. */
|
||||
MREMAP_MODE_POLY_NOR = MREMAP_MODE_POLY | MREMAP_USE_POLY | MREMAP_USE_NORMAL,
|
||||
|
||||
/* Project dest poly onto source mesh using its normal,
|
||||
/* Project destination poly onto source mesh using its normal,
|
||||
* and use interpolation of all intersecting source polys. */
|
||||
MREMAP_MODE_POLY_POLYINTERP_PNORPROJ = MREMAP_MODE_POLY | MREMAP_USE_POLY | MREMAP_USE_NORPROJ |
|
||||
MREMAP_USE_INTERP,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2005 Blender Foundation */
|
||||
* Copyright 2023 Blender Foundation */
|
||||
|
||||
#pragma once
|
||||
|
||||
|
|
|
@ -334,7 +334,7 @@ static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss,
|
|||
0, numEffectedF, &data, ccgSubSurf__calcVertNormals_faces_accumulate_cb, &settings);
|
||||
}
|
||||
|
||||
/* XXX can I reduce the number of normalisations here? */
|
||||
/* XXX can I reduce the number of normalization calls here? */
|
||||
for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) {
|
||||
CCGVert *v = (CCGVert *)effectedV[ptrIdx];
|
||||
float *no = VERT_getNo(v, lvl);
|
||||
|
|
|
@ -641,8 +641,8 @@ static int animsys_quaternion_evaluate_fcurves(PathResolvedRNA quat_rna,
|
|||
}
|
||||
|
||||
if (fcurve_offset < 4) {
|
||||
/* This quaternion was incompletely keyed, so the result is a mixture of the unit quaterion and
|
||||
* values from FCurves. This means that it's almost certainly no longer of unit length. */
|
||||
/* This quaternion was incompletely keyed, so the result is a mixture of the unit quaternion
|
||||
* and values from FCurves. This means that it's almost certainly no longer of unit length. */
|
||||
normalize_qt(r_quaternion);
|
||||
}
|
||||
|
||||
|
|
|
@ -611,7 +611,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(ListBase *r_map
|
|||
bool *data_dst_to_delete = nullptr;
|
||||
|
||||
if (!use_layers_src) {
|
||||
/* No source at all, we can only delete all dest if requested... */
|
||||
/* No source at all, we can only delete all destination if requested. */
|
||||
if (use_delete) {
|
||||
idx_dst = tot_dst;
|
||||
while (idx_dst--) {
|
||||
|
@ -1421,7 +1421,7 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
|
|||
}
|
||||
|
||||
/* Check all possible data types.
|
||||
* Note item mappings and dest mix weights are cached. */
|
||||
* Note item mappings and destination mix weights are cached. */
|
||||
for (int i = 0; i < DT_TYPE_MAX; i++) {
|
||||
const int dtdata_type = 1 << i;
|
||||
int cddata_type;
|
||||
|
|
|
@ -1006,7 +1006,7 @@ void BKE_main_view_layers_synced_ensure(const Main *bmain)
|
|||
BKE_scene_view_layers_synced_ensure(scene);
|
||||
}
|
||||
|
||||
/* NOTE: This is not (yet?) covered by the dirty tag and deffered re-sync system. */
|
||||
/* NOTE: This is not (yet?) covered by the dirty tag and deferred re-sync system. */
|
||||
BKE_layer_collection_local_sync_all(bmain);
|
||||
}
|
||||
|
||||
|
|
|
@ -198,8 +198,9 @@ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_f
|
|||
BKE_lib_override_library_init(dst_id, nullptr);
|
||||
}
|
||||
|
||||
/* If source is already overriding data, we copy it but reuse its reference for dest ID.
|
||||
* Otherwise, source is only an override template, it then becomes reference of dest ID. */
|
||||
/* If source is already overriding data, we copy it but reuse its reference for destination ID.
|
||||
* Otherwise, source is only an override template, it then becomes reference of destination ID.
|
||||
*/
|
||||
dst_id->override_library->reference = src_id->override_library->reference ?
|
||||
src_id->override_library->reference :
|
||||
const_cast<ID *>(src_id);
|
||||
|
@ -1776,7 +1777,7 @@ static void lib_override_library_remap(Main *bmain,
|
|||
*
|
||||
* In case linked data keep being modified, these conditions may fail and the mapping may start to
|
||||
* return 'wrong' results. However, this is considered as an acceptable limitation here, since this
|
||||
* is mainly a 'best effort' to recover from situations that should not be hapenning in the first
|
||||
* is mainly a 'best effort' to recover from situations that should not be happening in the first
|
||||
* place.
|
||||
*/
|
||||
|
||||
|
@ -2061,7 +2062,7 @@ static bool lib_override_library_resync(Main *bmain,
|
|||
}
|
||||
|
||||
/* Get a mapping of all missing linked IDs that were liboverrides, to search for 'old
|
||||
* liboverrides' for newly created ones that do not alredy have one, in next step. */
|
||||
* liboverrides' for newly created ones that do not already have one, in next step. */
|
||||
LibOverrideMissingIDsData missing_ids_data = lib_override_library_resync_build_missing_ids_data(
|
||||
bmain);
|
||||
|
||||
|
@ -2638,7 +2639,8 @@ static bool lib_override_library_main_resync_id_skip_check(ID *id,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Clear 'unreachable' tag of existing liboverrides if they are using another reachable liboverride
|
||||
/**
|
||||
* Clear 'unreachable' tag of existing liboverrides if they are using another reachable liboverride
|
||||
* (typical case: Mesh object which only relationship to the rest of the liboverride hierarchy is
|
||||
* though its 'parent' pointer (i.e. rest of the hierarchy has no actual relationship to this mesh
|
||||
* object). Sadge.
|
||||
|
@ -2646,7 +2648,8 @@ static bool lib_override_library_main_resync_id_skip_check(ID *id,
|
|||
* Logic and rational of this function are very similar to these of
|
||||
* #lib_override_hierarchy_dependencies_recursive_tag_from, but withing specific resync context.
|
||||
*
|
||||
* \returns True if it finds a non-isolated 'parent' ID, false otherwise. */
|
||||
* \returns True if it finds a non-isolated 'parent' ID, false otherwise.
|
||||
*/
|
||||
static bool lib_override_resync_tagging_finalize_recursive_check_from(
|
||||
Main *bmain, ID *id, const int library_indirect_level)
|
||||
{
|
||||
|
@ -3527,6 +3530,41 @@ void lib_override_library_property_clear(IDOverrideLibraryProperty *op)
|
|||
BLI_freelistN(&op->operations);
|
||||
}
|
||||
|
||||
bool BKE_lib_override_library_property_search_and_delete(IDOverrideLibrary *override,
|
||||
const char *rna_path)
|
||||
{
|
||||
IDOverrideLibraryProperty *override_property = BKE_lib_override_library_property_find(override,
|
||||
rna_path);
|
||||
if (override_property == nullptr) {
|
||||
return false;
|
||||
}
|
||||
BKE_lib_override_library_property_delete(override, override_property);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BKE_lib_override_library_property_rna_path_change(IDOverrideLibrary *override,
|
||||
const char *old_rna_path,
|
||||
const char *new_rna_path)
|
||||
{
|
||||
/* Find the override property by its old RNA path. */
|
||||
GHash *override_runtime = override_library_rna_path_mapping_ensure(override);
|
||||
IDOverrideLibraryProperty *override_property = static_cast<IDOverrideLibraryProperty *>(
|
||||
BLI_ghash_popkey(override_runtime, old_rna_path, nullptr));
|
||||
|
||||
if (override_property == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Switch over the RNA path. */
|
||||
MEM_SAFE_FREE(override_property->rna_path);
|
||||
override_property->rna_path = BLI_strdup(new_rna_path);
|
||||
|
||||
/* Put property back into the lookup mapping, using the new RNA path. */
|
||||
BLI_ghash_insert(override_runtime, override_property->rna_path, override_property);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BKE_lib_override_library_property_delete(IDOverrideLibrary *override,
|
||||
IDOverrideLibraryProperty *override_property)
|
||||
{
|
||||
|
|
|
@ -257,7 +257,7 @@ static void object_defgroup_remove_common(Object *ob, bDeformGroup *dg, const in
|
|||
BKE_object_defgroup_active_index_set(ob, active_index - 1);
|
||||
}
|
||||
|
||||
/* remove all dverts */
|
||||
/* Remove all deform-verts. */
|
||||
if (BLI_listbase_is_empty(defbase)) {
|
||||
if (ob->type == OB_MESH) {
|
||||
Mesh *me = ob->data;
|
||||
|
@ -404,8 +404,8 @@ void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked)
|
|||
dg = next_dg;
|
||||
}
|
||||
}
|
||||
else { /* defbase is empty... */
|
||||
/* remove all dverts */
|
||||
else { /* `defbase` is empty. */
|
||||
/* Remove all deform-verts. */
|
||||
if (ob->type == OB_MESH) {
|
||||
Mesh *me = ob->data;
|
||||
CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
|
||||
|
|
|
@ -111,7 +111,8 @@ template<typename Ret, typename... Params> class FunctionRef<Ret(Params...)> {
|
|||
*/
|
||||
template<typename Callable,
|
||||
BLI_ENABLE_IF((
|
||||
!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Callable>>, FunctionRef>))>
|
||||
!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Callable>>, FunctionRef>)),
|
||||
BLI_ENABLE_IF((std::is_invocable_r_v<Ret, Callable, Params...>))>
|
||||
FunctionRef(Callable &&callable)
|
||||
: callback_(callback_fn<typename std::remove_reference_t<Callable>>),
|
||||
callable_(intptr_t(&callable))
|
||||
|
|
|
@ -105,6 +105,11 @@ class IndexRange {
|
|||
return a.current_ == b.current_;
|
||||
}
|
||||
|
||||
constexpr friend int64_t operator-(const Iterator &a, const Iterator &b)
|
||||
{
|
||||
return a.current_ - b.current_;
|
||||
}
|
||||
|
||||
constexpr int64_t operator*() const
|
||||
{
|
||||
return current_;
|
||||
|
@ -151,6 +156,11 @@ class IndexRange {
|
|||
return size_;
|
||||
}
|
||||
|
||||
constexpr IndexRange index_range() const
|
||||
{
|
||||
return IndexRange(size_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the size is zero.
|
||||
*/
|
||||
|
|
|
@ -16,24 +16,30 @@
|
|||
|
||||
namespace blender {
|
||||
|
||||
/**
|
||||
* If enabled, #LinearAllocator keeps track of how much memory it owns and how much it has
|
||||
* allocated.
|
||||
*/
|
||||
// #define BLI_DEBUG_LINEAR_ALLOCATOR_SIZE
|
||||
|
||||
template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopyable, NonMovable {
|
||||
private:
|
||||
BLI_NO_UNIQUE_ADDRESS Allocator allocator_;
|
||||
Vector<void *> owned_buffers_;
|
||||
Vector<Span<char>> unused_borrowed_buffers_;
|
||||
Vector<void *, 2> owned_buffers_;
|
||||
|
||||
uintptr_t current_begin_;
|
||||
uintptr_t current_end_;
|
||||
|
||||
#ifdef DEBUG
|
||||
int64_t debug_allocated_amount_ = 0;
|
||||
#endif
|
||||
|
||||
/* Buffers larger than that are not packed together with smaller allocations to avoid wasting
|
||||
* memory. */
|
||||
constexpr static inline int64_t large_buffer_threshold = 4096;
|
||||
|
||||
public:
|
||||
#ifdef BLI_DEBUG_LINEAR_ALLOCATOR_SIZE
|
||||
int64_t user_requested_size_ = 0;
|
||||
int64_t owned_allocation_size_ = 0;
|
||||
#endif
|
||||
|
||||
LinearAllocator()
|
||||
{
|
||||
current_begin_ = 0;
|
||||
|
@ -65,8 +71,8 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
|
|||
const uintptr_t potential_allocation_end = potential_allocation_begin + size;
|
||||
|
||||
if (potential_allocation_end <= current_end_) {
|
||||
#ifdef DEBUG
|
||||
debug_allocated_amount_ += size;
|
||||
#ifdef BLI_DEBUG_LINEAR_ALLOCATOR_SIZE
|
||||
user_requested_size_ += size;
|
||||
#endif
|
||||
current_begin_ = potential_allocation_end;
|
||||
return reinterpret_cast<void *>(potential_allocation_begin);
|
||||
|
@ -75,6 +81,9 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
|
|||
this->allocate_new_buffer(size + alignment, alignment);
|
||||
return this->allocate(size, alignment);
|
||||
}
|
||||
#ifdef BLI_DEBUG_LINEAR_ALLOCATOR_SIZE
|
||||
user_requested_size_ += size;
|
||||
#endif
|
||||
return this->allocator_large_buffer(size, alignment);
|
||||
};
|
||||
|
||||
|
@ -189,9 +198,11 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
|
|||
* Tell the allocator to use up the given memory buffer, before allocating new memory from the
|
||||
* system.
|
||||
*/
|
||||
void provide_buffer(void *buffer, uint size)
|
||||
void provide_buffer(void *buffer, const int64_t size)
|
||||
{
|
||||
unused_borrowed_buffers_.append(Span<char>(static_cast<char *>(buffer), size));
|
||||
BLI_assert(owned_buffers_.is_empty());
|
||||
current_begin_ = uintptr_t(buffer);
|
||||
current_end_ = current_begin_ + size;
|
||||
}
|
||||
|
||||
template<size_t Size, size_t Alignment>
|
||||
|
@ -200,19 +211,28 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
|
|||
this->provide_buffer(aligned_buffer.ptr(), Size);
|
||||
}
|
||||
|
||||
/**
|
||||
* This allocator takes ownership of the buffers owned by `other`. Therefor, when `other` is
|
||||
* destructed, memory allocated using it is not freed.
|
||||
*
|
||||
* Note that the caller is responsible for making sure that buffers passed into #provide_buffer
|
||||
* of `other` live at least as long as this allocator.
|
||||
*/
|
||||
void transfer_ownership_from(LinearAllocator<> &other)
|
||||
{
|
||||
owned_buffers_.extend(other.owned_buffers_);
|
||||
#ifdef BLI_DEBUG_LINEAR_ALLOCATOR_SIZE
|
||||
user_requested_size_ += other.user_requested_size_;
|
||||
owned_allocation_size_ += other.owned_allocation_size_;
|
||||
#endif
|
||||
other.owned_buffers_.clear();
|
||||
std::destroy_at(&other);
|
||||
new (&other) LinearAllocator<>();
|
||||
}
|
||||
|
||||
private:
|
||||
void allocate_new_buffer(int64_t min_allocation_size, int64_t min_alignment)
|
||||
{
|
||||
for (int64_t i : unused_borrowed_buffers_.index_range()) {
|
||||
Span<char> buffer = unused_borrowed_buffers_[i];
|
||||
if (buffer.size() >= min_allocation_size) {
|
||||
unused_borrowed_buffers_.remove_and_reorder(i);
|
||||
current_begin_ = uintptr_t(buffer.begin());
|
||||
current_end_ = uintptr_t(buffer.end());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Possibly allocate more bytes than necessary for the current allocation. This way more small
|
||||
* allocations can be packed together. Large buffers are allocated exactly to avoid wasting too
|
||||
* much memory. */
|
||||
|
@ -224,16 +244,23 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
|
|||
std::max<int64_t>(size_in_bytes, grow_size));
|
||||
}
|
||||
|
||||
void *buffer = allocator_.allocate(size_in_bytes, min_alignment, __func__);
|
||||
owned_buffers_.append(buffer);
|
||||
void *buffer = this->allocated_owned(size_in_bytes, min_alignment);
|
||||
current_begin_ = uintptr_t(buffer);
|
||||
current_end_ = current_begin_ + size_in_bytes;
|
||||
}
|
||||
|
||||
void *allocator_large_buffer(const int64_t size, const int64_t alignment)
|
||||
{
|
||||
return this->allocated_owned(size, alignment);
|
||||
}
|
||||
|
||||
void *allocated_owned(const int64_t size, const int64_t alignment)
|
||||
{
|
||||
void *buffer = allocator_.allocate(size, alignment, __func__);
|
||||
owned_buffers_.append(buffer);
|
||||
#ifdef BLI_DEBUG_LINEAR_ALLOCATOR_SIZE
|
||||
owned_allocation_size_ += size;
|
||||
#endif
|
||||
return buffer;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -285,7 +285,8 @@ BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
|
|||
lb->first = lb->last = (void *)0;
|
||||
}
|
||||
|
||||
/** Validate the integrity of a given ListBase, returns `true` if evrything is OK, false otherwise.
|
||||
/** Validate the integrity of a given ListBase, returns `true` if everything is OK, false
|
||||
* otherwise.
|
||||
*/
|
||||
bool BLI_listbase_validate(struct ListBase *lb);
|
||||
|
||||
|
|
|
@ -621,7 +621,7 @@ bool BLI_path_frame_check_chars(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUS
|
|||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Blender Spesific File Relative Paths
|
||||
/** \name Blender Specific File Relative Paths
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
|
|
|
@ -531,6 +531,14 @@ template<typename T> class MutableSpan {
|
|||
return size_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes referenced by this Span.
|
||||
*/
|
||||
constexpr int64_t size_in_bytes() const
|
||||
{
|
||||
return sizeof(T) * size_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the size is zero.
|
||||
*/
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
# endif
|
||||
#endif
|
||||
|
||||
#include "BLI_function_ref.hh"
|
||||
#include "BLI_index_range.hh"
|
||||
#include "BLI_lazy_threading.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
|
@ -37,7 +38,7 @@
|
|||
namespace blender::threading {
|
||||
|
||||
template<typename Range, typename Function>
|
||||
void parallel_for_each(Range &&range, const Function &function)
|
||||
inline void parallel_for_each(Range &&range, const Function &function)
|
||||
{
|
||||
#ifdef WITH_TBB
|
||||
tbb::parallel_for_each(range, function);
|
||||
|
@ -48,27 +49,45 @@ void parallel_for_each(Range &&range, const Function &function)
|
|||
#endif
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
void parallel_for_impl(IndexRange range,
|
||||
int64_t grain_size,
|
||||
FunctionRef<void(IndexRange)> function);
|
||||
} // namespace detail
|
||||
|
||||
template<typename Function>
|
||||
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
|
||||
inline void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
|
||||
{
|
||||
if (range.size() == 0) {
|
||||
if (range.is_empty()) {
|
||||
return;
|
||||
}
|
||||
#ifdef WITH_TBB
|
||||
/* Invoking tbb for small workloads has a large overhead. */
|
||||
if (range.size() >= grain_size) {
|
||||
lazy_threading::send_hint();
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<int64_t>(range.first(), range.one_after_last(), grain_size),
|
||||
[&](const tbb::blocked_range<int64_t> &subrange) {
|
||||
function(IndexRange(subrange.begin(), subrange.size()));
|
||||
});
|
||||
if (range.size() <= grain_size) {
|
||||
function(range);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
UNUSED_VARS(grain_size);
|
||||
#endif
|
||||
function(range);
|
||||
detail::parallel_for_impl(range, grain_size, function);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the sub-range boundaries down to the next aligned index. The "global" begin and end
|
||||
* remain fixed though.
|
||||
*/
|
||||
inline IndexRange align_sub_range(const IndexRange unaligned_range,
|
||||
const int64_t alignment,
|
||||
const IndexRange global_range)
|
||||
{
|
||||
const int64_t global_begin = global_range.start();
|
||||
const int64_t global_end = global_range.one_after_last();
|
||||
const int64_t alignment_mask = ~(alignment - 1);
|
||||
|
||||
const int64_t unaligned_begin = unaligned_range.start();
|
||||
const int64_t unaligned_end = unaligned_range.one_after_last();
|
||||
const int64_t aligned_begin = std::max(global_begin, unaligned_begin & alignment_mask);
|
||||
const int64_t aligned_end = unaligned_end == global_end ?
|
||||
unaligned_end :
|
||||
std::max(global_begin, unaligned_end & alignment_mask);
|
||||
const IndexRange aligned_range{aligned_begin, aligned_end - aligned_begin};
|
||||
return aligned_range;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -79,34 +98,23 @@ void parallel_for(IndexRange range, int64_t grain_size, const Function &function
|
|||
* larger, which means that work is distributed less evenly.
|
||||
*/
|
||||
template<typename Function>
|
||||
void parallel_for_aligned(const IndexRange range,
|
||||
const int64_t grain_size,
|
||||
const int64_t alignment,
|
||||
const Function &function)
|
||||
inline void parallel_for_aligned(const IndexRange range,
|
||||
const int64_t grain_size,
|
||||
const int64_t alignment,
|
||||
const Function &function)
|
||||
{
|
||||
const int64_t global_begin = range.start();
|
||||
const int64_t global_end = range.one_after_last();
|
||||
const int64_t alignment_mask = ~(alignment - 1);
|
||||
parallel_for(range, grain_size, [&](const IndexRange unaligned_range) {
|
||||
/* Move the sub-range boundaries down to the next aligned index. The "global" begin and end
|
||||
* remain fixed though. */
|
||||
const int64_t unaligned_begin = unaligned_range.start();
|
||||
const int64_t unaligned_end = unaligned_range.one_after_last();
|
||||
const int64_t aligned_begin = std::max(global_begin, unaligned_begin & alignment_mask);
|
||||
const int64_t aligned_end = unaligned_end == global_end ?
|
||||
unaligned_end :
|
||||
std::max(global_begin, unaligned_end & alignment_mask);
|
||||
const IndexRange aligned_range{aligned_begin, aligned_end - aligned_begin};
|
||||
const IndexRange aligned_range = align_sub_range(unaligned_range, alignment, range);
|
||||
function(aligned_range);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename Value, typename Function, typename Reduction>
|
||||
Value parallel_reduce(IndexRange range,
|
||||
int64_t grain_size,
|
||||
const Value &identity,
|
||||
const Function &function,
|
||||
const Reduction &reduction)
|
||||
inline Value parallel_reduce(IndexRange range,
|
||||
int64_t grain_size,
|
||||
const Value &identity,
|
||||
const Function &function,
|
||||
const Reduction &reduction)
|
||||
{
|
||||
#ifdef WITH_TBB
|
||||
if (range.size() >= grain_size) {
|
||||
|
@ -125,11 +133,30 @@ Value parallel_reduce(IndexRange range,
|
|||
return function(range, identity);
|
||||
}
|
||||
|
||||
template<typename Value, typename Function, typename Reduction>
|
||||
inline Value parallel_reduce_aligned(const IndexRange range,
|
||||
const int64_t grain_size,
|
||||
const int64_t alignment,
|
||||
const Value &identity,
|
||||
const Function &function,
|
||||
const Reduction &reduction)
|
||||
{
|
||||
parallel_reduce(
|
||||
range,
|
||||
grain_size,
|
||||
identity,
|
||||
[&](const IndexRange unaligned_range, const Value &ident) {
|
||||
const IndexRange aligned_range = align_sub_range(unaligned_range, alignment, range);
|
||||
function(aligned_range, ident);
|
||||
},
|
||||
reduction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute all of the provided functions. The functions might be executed in parallel or in serial
|
||||
* or some combination of both.
|
||||
*/
|
||||
template<typename... Functions> void parallel_invoke(Functions &&...functions)
|
||||
template<typename... Functions> inline void parallel_invoke(Functions &&...functions)
|
||||
{
|
||||
#ifdef WITH_TBB
|
||||
tbb::parallel_invoke(std::forward<Functions>(functions)...);
|
||||
|
@ -144,7 +171,7 @@ template<typename... Functions> void parallel_invoke(Functions &&...functions)
|
|||
* tasks.
|
||||
*/
|
||||
template<typename... Functions>
|
||||
void parallel_invoke(const bool use_threading, Functions &&...functions)
|
||||
inline void parallel_invoke(const bool use_threading, Functions &&...functions)
|
||||
{
|
||||
if (use_threading) {
|
||||
lazy_threading::send_hint();
|
||||
|
@ -156,7 +183,7 @@ void parallel_invoke(const bool use_threading, Functions &&...functions)
|
|||
}
|
||||
|
||||
/** See #BLI_task_isolate for a description of what isolating a task means. */
|
||||
template<typename Function> void isolate_task(const Function &function)
|
||||
template<typename Function> inline void isolate_task(const Function &function)
|
||||
{
|
||||
#ifdef WITH_TBB
|
||||
lazy_threading::ReceiverIsolation isolation;
|
||||
|
|
|
@ -403,7 +403,7 @@ int BLI_rename_overwrite(const char *from, const char *to)
|
|||
* Support for checking the files aren't the same could be added, however path comparison
|
||||
* alone is *not* a guarantee the files are different (given the possibility of accessing
|
||||
* the same file through different paths via symbolic-links), we could instead support a
|
||||
* verizon of Python's * `os.path.samefile(..)` which compares the I-node & device.
|
||||
* version of Python's `os.path.samefile(..)` which compares the I-node & device.
|
||||
* In this particular case we would not want to follow symbolic-links as well.
|
||||
* Since this functionality isn't required at the moment, leave this as-is.
|
||||
* Noting it as a potential improvement. */
|
||||
|
|
|
@ -352,7 +352,7 @@ void mat3_normalized_to_quat_fast(float q[4], const float mat[3][3])
|
|||
|
||||
BLI_assert(!(q[0] < 0.0f));
|
||||
|
||||
/* Sometimes normalisation is necessary due to round-off errors in the above
|
||||
/* Sometimes normalization is necessary due to round-off errors in the above
|
||||
* calculations. The comparison here uses tighter tolerances than
|
||||
* BLI_ASSERT_UNIT_QUAT(), so it's likely that even after a few more
|
||||
* transformations the quaternion will still be considered unit-ish. */
|
||||
|
|
|
@ -344,7 +344,7 @@ void BLI_str_cursor_step_bounds_utf8(
|
|||
BLI_str_cursor_step_utf8(str, str_maxlen, r_start, STRCUR_DIR_PREV, STRCUR_JUMP_DELIM, false);
|
||||
}
|
||||
if ((prev >= next) && (next != STRCUR_DELIM_NONE)) {
|
||||
/* Expand forward if we are between similar content, after whitespace, or at beginning. */
|
||||
/* Expand forward if we are between similar content. */
|
||||
BLI_str_cursor_step_utf8(str, str_maxlen, r_end, STRCUR_DIR_NEXT, STRCUR_JUMP_DELIM, false);
|
||||
}
|
||||
}
|
||||
|
@ -361,11 +361,11 @@ void BLI_str_cursor_step_bounds_utf32(
|
|||
*r_end = pos;
|
||||
|
||||
if ((prev <= next) && (prev != STRCUR_DELIM_NONE)) {
|
||||
/* Expand backward if we are between similar content, before whitespace, or at end. */
|
||||
/* Expand backward if we are between similar content. */
|
||||
BLI_str_cursor_step_utf32(str, str_maxlen, r_start, STRCUR_DIR_PREV, STRCUR_JUMP_DELIM, false);
|
||||
}
|
||||
if ((prev >= next) && (next != STRCUR_DELIM_NONE)) {
|
||||
/* Expand forward if we are between similar content, after whitespace, or at beginning. */
|
||||
/* Expand forward if we are between similar content. */
|
||||
BLI_str_cursor_step_utf32(str, str_maxlen, r_end, STRCUR_DIR_NEXT, STRCUR_JUMP_DELIM, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "BLI_lazy_threading.hh"
|
||||
#include "BLI_task.h"
|
||||
#include "BLI_task.hh"
|
||||
#include "BLI_threads.h"
|
||||
|
||||
#include "atomic_ops.h"
|
||||
|
@ -154,3 +155,28 @@ int BLI_task_parallel_thread_id(const TaskParallelTLS * /*tls*/)
|
|||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace blender::threading::detail {
|
||||
|
||||
void parallel_for_impl(const IndexRange range,
|
||||
const int64_t grain_size,
|
||||
const FunctionRef<void(IndexRange)> function)
|
||||
{
|
||||
#ifdef WITH_TBB
|
||||
/* Invoking tbb for small workloads has a large overhead. */
|
||||
if (range.size() >= grain_size) {
|
||||
lazy_threading::send_hint();
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<int64_t>(range.first(), range.one_after_last(), grain_size),
|
||||
[function](const tbb::blocked_range<int64_t> &subrange) {
|
||||
function(IndexRange(subrange.begin(), subrange.size()));
|
||||
});
|
||||
return;
|
||||
}
|
||||
#else
|
||||
UNUSED_VARS(grain_size);
|
||||
#endif
|
||||
function(range);
|
||||
}
|
||||
|
||||
} // namespace blender::threading::detail
|
||||
|
|
|
@ -130,4 +130,23 @@ TEST(function_ref, InitializeWithNull)
|
|||
EXPECT_FALSE(f);
|
||||
}
|
||||
|
||||
static int overload_test(const FunctionRef<void(std::string)> /*fn*/)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int overload_test(const FunctionRef<void(int)> /*fn*/)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
TEST(function_ref, OverloadSelection)
|
||||
{
|
||||
const auto fn_1 = [](std::string /*x*/) {};
|
||||
const auto fn_2 = [](int /*x*/) {};
|
||||
|
||||
EXPECT_EQ(overload_test(fn_1), 1);
|
||||
EXPECT_EQ(overload_test(fn_2), 2);
|
||||
}
|
||||
|
||||
} // namespace blender::tests
|
||||
|
|
|
@ -149,4 +149,23 @@ TEST(linear_allocator, ConstructArray)
|
|||
}
|
||||
}
|
||||
|
||||
TEST(linear_allocator, TransferOwnership)
|
||||
{
|
||||
LinearAllocator<> main_allocator;
|
||||
MutableSpan<int> values;
|
||||
|
||||
/* Allocate a large buffer that is likely to be given back to the system when freed. This test
|
||||
* essentially only fails by crashing with a segfault. */
|
||||
const int size = 1'000'000;
|
||||
const int value = 42;
|
||||
const int index = 500'000;
|
||||
{
|
||||
LinearAllocator<> nested_allocator;
|
||||
values = nested_allocator.allocate_array<int>(size);
|
||||
values[index] = value;
|
||||
main_allocator.transfer_ownership_from(nested_allocator);
|
||||
}
|
||||
EXPECT_EQ(values[index], value);
|
||||
}
|
||||
|
||||
} // namespace blender::tests
|
||||
|
|
|
@ -271,12 +271,15 @@ struct BlendFileReadReport *BLO_read_data_reports(BlendDataReader *reader);
|
|||
* However, now only pointers to ID data blocks are updated.
|
||||
* \{ */
|
||||
|
||||
/** Search for the new address of given `id`, during liblinking part of blendfile reading process.
|
||||
/**
|
||||
* Search for the new address of given `id`,
|
||||
* during library linking part of blend-file reading process.
|
||||
*
|
||||
* \param self_id the ID owner of the given `id` pointer. Note that it may be an embedded ID.
|
||||
* \param do_linked_only If `true`, only return found pointer if it is a linked ID. Used to
|
||||
* preventlinked data to point to local IDs.
|
||||
* \return the new address of the given ID pointer, or null if not found. */
|
||||
* \param self_id: the ID owner of the given `id` pointer. Note that it may be an embedded ID.
|
||||
* \param do_linked_only: If `true`, only return found pointer if it is a linked ID. Used to
|
||||
* prevent linked data to point to local IDs.
|
||||
* \return the new address of the given ID pointer, or null if not found.
|
||||
*/
|
||||
ID *BLO_read_get_new_id_address(BlendLibReader *reader,
|
||||
struct ID *self_id,
|
||||
const bool do_linked_only,
|
||||
|
|
|
@ -199,7 +199,7 @@ bool BLO_main_validate_shapekeys(Main *bmain, ReportList *reports)
|
|||
shapekey->from);
|
||||
/* NOTE: also need to remap UI data ID pointers here, since `bmain` is not the current
|
||||
* `G_MAIN`, default UI-handling remapping callback (defined by call to
|
||||
* `BKE_library_callback_remap_editor_id_reference_set`) won't work on exoected data here. */
|
||||
* `BKE_library_callback_remap_editor_id_reference_set`) won't work on expected data here. */
|
||||
BKE_id_delete_ex(bmain, shapekey, ID_REMAP_FORCE_UI_POINTERS);
|
||||
}
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ typedef struct FileData {
|
|||
/**
|
||||
* Store mapping from old ID pointers (the values they have in the .blend file) to new ones,
|
||||
* typically from value in `bhead->old` to address in memory where the ID was read.
|
||||
* Used during liblinking process (see #lib_link_all).
|
||||
* Used during library-linking process (see #lib_link_all).
|
||||
*/
|
||||
struct OldNewMap *libmap;
|
||||
|
||||
|
@ -115,7 +115,7 @@ typedef struct FileData {
|
|||
/** Used for undo. */
|
||||
ListBase *old_mainlist;
|
||||
/**
|
||||
* IDMap using uuids as keys of all the old IDs in the old bmain. Used during undo to find a
|
||||
* IDMap using UUID's as keys of all the old IDs in the old bmain. Used during undo to find a
|
||||
* matching old data when reading a new ID. */
|
||||
struct IDNameLib_Map *old_idmap_uuid;
|
||||
|
||||
|
|
|
@ -996,8 +996,8 @@ void blo_do_versions_250(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
|||
* to the evaluated #Mesh, so here we ensure that the basis
|
||||
* shape key is always set in the mesh coordinates. */
|
||||
for (me = bmain->meshes.first; me; me = me->id.next) {
|
||||
if ((key = blo_do_versions_newlibadr(fd, &me->id, ID_IS_LINKED(me), me->key)) &&
|
||||
key->refkey) {
|
||||
if ((key = blo_do_versions_newlibadr(fd, &me->id, ID_IS_LINKED(me), me->key)) && key->refkey)
|
||||
{
|
||||
data = key->refkey->data;
|
||||
tot = MIN2(me->totvert, key->refkey->totelem);
|
||||
MVert *verts = (MVert *)CustomData_get_layer_for_write(&me->vdata, CD_MVERT, me->totvert);
|
||||
|
@ -1008,8 +1008,8 @@ void blo_do_versions_250(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
|||
}
|
||||
|
||||
for (lt = bmain->lattices.first; lt; lt = lt->id.next) {
|
||||
if ((key = blo_do_versions_newlibadr(fd, <->id, ID_IS_LINKED(lt), lt->key)) &&
|
||||
key->refkey) {
|
||||
if ((key = blo_do_versions_newlibadr(fd, <->id, ID_IS_LINKED(lt), lt->key)) && key->refkey)
|
||||
{
|
||||
data = key->refkey->data;
|
||||
tot = MIN2(lt->pntsu * lt->pntsv * lt->pntsw, key->refkey->totelem);
|
||||
|
||||
|
@ -1020,8 +1020,8 @@ void blo_do_versions_250(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
|||
}
|
||||
|
||||
for (cu = bmain->curves.first; cu; cu = cu->id.next) {
|
||||
if ((key = blo_do_versions_newlibadr(fd, &cu->id, ID_IS_LINKED(cu), cu->key)) &&
|
||||
key->refkey) {
|
||||
if ((key = blo_do_versions_newlibadr(fd, &cu->id, ID_IS_LINKED(cu), cu->key)) && key->refkey)
|
||||
{
|
||||
data = key->refkey->data;
|
||||
|
||||
for (nu = cu->nurb.first; nu; nu = nu->next) {
|
||||
|
|
|
@ -644,6 +644,11 @@ static bool seq_speed_factor_set(Sequence *seq, void *user_data)
|
|||
seq_speed_factor_fix_rna_path(seq, &scene->adt->drivers);
|
||||
}
|
||||
|
||||
/* Pitch value of 0 has been found in some files. This would cause problems. */
|
||||
if (seq->pitch <= 0.0f) {
|
||||
seq->pitch = 1.0f;
|
||||
}
|
||||
|
||||
seq->speed_factor = seq->pitch;
|
||||
}
|
||||
else {
|
||||
|
@ -2317,6 +2322,73 @@ static void version_ensure_missing_regions(ScrArea *area, SpaceLink *sl)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change override RNA path from `frame_{start,end}` to `frame_{start,end}_raw`.
|
||||
* See #102662.
|
||||
*/
|
||||
static void version_liboverride_nla_strip_frame_start_end(IDOverrideLibrary *liboverride,
|
||||
const char *parent_rna_path,
|
||||
NlaStrip *strip)
|
||||
{
|
||||
if (!strip) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Escape the strip name for inclusion in the RNA path. */
|
||||
char name_esc_strip[sizeof(strip->name) * 2];
|
||||
BLI_str_escape(name_esc_strip, strip->name, sizeof(name_esc_strip));
|
||||
|
||||
const std::string rna_path_strip = std::string(parent_rna_path) + ".strips[\"" + name_esc_strip +
|
||||
"\"]";
|
||||
|
||||
{ /* Rename .frame_start -> .frame_start_raw: */
|
||||
const std::string rna_path_prop = rna_path_strip + ".frame_start";
|
||||
BKE_lib_override_library_property_rna_path_change(
|
||||
liboverride, rna_path_prop.c_str(), (rna_path_prop + "_raw").c_str());
|
||||
}
|
||||
|
||||
{ /* Rename .frame_end -> .frame_end_raw: */
|
||||
const std::string rna_path_prop = rna_path_strip + ".frame_end";
|
||||
BKE_lib_override_library_property_rna_path_change(
|
||||
liboverride, rna_path_prop.c_str(), (rna_path_prop + "_raw").c_str());
|
||||
}
|
||||
|
||||
{ /* Remove .frame_start_ui: */
|
||||
const std::string rna_path_prop = rna_path_strip + ".frame_start_ui";
|
||||
BKE_lib_override_library_property_search_and_delete(liboverride, rna_path_prop.c_str());
|
||||
}
|
||||
|
||||
{ /* Remove .frame_end_ui: */
|
||||
const std::string rna_path_prop = rna_path_strip + ".frame_end_ui";
|
||||
BKE_lib_override_library_property_search_and_delete(liboverride, rna_path_prop.c_str());
|
||||
}
|
||||
|
||||
/* Handle meta-strip contents. */
|
||||
LISTBASE_FOREACH (NlaStrip *, substrip, &strip->strips) {
|
||||
version_liboverride_nla_strip_frame_start_end(liboverride, rna_path_strip.c_str(), substrip);
|
||||
}
|
||||
}
|
||||
|
||||
/** Fix the `frame_start` and `frame_end` overrides on NLA strips. See #102662. */
|
||||
static void version_liboverride_nla_frame_start_end(ID *id, AnimData *adt, void * /*user_data*/)
|
||||
{
|
||||
IDOverrideLibrary *liboverride = id->override_library;
|
||||
if (!liboverride) {
|
||||
return;
|
||||
}
|
||||
|
||||
int track_index;
|
||||
LISTBASE_FOREACH_INDEX (NlaTrack *, track, &adt->nla_tracks, track_index) {
|
||||
char *rna_path_track = BLI_sprintfN("animation_data.nla_tracks[%d]", track_index);
|
||||
|
||||
LISTBASE_FOREACH (NlaStrip *, strip, &track->strips) {
|
||||
version_liboverride_nla_strip_frame_start_end(liboverride, rna_path_track, strip);
|
||||
}
|
||||
|
||||
MEM_freeN(rna_path_track);
|
||||
}
|
||||
}
|
||||
|
||||
/* NOLINTNEXTLINE: readability-function-size */
|
||||
void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
|
||||
{
|
||||
|
@ -3251,20 +3323,6 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 301, 5)) {
|
||||
LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
|
||||
if (ntree->type != NTREE_GEOMETRY) {
|
||||
continue;
|
||||
}
|
||||
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
|
||||
if (node->type != GEO_NODE_REALIZE_INSTANCES) {
|
||||
continue;
|
||||
}
|
||||
node->custom1 |= GEO_NODE_REALIZE_INSTANCES_LEGACY_BEHAVIOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 301, 6)) {
|
||||
/* Add node storage for map range node. */
|
||||
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
|
||||
|
@ -4418,5 +4476,7 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
versioning_remove_microfacet_sharp_distribution(ntree);
|
||||
}
|
||||
FOREACH_NODETREE_END;
|
||||
|
||||
BKE_animdata_main_cb(bmain, version_liboverride_nla_frame_start_end, NULL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -234,7 +234,7 @@ void _bmo_slot_copy(BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS],
|
|||
slot_dst->data.buf = NULL;
|
||||
slot_dst->len = slot_src->len;
|
||||
if (slot_dst->len) {
|
||||
/* check dest has all flags enabled that the source has */
|
||||
/* Check destination has all flags enabled that the source has. */
|
||||
const eBMOpSlotSubType_Elem src_elem_flag = (slot_src->slot_subtype.elem & BM_ALL_NOLOOP);
|
||||
const eBMOpSlotSubType_Elem dst_elem_flag = (slot_dst->slot_subtype.elem & BM_ALL_NOLOOP);
|
||||
|
||||
|
|
|
@ -293,7 +293,7 @@ void DeferredLayer::begin_sync()
|
|||
|
||||
/* Textures. */
|
||||
prepass_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
|
||||
/* Uniform Buf. */
|
||||
/* Uniform Buffer. */
|
||||
prepass_ps_.bind_ubo(CAMERA_BUF_SLOT, inst_.camera.ubo_get());
|
||||
|
||||
inst_.velocity.bind_resources(&prepass_ps_);
|
||||
|
@ -338,11 +338,11 @@ void DeferredLayer::begin_sync()
|
|||
gbuffer_ps_.bind_image(RBUFS_AOV_VALUE_SLOT, &inst_.render_buffers.aov_value_tx);
|
||||
/* Cryptomatte. */
|
||||
gbuffer_ps_.bind_image(RBUFS_CRYPTOMATTE_SLOT, &inst_.render_buffers.cryptomatte_tx);
|
||||
/* Storage Buf. */
|
||||
/* Storage Buffer. */
|
||||
gbuffer_ps_.bind_ssbo(RBUFS_AOV_BUF_SLOT, &inst_.film.aovs_info);
|
||||
/* Textures. */
|
||||
gbuffer_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
|
||||
/* Uniform Buf. */
|
||||
/* Uniform Buffer. */
|
||||
gbuffer_ps_.bind_ubo(CAMERA_BUF_SLOT, inst_.camera.ubo_get());
|
||||
|
||||
inst_.sampling.bind_resources(&gbuffer_ps_);
|
||||
|
|
|
@ -89,7 +89,7 @@ class Sampling {
|
|||
|
||||
template<typename T> void bind_resources(draw::detail::PassBase<T> *pass)
|
||||
{
|
||||
/* Storage Buf. */
|
||||
/* Storage Buffer. */
|
||||
pass->bind_ssbo(SAMPLING_BUF_SLOT, &data_);
|
||||
}
|
||||
|
||||
|
|
|
@ -120,13 +120,13 @@ class VelocityModule {
|
|||
|
||||
template<typename T> void bind_resources(draw::detail::Pass<T> *pass)
|
||||
{
|
||||
/* Storage Buf. */
|
||||
/* Storage Buffer. */
|
||||
pass->bind_ssbo(VELOCITY_OBJ_PREV_BUF_SLOT, &(*object_steps[STEP_PREVIOUS]));
|
||||
pass->bind_ssbo(VELOCITY_OBJ_NEXT_BUF_SLOT, &(*object_steps[next_step_]));
|
||||
pass->bind_ssbo(VELOCITY_GEO_PREV_BUF_SLOT, &(*geometry_steps[STEP_PREVIOUS]));
|
||||
pass->bind_ssbo(VELOCITY_GEO_NEXT_BUF_SLOT, &(*geometry_steps[next_step_]));
|
||||
pass->bind_ssbo(VELOCITY_INDIRECTION_BUF_SLOT, &indirection_buf);
|
||||
/* Uniform Buf. */
|
||||
/* Uniform Buffer. */
|
||||
pass->bind_ubo(VELOCITY_CAMERA_PREV_BUF, &(*camera_steps[STEP_PREVIOUS]));
|
||||
pass->bind_ubo(VELOCITY_CAMERA_CURR_BUF, &(*camera_steps[STEP_CURRENT]));
|
||||
pass->bind_ubo(VELOCITY_CAMERA_NEXT_BUF, &(*camera_steps[next_step_]));
|
||||
|
|
|
@ -61,7 +61,6 @@ static int g_tf_target_width;
|
|||
static int g_tf_target_height;
|
||||
|
||||
static GPUVertBuf *g_dummy_vbo = nullptr;
|
||||
static GPUTexture *g_dummy_texture = nullptr;
|
||||
static DRWPass *g_tf_pass; /* XXX can be a problem with multiple DRWManager in the future */
|
||||
|
||||
using CurvesInfosBuf = blender::draw::UniformBuffer<CurvesInfos>;
|
||||
|
@ -121,8 +120,6 @@ void DRW_curves_init(DRWData *drw_data)
|
|||
GPU_vertbuf_attr_fill(g_dummy_vbo, dummy_id, vert);
|
||||
/* Create vbo immediately to bind to texture buffer. */
|
||||
GPU_vertbuf_use(g_dummy_vbo);
|
||||
|
||||
g_dummy_texture = GPU_texture_create_from_vertbuf("hair_dummy_attr", g_dummy_vbo);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,12 +315,12 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object,
|
|||
|
||||
DRWShadingGroup *shgrp = DRW_shgroup_create_sub(shgrp_parent);
|
||||
|
||||
/* Fix issue with certain driver not drawing anything if there is no texture bound to
|
||||
/* Fix issue with certain driver not drawing anything if there is nothing bound to
|
||||
* "ac", "au", "u" or "c". */
|
||||
DRW_shgroup_uniform_texture(shgrp, "u", g_dummy_texture);
|
||||
DRW_shgroup_uniform_texture(shgrp, "au", g_dummy_texture);
|
||||
DRW_shgroup_uniform_texture(shgrp, "c", g_dummy_texture);
|
||||
DRW_shgroup_uniform_texture(shgrp, "ac", g_dummy_texture);
|
||||
DRW_shgroup_buffer_texture(shgrp, "u", g_dummy_vbo);
|
||||
DRW_shgroup_buffer_texture(shgrp, "au", g_dummy_vbo);
|
||||
DRW_shgroup_buffer_texture(shgrp, "c", g_dummy_vbo);
|
||||
DRW_shgroup_buffer_texture(shgrp, "ac", g_dummy_vbo);
|
||||
|
||||
/* TODO: Generalize radius implementation for curves data type. */
|
||||
float hair_rad_shape = 0.0f;
|
||||
|
@ -415,7 +412,7 @@ void DRW_curves_update()
|
|||
/* Update legacy hair too, to avoid verbosity in callers. */
|
||||
DRW_hair_update();
|
||||
|
||||
if (!GPU_transform_feedback_support()) {
|
||||
if (drw_curves_shader_type_get() == PART_REFINE_SHADER_TRANSFORM_FEEDBACK_WORKAROUND) {
|
||||
/**
|
||||
* Workaround to transform feedback not working on mac.
|
||||
* On some system it crashes (see #58489) and on some other it renders garbage (see #60171).
|
||||
|
@ -538,5 +535,4 @@ void DRW_curves_free()
|
|||
DRW_hair_free();
|
||||
|
||||
GPU_VERTBUF_DISCARD_SAFE(g_dummy_vbo);
|
||||
DRW_TEXTURE_FREE_SAFE(g_dummy_texture);
|
||||
}
|
||||
|
|
|
@ -64,7 +64,6 @@ static int g_tf_target_width;
|
|||
static int g_tf_target_height;
|
||||
|
||||
static GPUVertBuf *g_dummy_vbo = nullptr;
|
||||
static GPUTexture *g_dummy_texture = nullptr;
|
||||
static DRWPass *g_tf_pass; /* XXX can be a problem with multiple #DRWManager in the future */
|
||||
static blender::draw::UniformBuffer<CurvesInfos> *g_dummy_curves_info = nullptr;
|
||||
|
||||
|
@ -96,8 +95,6 @@ void DRW_hair_init(void)
|
|||
/* Create VBO immediately to bind to texture buffer. */
|
||||
GPU_vertbuf_use(g_dummy_vbo);
|
||||
|
||||
g_dummy_texture = GPU_texture_create_from_vertbuf("hair_dummy_attr", g_dummy_vbo);
|
||||
|
||||
g_dummy_curves_info = MEM_new<blender::draw::UniformBuffer<CurvesInfos>>(
|
||||
"g_dummy_curves_info");
|
||||
memset(g_dummy_curves_info->is_point_attribute,
|
||||
|
@ -266,15 +263,15 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object,
|
|||
}
|
||||
}
|
||||
|
||||
/* Fix issue with certain driver not drawing anything if there is no texture bound to
|
||||
/* Fix issue with certain driver not drawing anything if there is nothing bound to
|
||||
* "ac", "au", "u" or "c". */
|
||||
if (hair_cache->num_uv_layers == 0) {
|
||||
DRW_shgroup_uniform_texture(shgrp, "u", g_dummy_texture);
|
||||
DRW_shgroup_uniform_texture(shgrp, "au", g_dummy_texture);
|
||||
DRW_shgroup_buffer_texture(shgrp, "u", g_dummy_vbo);
|
||||
DRW_shgroup_buffer_texture(shgrp, "au", g_dummy_vbo);
|
||||
}
|
||||
if (hair_cache->num_col_layers == 0) {
|
||||
DRW_shgroup_uniform_texture(shgrp, "c", g_dummy_texture);
|
||||
DRW_shgroup_uniform_texture(shgrp, "ac", g_dummy_texture);
|
||||
DRW_shgroup_buffer_texture(shgrp, "c", g_dummy_vbo);
|
||||
DRW_shgroup_buffer_texture(shgrp, "ac", g_dummy_vbo);
|
||||
}
|
||||
|
||||
DRW_hair_duplimat_get(object, psys, md, dupli_mat);
|
||||
|
@ -314,7 +311,7 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object,
|
|||
|
||||
void DRW_hair_update()
|
||||
{
|
||||
if (!GPU_transform_feedback_support()) {
|
||||
if (drw_hair_shader_type_get() == PART_REFINE_SHADER_TRANSFORM_FEEDBACK_WORKAROUND) {
|
||||
/**
|
||||
* Workaround to transform feedback not working on mac.
|
||||
* On some system it crashes (see #58489) and on some other it renders garbage (see #60171).
|
||||
|
@ -433,6 +430,5 @@ void DRW_hair_update()
|
|||
void DRW_hair_free(void)
|
||||
{
|
||||
GPU_VERTBUF_DISCARD_SAFE(g_dummy_vbo);
|
||||
DRW_TEXTURE_FREE_SAFE(g_dummy_texture);
|
||||
MEM_delete(g_dummy_curves_info);
|
||||
}
|
||||
|
|
|
@ -2792,6 +2792,9 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, cons
|
|||
/* Only background (non-edit) objects are used for occlusion. */
|
||||
continue;
|
||||
}
|
||||
if (!BKE_object_is_visible_in_viewport(v3d, ob)) {
|
||||
continue;
|
||||
}
|
||||
drw_engines_cache_populate(ob);
|
||||
}
|
||||
DEG_OBJECT_ITER_END;
|
||||
|
|
|
@ -203,16 +203,13 @@ static void change_frame_seq_preview_begin(bContext *C, const wmEvent *event, Sp
|
|||
}
|
||||
}
|
||||
|
||||
static void change_frame_seq_preview_end(bContext *C, SpaceSeq *sseq)
|
||||
static void change_frame_seq_preview_end(SpaceSeq *sseq)
|
||||
{
|
||||
BLI_assert(sseq != NULL);
|
||||
UNUSED_VARS_NDEBUG(sseq);
|
||||
if (ED_sequencer_special_preview_get() != NULL) {
|
||||
ED_sequencer_special_preview_clear();
|
||||
}
|
||||
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
|
||||
}
|
||||
|
||||
static bool use_sequencer_snapping(bContext *C)
|
||||
|
@ -260,6 +257,36 @@ static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event
|
|||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static bool need_extra_redraw_after_scrubbing_ends(bContext *C)
|
||||
{
|
||||
if (CTX_wm_space_seq(C)) {
|
||||
/* During scrubbing in the sequencer, a preview of the final video might be drawn. After
|
||||
* scrubbing, the actual result should be shown again. */
|
||||
return true;
|
||||
}
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
Object *object = CTX_data_active_object(C);
|
||||
if (object && object->type == OB_GPENCIL_LEGACY) {
|
||||
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
|
||||
bScreen *screen = WM_window_get_active_screen(win);
|
||||
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
||||
SpaceLink *sl = (SpaceLink *)area->spacedata.first;
|
||||
if (sl->spacetype == SPACE_VIEW3D) {
|
||||
View3D *v3d = (View3D *)sl;
|
||||
if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) {
|
||||
if (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) {
|
||||
/* Grease pencil onion skin is not drawn during scrubbing. Redraw is necessary after
|
||||
* scrubbing ends to show onion skin again. */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void change_frame_cancel(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
bScreen *screen = CTX_wm_screen(C);
|
||||
|
@ -267,7 +294,12 @@ static void change_frame_cancel(bContext *C, wmOperator *UNUSED(op))
|
|||
|
||||
SpaceSeq *sseq = CTX_wm_space_seq(C);
|
||||
if (sseq != NULL) {
|
||||
change_frame_seq_preview_end(C, sseq);
|
||||
change_frame_seq_preview_end(sseq);
|
||||
}
|
||||
|
||||
if (need_extra_redraw_after_scrubbing_ends(C)) {
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -323,7 +355,11 @@ static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
|||
|
||||
SpaceSeq *sseq = CTX_wm_space_seq(C);
|
||||
if (sseq != NULL) {
|
||||
change_frame_seq_preview_end(C, sseq);
|
||||
change_frame_seq_preview_end(sseq);
|
||||
}
|
||||
if (need_extra_redraw_after_scrubbing_ends(C)) {
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -397,8 +397,8 @@ static void generator_panel_draw(const bContext *C, Panel *panel)
|
|||
uiLayoutColumn(split, false);
|
||||
uiLayout *title_col = uiLayoutColumn(split, false);
|
||||
uiLayout *title_row = uiLayoutRow(title_col, true);
|
||||
uiItemL(title_row, IFACE_("A"), ICON_NONE);
|
||||
uiItemL(title_row, IFACE_("B"), ICON_NONE);
|
||||
uiItemL(title_row, CTX_IFACE_(BLT_I18NCONTEXT_ID_ACTION, "A"), ICON_NONE);
|
||||
uiItemL(title_row, CTX_IFACE_(BLT_I18NCONTEXT_ID_ACTION, "B"), ICON_NONE);
|
||||
}
|
||||
|
||||
uiLayout *first_row = uiLayoutRow(col, true);
|
||||
|
|
|
@ -1142,7 +1142,7 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
|
|||
* A symmetrizable selection contains selected ebones of the input direction
|
||||
* and unique selected bones with an unique flippable name.
|
||||
*
|
||||
* Storing temp ptrs to mirrored unselected ebones. */
|
||||
* Storing temp pointers to mirrored unselected ebones. */
|
||||
for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
|
||||
if (!(EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED))) {
|
||||
/* Skipping invisible selected bones. */
|
||||
|
|
|
@ -419,8 +419,9 @@ void paintface_select_linked(struct bContext *C,
|
|||
struct Object *ob,
|
||||
const int mval[2],
|
||||
bool select);
|
||||
/** Grow the selection of faces.
|
||||
* \param face_step If true will also select faces that only touch on the corner.
|
||||
/**
|
||||
* Grow the selection of faces.
|
||||
* \param face_step: If true will also select faces that only touch on the corner.
|
||||
*/
|
||||
void paintface_select_more(struct Mesh *mesh, bool face_step);
|
||||
void paintface_select_less(struct Mesh *mesh, bool face_step);
|
||||
|
|
|
@ -125,8 +125,9 @@ int BIF_countTransformOrientation(const struct bContext *C);
|
|||
#define P_CURSOR_EDIT (1 << 16)
|
||||
#define P_CLNOR_INVALIDATE (1 << 17)
|
||||
#define P_VIEW2D_EDGE_PAN (1 << 18)
|
||||
#define P_VIEW3D_NAVIGATION (1 << 19)
|
||||
/* For properties performed when confirming the transformation. */
|
||||
#define P_POST_TRANSFORM (1 << 19)
|
||||
#define P_POST_TRANSFORM (1 << 20)
|
||||
|
||||
void Transform_Properties(struct wmOperatorType *ot, int flags);
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ struct SnapObjectContext;
|
|||
struct View3D;
|
||||
struct ViewContext;
|
||||
struct ViewLayer;
|
||||
struct ViewOpsData;
|
||||
struct bContext;
|
||||
struct bPoseChannel;
|
||||
struct bScreen;
|
||||
|
@ -210,6 +211,19 @@ bool ED_view3d_depth_unproject_v3(const struct ARegion *region,
|
|||
double depth,
|
||||
float r_location_world[3]);
|
||||
|
||||
/**
|
||||
* Utilities to perform navigation.
|
||||
* Call `ED_view3d_navigation_init` to create a context and `ED_view3d_navigation_do` to perform
|
||||
* navigation in modal operators.
|
||||
*
|
||||
* \note modal map events can also be used in `ED_view3d_navigation_do`.
|
||||
*/
|
||||
struct ViewOpsData *ED_view3d_navigation_init(struct bContext *C);
|
||||
bool ED_view3d_navigation_do(struct bContext *C,
|
||||
struct ViewOpsData *vod,
|
||||
const struct wmEvent *event);
|
||||
void ED_view3d_navigation_free(struct bContext *C, struct ViewOpsData *vod);
|
||||
|
||||
/* Projection */
|
||||
#define IS_CLIPPED 12000
|
||||
|
||||
|
|
|
@ -191,11 +191,11 @@ static void ui_popup_menu_create_block(bContext *C,
|
|||
if (!pup->but) {
|
||||
pup->block->flag |= UI_BLOCK_NO_FLIP;
|
||||
}
|
||||
/* A title is only provided when a Menu has a label, this is not alwas the case, see e.g.
|
||||
/* A title is only provided when a Menu has a label, this is not always the case, see e.g.
|
||||
* `VIEW3D_MT_edit_mesh_context_menu` -- this specifies its own label inside the draw function
|
||||
* depending on vertex/edge/face mode. We still want to flag the uiBlock (but only insert into
|
||||
* the puphash if we have a title provided). Choosing an entry in a menu will still handle
|
||||
* puphash later (see `button_activate_exit`) though multiple menus without a label might fight
|
||||
* the `puphash` if we have a title provided). Choosing an entry in a menu will still handle
|
||||
* `puphash` later (see `button_activate_exit`) though multiple menus without a label might fight
|
||||
* for the same storage of the menu memory. Using idname instead (or in combination with the
|
||||
* label) for the hash could be looked at to solve this. */
|
||||
pup->block->flag |= UI_BLOCK_POPUP_MEMORY;
|
||||
|
|
|
@ -71,8 +71,8 @@ static void undolatt_to_editlatt(UndoLattice *ult, EditLatt *editlatt)
|
|||
memcpy(editlatt->latt->def, ult->def, sizeof(BPoint) * len_src);
|
||||
}
|
||||
|
||||
/* Even for the same amount of points we dont just copy memory for MDeformVert, relations to
|
||||
* MDeformWeight might have changed. */
|
||||
/* Even for the same amount of points we don't just copy memory for MDeformVert,
|
||||
* relations to #MDeformWeight might have changed. */
|
||||
if (editlatt->latt->dvert && ult->dvert) {
|
||||
BKE_defvert_array_free(editlatt->latt->dvert, len_dst);
|
||||
editlatt->latt->dvert = MEM_mallocN(sizeof(MDeformVert) * len_src, "Lattice MDeformVert");
|
||||
|
|
|
@ -2796,7 +2796,7 @@ static int vertex_group_copy_exec(bContext *C, wmOperator * /*op*/)
|
|||
void OBJECT_OT_vertex_group_copy(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Copy Vertex Group";
|
||||
ot->name = "Duplicate Vertex Group";
|
||||
ot->idname = "OBJECT_OT_vertex_group_copy";
|
||||
ot->description = "Make a copy of the active vertex group";
|
||||
|
||||
|
|
|
@ -4508,6 +4508,11 @@ static bool match_region_with_redraws(const ScrArea *area,
|
|||
return true;
|
||||
}
|
||||
break;
|
||||
case SPACE_SPREADSHEET:
|
||||
if ((redraws & TIME_SPREADSHEETS)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1934,7 +1934,7 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps,
|
|||
zero_v4(projPixel->newColor.f);
|
||||
}
|
||||
else {
|
||||
projPixel->pixel.ch_pt = ibuf->byte_buffer.data + (x_px + y_px * ibuf->x);
|
||||
projPixel->pixel.ch_pt = ibuf->byte_buffer.data + (x_px + y_px * ibuf->x) * 4;
|
||||
projPixel->origColor.uint_pt = (uint *)projima->undoRect[tile_index] + tile_offset;
|
||||
projPixel->newColor.uint_ = 0;
|
||||
}
|
||||
|
|
|
@ -235,8 +235,8 @@ static void imapaint_tri_weights(float matrix[4][4],
|
|||
h[1] = (co[1] - view[1]) * 2.0f / view[3] - 1.0f;
|
||||
h[2] = 1.0f;
|
||||
|
||||
/* solve for (w1,w2,w3)/perspdiv in:
|
||||
* h * perspdiv = Project * Model * (w1 * v1 + w2 * v2 + w3 * v3) */
|
||||
/* Solve for `(w1,w2,w3)/perspdiv` in:
|
||||
* `h * perspdiv = Project * Model * (w1 * v1 + w2 * v2 + w3 * v3)`. */
|
||||
|
||||
wmat[0][0] = pv1[0];
|
||||
wmat[1][0] = pv2[0];
|
||||
|
@ -253,7 +253,7 @@ static void imapaint_tri_weights(float matrix[4][4],
|
|||
|
||||
copy_v3_v3(w, h);
|
||||
|
||||
/* w is still divided by perspdiv, make it sum to one */
|
||||
/* w is still divided by `perspdiv`, make it sum to one */
|
||||
divw = w[0] + w[1] + w[2];
|
||||
if (divw != 0.0f) {
|
||||
mul_v3_fl(w, 1.0f / divw);
|
||||
|
|
|
@ -58,7 +58,7 @@ bool ED_wpaint_ensure_data(bContext *C,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* if nothing was added yet, we make dverts and a vertex deform group */
|
||||
/* If nothing was added yet, we make deform-verts and a vertex deform group. */
|
||||
if (BKE_mesh_deform_verts(me) == nullptr) {
|
||||
BKE_object_defgroup_data_create(&me->id);
|
||||
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
|
||||
|
@ -136,8 +136,7 @@ int ED_wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active)
|
|||
}
|
||||
}
|
||||
|
||||
/* curdef should never be nullptr unless this is
|
||||
* a light and BKE_object_defgroup_add_name fails */
|
||||
/* `mirrdef` shouldn't be -1 unless the object is a light & #BKE_object_defgroup_new fails. */
|
||||
return mirrdef;
|
||||
}
|
||||
|
||||
|
|
|
@ -445,9 +445,9 @@ static void gizmo_retime_handle_draw(const bContext *C, wmGizmo *gz)
|
|||
RetimeHandleMoveGizmo *gizmo = (RetimeHandleMoveGizmo *)gz;
|
||||
const View2D *v2d = UI_view2d_fromcontext(C);
|
||||
|
||||
/* TODO: This is hardcoded behavior, same as preselect gizmos in 3D view.
|
||||
/* TODO: This is hard-coded behavior, same as pre-select gizmos in 3D view.
|
||||
* Better solution would be to check operator keymap and display this information in status bar
|
||||
* and tooltip. */
|
||||
* and tool-tip. */
|
||||
wmEvent *event = CTX_wm_window(C)->eventstate;
|
||||
gizmo->create_transition_operation = (event->modifier & KM_SHIFT) != 0;
|
||||
|
||||
|
|
|
@ -216,7 +216,7 @@ static int sequencer_retiming_handle_move_modal(bContext *C, wmOperator *op, con
|
|||
const bool handle_is_transition = SEQ_retiming_handle_is_transition_type(handle);
|
||||
const bool prev_handle_is_transition = SEQ_retiming_handle_is_transition_type(handle - 1);
|
||||
|
||||
/* When working with transiton, change handles when moving past pivot point. */
|
||||
/* When working with transition, change handles when moving past pivot point. */
|
||||
if (handle_is_transition || prev_handle_is_transition) {
|
||||
SeqRetimingHandle *transition_start, *transition_end;
|
||||
if (handle_is_transition) {
|
||||
|
|
|
@ -74,6 +74,8 @@ const char *viewops_operator_idname_get(eV3D_OpMode nav_type)
|
|||
case V3D_OP_MODE_NDOF_ORBIT_ZOOM:
|
||||
return "VIEW3D_OT_ndof_orbit_zoom";
|
||||
#endif
|
||||
case V3D_OP_MODE_NONE:
|
||||
break;
|
||||
}
|
||||
BLI_assert(false);
|
||||
return nullptr;
|
||||
|
@ -1942,3 +1944,142 @@ void VIEW3D_OT_view_pan(wmOperatorType *ot)
|
|||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Navigation Utilities
|
||||
* \{ */
|
||||
|
||||
/* Detect the navigation operation, by the name of the navigation operator (obtained by
|
||||
* `wmKeyMapItem::idname`) */
|
||||
static eV3D_OpMode view3d_navigation_type_from_idname(const char *idname)
|
||||
{
|
||||
const char *op_name = idname + sizeof("VIEW3D_OT_");
|
||||
for (int i = 0; i < V3D_OP_MODE_LEN; i++) {
|
||||
if (STREQ(op_name, viewops_operator_idname_get((eV3D_OpMode)i) + sizeof("VIEW3D_OT_"))) {
|
||||
return (eV3D_OpMode)i;
|
||||
}
|
||||
}
|
||||
return V3D_OP_MODE_NONE;
|
||||
}
|
||||
|
||||
/* Unlike `viewops_data_create`, `ED_view3d_navigation_init` creates a navigation context along
|
||||
* with an array of `wmKeyMapItem`s used for navigation. */
|
||||
ViewOpsData *ED_view3d_navigation_init(bContext *C)
|
||||
{
|
||||
if (!CTX_wm_region_view3d(C)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ViewOpsData *vod = MEM_cnew<ViewOpsData>(__func__);
|
||||
viewops_data_init_context(C, vod);
|
||||
|
||||
vod->keymap = WM_keymap_find_all(CTX_wm_manager(C), "3D View", SPACE_VIEW3D, 0);
|
||||
return vod;
|
||||
}
|
||||
|
||||
/* Checks and initializes the navigation modal operation. */
|
||||
static int view3d_navigation_invoke(bContext *C,
|
||||
ViewOpsData *vod,
|
||||
const wmEvent *event,
|
||||
struct wmKeyMapItem *kmi,
|
||||
eV3D_OpMode nav_type)
|
||||
{
|
||||
switch (nav_type) {
|
||||
case V3D_OP_MODE_ZOOM:
|
||||
if (!view3d_zoom_or_dolly_poll(C)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
break;
|
||||
case V3D_OP_MODE_MOVE:
|
||||
case V3D_OP_MODE_VIEW_PAN:
|
||||
if (!view3d_location_poll(C)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
break;
|
||||
case V3D_OP_MODE_ROTATE:
|
||||
if (!view3d_rotation_poll(C)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
break;
|
||||
case V3D_OP_MODE_VIEW_ROLL:
|
||||
case V3D_OP_MODE_DOLLY:
|
||||
#ifdef WITH_INPUT_NDOF
|
||||
case V3D_OP_MODE_NDOF_ORBIT:
|
||||
case V3D_OP_MODE_NDOF_ORBIT_ZOOM:
|
||||
#endif
|
||||
case V3D_OP_MODE_NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
return view3d_navigation_invoke_generic(C, vod, event, kmi->ptr, nav_type);
|
||||
}
|
||||
|
||||
bool ED_view3d_navigation_do(bContext *C, ViewOpsData *vod, const wmEvent *event)
|
||||
{
|
||||
if (!vod) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wmEvent event_tmp;
|
||||
if (event->type == EVT_MODAL_MAP) {
|
||||
/* Workaround to use the original event values. */
|
||||
event_tmp = *event;
|
||||
event_tmp.type = event->prev_type;
|
||||
event_tmp.val = event->prev_val;
|
||||
event = &event_tmp;
|
||||
}
|
||||
|
||||
int op_return = OPERATOR_CANCELLED;
|
||||
|
||||
if (vod->is_modal_event) {
|
||||
const eV3D_OpEvent event_code = view3d_navigate_event(vod, event);
|
||||
op_return = view3d_navigation_modal(C, vod, event_code, event->xy);
|
||||
if (op_return != OPERATOR_RUNNING_MODAL) {
|
||||
viewops_data_end_navigation(C, vod);
|
||||
vod->is_modal_event = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
eV3D_OpMode nav_type;
|
||||
LISTBASE_FOREACH (wmKeyMapItem *, kmi, &vod->keymap->items) {
|
||||
if (!STRPREFIX(kmi->idname, "VIEW3D")) {
|
||||
continue;
|
||||
}
|
||||
if (kmi->flag & KMI_INACTIVE) {
|
||||
continue;
|
||||
}
|
||||
if ((nav_type = view3d_navigation_type_from_idname(kmi->idname)) == V3D_OP_MODE_NONE) {
|
||||
continue;
|
||||
}
|
||||
if (!WM_event_match(event, kmi)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
op_return = view3d_navigation_invoke(C, vod, event, kmi, nav_type);
|
||||
if (op_return == OPERATOR_RUNNING_MODAL) {
|
||||
vod->is_modal_event = true;
|
||||
}
|
||||
else {
|
||||
viewops_data_end_navigation(C, vod);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (op_return != OPERATOR_CANCELLED) {
|
||||
/* Although #ED_view3d_update_viewmat is already called when redrawing the 3D View, do it here
|
||||
* as well, so the updated matrix values can be accessed by the operator. */
|
||||
ED_view3d_update_viewmat(
|
||||
vod->depsgraph, vod->scene, vod->v3d, vod->region, NULL, NULL, NULL, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ED_view3d_navigation_free(bContext *C, ViewOpsData *vod)
|
||||
{
|
||||
viewops_data_free(C, vod);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -33,6 +33,7 @@ struct wmEvent;
|
|||
struct wmOperator;
|
||||
|
||||
typedef enum eV3D_OpMode {
|
||||
V3D_OP_MODE_NONE = -1,
|
||||
V3D_OP_MODE_ZOOM = 0,
|
||||
V3D_OP_MODE_ROTATE,
|
||||
V3D_OP_MODE_MOVE,
|
||||
|
@ -44,6 +45,11 @@ typedef enum eV3D_OpMode {
|
|||
V3D_OP_MODE_NDOF_ORBIT_ZOOM,
|
||||
#endif
|
||||
} eV3D_OpMode;
|
||||
#ifndef WITH_INPUT_NDOF
|
||||
# define V3D_OP_MODE_LEN V3D_OP_MODE_DOLLY + 1
|
||||
#else
|
||||
# define V3D_OP_MODE_LEN V3D_OP_MODE_NDOF_ORBIT_ZOOM + 1
|
||||
#endif
|
||||
|
||||
enum eV3D_OpPropFlag {
|
||||
V3D_OP_PROP_MOUSE_CO = (1 << 0),
|
||||
|
@ -179,6 +185,10 @@ typedef struct ViewOpsData {
|
|||
* See #view3d_orbit_apply_dyn_ofs code-comments for an example, also see: #104385.
|
||||
*/
|
||||
bool use_dyn_ofs_ortho_correction;
|
||||
|
||||
/** Used for navigation on non view3d operators. */
|
||||
wmKeyMap *keymap;
|
||||
bool is_modal_event;
|
||||
} ViewOpsData;
|
||||
|
||||
/* view3d_navigate.cc */
|
||||
|
|
|
@ -891,7 +891,7 @@ static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_
|
|||
mul_qt_v3(viewinv, view_dst_x);
|
||||
mul_qt_v3(viewinv, view_dst_y);
|
||||
|
||||
/* check source and dest have a matching axis */
|
||||
/* Check source and destination have a matching axis. */
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (((fabsf(view_src_x[i]) > axis_eps) || (fabsf(view_src_y[i]) > axis_eps)) &&
|
||||
((fabsf(view_dst_x[i]) > axis_eps) || (fabsf(view_dst_y[i]) > axis_eps)))
|
||||
|
|
|
@ -92,9 +92,6 @@ void setTransformViewMatrices(TransInfo *t)
|
|||
unit_m4(t->persinv);
|
||||
t->persp = RV3D_ORTHO;
|
||||
}
|
||||
|
||||
calculateCenter2D(t);
|
||||
calculateCenterLocal(t, t->center_global);
|
||||
}
|
||||
|
||||
void setTransformViewAspect(TransInfo *t, float r_aspect[3])
|
||||
|
@ -926,15 +923,17 @@ static bool transform_event_modal_constraint(TransInfo *t, short modal_type)
|
|||
int transformEvent(TransInfo *t, const wmEvent *event)
|
||||
{
|
||||
bool handled = false;
|
||||
bool is_navigating = t->vod ? ((RegionView3D *)t->region->regiondata)->rflag & RV3D_NAVIGATING :
|
||||
false;
|
||||
|
||||
/* Handle modal numinput events first, if already activated. */
|
||||
if (((event->val == KM_PRESS) || (event->type == EVT_MODAL_MAP)) && hasNumInput(&t->num) &&
|
||||
handleNumInput(t->context, &(t->num), event))
|
||||
if (!is_navigating && ((event->val == KM_PRESS) || (event->type == EVT_MODAL_MAP)) &&
|
||||
hasNumInput(&t->num) && handleNumInput(t->context, &(t->num), event))
|
||||
{
|
||||
t->redraw |= TREDRAW_HARD;
|
||||
handled = true;
|
||||
}
|
||||
else if (event->type == MOUSEMOVE) {
|
||||
else if (!is_navigating && event->type == MOUSEMOVE) {
|
||||
copy_v2_v2_int(t->mval, event->mval);
|
||||
|
||||
/* Use this for soft redraw. Might cause flicker in object mode */
|
||||
|
|
|
@ -41,6 +41,7 @@ struct TransDataContainer;
|
|||
struct TransInfo;
|
||||
struct TransSnap;
|
||||
struct ViewLayer;
|
||||
struct ViewOpsData;
|
||||
struct bContext;
|
||||
struct wmEvent;
|
||||
struct wmKeyConfig;
|
||||
|
@ -673,6 +674,8 @@ typedef struct TransInfo {
|
|||
/** Currently only used for random curve of proportional editing. */
|
||||
struct RNG *rng;
|
||||
|
||||
struct ViewOpsData *vod;
|
||||
|
||||
/** Typically for mode settings. */
|
||||
TransCustomDataContainer custom;
|
||||
|
||||
|
|
|
@ -660,7 +660,16 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
|
|||
t->flag |= T_NO_CURSOR_WRAP;
|
||||
}
|
||||
|
||||
if (op && (t->flag & T_MODAL) && !(t->flag & T_RELEASE_CONFIRM) &&
|
||||
(prop = RNA_struct_find_property(op->ptr, "allow_navigation")) &&
|
||||
RNA_property_boolean_get(op->ptr, prop))
|
||||
{
|
||||
t->vod = ED_view3d_navigation_init(C);
|
||||
}
|
||||
|
||||
setTransformViewMatrices(t);
|
||||
calculateCenter2D(t);
|
||||
calculateCenterLocal(t, t->center_global);
|
||||
initNumInput(&t->num);
|
||||
|
||||
transform_gizmo_3d_model_from_constraint_and_mode_init(t);
|
||||
|
@ -770,6 +779,10 @@ void postTrans(bContext *C, TransInfo *t)
|
|||
}
|
||||
|
||||
freeSnapping(t);
|
||||
|
||||
if (t->vod) {
|
||||
ED_view3d_navigation_free(C, t->vod);
|
||||
}
|
||||
}
|
||||
|
||||
void applyTransObjects(TransInfo *t)
|
||||
|
|
|
@ -474,6 +474,23 @@ static void protectflag_to_drawflags(short protectflag, short *drawflags)
|
|||
}
|
||||
}
|
||||
|
||||
/* Similar to #transform_object_deform_pose_armature_get but does not check visibility. */
|
||||
static Object *gizmo_3d_transform_space_object_get(Scene *scene, ViewLayer *view_layer)
|
||||
{
|
||||
BKE_view_layer_synced_ensure(scene, view_layer);
|
||||
Object *ob = BKE_view_layer_active_object_get(view_layer);
|
||||
if (ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
|
||||
/* It is assumed that when the object is in Weight Paint mode, it is not in Edit mode. So we
|
||||
* don't need to check the #OB_MODE_EDIT flag. */
|
||||
BLI_assert(!(ob->mode & OB_MODE_EDIT));
|
||||
Object *obpose = BKE_object_pose_armature_get(ob);
|
||||
if (obpose != nullptr) {
|
||||
ob = obpose;
|
||||
}
|
||||
}
|
||||
return ob;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run \a user_fn for each coordinate of elements selected in View3D (vertices, particles...).
|
||||
* \note Each coordinate has the space matrix of the active object.
|
||||
|
@ -519,15 +536,7 @@ static int gizmo_3d_foreach_selected(const bContext *C,
|
|||
const bool is_curve_edit = GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
|
||||
int a, totsel = 0;
|
||||
|
||||
BKE_view_layer_synced_ensure(scene, view_layer);
|
||||
Object *ob = BKE_view_layer_active_object_get(view_layer);
|
||||
Object *obedit = OBEDIT_FROM_OBACT(ob);
|
||||
if (ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
|
||||
Object *obpose = BKE_object_pose_armature_get(ob);
|
||||
if (obpose != nullptr) {
|
||||
ob = obpose;
|
||||
}
|
||||
}
|
||||
Object *ob = gizmo_3d_transform_space_object_get(scene, view_layer);
|
||||
|
||||
if (is_gp_edit) {
|
||||
float diff_mat[4][4];
|
||||
|
@ -586,7 +595,7 @@ static int gizmo_3d_foreach_selected(const bContext *C,
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (obedit) {
|
||||
else if (Object *obedit = OBEDIT_FROM_OBACT(ob)) {
|
||||
|
||||
#define FOREACH_EDIT_OBJECT_BEGIN(ob_iter, use_mat_local) \
|
||||
{ \
|
||||
|
@ -937,15 +946,8 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
|
|||
(params->orientation_index - 1) :
|
||||
BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT);
|
||||
|
||||
BKE_view_layer_synced_ensure(scene, view_layer);
|
||||
Object *ob = BKE_view_layer_active_object_get(view_layer);
|
||||
Object *ob = gizmo_3d_transform_space_object_get(scene, view_layer);
|
||||
Object *obedit = OBEDIT_FROM_OBACT(ob);
|
||||
if (ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
|
||||
Object *obpose = BKE_object_pose_armature_get(ob);
|
||||
if (obpose != nullptr) {
|
||||
ob = obpose;
|
||||
}
|
||||
}
|
||||
|
||||
tbounds->use_matrix_space = false;
|
||||
unit_m3(tbounds->axis);
|
||||
|
@ -972,7 +974,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
|
|||
copy_m3_m4(diff_mat, ob->object_to_world);
|
||||
normalize_m3(diff_mat);
|
||||
invert_m3(diff_mat);
|
||||
mul_m3_m3m3(tbounds->axis, tbounds->axis, diff_mat);
|
||||
mul_m3_m3_pre(tbounds->axis, diff_mat);
|
||||
normalize_m3(tbounds->axis);
|
||||
|
||||
tbounds->use_matrix_space = true;
|
||||
|
@ -997,7 +999,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
|
|||
bGPdata *gpd = CTX_data_gpencil_data(C);
|
||||
const bool is_gp_edit = GPENCIL_ANY_MODE(gpd);
|
||||
if (!is_gp_edit && (obedit || (ob && (ob->mode & (OB_MODE_POSE | OB_MODE_SCULPT))))) {
|
||||
if (ob && (ob->mode & OB_MODE_POSE)) {
|
||||
if (ob->mode & OB_MODE_POSE) {
|
||||
invert_m4_m4(ob->world_to_object, ob->object_to_world);
|
||||
}
|
||||
mul_m4_v3(ob->object_to_world, tbounds->center);
|
||||
|
|
|
@ -399,7 +399,7 @@ static int transformops_data(bContext *C, wmOperator *op, const wmEvent *event)
|
|||
|
||||
static int transform_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
int exit_code;
|
||||
int exit_code = OPERATOR_PASS_THROUGH;
|
||||
|
||||
TransInfo *t = op->customdata;
|
||||
const eTfmMode mode_prev = t->mode;
|
||||
|
@ -419,6 +419,31 @@ static int transform_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
|||
exit_code = transformEvent(t, event);
|
||||
t->context = NULL;
|
||||
|
||||
/* Allow navigation while transforming. */
|
||||
if (t->vod && (exit_code & OPERATOR_PASS_THROUGH) && ED_view3d_navigation_do(C, t->vod, event)) {
|
||||
RegionView3D *rv3d = t->region->regiondata;
|
||||
if (rv3d->rflag & RV3D_NAVIGATING) {
|
||||
/* Do not update transform while navigating. This can be distracting. */
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
if (t->modifiers & MOD_PRECISION) {
|
||||
/* Remove Precision modifier, it may have be unintentionally enabled. */
|
||||
t->modifiers &= ~MOD_PRECISION;
|
||||
t->mouse.precision = 0;
|
||||
}
|
||||
|
||||
/* Make sure `t->mval` is up to date before calling #transformViewUpdate. */
|
||||
copy_v2_v2_int(t->mval, event->mval);
|
||||
|
||||
/* Call before #applyMouseInput. */
|
||||
tranformViewUpdate(t);
|
||||
|
||||
/* Mouse input is outdated. */
|
||||
applyMouseInput(t, &t->mouse, t->mval, t->values);
|
||||
t->redraw |= TREDRAW_HARD;
|
||||
}
|
||||
|
||||
transformApply(C, t);
|
||||
|
||||
exit_code |= transformEnd(C, t);
|
||||
|
@ -752,6 +777,15 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
|
|||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
if (flags & P_VIEW3D_NAVIGATION) {
|
||||
prop = RNA_def_boolean(ot->srna,
|
||||
"allow_navigation",
|
||||
0,
|
||||
"Allow Navigation",
|
||||
"Allow navigation while transforming");
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
if (flags & P_POST_TRANSFORM) {
|
||||
prop = RNA_def_boolean(ot->srna,
|
||||
"use_automerge_and_split",
|
||||
|
@ -786,7 +820,7 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
|
|||
Transform_Properties(ot,
|
||||
P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP |
|
||||
P_OPTIONS | P_GPENCIL_EDIT | P_CURSOR_EDIT | P_VIEW2D_EDGE_PAN |
|
||||
P_POST_TRANSFORM);
|
||||
P_VIEW3D_NAVIGATION | P_POST_TRANSFORM);
|
||||
}
|
||||
|
||||
static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
|
||||
|
@ -825,7 +859,7 @@ static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
|
|||
|
||||
Transform_Properties(ot,
|
||||
P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP |
|
||||
P_OPTIONS | P_GPENCIL_EDIT | P_CENTER);
|
||||
P_OPTIONS | P_GPENCIL_EDIT | P_CENTER | P_VIEW3D_NAVIGATION);
|
||||
}
|
||||
|
||||
static void TRANSFORM_OT_skin_resize(struct wmOperatorType *ot)
|
||||
|
@ -902,7 +936,7 @@ static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
|
|||
|
||||
Transform_Properties(ot,
|
||||
P_ORIENT_AXIS | P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR |
|
||||
P_GEO_SNAP | P_GPENCIL_EDIT | P_CENTER);
|
||||
P_GEO_SNAP | P_GPENCIL_EDIT | P_CENTER | P_VIEW3D_NAVIGATION);
|
||||
}
|
||||
|
||||
static void TRANSFORM_OT_tilt(struct wmOperatorType *ot)
|
||||
|
@ -1147,7 +1181,7 @@ static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
|
|||
"When Even mode is active, flips between the two adjacent edge loops");
|
||||
RNA_def_boolean(ot->srna, "use_clamp", true, "Clamp", "Clamp within the edge extents");
|
||||
|
||||
Transform_Properties(ot, P_MIRROR | P_GEO_SNAP | P_CORRECT_UV);
|
||||
Transform_Properties(ot, P_MIRROR | P_GEO_SNAP | P_CORRECT_UV | P_VIEW3D_NAVIGATION);
|
||||
}
|
||||
|
||||
static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot)
|
||||
|
@ -1182,7 +1216,7 @@ static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot)
|
|||
"When Even mode is active, flips between the two adjacent edge loops");
|
||||
RNA_def_boolean(ot->srna, "use_clamp", true, "Clamp", "Clamp within the edge extents");
|
||||
|
||||
Transform_Properties(ot, P_MIRROR | P_GEO_SNAP | P_CORRECT_UV);
|
||||
Transform_Properties(ot, P_MIRROR | P_GEO_SNAP | P_CORRECT_UV | P_VIEW3D_NAVIGATION);
|
||||
}
|
||||
|
||||
static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot)
|
||||
|
@ -1330,7 +1364,7 @@ static void TRANSFORM_OT_transform(struct wmOperatorType *ot)
|
|||
|
||||
Transform_Properties(ot,
|
||||
P_ORIENT_AXIS | P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR |
|
||||
P_ALIGN_SNAP | P_GPENCIL_EDIT | P_CENTER);
|
||||
P_ALIGN_SNAP | P_GPENCIL_EDIT | P_CENTER | P_VIEW3D_NAVIGATION);
|
||||
}
|
||||
|
||||
static int transform_from_gizmo_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
|
||||
|
|
|
@ -715,6 +715,10 @@ static eSnapTargetOP snap_target_select_from_spacetype(TransInfo *t)
|
|||
/* Exclude editmesh when using proportional edit */
|
||||
ret |= SCE_SNAP_TARGET_NOT_EDITED;
|
||||
}
|
||||
/* UV editing must never snap to the selection as this is what is transformed. */
|
||||
if (t->spacetype == SPACE_IMAGE) {
|
||||
ret |= SCE_SNAP_TARGET_NOT_SELECTED;
|
||||
}
|
||||
}
|
||||
else if (ELEM(obedit_type, OB_ARMATURE, OB_CURVES_LEGACY, OB_SURF, OB_LATTICE, OB_MBALL)) {
|
||||
/* Temporary limited to edit mode armature, curves, surfaces, lattices, and metaballs. */
|
||||
|
|
|
@ -1150,12 +1150,12 @@ static bool rotate_inside_square(const Span<UVAABBIsland *> island_indices,
|
|||
return false; /* Nothing to do. */
|
||||
}
|
||||
|
||||
/* Transform phis. */
|
||||
/* Transform phis, rotate by best_angle, then translate back to the origin. No scale. */
|
||||
for (const int64_t j : island_indices.index_range()) {
|
||||
const int64_t i = island_indices[j]->index;
|
||||
const PackIsland *island = islands[i];
|
||||
const float island_scale = island->can_scale_(params) ? scale : 1.0f;
|
||||
island->build_transformation(island_scale, square_finder.best_angle, matrix);
|
||||
const float identity_scale = 1.0f; /* Don't rescale the placement, just rotate. */
|
||||
island->build_transformation(identity_scale, square_finder.best_angle, matrix);
|
||||
r_phis[i].rotation += square_finder.best_angle;
|
||||
mul_m2_v2(matrix, r_phis[i].translation);
|
||||
r_phis[i].translation.x -= square_finder.best_bounds.xmin;
|
||||
|
@ -1777,17 +1777,25 @@ class OverlapMerger {
|
|||
sub_params.merge_overlap = false;
|
||||
const float result = pack_islands(sub_islands, sub_params);
|
||||
|
||||
/* Must loop backwards! */
|
||||
/* Must loop backwards, or we will miss sub-sub-islands. */
|
||||
for (int64_t i = merge_trace.size() - 3; i >= 0; i -= 3) {
|
||||
PackIsland *sub_a = merge_trace[i];
|
||||
PackIsland *sub_b = merge_trace[i + 1];
|
||||
PackIsland *merge = merge_trace[i + 2];
|
||||
|
||||
/* Copy `angle`, `pre_translate` and `pre_rotate` from merged island to sub islands. */
|
||||
sub_a->angle = merge->angle;
|
||||
sub_b->angle = merge->angle;
|
||||
sub_a->pre_translate = merge->pre_translate;
|
||||
sub_b->pre_translate = merge->pre_translate;
|
||||
sub_a->pre_rotate_ = merge->pre_rotate_;
|
||||
sub_b->pre_rotate_ = merge->pre_rotate_;
|
||||
|
||||
/* If the merged island is pinned, the sub-islands are also pinned to correct scaling. */
|
||||
if (merge->pinned) {
|
||||
sub_a->pinned = true;
|
||||
sub_b->pinned = true;
|
||||
}
|
||||
delete merge;
|
||||
}
|
||||
|
||||
|
@ -1823,8 +1831,24 @@ float pack_islands(const Span<PackIsland *> &islands, const UVPackIsland_Params
|
|||
|
||||
finalize_geometry(islands, params);
|
||||
|
||||
/* Count the number of islands which can scale and which can translate. */
|
||||
int64_t can_scale_count = 0;
|
||||
int64_t can_translate_count = 0;
|
||||
for (const int64_t i : islands.index_range()) {
|
||||
if (islands[i]->can_scale_(params)) {
|
||||
can_scale_count++;
|
||||
}
|
||||
if (islands[i]->can_translate_(params)) {
|
||||
can_translate_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (can_translate_count == 0) {
|
||||
return 1.0f; /* Nothing to do, all islands are locked. */
|
||||
}
|
||||
|
||||
if (params.margin_method == ED_UVPACK_MARGIN_FRACTION && params.margin > 0.0f &&
|
||||
params.scale_to_fit)
|
||||
can_scale_count > 0)
|
||||
{
|
||||
/* Uses a line search on scale. ~10x slower than other method. */
|
||||
return pack_islands_margin_fraction(islands, params.margin, false, params);
|
||||
|
@ -1837,28 +1861,24 @@ float pack_islands(const Span<PackIsland *> &islands, const UVPackIsland_Params
|
|||
case ED_UVPACK_MARGIN_SCALED: /* Default for Blender 3.3 and later. */
|
||||
margin = calc_margin_from_aabb_length_sum(islands, params);
|
||||
break;
|
||||
case ED_UVPACK_MARGIN_FRACTION: /* Added as an option in Blender 3.4. */
|
||||
BLI_assert(params.margin == 0.0f); /* Other (slower) cases are handled above. */
|
||||
case ED_UVPACK_MARGIN_FRACTION: /* Added as an option in Blender 3.4. */
|
||||
/* Most other cases are handled above, unless pinning is involved. */
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
/* TODO: Only line-search if *some* islands can scale and *some* are locked. */
|
||||
switch (params.pin_method) {
|
||||
case ED_UVPACK_PIN_LOCK_ALL:
|
||||
case ED_UVPACK_PIN_LOCK_SCALE:
|
||||
case ED_UVPACK_PIN_LOCK_ROTATION_SCALE:
|
||||
return pack_islands_margin_fraction(islands, margin, true, params);
|
||||
default:
|
||||
break;
|
||||
if (can_scale_count > 0 && can_scale_count != islands.size()) {
|
||||
/* Search for the best scale parameter. (slow) */
|
||||
return pack_islands_margin_fraction(islands, margin, true, params);
|
||||
}
|
||||
|
||||
/* Either all of the islands can scale, or none of them can.
|
||||
* In either case, we pack them all tight to the origin. */
|
||||
blender::Array<uv_phi> phis(islands.size());
|
||||
|
||||
const float scale = 1.0f;
|
||||
const float max_uv = pack_islands_scale_margin(islands, scale, margin, params, phis);
|
||||
const float result = params.scale_to_fit ? 1.0f / max_uv : 1.0f;
|
||||
const float result = can_scale_count > 0 ? 1.0f / max_uv : 1.0f;
|
||||
for (const int64_t i : islands.index_range()) {
|
||||
BLI_assert(result == 1.0f || islands[i]->can_scale_(params));
|
||||
islands[i]->place_(scale, phis[i]);
|
||||
|
|
|
@ -87,7 +87,7 @@ void *GPU_debug_capture_scope_create(const char *name);
|
|||
/**
|
||||
* Used to declare the region within which GPU calls are captured when the scope is triggered.
|
||||
*
|
||||
* \param scope Pointer to capture scope object created with GPU_debug_capture_scope_create.
|
||||
* \param scope: Pointer to capture scope object created with GPU_debug_capture_scope_create.
|
||||
* \return True if the capture tool is actively capturing this scope when function is executed.
|
||||
* Otherwise, False.
|
||||
*/
|
||||
|
|
|
@ -178,6 +178,9 @@ bool Texture::init_view(GPUTexture *src_,
|
|||
void Texture::usage_set(eGPUTextureUsage usage_flags)
|
||||
{
|
||||
gpu_image_usage_flags_ = usage_flags;
|
||||
/* Metal: Texture clearing is done using frame-buffer clear. This has no performance impact. */
|
||||
/* TODO(fclem): Move this to metal backend instead to avoid side effects in other back-ends. */
|
||||
gpu_image_usage_flags_ |= GPU_TEXTURE_USAGE_ATTACHMENT;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -1390,9 +1390,15 @@ bool MTLShader::bake_compute_pipeline_state(MTLContext *ctx)
|
|||
}
|
||||
|
||||
/* Compile PSO. */
|
||||
MTLComputePipelineDescriptor *desc = [[MTLComputePipelineDescriptor alloc] init];
|
||||
desc.maxTotalThreadsPerThreadgroup = 1024;
|
||||
desc.computeFunction = compute_function;
|
||||
|
||||
id<MTLComputePipelineState> pso = [ctx->device
|
||||
newComputePipelineStateWithFunction:compute_function
|
||||
error:&error];
|
||||
newComputePipelineStateWithDescriptor:desc
|
||||
options:MTLPipelineOptionNone
|
||||
reflection:nullptr
|
||||
error:&error];
|
||||
|
||||
if (error) {
|
||||
NSLog(@"Failed to create PSO for compute shader: %s error %@\n", this->name, error);
|
||||
|
|
|
@ -142,7 +142,7 @@ VKStateManager &VKContext::state_manager_get()
|
|||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Framebuffer
|
||||
/** \name Frame-buffer
|
||||
* \{ */
|
||||
|
||||
void VKContext::activate_framebuffer(VKFrameBuffer &framebuffer)
|
||||
|
|
|
@ -33,9 +33,9 @@ class VKFrameBuffer : public FrameBuffer {
|
|||
|
||||
/**
|
||||
* Should we flip the viewport to match Blenders coordinate system. We flip the viewport for
|
||||
* offscreen framebuffers.
|
||||
* off-screen frame-buffers.
|
||||
*
|
||||
* When two framebuffers are blitted we also check if the coordinate system should be flipped
|
||||
* When two frame-buffers are blitted we also check if the coordinate system should be flipped
|
||||
* during blitting.
|
||||
*/
|
||||
bool flip_viewport_ = false;
|
||||
|
|
|
@ -169,7 +169,7 @@ void VKPipeline::finalize(VKContext &context,
|
|||
viewport_state.scissorCount = 1;
|
||||
pipeline_create_info.pViewportState = &viewport_state;
|
||||
|
||||
/* Multisample state. */
|
||||
/* Multi-sample state. */
|
||||
VkPipelineMultisampleStateCreateInfo multisample_state = {};
|
||||
multisample_state.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||
multisample_state.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
|
|
@ -20,7 +20,7 @@ VKPipelineStateManager::VKPipelineStateManager()
|
|||
depth_stencil_state = {};
|
||||
depth_stencil_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||
|
||||
/* TODO should be extracted from current framebuffer and should not be done here and now. */
|
||||
/* TODO should be extracted from current frame-buffer and should not be done here and now. */
|
||||
/* When the attachments differ the state should be forced. */
|
||||
VkPipelineColorBlendAttachmentState color_blend_attachment = {};
|
||||
color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
|
@ -364,4 +364,4 @@ void VKPipelineStateManager::set_shadow_bias(const bool enable)
|
|||
}
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
||||
} // namespace blender::gpu
|
||||
|
|
|
@ -65,7 +65,7 @@ void path_reference_copy(const Set<std::pair<std::string, std::string>> ©_se
|
|||
continue;
|
||||
}
|
||||
if (0 == BLI_path_cmp_normalized(src, dst)) {
|
||||
continue; /* Source and dest are the same. */
|
||||
continue; /* Source and destination are the same. */
|
||||
}
|
||||
if (!BLI_file_ensure_parent_dir_exists(dst)) {
|
||||
fprintf(stderr, "Can't make directory for '%s', not copying\n", dst);
|
||||
|
|
|
@ -103,8 +103,10 @@ static bool prim_path_valid(const char *path)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Perform validation of export parameter settings. Returns
|
||||
* true if the paramters are valid; returns false otherwise. */
|
||||
/**
|
||||
* Perform validation of export parameter settings.
|
||||
* \return true if the parameters are valid; returns false otherwise.
|
||||
*/
|
||||
static bool export_params_valid(const USDExportParams ¶ms)
|
||||
{
|
||||
bool valid = true;
|
||||
|
|
|
@ -296,7 +296,7 @@ static void populate_curve_props_for_nurbs(const bke::CurvesGeometry &geometry,
|
|||
Array<float> temp_knots(knots_num);
|
||||
bke::curves::nurbs::calculate_knots(tot_points, mode, order, is_cyclic, temp_knots);
|
||||
|
||||
/* Knots should be the concatentation of all batched curves.
|
||||
/* Knots should be the concatenation of all batched curves.
|
||||
* https://graphics.pixar.com/usd/dev/api/class_usd_geom_nurbs_curves.html#details */
|
||||
for (int i_knot = 0; i_knot < knots_num; i_knot++) {
|
||||
knots.push_back(double(temp_knots[i_knot]));
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue