Refactor: change light linking object storage be dynamically allocated #108090

Closed
Brecht Van Lommel wants to merge 128 commits from light-linking-dna into cycles-light-linking

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
398 changed files with 4521 additions and 4882 deletions

View File

@ -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",

View File

@ -39,8 +39,14 @@ if(CMAKE_C_COMPILER_ID MATCHES "Clang")
set(WITH_WINDOWS_STRIPPED_PDB OFF)
endif()
else()
if(WITH_BLENDER AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.28.29921) # MSVC 2019 16.9.16
message(FATAL_ERROR "Compiler is unsupported, MSVC 2019 16.9.16 or newer is required for building blender.")
if(WITH_BLENDER)
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.28.29921) # MSVC 2019 16.9.16
message(FATAL_ERROR "Compiler is unsupported, MSVC 2019 16.9.16 or newer is required for building blender.")
endif()
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.36.32532 AND # MSVC 2022 17.6.0 has a bad codegen
CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.37.32705) # But it is fixed in 2022 17.7 preview 1
message(FATAL_ERROR "Compiler is unsupported, MSVC 2022 17.6.x has codegen issues and cannot be used to build blender. Please use MSVC 17.5 for the time being.")
endif()
endif()
endif()

View File

@ -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",

View File

@ -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")

View File

@ -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. */

View File

@ -3,6 +3,8 @@
#include "blender/light_linking.h"
#include "scene/object.h"
#include "DNA_object_types.h"
CCL_NAMESPACE_BEGIN
@ -12,7 +14,7 @@ static const ::Object *get_blender_object(const BL::Object &object)
return reinterpret_cast<::Object *>(object.ptr.data);
}
static const ::LightLinking &get_light_linking(const BL::Object &object)
static const ::LightLinking *get_light_linking(const BL::Object &object)
{
const ::Object *blender_object = get_blender_object(object);
return blender_object->light_linking;
@ -21,41 +23,41 @@ static const ::LightLinking &get_light_linking(const BL::Object &object)
uint64_t BlenderLightLink::get_light_set_membership(const BL::Object & /*parent*/,
const BL::Object &object)
{
const ::LightLinking &light_linking = get_light_linking(object);
return light_linking.runtime.light_set_membership;
const ::LightLinking *light_linking = get_light_linking(object);
return (light_linking) ? light_linking->runtime.light_set_membership : LIGHT_LINK_MASK_ALL;
}
uint BlenderLightLink::get_receiver_light_set(const BL::Object &parent, const BL::Object &object)
{
if (parent) {
const ::LightLinking &parent_light_linking = get_light_linking(parent);
if (parent_light_linking.runtime.receiver_light_set) {
return parent_light_linking.runtime.receiver_light_set;
const ::LightLinking *parent_light_linking = get_light_linking(parent);
if (parent_light_linking && parent_light_linking->runtime.receiver_light_set) {
return parent_light_linking->runtime.receiver_light_set;
}
}
const ::LightLinking &light_linking = get_light_linking(object);
return light_linking.runtime.receiver_light_set;
const ::LightLinking *light_linking = get_light_linking(object);
return (light_linking) ? light_linking->runtime.receiver_light_set : 0;
}
uint64_t BlenderLightLink::get_shadow_set_membership(const BL::Object & /*parent*/,
const BL::Object &object)
{
const ::LightLinking &light_linking = get_light_linking(object);
return light_linking.runtime.shadow_set_membership;
const ::LightLinking *light_linking = get_light_linking(object);
return (light_linking) ? light_linking->runtime.shadow_set_membership : LIGHT_LINK_MASK_ALL;
}
uint BlenderLightLink::get_blocker_shadow_set(const BL::Object &parent, const BL::Object &object)
{
if (parent) {
const ::LightLinking &parent_light_linking = get_light_linking(parent);
if (parent_light_linking.runtime.blocker_shadow_set) {
return parent_light_linking.runtime.blocker_shadow_set;
const ::LightLinking *parent_light_linking = get_light_linking(parent);
if (parent_light_linking && parent_light_linking->runtime.blocker_shadow_set) {
return parent_light_linking->runtime.blocker_shadow_set;
}
}
const ::LightLinking &light_linking = get_light_linking(object);
return light_linking.runtime.blocker_shadow_set;
const ::LightLinking *light_linking = get_light_linking(object);
return (light_linking) ? light_linking->runtime.blocker_shadow_set : 0;
}
CCL_NAMESPACE_END

View File

@ -523,27 +523,6 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeHoldout)) {
node = graph->create_node<HoldoutNode>();
}
else if (b_node.is_a(&RNA_ShaderNodeBsdfAnisotropic)) {
BL::ShaderNodeBsdfAnisotropic b_aniso_node(b_node);
AnisotropicBsdfNode *aniso = graph->create_node<AnisotropicBsdfNode>();
switch (b_aniso_node.distribution()) {
case BL::ShaderNodeBsdfAnisotropic::distribution_BECKMANN:
aniso->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
break;
case BL::ShaderNodeBsdfAnisotropic::distribution_GGX:
aniso->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_ID);
break;
case BL::ShaderNodeBsdfAnisotropic::distribution_MULTI_GGX:
aniso->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
break;
case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY:
aniso->set_distribution(CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
break;
}
node = aniso;
}
else if (b_node.is_a(&RNA_ShaderNodeBsdfDiffuse)) {
node = graph->create_node<DiffuseBsdfNode>();
}
@ -566,24 +545,21 @@ static ShaderNode *add_node(Scene *scene,
node = subsurface;
}
else if (b_node.is_a(&RNA_ShaderNodeBsdfGlossy)) {
BL::ShaderNodeBsdfGlossy b_glossy_node(b_node);
else if (b_node.is_a(&RNA_ShaderNodeBsdfAnisotropic)) {
BL::ShaderNodeBsdfAnisotropic b_glossy_node(b_node);
GlossyBsdfNode *glossy = graph->create_node<GlossyBsdfNode>();
switch (b_glossy_node.distribution()) {
case BL::ShaderNodeBsdfGlossy::distribution_SHARP:
glossy->set_distribution(CLOSURE_BSDF_REFLECTION_ID);
break;
case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN:
case BL::ShaderNodeBsdfAnisotropic::distribution_BECKMANN:
glossy->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
break;
case BL::ShaderNodeBsdfGlossy::distribution_GGX:
case BL::ShaderNodeBsdfAnisotropic::distribution_GGX:
glossy->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_ID);
break;
case BL::ShaderNodeBsdfGlossy::distribution_ASHIKHMIN_SHIRLEY:
case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY:
glossy->set_distribution(CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
break;
case BL::ShaderNodeBsdfGlossy::distribution_MULTI_GGX:
case BL::ShaderNodeBsdfAnisotropic::distribution_MULTI_GGX:
glossy->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
break;
}
@ -593,9 +569,6 @@ static ShaderNode *add_node(Scene *scene,
BL::ShaderNodeBsdfGlass b_glass_node(b_node);
GlassBsdfNode *glass = graph->create_node<GlassBsdfNode>();
switch (b_glass_node.distribution()) {
case BL::ShaderNodeBsdfGlass::distribution_SHARP:
glass->set_distribution(CLOSURE_BSDF_SHARP_GLASS_ID);
break;
case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
glass->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID);
break;
@ -612,9 +585,6 @@ static ShaderNode *add_node(Scene *scene,
BL::ShaderNodeBsdfRefraction b_refraction_node(b_node);
RefractionBsdfNode *refraction = graph->create_node<RefractionBsdfNode>();
switch (b_refraction_node.distribution()) {
case BL::ShaderNodeBsdfRefraction::distribution_SHARP:
refraction->set_distribution(CLOSURE_BSDF_REFRACTION_ID);
break;
case BL::ShaderNodeBsdfRefraction::distribution_BECKMANN:
refraction->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID);
break;

View File

@ -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);

View File

@ -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 &params,
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 &params,
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:

View File

@ -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) {

View File

@ -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 &&

View File

@ -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) */

View File

@ -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));
}
};

View File

@ -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. */

View File

@ -463,7 +463,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,
@ -520,7 +520,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,

View File

@ -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;
@ -198,7 +198,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)) ==

View File

@ -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,

View File

@ -26,6 +26,7 @@ CCL_NAMESPACE_BEGIN
ccl_device int shadow_linking_pick_mesh_intersection(KernelGlobals kg,
IntegratorState state,
ccl_private Ray *ccl_restrict ray,
const int object_receiver,
ccl_private Intersection *ccl_restrict
linked_isect,
ccl_private uint *lcg_state,
@ -47,13 +48,22 @@ ccl_device int shadow_linking_pick_mesh_intersection(KernelGlobals kg,
break;
}
const uint64_t set_membership =
kernel_data_fetch(objects, current_isect.object).shadow_set_membership;
if (set_membership != LIGHT_LINK_MASK_ALL) {
++num_hits;
/* Only record primitives that potentially have emission.
* TODO: optimize with a dedicated ray visiblity flag, which could then also be
* used once lights are in the BVH as geometry? */
const int shader = intersection_get_shader(kg, &current_isect);
const int shader_flags = kernel_data_fetch(shaders, shader).flags;
if (light_link_object_match(kg, object_receiver, current_isect.object) &&
(shader_flags & SD_HAS_EMISSION))
{
const uint64_t set_membership =
kernel_data_fetch(objects, current_isect.object).shadow_set_membership;
if (set_membership != LIGHT_LINK_MASK_ALL) {
++num_hits;
if ((linked_isect->prim == PRIM_NONE) && (lcg_step_float(lcg_state) < 1.0f / num_hits)) {
*linked_isect = current_isect;
if ((linked_isect->prim == PRIM_NONE) && (lcg_step_float(lcg_state) < 1.0f / num_hits)) {
*linked_isect = current_isect;
}
}
}
@ -86,10 +96,12 @@ ccl_device bool shadow_linking_pick_light_intersection(KernelGlobals kg,
ccl_private Intersection *ccl_restrict
linked_isect)
{
uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
const int last_type = INTEGRATOR_STATE(state, isect, type);
const int object_receiver = light_link_receiver_forward(kg, state);
uint lcg_state = lcg_state_init(INTEGRATOR_STATE(state, path, rng_hash),
INTEGRATOR_STATE(state, path, rng_offset),
INTEGRATOR_STATE(state, path, sample),
@ -106,9 +118,8 @@ ccl_device bool shadow_linking_pick_light_intersection(KernelGlobals kg,
// tracing potentially expensive ray.
num_hits = shadow_linking_pick_mesh_intersection(
kg, state, ray, linked_isect, &lcg_state, num_hits);
kg, state, ray, object_receiver, linked_isect, &lcg_state, num_hits);
const int receiver_forward = light_link_receiver_forward(kg, state);
num_hits = lights_intersect_shadow_linked(kg,
ray,
linked_isect,
@ -116,7 +127,7 @@ ccl_device bool shadow_linking_pick_light_intersection(KernelGlobals kg,
ray->self.object,
last_type,
path_flag,
receiver_forward,
object_receiver,
&lcg_state,
num_hits);

View File

@ -413,6 +413,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) {
@ -424,9 +425,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;
@ -451,7 +454,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;
}
@ -486,7 +489,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));

View File

@ -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 = LABEL_NONE;
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

View File

@ -6,7 +6,6 @@
set(SRC_OSL
node_add_closure.osl
node_ambient_occlusion.osl
node_anisotropic_bsdf.osl
node_attribute.osl
node_background.osl
node_bevel.osl

View File

@ -1,45 +0,0 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include "stdcycles.h"
shader node_anisotropic_bsdf(color Color = 0.0,
string distribution = "GGX",
float Roughness = 0.0,
float Anisotropy = 0.0,
float Rotation = 0.0,
normal Normal = N,
normal Tangent = normalize(dPdu),
output closure color BSDF = 0)
{
/* rotate tangent around normal */
vector T = Tangent;
if (Rotation != 0.0)
T = rotate(T, Rotation * M_2PI, point(0.0, 0.0, 0.0), Normal);
/* compute roughness */
float roughness = Roughness * Roughness;
float roughness_u, roughness_v;
float aniso = clamp(Anisotropy, -0.99, 0.99);
if (aniso < 0.0) {
roughness_u = roughness / (1.0 + aniso);
roughness_v = roughness * (1.0 + aniso);
}
else {
roughness_u = roughness * (1.0 - aniso);
roughness_v = roughness / (1.0 - aniso);
}
if (distribution == "sharp")
BSDF = Color * reflection(Normal);
else if (distribution == "beckmann")
BSDF = Color * microfacet_beckmann_aniso(Normal, T, roughness_u, roughness_v);
else if (distribution == "GGX")
BSDF = Color * microfacet_ggx_aniso(Normal, T, roughness_u, roughness_v);
else if (distribution == "Multiscatter GGX")
BSDF = Color * microfacet_multi_ggx_aniso(Normal, T, roughness_u, roughness_v, Color);
else
BSDF = Color * ashikhmin_shirley(Normal, T, roughness_u, roughness_v);
}

View File

@ -7,13 +7,40 @@
shader node_glossy_bsdf(color Color = 0.8,
string distribution = "ggx",
float Roughness = 0.2,
float Anisotropy = 0.0,
float Rotation = 0.0,
normal Normal = N,
normal Tangent = 0.0,
output closure color BSDF = 0)
{
/* compute roughness */
float roughness = Roughness * Roughness;
float roughness_u, roughness_v;
float aniso = clamp(Anisotropy, -0.99, 0.99);
/* rotate tangent around normal */
vector T = Tangent;
if (abs(aniso) <= 1e-4) {
roughness_u = roughness;
roughness_v = roughness;
}
else {
if (Rotation != 0.0)
T = rotate(T, Rotation * M_2PI, point(0.0, 0.0, 0.0), Normal);
if (aniso < 0.0) {
roughness_u = roughness / (1.0 + aniso);
roughness_v = roughness * (1.0 + aniso);
}
else {
roughness_u = roughness * (1.0 - aniso);
roughness_v = roughness / (1.0 - aniso);
}
}
if (distribution == "Multiscatter GGX")
BSDF = Color * microfacet_multi_ggx(Normal, roughness, Color);
else
BSDF = Color * microfacet(distribution, Normal, roughness, 0.0, 0);
BSDF = Color * microfacet(distribution, Normal, T, roughness_u, roughness_v, 0.0, 0);
}

View File

@ -494,7 +494,10 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
bsdf->ior = 1.0f;
bsdf->fresnel = NULL;
if (data_node.y == SVM_STACK_INVALID) {
/* compute roughness */
float anisotropy = clamp(param2, -0.99f, 0.99f);
if (data_node.y == SVM_STACK_INVALID || fabsf(anisotropy) <= 1e-4f) {
/* Isotropic case. */
bsdf->T = zero_float3();
bsdf->alpha_x = roughness;
bsdf->alpha_y = roughness;
@ -507,8 +510,6 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
if (rotation != 0.0f)
bsdf->T = rotate_around_axis(bsdf->T, bsdf->N, rotation * M_2PI_F);
/* compute roughness */
float anisotropy = clamp(param2, -0.99f, 0.99f);
if (anisotropy < 0.0f) {
bsdf->alpha_x = roughness / (1.0f + anisotropy);
bsdf->alpha_y = roughness * (1.0f + anisotropy);

View File

@ -168,6 +168,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,
@ -513,6 +518,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 };
@ -1180,11 +1195,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. */

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -138,8 +138,8 @@ NODE_DEFINE(Light)
SOCKET_NODE(shader, "Shader", Shader::get_node_type());
SOCKET_STRING(lightgroup, "Light Group", ustring());
SOCKET_UINT64(light_set_membership, "Light Set Membership", 0);
SOCKET_UINT64(shadow_set_membership, "Shadow Set Membership", 0);
SOCKET_UINT64(light_set_membership, "Light Set Membership", LIGHT_LINK_MASK_ALL);
SOCKET_UINT64(shadow_set_membership, "Shadow Set Membership", LIGHT_LINK_MASK_ALL);
SOCKET_BOOLEAN(normalize, "Normalize", true);

View File

@ -101,9 +101,9 @@ NODE_DEFINE(Object)
SOCKET_STRING(lightgroup, "Light Group", ustring());
SOCKET_UINT(receiver_light_set, "Light Set Index", 0);
SOCKET_UINT64(light_set_membership, "Light Set Membership", 0);
SOCKET_UINT64(light_set_membership, "Light Set Membership", LIGHT_LINK_MASK_ALL);
SOCKET_UINT(blocker_shadow_set, "Shadow Set Index", 0);
SOCKET_UINT64(shadow_set_membership, "Shadow Set Membership", 0);
SOCKET_UINT64(shadow_set_membership, "Shadow Set Membership", LIGHT_LINK_MASK_ALL);
return type;
}

View File

@ -2335,68 +2335,6 @@ void BsdfNode::compile(OSLCompiler & /*compiler*/)
assert(0);
}
/* Anisotropic BSDF Closure */
NODE_DEFINE(AnisotropicBsdfNode)
{
NodeType *type = NodeType::add("anisotropic_bsdf", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
static NodeEnum distribution_enum;
distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID);
distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID);
SOCKET_IN_VECTOR(tangent, "Tangent", zero_float3(), SocketType::LINK_TANGENT);
SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.5f);
SOCKET_IN_FLOAT(rotation, "Rotation", 0.0f);
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
return type;
}
AnisotropicBsdfNode::AnisotropicBsdfNode() : BsdfNode(get_node_type())
{
closure = CLOSURE_BSDF_MICROFACET_GGX_ID;
}
void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if (shader->has_surface_link()) {
ShaderInput *tangent_in = input("Tangent");
if (!tangent_in->link)
attributes->add(ATTR_STD_GENERATED);
}
ShaderNode::attributes(shader, attributes);
}
void AnisotropicBsdfNode::compile(SVMCompiler &compiler)
{
closure = distribution;
if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID)
BsdfNode::compile(
compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), input("Color"));
else
BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"));
}
void AnisotropicBsdfNode::compile(OSLCompiler &compiler)
{
compiler.parameter(this, "distribution");
compiler.add(this, "node_anisotropic_bsdf");
}
/* Glossy BSDF Closure */
NODE_DEFINE(GlossyBsdfNode)
@ -2414,7 +2352,12 @@ NODE_DEFINE(GlossyBsdfNode)
distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID);
SOCKET_IN_VECTOR(tangent, "Tangent", zero_float3(), SocketType::LINK_TANGENT);
SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.0f);
SOCKET_IN_FLOAT(rotation, "Rotation", 0.0f);
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
@ -2427,8 +2370,32 @@ GlossyBsdfNode::GlossyBsdfNode() : BsdfNode(get_node_type())
distribution_orig = NBUILTIN_CLOSURES;
}
bool GlossyBsdfNode::is_isotropic()
{
ShaderInput *anisotropy_input = input("Anisotropy");
/* Keep in sync with the thresholds in OSL's node_glossy_bsdf and SVM's svm_node_closure_bsdf. */
return (!anisotropy_input->link && fabsf(anisotropy) <= 1e-4f);
}
void GlossyBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if (shader->has_surface_link()) {
ShaderInput *tangent_in = input("Tangent");
if (!tangent_in->link && !is_isotropic())
attributes->add(ATTR_STD_GENERATED);
}
ShaderNode::attributes(shader, attributes);
}
void GlossyBsdfNode::simplify_settings(Scene *scene)
{
/* If the anisotropy is close enough to zero, fall back to the isotropic case. */
ShaderInput *tangent_input = input("Tangent");
if (tangent_input->link && is_isotropic()) {
tangent_input->disconnect();
}
if (distribution_orig == NBUILTIN_CLOSURES) {
roughness_orig = roughness;
distribution_orig = distribution;
@ -2478,9 +2445,10 @@ void GlossyBsdfNode::compile(SVMCompiler &compiler)
if (closure == CLOSURE_BSDF_REFLECTION_ID)
BsdfNode::compile(compiler, NULL, NULL);
else if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID)
BsdfNode::compile(compiler, input("Roughness"), NULL, NULL, input("Color"));
BsdfNode::compile(
compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), input("Color"));
else
BsdfNode::compile(compiler, input("Roughness"), NULL);
BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"));
}
void GlossyBsdfNode::compile(OSLCompiler &compiler)

View File

@ -495,27 +495,6 @@ class BsdfNode : public BsdfBaseNode {
NODE_SOCKET_API(float, surface_mix_weight)
};
class AnisotropicBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(AnisotropicBsdfNode)
NODE_SOCKET_API(float3, tangent)
NODE_SOCKET_API(float, roughness)
NODE_SOCKET_API(float, anisotropy)
NODE_SOCKET_API(float, rotation)
NODE_SOCKET_API(ClosureType, distribution)
ClosureType get_closure_type()
{
return distribution;
}
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_attribute_dependency()
{
return true;
}
};
class DiffuseBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(DiffuseBsdfNode)
@ -624,12 +603,23 @@ class GlossyBsdfNode : public BsdfNode {
return distribution;
}
NODE_SOCKET_API(float3, tangent)
NODE_SOCKET_API(float, roughness)
NODE_SOCKET_API(float, anisotropy)
NODE_SOCKET_API(float, rotation)
NODE_SOCKET_API(ClosureType, distribution)
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_attribute_dependency()
{
return true;
}
private:
float roughness_orig;
ClosureType distribution_orig;
bool is_isotropic();
};
class GlassBsdfNode : public BsdfNode {

View File

@ -567,29 +567,15 @@ ccl_device_inline float triangle_area(ccl_private const float3 &v1,
/* Orthonormal vectors */
ccl_device_inline void make_orthonormals(const float3 N,
ccl_private float3 *a,
ccl_private float3 *b)
ccl_private float3 *T,
ccl_private float3 *B)
{
#if 0
if (fabsf(N.y) >= 0.999f) {
*a = make_float3(1, 0, 0);
*b = make_float3(0, 0, 1);
return;
}
if (fabsf(N.z) >= 0.999f) {
*a = make_float3(1, 0, 0);
*b = make_float3(0, 1, 0);
return;
}
#endif
if (N.x != N.y || N.x != N.z)
*a = make_float3(N.z - N.y, N.x - N.z, N.y - N.x); //(1,1,1)x N
else
*a = make_float3(N.z - N.y, N.x + N.z, -N.y - N.x); //(-1,1,1)x N
*a = normalize(*a);
*b = cross(N, *a);
/* Duff, Tom, et al. "Building an orthonormal basis, revisited." JCGT 6.1 (2017). */
float sign = signf(N.z);
float a = -1.0f / (sign + N.z);
float b = N.x * N.y * a;
*T = make_float3(1.0f + sign * N.x * N.x * a, sign * b, -sign * N.x);
*B = make_float3(b, sign + N.y * N.y * a, -N.y);
}
/* Color division */

View File

@ -1261,7 +1261,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
![bitmapImage isPlanar])
{
/* Try a fast copy if the image is a meshed RGBA 32bit bitmap. */
toIBuf = (uint8_t *)ibuf->rect;
toIBuf = ibuf->byte_buffer.data;
rasterRGB = (uint8_t *)[bitmapImage bitmapData];
for (y = 0; y < imgSize.height; y++) {
to_i = (imgSize.height - y - 1) * imgSize.width;
@ -1338,7 +1338,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
}
/* Copy the image to ibuf, flipping it vertically. */
toIBuf = (uint8_t *)ibuf->rect;
toIBuf = ibuf->byte_buffer.data;
for (y = 0; y < imgSize.height; y++) {
for (x = 0; x < imgSize.width; x++) {
to_i = (imgSize.height - y - 1) * imgSize.width + x;

View File

@ -173,7 +173,7 @@ static bool use_gnome_confine_hack = false;
* This is a hack because it seems there is no way to check if the compositor supports
* server side decorations when initializing WAYLAND.
*/
#if defined(WITH_GHOST_WAYLAND_LIBDECOR) && defined(WITH_GHOST_X11)
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
# define USE_GNOME_NEEDS_LIBDECOR_HACK
#endif
@ -1002,6 +1002,10 @@ static void gwl_display_destroy(GWL_Display *display)
delete display->ghost_timer_manager;
display->ghost_timer_manager = nullptr;
}
/* Pending events may be left unhandled. */
for (GHOST_IEvent *event : display->events_pending) {
delete event;
}
#endif /* USE_EVENT_BACKGROUND_THREAD */
@ -1333,6 +1337,22 @@ static void ghost_wayland_log_handler(const char *msg, va_list arg)
}
}
#ifdef WITH_GHOST_X11
/**
* Check if the system is running X11.
* This is not intended to be a fool-proof check (the `DISPLAY` is not validated for e.g.).
* Just check `DISPLAY` is set and not-empty.
*/
static bool ghost_wayland_is_x11_available()
{
const char *x11_display = getenv("DISPLAY");
if (x11_display && x11_display[0]) {
return true;
}
return false;
}
#endif /* WITH_GHOST_X11 */
static GHOST_TKey xkb_map_gkey(const xkb_keysym_t sym)
{
@ -2288,7 +2308,7 @@ static void data_device_handle_enter(void *data,
const wl_fixed_t y,
struct wl_data_offer *id)
{
if (!ghost_wl_surface_own(wl_surface)) {
if (!ghost_wl_surface_own_with_null_check(wl_surface)) {
CLOG_INFO(LOG, 2, "enter (skipped)");
return;
}
@ -2623,7 +2643,8 @@ static void pointer_handle_enter(void *data,
const wl_fixed_t surface_x,
const wl_fixed_t surface_y)
{
if (!ghost_wl_surface_own(wl_surface)) {
/* Null when just destroyed. */
if (!ghost_wl_surface_own_with_null_check(wl_surface)) {
CLOG_INFO(LOG, 2, "enter (skipped)");
return;
}
@ -2662,12 +2683,11 @@ static void pointer_handle_leave(void *data,
{
/* First clear the `pointer.wl_surface`, since the window won't exist when closing the window. */
static_cast<GWL_Seat *>(data)->pointer.wl_surface_window = nullptr;
if (wl_surface && ghost_wl_surface_own(wl_surface)) {
CLOG_INFO(LOG, 2, "leave");
}
else {
if (!ghost_wl_surface_own_with_null_check(wl_surface)) {
CLOG_INFO(LOG, 2, "leave (skipped)");
return;
}
CLOG_INFO(LOG, 2, "leave");
}
static void pointer_handle_motion(void *data,
@ -3304,7 +3324,7 @@ static void tablet_tool_handle_proximity_in(void *data,
struct zwp_tablet_v2 * /*tablet*/,
struct wl_surface *wl_surface)
{
if (!ghost_wl_surface_own(wl_surface)) {
if (!ghost_wl_surface_own_with_null_check(wl_surface)) {
CLOG_INFO(LOG, 2, "proximity_in (skipped)");
return;
}
@ -3723,7 +3743,8 @@ static void keyboard_handle_enter(void *data,
struct wl_surface *wl_surface,
struct wl_array *keys)
{
if (!ghost_wl_surface_own(wl_surface)) {
/* Null when just destroyed. */
if (!ghost_wl_surface_own_with_null_check(wl_surface)) {
CLOG_INFO(LOG, 2, "enter (skipped)");
return;
}
@ -3765,7 +3786,7 @@ static void keyboard_handle_leave(void *data,
const uint32_t /*serial*/,
struct wl_surface *wl_surface)
{
if (!(wl_surface && ghost_wl_surface_own(wl_surface))) {
if (!ghost_wl_surface_own_with_null_check(wl_surface)) {
CLOG_INFO(LOG, 2, "leave (skipped)");
return;
}
@ -5449,6 +5470,13 @@ static void *gwl_display_event_thread_fn(void *display_voidp)
break;
}
}
/* Wait until the main thread cancels this thread, otherwise this thread may exit
* before cancel is called, causing a crash on exit. */
while (true) {
pause();
}
return nullptr;
}
@ -5517,12 +5545,21 @@ GHOST_SystemWayland::GHOST_SystemWayland(bool background)
}
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
/* Ignore windowing requirements when running in background mode,
* as it doesn't make sense to fall back to X11 because of windowing functionality
* in background mode, also LIBDECOR is crashing in background mode `blender -b -f 1`
* for e.g. while it could be fixed, requiring the library at all makes no sense . */
if (background) {
display_->libdecor_required = false;
if (display_->libdecor_required) {
/* Ignore windowing requirements when running in background mode,
* as it doesn't make sense to fall back to X11 because of windowing functionality
* in background mode, also LIBDECOR is crashing in background mode `blender -b -f 1`
* for e.g. while it could be fixed, requiring the library at all makes no sense . */
if (background) {
display_->libdecor_required = false;
}
# ifdef WITH_GHOST_X11
else if (!has_libdecor && !ghost_wayland_is_x11_available()) {
/* Only require LIBDECOR when X11 is available, otherwise there is nothing to fall back to.
* It's better to open without window decorations than failing entirely. */
display_->libdecor_required = false;
}
# endif /* WITH_GHOST_X11 */
}
if (display_->libdecor_required) {
@ -6833,6 +6870,11 @@ bool ghost_wl_surface_own(const struct wl_surface *wl_surface)
return wl_proxy_get_tag((struct wl_proxy *)wl_surface) == &ghost_wl_surface_tag_id;
}
bool ghost_wl_surface_own_with_null_check(const struct wl_surface *wl_surface)
{
return wl_surface && ghost_wl_surface_own(wl_surface);
}
bool ghost_wl_surface_own_cursor_pointer(const struct wl_surface *wl_surface)
{
return wl_proxy_get_tag((struct wl_proxy *)wl_surface) ==

View File

@ -37,6 +37,14 @@ bool ghost_wl_output_own(const struct wl_output *wl_output);
void ghost_wl_output_tag(struct wl_output *wl_output);
struct GWL_Output *ghost_wl_output_user_data(struct wl_output *wl_output);
/**
* Enter/exit handlers may be called with a null window surface (when the window just closed),
* so add a version of the function that checks this.
*
* All of the functions could in fact however paranoid null checks make the expected
* state difficult to reason about, so only use this in cases the surface may be null.
*/
bool ghost_wl_surface_own_with_null_check(const struct wl_surface *wl_surface);
bool ghost_wl_surface_own(const struct wl_surface *wl_surface);
void ghost_wl_surface_tag(struct wl_surface *wl_surface);
GHOST_WindowWayland *ghost_wl_surface_user_data(struct wl_surface *wl_surface);

View File

@ -2422,7 +2422,7 @@ static uint *getClipboardImageImBuf(int *r_width, int *r_height, UINT format)
*r_width = ibuf->x;
*r_height = ibuf->y;
rgba = (uint *)malloc(4 * ibuf->x * ibuf->y);
memcpy(rgba, ibuf->rect, 4 * ibuf->x * ibuf->y);
memcpy(rgba, ibuf->byte_buffer.data, 4 * ibuf->x * ibuf->y);
IMB_freeImBuf(ibuf);
}
@ -2513,7 +2513,7 @@ static bool putClipboardImagePNG(uint *rgba, int width, int height)
UINT cf = RegisterClipboardFormat("PNG");
/* Load buffer into ImBuf, convert to PNG. */
ImBuf *ibuf = IMB_allocFromBuffer(rgba, nullptr, width, height, 32);
ImBuf *ibuf = IMB_allocFromBuffer(reinterpret_cast<uint8_t *>(rgba), nullptr, width, height, 32);
ibuf->ftype = IMB_FTYPE_PNG;
ibuf->foptions.quality = 15;
if (!IMB_saveiff(ibuf, "<memory>", IB_rect | IB_mem)) {
@ -2521,7 +2521,7 @@ static bool putClipboardImagePNG(uint *rgba, int width, int height)
return false;
}
HGLOBAL hMem = GlobalAlloc(GHND, ibuf->encodedbuffersize);
HGLOBAL hMem = GlobalAlloc(GHND, ibuf->encoded_buffer_size);
if (!hMem) {
IMB_freeImBuf(ibuf);
return false;
@ -2534,7 +2534,7 @@ static bool putClipboardImagePNG(uint *rgba, int width, int height)
return false;
}
memcpy(pMem, ibuf->encodedbuffer, ibuf->encodedbuffersize);
memcpy(pMem, ibuf->encoded_buffer.data, ibuf->encoded_buffer_size);
GlobalUnlock(hMem);
IMB_freeImBuf(ibuf);

View File

@ -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 = {

View File

@ -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

View File

@ -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

View File

@ -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,
),
)

View File

@ -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),
@ -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),
])

View File

@ -496,16 +496,6 @@ class DATA_PT_customdata(MeshButtonsPanel, Panel):
else:
col.operator("mesh.customdata_custom_splitnormals_add", icon='ADD')
if me.has_bevel_weight_edge:
col.operator("mesh.customdata_bevel_weight_edge_clear", icon='X')
else:
col.operator("mesh.customdata_bevel_weight_edge_add", icon='ADD')
if me.has_bevel_weight_vertex:
col.operator("mesh.customdata_bevel_weight_vertex_clear", icon='X')
else:
col.operator("mesh.customdata_bevel_weight_vertex_add", icon='ADD')
if me.has_crease_edge:
col.operator("mesh.customdata_crease_edge_clear", icon='X')
else:

View File

@ -434,6 +434,7 @@ class SEQUENCER_MT_view(Menu):
if is_sequencer_view:
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator("sequencer.view_all")
layout.operator("sequencer.view_frame")
layout.operator("view2d.zoom_border", text="Zoom")
layout.prop(st, "use_clamp_view")

View File

@ -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")

View File

@ -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()

View File

@ -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,

View File

@ -191,7 +191,6 @@ shader_node_categories = [
NodeItem("ShaderNodeBsdfRefraction", poll=object_eevee_cycles_shader_nodes_poll),
NodeItem("ShaderNodeBsdfGlass", poll=object_eevee_cycles_shader_nodes_poll),
NodeItem("ShaderNodeBsdfTranslucent", poll=object_eevee_cycles_shader_nodes_poll),
NodeItem("ShaderNodeBsdfAnisotropic", poll=object_cycles_shader_nodes_poll),
NodeItem("ShaderNodeBsdfVelvet", poll=object_cycles_shader_nodes_poll),
NodeItem("ShaderNodeBsdfToon", poll=object_cycles_shader_nodes_poll),
NodeItem("ShaderNodeSubsurfaceScattering", poll=object_eevee_cycles_shader_nodes_poll),

View File

@ -25,13 +25,13 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 0
#define BLENDER_FILE_SUBVERSION 2
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
* was written with too new a version. */
#define BLENDER_FILE_MIN_VERSION 305
#define BLENDER_FILE_MIN_SUBVERSION 9
#define BLENDER_FILE_MIN_VERSION 400
#define BLENDER_FILE_MIN_SUBVERSION 2
/** User readable version string. */
const char *BKE_blender_version_string(void);

View File

@ -314,6 +314,9 @@ void CustomData_free_layers(struct CustomData *data, eCustomDataType type, int t
* Returns true if a layer with the specified type exists.
*/
bool CustomData_has_layer(const struct CustomData *data, eCustomDataType type);
bool CustomData_has_layer_named(const struct CustomData *data,
eCustomDataType type,
const char *name);
/**
* Returns the number of layers with this type.
@ -700,6 +703,8 @@ enum {
CD_CUSTOMLOOPNORMAL, /* Because we play with clnor and temp lnor layers here. */
CD_FAKE_SHARP = CD_FAKE | 200, /* Sharp flag for edges, smooth flag for faces. */
CD_FAKE_BWEIGHT = CD_FAKE | 300, /* UV seam flag for edges. */
};
enum {

View File

@ -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);

View File

@ -2,8 +2,6 @@
#pragma once
#include "BLI_math_matrix_types.hh"
#include "BKE_geometry_set.hh"
namespace blender::bke {
@ -13,36 +11,4 @@ namespace blender::bke {
*/
GeometrySet object_get_evaluated_geometry_set(const Object &object);
/**
* Used to keep track of a group of instances using the same geometry data.
*/
struct GeometryInstanceGroup {
/**
* The geometry set instanced on each of the transforms. The components are not necessarily
* owned here. For example, they may be owned by the instanced object. This cannot be a
* reference because not all instanced data will necessarily have a #geometry_set_eval.
*/
GeometrySet geometry_set;
/**
* As an optimization to avoid copying, the same geometry set can be associated with multiple
* instances. Each instance is stored as a transform matrix here. Again, these must be owned
* because they may be transformed from the original data. TODO: Validate that last statement.
*/
Vector<float4x4> transforms;
};
/**
* Return flattened vector of the geometry component's recursive instances. I.e. all collection
* instances and object instances will be expanded into the instances of their geometry components.
* Even the instances in those geometry components' will be included.
*
* \note For convenience (to avoid duplication in the caller), the returned vector also contains
* the argument geometry set.
*
* \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
*/
void geometry_set_gather_instances(const GeometrySet &geometry_set,
Vector<GeometryInstanceGroup> &r_instance_groups);
} // namespace blender::bke

View File

@ -57,13 +57,14 @@ template<typename T, int Channels = 4> struct ImageBufferAccessor {
{
if constexpr ((std::is_same_v<T, float4>)) {
int offset = (coordinate.y * image_buffer.x + coordinate.x) * Channels;
return float4(&image_buffer.rect_float[offset]);
return float4(&image_buffer.float_buffer.data[offset]);
}
if constexpr ((std::is_same_v<T, int>)) {
int offset = (coordinate.y * image_buffer.x + coordinate.x);
float4 result;
rgba_uchar_to_float(result,
static_cast<uchar *>(static_cast<void *>(&image_buffer.rect[offset])));
rgba_uchar_to_float(
result,
static_cast<uchar *>(static_cast<void *>(&image_buffer.byte_buffer.data[offset])));
return result;
}
return float4();
@ -73,12 +74,13 @@ template<typename T, int Channels = 4> struct ImageBufferAccessor {
{
if constexpr ((std::is_same_v<T, float>)) {
int offset = (coordinate.y * image_buffer.x + coordinate.x) * Channels;
copy_v4_v4(&image_buffer.rect_float[offset], new_value);
copy_v4_v4(&image_buffer.float_buffer.data[offset], new_value);
}
if constexpr ((std::is_same_v<T, int>)) {
int offset = (coordinate.y * image_buffer.x + coordinate.x);
rgba_float_to_uchar(static_cast<uchar *>(static_cast<void *>(&image_buffer.rect[offset])),
new_value);
rgba_float_to_uchar(
static_cast<uchar *>(static_cast<void *>(&image_buffer.byte_buffer.data[offset])),
new_value);
}
}
};

View File

@ -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);
/**

View File

@ -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).

View File

@ -28,10 +28,8 @@ typedef enum LightLinkingType {
LIGHT_LINKING_BLOCKER,
} LightLinkingType;
/* Get pointer or a collection of the given light linking type i=if the given object. */
struct Collection **BKE_light_linking_collection_ptr_get(struct Object *object,
LightLinkingType link_type);
struct Collection *BKE_light_linking_collection_get(struct Object *object,
/* Get a collection of the given light linking type of the given object. */
struct Collection *BKE_light_linking_collection_get(const struct Object *object,
LightLinkingType link_type);
/* Create new collection and assign it as a light or shadow linking collection (denoted by the

View File

@ -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.
*/

View File

@ -30,107 +30,55 @@ void BKE_mesh_legacy_convert_uvs_to_struct(
blender::Vector<CustomDataLayer, 16> &loop_layers_to_write);
void BKE_mesh_legacy_convert_uvs_to_generic(Mesh *mesh);
/**
* Move face sets to the legacy type from a generic type.
*/
void BKE_mesh_legacy_face_set_from_generic(
blender::MutableSpan<CustomDataLayer> poly_layers_to_write);
/**
* Copy face sets to the generic data type from the legacy type.
*/
void BKE_mesh_legacy_face_set_to_generic(struct Mesh *mesh);
/**
* Copy edge creases from a separate layer into edges.
*/
void BKE_mesh_legacy_edge_crease_from_layers(struct Mesh *mesh);
/**
* Copy edge creases from edges to a separate layer.
*/
void BKE_mesh_legacy_edge_crease_to_layers(struct Mesh *mesh);
/**
* Copy bevel weights from separate layers into vertices and edges.
*/
void BKE_mesh_legacy_bevel_weight_from_layers(struct Mesh *mesh);
/**
* Copy bevel weights from vertices and edges to separate layers.
*/
void BKE_mesh_legacy_bevel_weight_to_layers(struct Mesh *mesh);
/**
* Convert the hidden element attributes to the old flag format for writing.
* Move bevel weight to generic float attribute type.
*/
void BKE_mesh_legacy_convert_hide_layers_to_flags(struct Mesh *mesh,
blender::MutableSpan<MPoly> legacy_polys);
void BKE_mesh_legacy_bevel_weight_to_generic(struct Mesh *mesh);
/**
* Convert the old hide flags (#ME_HIDE) to the hidden element attribute for reading.
* Only add the attributes when there are any elements in each domain hidden.
*/
void BKE_mesh_legacy_convert_flags_to_hide_layers(struct Mesh *mesh);
/**
* Convert the selected element attributes to the old flag format for writing.
*/
void BKE_mesh_legacy_convert_selection_layers_to_flags(struct Mesh *mesh,
blender::MutableSpan<MPoly> legacy_polys);
/**
* Convert the old selection flags (#SELECT/#ME_FACE_SEL) to the selected element attribute for
* reading. Only add the attributes when there are any elements in each domain selected.
*/
void BKE_mesh_legacy_convert_flags_to_selection_layers(struct Mesh *mesh);
/**
* Move material indices from a generic attribute to #MPoly.
*/
void BKE_mesh_legacy_convert_material_indices_to_mpoly(struct Mesh *mesh,
blender::MutableSpan<MPoly> legacy_polys);
/**
* Move material indices from the #MPoly struct to a generic attributes.
* Only add the attribute when the indices are not all zero.
*/
void BKE_mesh_legacy_convert_mpoly_to_material_indices(struct Mesh *mesh);
/** Convert from runtime loose edge cache to legacy edge flag. */
void BKE_mesh_legacy_convert_loose_edges_to_flag(struct Mesh *mesh);
void BKE_mesh_legacy_attribute_flags_to_strings(struct Mesh *mesh);
void BKE_mesh_legacy_attribute_strings_to_flags(struct Mesh *mesh);
void BKE_mesh_legacy_sharp_faces_to_flags(struct Mesh *mesh,
blender::MutableSpan<MPoly> legacy_polys);
void BKE_mesh_legacy_sharp_faces_from_flags(struct Mesh *mesh);
void BKE_mesh_legacy_sharp_edges_to_flags(struct Mesh *mesh);
void BKE_mesh_legacy_sharp_edges_from_flags(struct Mesh *mesh);
void BKE_mesh_legacy_uv_seam_to_flags(struct Mesh *mesh);
void BKE_mesh_legacy_uv_seam_from_flags(struct Mesh *mesh);
struct MVert *BKE_mesh_legacy_convert_positions_to_verts(
Mesh *mesh,
blender::ResourceScope &temp_arrays_for_convert,
blender::Vector<CustomDataLayer, 16> &vert_layers_to_write);
void BKE_mesh_legacy_convert_verts_to_positions(Mesh *mesh);
MEdge *BKE_mesh_legacy_convert_edges_to_medge(
Mesh *mesh,
blender::ResourceScope &temp_arrays_for_convert,
blender::Vector<CustomDataLayer, 16> &edge_layers_to_write);
void BKE_mesh_legacy_convert_edges_to_generic(Mesh *mesh);
struct MLoop *BKE_mesh_legacy_convert_corners_to_loops(
Mesh *mesh,
blender::ResourceScope &temp_arrays_for_convert,
blender::Vector<CustomDataLayer, 16> &loop_layers_to_write);
blender::MutableSpan<MPoly> BKE_mesh_legacy_convert_offsets_to_polys(
const Mesh *mesh,
blender::ResourceScope &temp_arrays_for_convert,
blender::Vector<CustomDataLayer, 16> &poly_layers_to_write);
void BKE_mesh_legacy_convert_polys_to_offsets(Mesh *mesh);
void BKE_mesh_legacy_convert_loops_to_corners(struct Mesh *mesh);

View File

@ -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,

View File

@ -35,6 +35,14 @@ void sample_point_attribute(Span<int> corner_verts,
IndexMask mask,
GMutableSpan dst);
void sample_point_normals(Span<int> corner_verts,
Span<MLoopTri> looptris,
Span<int> looptri_indices,
Span<float3> bary_coords,
Span<float3> src,
IndexMask mask,
MutableSpan<float3> dst);
void sample_corner_attribute(Span<MLoopTri> looptris,
Span<int> looptri_indices,
Span<float3> bary_coords,

View File

@ -554,8 +554,10 @@ struct bNodeSocket *ntreeAddSocketInterface(struct bNodeTree *ntree,
* \{ */
struct bNodeType *nodeTypeFind(const char *idname);
const char *nodeTypeFindAlias(const char *idname);
void nodeRegisterType(struct bNodeType *ntype);
void nodeUnregisterType(struct bNodeType *ntype);
void nodeRegisterAlias(struct bNodeType *nt, const char *alias);
struct GHashIterator *nodeTypeGetIterator(void);
/* Helper macros for iterating over node types. */
@ -893,9 +895,9 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define SH_NODE_MIX_SHADER 128
#define SH_NODE_ATTRIBUTE 129
#define SH_NODE_BACKGROUND 130
#define SH_NODE_BSDF_ANISOTROPIC 131
#define SH_NODE_BSDF_GLOSSY 131
#define SH_NODE_BSDF_DIFFUSE 132
#define SH_NODE_BSDF_GLOSSY 133
#define SH_NODE_BSDF_GLOSSY_LEGACY 133
#define SH_NODE_BSDF_GLASS 134
#define SH_NODE_BSDF_TRANSLUCENT 137
#define SH_NODE_BSDF_TRANSPARENT 138

View File

@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2005 Blender Foundation */
* Copyright 2023 Blender Foundation */
#pragma once

View File

@ -346,7 +346,7 @@ struct CopyPixelTile {
void copy_pixels(ImBuf &tile_buffer, IndexRange group_range) const
{
if (tile_buffer.rect_float) {
if (tile_buffer.float_buffer.data) {
image::ImageBufferAccessor<float4> accessor(tile_buffer);
copy_pixels<float4>(accessor, group_range);
}

View File

@ -94,6 +94,9 @@ void txt_sel_clear(struct Text *text);
void txt_sel_line(struct Text *text);
void txt_sel_set(struct Text *text, int startl, int startc, int endl, int endc);
char *txt_sel_to_buf(const struct Text *text, size_t *r_buf_strlen);
/**
* \param in_buffer: UTF8 encoded text, invalid UTF8 byte-sequences are handled gracefully.
*/
void txt_insert_buf(struct Text *text, const char *in_buffer, int in_buffer_len)
ATTR_NONNULL(1, 2);
void txt_split_curline(struct Text *text);

View File

@ -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);

View File

@ -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);
}

View File

@ -446,7 +446,7 @@ bool BuiltinCustomDataLayerProvider::try_create(void *owner,
const int element_num = custom_data_access_.get_element_num(owner);
if (stored_as_named_attribute_) {
if (CustomData_get_layer_named(custom_data, data_type_, name_.c_str())) {
if (CustomData_has_layer_named(custom_data, data_type_, name_.c_str())) {
/* Exists already. */
return false;
}
@ -469,7 +469,7 @@ bool BuiltinCustomDataLayerProvider::exists(const void *owner) const
return false;
}
if (stored_as_named_attribute_) {
return CustomData_get_layer_named(custom_data, stored_type_, name_.c_str()) != nullptr;
return CustomData_has_layer_named(custom_data, stored_type_, name_.c_str());
}
return CustomData_get_layer(custom_data, stored_type_) != nullptr;
}

View File

@ -2624,18 +2624,22 @@ struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary, bool
int half = side / 2;
BKE_curvemapping_init(br->curve);
im->rect_float = (float *)MEM_callocN(sizeof(float) * side * side, "radial control rect");
float *rect_float = (float *)MEM_callocN(sizeof(float) * side * side, "radial control rect");
IMB_assign_float_buffer(im, rect_float, IB_DO_NOT_TAKE_OWNERSHIP);
im->x = im->y = side;
const bool have_texture = brush_gen_texture(br, side, secondary, im->rect_float);
const bool have_texture = brush_gen_texture(br, side, secondary, im->float_buffer.data);
if (display_gradient || have_texture) {
for (int i = 0; i < side; i++) {
for (int j = 0; j < side; j++) {
const float magn = sqrtf(pow2f(i - half) + pow2f(j - half));
const float strength = BKE_brush_curve_strength_clamped(br, magn, half);
im->rect_float[i * side + j] = (have_texture) ? im->rect_float[i * side + j] * strength :
strength;
im->float_buffer.data[i * side + j] = (have_texture) ?
im->float_buffer.data[i * side + j] * strength :
strength;
}
}
}

View File

@ -1382,11 +1382,11 @@ void BKE_histogram_update_sample_line(Histogram *hist,
hist->xmax = 1.0f;
/* hist->ymax = 1.0f; */ /* now do this on the operator _only_ */
if (ibuf->rect == NULL && ibuf->rect_float == NULL) {
if (ibuf->byte_buffer.data == NULL && ibuf->float_buffer.data == NULL) {
return;
}
if (ibuf->rect_float) {
if (ibuf->float_buffer.data) {
cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
}
@ -1399,9 +1399,9 @@ void BKE_histogram_update_sample_line(Histogram *hist,
0.0f;
}
else {
if (ibuf->rect_float) {
if (ibuf->float_buffer.data) {
float rgba[4];
fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
fp = (ibuf->float_buffer.data + (ibuf->channels) * (y * ibuf->x + x));
switch (ibuf->channels) {
case 4:
@ -1431,8 +1431,8 @@ void BKE_histogram_update_sample_line(Histogram *hist,
hist->data_b[i] = rgba[2];
hist->data_a[i] = rgba[3];
}
else if (ibuf->rect) {
cp = (uchar *)(ibuf->rect + y * ibuf->x + x);
else if (ibuf->byte_buffer.data) {
cp = ibuf->byte_buffer.data + 4 * (y * ibuf->x + x);
hist->data_luma[i] = (float)IMB_colormanagement_get_luminance_byte(cp) / 255.0f;
hist->data_r[i] = (float)cp[0] / 255.0f;
hist->data_g[i] = (float)cp[1] / 255.0f;
@ -1492,10 +1492,10 @@ static void scopes_update_cb(void *__restrict userdata,
const int savedlines = y / rows_per_sample_line;
const bool do_sample_line = (savedlines < scopes->sample_lines) &&
(y % rows_per_sample_line) == 0;
const bool is_float = (ibuf->rect_float != NULL);
const bool is_float = (ibuf->float_buffer.data != NULL);
if (is_float) {
rf = ibuf->rect_float + ((size_t)y) * ibuf->x * ibuf->channels;
rf = ibuf->float_buffer.data + ((size_t)y) * ibuf->x * ibuf->channels;
}
else {
rc = display_buffer + ((size_t)y) * ibuf->x * ibuf->channels;
@ -1616,7 +1616,7 @@ void BKE_scopes_update(Scopes *scopes,
void *cache_handle = NULL;
struct ColormanageProcessor *cm_processor = NULL;
if (ibuf->rect == NULL && ibuf->rect_float == NULL) {
if (ibuf->byte_buffer.data == NULL && ibuf->float_buffer.data == NULL) {
return;
}
@ -1692,7 +1692,7 @@ void BKE_scopes_update(Scopes *scopes,
scopes->vecscope = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float),
"vectorscope point channel");
if (ibuf->rect_float) {
if (ibuf->float_buffer.data) {
cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
}
else {

View File

@ -770,7 +770,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
mesh->tag_loose_verts_none();
if (!offsets.any_single_point_profile) {
/* If there are no single point profiles, every combination will have faces. */
mesh->loose_edges_tag_none();
mesh->tag_loose_edges_none();
}
}

View File

@ -1167,29 +1167,6 @@ static void layerDefault_origindex(void *data, const int count)
copy_vn_i((int *)data, count, ORIGINDEX_NONE);
}
static void layerInterp_bweight(const void **sources,
const float *weights,
const float * /*sub_weights*/,
int count,
void *dest)
{
float **in = (float **)sources;
if (count <= 0) {
return;
}
float f = 0.0f;
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
f += *in[i] * interp_weight;
}
/* Delay writing to the destination in case dest is in sources. */
*((float *)dest) = f;
}
static void layerInterp_shapekey(const void **sources,
const float *weights,
const float * /*sub_weights*/,
@ -1786,8 +1763,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 28: CD_SHAPEKEY */
{sizeof(float[3]), "", 0, N_("ShapeKey"), nullptr, nullptr, layerInterp_shapekey},
/* 29: CD_BWEIGHT */
{sizeof(MFloatProperty), "MFloatProperty", 1, nullptr, nullptr, nullptr, layerInterp_bweight},
/* 29: CD_BWEIGHT */ /* DEPRECATED*/
{sizeof(MFloatProperty), "MFloatProperty", 1},
/* 30: CD_CREASE */
{sizeof(float), "", 0, nullptr, nullptr, nullptr, layerInterp_propFloat},
/* 31: CD_ORIGSPACE_MLOOP */
@ -2043,9 +2020,9 @@ const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX = {
};
const CustomData_MeshMasks CD_MASK_MESH = {
/*vmask*/ (CD_MASK_PROP_FLOAT3 | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN |
CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_CREASE | CD_MASK_BWEIGHT),
CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_CREASE),
/*emask*/
(CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL | CD_MASK_BWEIGHT | CD_MASK_CREASE),
(CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL | CD_MASK_CREASE),
/*fmask*/ 0,
/*pmask*/
(CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL),
@ -2055,10 +2032,9 @@ const CustomData_MeshMasks CD_MASK_MESH = {
const CustomData_MeshMasks CD_MASK_DERIVEDMESH = {
/*vmask*/ (CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | CD_MASK_SHAPEKEY | CD_MASK_MVERT_SKIN |
CD_MASK_PAINT_MASK | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_PROP_ALL |
CD_MASK_CREASE | CD_MASK_BWEIGHT),
CD_MASK_CREASE),
/*emask*/
(CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_BWEIGHT | CD_MASK_PROP_ALL |
CD_MASK_CREASE),
(CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL | CD_MASK_CREASE),
/*fmask*/ (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT),
/*pmask*/
(CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL),
@ -2067,9 +2043,9 @@ const CustomData_MeshMasks CD_MASK_DERIVEDMESH = {
CD_MASK_PROP_ALL), /* XXX: MISSING #CD_MASK_MLOOPTANGENT ? */
};
const CustomData_MeshMasks CD_MASK_BMESH = {
/*vmask*/ (CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
/*vmask*/ (CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_CREASE),
/*emask*/ (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
/*emask*/ (CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
/*fmask*/ 0,
/*pmask*/
(CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL),
@ -2077,12 +2053,12 @@ const CustomData_MeshMasks CD_MASK_BMESH = {
(CD_MASK_MDISPS | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
};
const CustomData_MeshMasks CD_MASK_EVERYTHING = {
/*vmask*/ (CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT |
/*vmask*/ (CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT |
CD_MASK_MVERT_SKIN | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_SHAPEKEY |
CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_CREASE),
/*emask*/
(CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_BWEIGHT | CD_MASK_CREASE |
CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
(CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE |
CD_MASK_PROP_ALL),
/*fmask*/
(CD_MASK_MFACE | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_MTFACE | CD_MASK_MCOL |
CD_MASK_ORIGSPACE | CD_MASK_TANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_PREVIEW_MCOL |
@ -3176,6 +3152,13 @@ void CustomData_free_layers(CustomData *data, const eCustomDataType type, const
}
}
bool CustomData_has_layer_named(const CustomData *data,
const eCustomDataType type,
const char *name)
{
return CustomData_get_named_layer_index(data, type, name) != -1;
}
bool CustomData_has_layer(const CustomData *data, const eCustomDataType type)
{
return (CustomData_get_layer_index(data, type) != -1);
@ -5181,9 +5164,6 @@ void CustomData_blend_write(BlendWriter *writer,
case CD_PAINT_MASK:
BLO_write_raw(writer, sizeof(float) * count, static_cast<const float *>(layer.data));
break;
case CD_SCULPT_FACE_SETS:
BLO_write_raw(writer, sizeof(float) * count, static_cast<const float *>(layer.data));
break;
case CD_GRID_PAINT_MASK:
write_grid_paint_mask(writer, count, static_cast<const GridPaintMask *>(layer.data));
break;

View File

@ -193,7 +193,7 @@ int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type)
case DT_TYPE_SKIN:
return CD_MVERT_SKIN;
case DT_TYPE_BWEIGHT_VERT:
return CD_BWEIGHT;
return CD_FAKE_BWEIGHT;
case DT_TYPE_SHARP_EDGE:
return CD_FAKE_SHARP;
@ -202,7 +202,7 @@ int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type)
case DT_TYPE_CREASE:
return CD_CREASE;
case DT_TYPE_BWEIGHT_EDGE:
return CD_BWEIGHT;
return CD_FAKE_BWEIGHT;
case DT_TYPE_FREESTYLE_EDGE:
return CD_FREESTYLE_EDGE;
@ -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--) {
@ -977,6 +977,24 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map,
* since we can't access them from mesh vertices :/ */
return false;
}
if (r_map && cddata_type == CD_FAKE_BWEIGHT) {
if (!CustomData_get_layer_named(&me_dst->vdata, CD_PROP_FLOAT, "bevel_weight_vert")) {
CustomData_add_layer_named(
&me_dst->vdata, CD_PROP_FLOAT, CD_SET_DEFAULT, me_dst->totvert, "bevel_weight_vert");
}
data_transfer_layersmapping_add_item_cd(
r_map,
CD_PROP_FLOAT,
mix_mode,
mix_factor,
mix_weights,
CustomData_get_layer_named(&me_src->vdata, CD_PROP_FLOAT, "bevel_weight_vert"),
CustomData_get_layer_named_for_write(
&me_dst->vdata, CD_PROP_FLOAT, "bevel_weight_vert", me_dst->totvert),
interp,
interp_data);
return true;
}
}
else if (elem_type == ME_EDGE) {
if (!(cddata_type & CD_FAKE)) { /* Unused for edges, currently... */
@ -1004,7 +1022,7 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map,
return true;
}
if (r_map && cddata_type == CD_FAKE_SEAM) {
if (!CustomData_get_layer_named(&me_dst->edata, CD_PROP_BOOL, ".uv_seam")) {
if (!CustomData_has_layer_named(&me_dst->edata, CD_PROP_BOOL, ".uv_seam")) {
CustomData_add_layer_named(
&me_dst->edata, CD_PROP_BOOL, CD_SET_DEFAULT, me_dst->totedge, ".uv_seam");
}
@ -1022,7 +1040,7 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map,
return true;
}
if (r_map && cddata_type == CD_FAKE_SHARP) {
if (!CustomData_get_layer_named(&me_dst->edata, CD_PROP_BOOL, "sharp_edge")) {
if (!CustomData_has_layer_named(&me_dst->edata, CD_PROP_BOOL, "sharp_edge")) {
CustomData_add_layer_named(
&me_dst->edata, CD_PROP_BOOL, CD_SET_DEFAULT, me_dst->totedge, "sharp_edge");
}
@ -1039,6 +1057,25 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map,
interp_data);
return true;
}
if (r_map && cddata_type == CD_FAKE_BWEIGHT) {
if (!CustomData_get_layer_named(&me_dst->edata, CD_PROP_FLOAT, "bevel_weight_edge")) {
CustomData_add_layer_named(
&me_dst->edata, CD_PROP_FLOAT, CD_SET_DEFAULT, me_dst->totedge, "bevel_weight_edge");
}
data_transfer_layersmapping_add_item_cd(
r_map,
CD_PROP_FLOAT,
mix_mode,
mix_factor,
mix_weights,
CustomData_get_layer_named(&me_src->edata, CD_PROP_FLOAT, "bevel_weight_edge"),
CustomData_get_layer_named_for_write(
&me_dst->edata, CD_PROP_FLOAT, "bevel_weight_edge", me_dst->totedge),
interp,
interp_data);
return true;
}
return false;
}
else if (elem_type == ME_LOOP) {
@ -1110,7 +1147,7 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map,
return true;
}
if (r_map && cddata_type == CD_FAKE_SHARP) {
if (!CustomData_get_layer_named(&me_dst->pdata, CD_PROP_BOOL, "sharp_face")) {
if (!CustomData_has_layer_named(&me_dst->pdata, CD_PROP_BOOL, "sharp_face")) {
CustomData_add_layer_named(
&me_dst->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, me_dst->totpoly, "sharp_face");
}
@ -1384,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;

View File

@ -3210,12 +3210,15 @@ static void dynamic_paint_output_surface_image_paint_cb(void *__restrict userdat
const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
/* blend wet and dry layers */
blendColors(
point->color, point->color[3], point->e_color, point->e_color[3], &ibuf->rect_float[pos]);
blendColors(point->color,
point->color[3],
point->e_color,
point->e_color[3],
&ibuf->float_buffer.data[pos]);
/* Multiply color by alpha if enabled */
if (surface->flags & MOD_DPAINT_MULALPHA) {
mul_v3_fl(&ibuf->rect_float[pos], ibuf->rect_float[pos + 3]);
mul_v3_fl(&ibuf->float_buffer.data[pos], ibuf->float_buffer.data[pos + 3]);
}
}
@ -3242,8 +3245,8 @@ static void dynamic_paint_output_surface_image_displace_cb(
CLAMP(depth, 0.0f, 1.0f);
copy_v3_fl(&ibuf->rect_float[pos], depth);
ibuf->rect_float[pos + 3] = 1.0f;
copy_v3_fl(&ibuf->float_buffer.data[pos], depth);
ibuf->float_buffer.data[pos + 3] = 1.0f;
}
static void dynamic_paint_output_surface_image_wave_cb(void *__restrict userdata,
@ -3268,8 +3271,8 @@ static void dynamic_paint_output_surface_image_wave_cb(void *__restrict userdata
depth = (0.5f + depth / 2.0f);
CLAMP(depth, 0.0f, 1.0f);
copy_v3_fl(&ibuf->rect_float[pos], depth);
ibuf->rect_float[pos + 3] = 1.0f;
copy_v3_fl(&ibuf->float_buffer.data[pos], depth);
ibuf->float_buffer.data[pos + 3] = 1.0f;
}
static void dynamic_paint_output_surface_image_wetmap_cb(void *__restrict userdata,
@ -3286,8 +3289,8 @@ static void dynamic_paint_output_surface_image_wetmap_cb(void *__restrict userda
/* image buffer position */
const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
copy_v3_fl(&ibuf->rect_float[pos], (point->wetness > 1.0f) ? 1.0f : point->wetness);
ibuf->rect_float[pos + 3] = 1.0f;
copy_v3_fl(&ibuf->float_buffer.data[pos], (point->wetness > 1.0f) ? 1.0f : point->wetness);
ibuf->float_buffer.data[pos + 3] = 1.0f;
}
void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface,

View File

@ -3,28 +3,16 @@
#include "BKE_collection.h"
#include "BKE_geometry_set_instances.hh"
#include "BKE_instances.hh"
#include "BKE_material.h"
#include "BKE_mesh.hh"
#include "BKE_mesh_wrapper.h"
#include "BKE_modifier.h"
#include "BKE_pointcloud.h"
#include "DNA_collection_types.h"
#include "DNA_layer_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
namespace blender::bke {
static void geometry_set_collect_recursive(const GeometrySet &geometry_set,
const float4x4 &transform,
Vector<GeometryInstanceGroup> &r_sets);
static void geometry_set_collect_recursive_collection(const Collection &collection,
const float4x4 &transform,
Vector<GeometryInstanceGroup> &r_sets);
static void add_final_mesh_as_geometry_component(const Object &object, GeometrySet &geometry_set)
{
Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(
@ -74,87 +62,6 @@ GeometrySet object_get_evaluated_geometry_set(const Object &object)
return {};
}
static void geometry_set_collect_recursive_collection_instance(
const Collection &collection, const float4x4 &transform, Vector<GeometryInstanceGroup> &r_sets)
{
float4x4 offset_matrix = float4x4::identity();
offset_matrix.location() -= float3(collection.instance_offset);
const float4x4 instance_transform = transform * offset_matrix;
geometry_set_collect_recursive_collection(collection, instance_transform, r_sets);
}
static void geometry_set_collect_recursive_object(const Object &object,
const float4x4 &transform,
Vector<GeometryInstanceGroup> &r_sets)
{
GeometrySet instance_geometry_set = object_get_evaluated_geometry_set(object);
geometry_set_collect_recursive(instance_geometry_set, transform, r_sets);
}
static void geometry_set_collect_recursive_collection(const Collection &collection,
const float4x4 &transform,
Vector<GeometryInstanceGroup> &r_sets)
{
LISTBASE_FOREACH (const CollectionObject *, collection_object, &collection.gobject) {
BLI_assert(collection_object->ob != nullptr);
const Object &object = *collection_object->ob;
const float4x4 object_transform = transform * float4x4_view(object.object_to_world);
geometry_set_collect_recursive_object(object, object_transform, r_sets);
}
LISTBASE_FOREACH (const CollectionChild *, collection_child, &collection.children) {
BLI_assert(collection_child->collection != nullptr);
const Collection &collection = *collection_child->collection;
geometry_set_collect_recursive_collection(collection, transform, r_sets);
}
}
static void geometry_set_collect_recursive(const GeometrySet &geometry_set,
const float4x4 &transform,
Vector<GeometryInstanceGroup> &r_sets)
{
r_sets.append({geometry_set, {transform}});
if (geometry_set.has_instances()) {
const Instances &instances = *geometry_set.get_instances_for_read();
Span<float4x4> transforms = instances.transforms();
Span<int> handles = instances.reference_handles();
Span<InstanceReference> references = instances.references();
for (const int i : transforms.index_range()) {
const InstanceReference &reference = references[handles[i]];
const float4x4 instance_transform = transform * transforms[i];
switch (reference.type()) {
case InstanceReference::Type::Object: {
Object &object = reference.object();
geometry_set_collect_recursive_object(object, instance_transform, r_sets);
break;
}
case InstanceReference::Type::Collection: {
Collection &collection = reference.collection();
geometry_set_collect_recursive_collection_instance(
collection, instance_transform, r_sets);
break;
}
case InstanceReference::Type::GeometrySet: {
const GeometrySet &geometry_set = reference.geometry_set();
geometry_set_collect_recursive(geometry_set, instance_transform, r_sets);
break;
}
case InstanceReference::Type::None: {
break;
}
}
}
}
}
void geometry_set_gather_instances(const GeometrySet &geometry_set,
Vector<GeometryInstanceGroup> &r_instance_groups)
{
geometry_set_collect_recursive(geometry_set, float4x4::identity(), r_instance_groups);
}
void Instances::foreach_referenced_geometry(
blender::FunctionRef<void(const GeometrySet &geometry_set)> callback) const
{

View File

@ -2221,8 +2221,7 @@ int BKE_gpencil_object_material_index_get_by_name(Object *ob, const char *name)
Material *read_ma = NULL;
for (short i = 0; i < *totcol; i++) {
read_ma = BKE_object_material_get(ob, i + 1);
/* Material names are like "MAMaterial.001" */
if (STREQ(name, &read_ma->id.name[2])) {
if (STREQ(name, read_ma->id.name + 2)) {
return i;
}
}
@ -2308,7 +2307,7 @@ bool BKE_gpencil_from_image(
ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
if (ibuf && ibuf->rect) {
if (ibuf && ibuf->byte_buffer.data) {
int img_x = ibuf->x;
int img_y = ibuf->y;

View File

@ -552,7 +552,7 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
if (do_preview) {
prv->w[ICON_SIZE_PREVIEW] = thumb->x;
prv->h[ICON_SIZE_PREVIEW] = thumb->y;
prv->rect[ICON_SIZE_PREVIEW] = (uint *)MEM_dupallocN(thumb->rect);
prv->rect[ICON_SIZE_PREVIEW] = (uint *)MEM_dupallocN(thumb->byte_buffer.data);
prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED | PRV_RENDERING);
}
if (do_icon) {
@ -571,7 +571,7 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
IMB_scaleImBuf(thumb, icon_w, icon_h);
prv->w[ICON_SIZE_ICON] = icon_w;
prv->h[ICON_SIZE_ICON] = icon_h;
prv->rect[ICON_SIZE_ICON] = (uint *)MEM_dupallocN(thumb->rect);
prv->rect[ICON_SIZE_ICON] = (uint *)MEM_dupallocN(thumb->byte_buffer.data);
prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED | PRV_RENDERING);
}
IMB_freeImBuf(thumb);
@ -588,7 +588,7 @@ ImBuf *BKE_previewimg_to_imbuf(PreviewImage *prv, const int size)
if (w > 0 && h > 0 && rect) {
/* first allocate imbuf for copying preview into it */
ima = IMB_allocImBuf(w, h, 32, IB_rect);
memcpy(ima->rect, rect, w * h * sizeof(*ima->rect));
memcpy(ima->byte_buffer.data, rect, w * h * sizeof(uint8_t) * 4);
}
return ima;

View File

@ -85,7 +85,7 @@ ImBuf *BKE_icon_geom_rasterize(const struct Icon_Geom *geom, const uint size_x,
data.rect_size[0] = rect_size[0];
data.rect_size[1] = rect_size[1];
data.rect = ibuf->rect;
data.rect = (uint *)ibuf->byte_buffer.data;
float scale[2];
const bool use_scale = (rect_size[0] != 256) || (rect_size[1] != 256);

View File

@ -1138,7 +1138,7 @@ static ImBuf *add_ibuf_for_tile(Image *ima, ImageTile *tile)
}
if (ibuf != nullptr) {
rect_float = ibuf->rect_float;
rect_float = ibuf->float_buffer.data;
IMB_colormanagement_check_is_data(ibuf, ima->colorspace_settings.name);
}
@ -1162,7 +1162,7 @@ static ImBuf *add_ibuf_for_tile(Image *ima, ImageTile *tile)
}
if (ibuf != nullptr) {
rect = (uchar *)ibuf->rect;
rect = ibuf->byte_buffer.data;
IMB_colormanagement_assign_rect_colorspace(ibuf, ima->colorspace_settings.name);
}
@ -1261,7 +1261,7 @@ static void image_colorspace_from_imbuf(Image *image, const ImBuf *ibuf)
{
const char *colorspace_name = nullptr;
if (ibuf->rect_float) {
if (ibuf->float_buffer.data) {
if (ibuf->float_colorspace) {
colorspace_name = IMB_colormanagement_colorspace_get_name(ibuf->float_colorspace);
}
@ -1270,7 +1270,7 @@ static void image_colorspace_from_imbuf(Image *image, const ImBuf *ibuf)
}
}
if (ibuf->rect && !colorspace_name) {
if (ibuf->byte_buffer.data && !colorspace_name) {
if (ibuf->rect_colorspace) {
colorspace_name = IMB_colormanagement_colorspace_get_name(ibuf->rect_colorspace);
}
@ -1318,7 +1318,7 @@ void BKE_image_replace_imbuf(Image *image, ImBuf *ibuf)
/* Keep generated image type flags consistent with the image buffer. */
if (image->source == IMA_SRC_GENERATED) {
if (ibuf->rect_float) {
if (ibuf->float_buffer.data) {
image->gen_flag |= IMA_GEN_FLOAT;
}
else {
@ -1338,11 +1338,11 @@ void BKE_image_replace_imbuf(Image *image, ImBuf *ibuf)
static bool image_memorypack_imbuf(
Image *ima, ImBuf *ibuf, int view, int tile_number, const char *filepath)
{
ibuf->ftype = (ibuf->rect_float) ? IMB_FTYPE_OPENEXR : IMB_FTYPE_PNG;
ibuf->ftype = (ibuf->float_buffer.data) ? IMB_FTYPE_OPENEXR : IMB_FTYPE_PNG;
IMB_saveiff(ibuf, filepath, IB_rect | IB_mem);
if (ibuf->encodedbuffer == nullptr) {
if (ibuf->encoded_buffer.data == nullptr) {
CLOG_STR_ERROR(&LOG, "memory save for pack error");
IMB_freeImBuf(ibuf);
image_free_packedfiles(ima);
@ -1352,8 +1352,8 @@ static bool image_memorypack_imbuf(
ImagePackedFile *imapf;
PackedFile *pf = MEM_cnew<PackedFile>("PackedFile");
pf->data = ibuf->encodedbuffer;
pf->size = ibuf->encodedsize;
pf->data = IMB_steal_encoded_buffer(ibuf);
pf->size = ibuf->encoded_size;
imapf = static_cast<ImagePackedFile *>(MEM_mallocN(sizeof(ImagePackedFile), "Image PackedFile"));
STRNCPY(imapf->filepath, filepath);
@ -1362,8 +1362,6 @@ static bool image_memorypack_imbuf(
imapf->tile_number = tile_number;
BLI_addtail(&ima->packedfiles, imapf);
ibuf->encodedbuffer = nullptr;
ibuf->encodedsize = 0;
ibuf->userflags &= ~IB_BITMAPDIRTY;
return true;
@ -1505,26 +1503,12 @@ static uintptr_t image_mem_size(Image *image)
if (ibuf == nullptr) {
continue;
}
ImBuf *ibufm;
int level;
if (ibuf->rect) {
size += MEM_allocN_len(ibuf->rect);
}
if (ibuf->rect_float) {
size += MEM_allocN_len(ibuf->rect_float);
}
size += IMB_get_size_in_memory(ibuf);
for (level = 0; level < IMB_MIPMAP_LEVELS; level++) {
ibufm = ibuf->mipmap[level];
if (ibufm) {
if (ibufm->rect) {
size += MEM_allocN_len(ibufm->rect);
}
if (ibufm->rect_float) {
size += MEM_allocN_len(ibufm->rect_float);
}
}
for (int level = 0; level < IMB_MIPMAP_LEVELS; level++) {
ImBuf *ibufm = ibuf->mipmap[level];
size += IMB_get_size_in_memory(ibufm);
}
}
IMB_moviecacheIter_free(iter);
@ -2537,16 +2521,16 @@ void BKE_stamp_info_from_imbuf(RenderResult *rr, ImBuf *ibuf)
bool BKE_imbuf_alpha_test(ImBuf *ibuf)
{
int tot;
if (ibuf->rect_float) {
const float *buf = ibuf->rect_float;
if (ibuf->float_buffer.data) {
const float *buf = ibuf->float_buffer.data;
for (tot = ibuf->x * ibuf->y; tot--; buf += 4) {
if (buf[3] < 1.0f) {
return true;
}
}
}
else if (ibuf->rect) {
uchar *buf = (uchar *)ibuf->rect;
else if (ibuf->byte_buffer.data) {
uchar *buf = ibuf->byte_buffer.data;
for (tot = ibuf->x * ibuf->y; tot--; buf += 4) {
if (buf[3] != 255) {
return true;
@ -4007,9 +3991,8 @@ static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int e
// printf("load from pass %s\n", rpass->name);
/* since we free render results, we copy the rect */
ibuf = IMB_allocImBuf(ima->rr->rectx, ima->rr->recty, 32, 0);
ibuf->rect_float = static_cast<float *>(MEM_dupallocN(rpass->rect));
ibuf->flags |= IB_rectfloat;
ibuf->mall = IB_rectfloat;
IMB_assign_float_buffer(
ibuf, static_cast<float *>(MEM_dupallocN(rpass->rect)), IB_TAKE_OWNERSHIP);
ibuf->channels = rpass->channels;
BKE_imbuf_stamp_info(ima->rr, ibuf);
@ -4318,8 +4301,7 @@ static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser)
image_init_after_load(ima, iuser, ibuf);
ibuf->rect_float = rpass->rect;
ibuf->flags |= IB_rectfloat;
IMB_assign_float_buffer(ibuf, rpass->rect, IB_DO_NOT_TAKE_OWNERSHIP);
ibuf->channels = rpass->channels;
BKE_imbuf_stamp_info(ima->rr, ibuf);
@ -4459,56 +4441,29 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
*
* For other cases we need to be sure it stays to default byte buffer space.
*/
if (ibuf->rect != rect) {
if (ibuf->byte_buffer.data != (uint8_t *)rect) {
const char *colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_BYTE);
IMB_colormanagement_assign_rect_colorspace(ibuf, colorspace);
}
/* invalidate color managed buffers if render result changed */
BLI_thread_lock(LOCK_COLORMANAGE);
if (ibuf->x != rres.rectx || ibuf->y != rres.recty || ibuf->rect_float != rectf) {
if (ibuf->x != rres.rectx || ibuf->y != rres.recty || ibuf->float_buffer.data != rectf) {
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
}
ibuf->x = rres.rectx;
ibuf->y = rres.recty;
ibuf->channels = channels;
if (rect) {
imb_freerectImBuf(ibuf);
ibuf->rect = rect;
}
else {
/* byte buffer of render result has been freed, make sure image buffers
* does not reference to this buffer anymore
* need check for whether byte buffer was allocated and owned by image itself
* or if it's reusing buffer from render result
*/
if ((ibuf->mall & IB_rect) == 0) {
ibuf->rect = nullptr;
}
}
imb_freerectImBuf(ibuf);
if (rectf) {
ibuf->rect_float = rectf;
ibuf->flags |= IB_rectfloat;
ibuf->channels = channels;
}
else {
ibuf->rect_float = nullptr;
ibuf->flags &= ~IB_rectfloat;
}
if (rectz) {
ibuf->zbuf_float = rectz;
ibuf->flags |= IB_zbuffloat;
}
else {
ibuf->zbuf_float = nullptr;
ibuf->flags &= ~IB_zbuffloat;
}
IMB_assign_byte_buffer(ibuf, (uint8_t *)rect, IB_DO_NOT_TAKE_OWNERSHIP);
IMB_assign_float_buffer(ibuf, rectf, IB_DO_NOT_TAKE_OWNERSHIP);
IMB_assign_float_z_buffer(ibuf, rectz, IB_DO_NOT_TAKE_OWNERSHIP);
/* TODO(sergey): Make this faster by either simply referencing the stamp
* or by changing both ImBug and RenderResult to use same data type to
* or by changing both ImBuf and RenderResult to use same data type to
* store metadata. */
if (ibuf->metadata != nullptr) {
IMB_metadata_free(ibuf->metadata);
@ -5269,7 +5224,7 @@ uchar *BKE_image_get_pixels_for_frame(struct Image *image, int frame, int tile)
ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
if (ibuf) {
pixels = (uchar *)ibuf->rect;
pixels = ibuf->byte_buffer.data;
if (pixels) {
pixels = static_cast<uchar *>(MEM_dupallocN(pixels));
@ -5299,7 +5254,7 @@ float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame, int
ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
if (ibuf) {
pixels = ibuf->rect_float;
pixels = ibuf->float_buffer.data;
if (pixels) {
pixels = static_cast<float *>(MEM_dupallocN(pixels));

View File

@ -799,7 +799,7 @@ void BKE_image_format_from_imbuf(ImageFormatData *im_format, const ImBuf *imbuf)
if (custom_flags & OPENEXR_COMPRESS) {
im_format->exr_codec = R_IMF_EXR_CODEC_ZIP; /* Can't determine compression */
}
if (imbuf->zbuf_float) {
if (imbuf->float_z_buffer.data) {
im_format->flag |= R_IMF_FLAG_ZBUF;
}
}

View File

@ -50,11 +50,11 @@ bool BKE_image_has_gpu_texture_premultiplied_alpha(Image *image, ImBuf *ibuf)
}
/* Generated images use pre multiplied float buffer, but straight alpha for byte buffers. */
if (image->type == IMA_TYPE_UV_TEST && ibuf) {
return ibuf->rect_float != nullptr;
return ibuf->float_buffer.data != nullptr;
}
}
if (ibuf) {
if (ibuf->rect_float) {
if (ibuf->float_buffer.data) {
return image ? (image->alpha_mode != IMA_ALPHA_STRAIGHT) : false;
}
@ -643,7 +643,7 @@ static ImBuf *update_do_scale(uchar *rect,
}
/* Scale pixels. */
ImBuf *ibuf = IMB_allocFromBuffer((uint *)rect, rect_float, part_w, part_h, 4);
ImBuf *ibuf = IMB_allocFromBuffer(rect, rect_float, part_w, part_h, 4);
IMB_scaleImBuf(ibuf, *w, *h);
return ibuf;
@ -679,8 +679,9 @@ static void gpu_texture_update_scaled(GPUTexture *tex,
ibuf = update_do_scale(rect, rect_float, &x, &y, &w, &h, limit_w, limit_h, full_w, full_h);
}
void *data = (ibuf->rect_float) ? (void *)(ibuf->rect_float) : (void *)(ibuf->rect);
eGPUDataFormat data_format = (ibuf->rect_float) ? GPU_DATA_FLOAT : GPU_DATA_UBYTE;
void *data = (ibuf->float_buffer.data) ? (void *)(ibuf->float_buffer.data) :
(void *)(ibuf->byte_buffer.data);
eGPUDataFormat data_format = (ibuf->float_buffer.data) ? GPU_DATA_FLOAT : GPU_DATA_UBYTE;
GPU_texture_update_sub(tex, data_format, data, x, y, layer, w, h, 1);
@ -742,8 +743,8 @@ static void gpu_texture_update_from_ibuf(
}
/* Get texture data pointers. */
float *rect_float = ibuf->rect_float;
uchar *rect = (uchar *)ibuf->rect;
float *rect_float = ibuf->float_buffer.data;
uchar *rect = ibuf->byte_buffer.data;
int tex_stride = ibuf->x;
int tex_offset = ibuf->channels * (y * ibuf->x + x);
@ -832,10 +833,10 @@ static void gpu_texture_update_from_ibuf(
}
/* Free buffers if needed. */
if (rect && rect != (uchar *)ibuf->rect) {
if (rect && rect != ibuf->byte_buffer.data) {
MEM_freeN(rect);
}
if (rect_float && rect_float != ibuf->rect_float) {
if (rect_float && rect_float != ibuf->float_buffer.data) {
MEM_freeN(rect_float);
}

View File

@ -42,7 +42,7 @@ static char imtype_best_depth(ImBuf *ibuf, const char imtype)
{
const char depth_ok = BKE_imtype_valid_depths(imtype);
if (ibuf->rect_float) {
if (ibuf->float_buffer.data) {
if (depth_ok & R_IMF_CHAN_DEPTH_32) {
return R_IMF_CHAN_DEPTH_32;
}
@ -298,18 +298,10 @@ static void image_save_post(ReportList *reports,
/* workaround to ensure the render result buffer is no longer used
* by this image, otherwise can crash when a new render result is
* created. */
if (ibuf->rect && !(ibuf->mall & IB_rect)) {
imb_freerectImBuf(ibuf);
}
if (ibuf->rect_float && !(ibuf->mall & IB_rectfloat)) {
imb_freerectfloatImBuf(ibuf);
}
if (ibuf->zbuf && !(ibuf->mall & IB_zbuf)) {
IMB_freezbufImBuf(ibuf);
}
if (ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat)) {
IMB_freezbuffloatImBuf(ibuf);
}
imb_freerectImBuf(ibuf);
imb_freerectfloatImBuf(ibuf);
IMB_freezbufImBuf(ibuf);
IMB_freezbuffloatImBuf(ibuf);
}
if (ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
ima->source = IMA_SRC_FILE;
@ -365,7 +357,8 @@ static bool image_save_single(ReportList *reports,
RenderResult *rr = nullptr;
bool ok = false;
if (ibuf == nullptr || (ibuf->rect == nullptr && ibuf->rect_float == nullptr)) {
if (ibuf == nullptr || (ibuf->byte_buffer.data == nullptr && ibuf->float_buffer.data == nullptr))
{
BKE_image_release_ibuf(ima, ibuf, lock);
return ok;
}

View File

@ -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);
}

View File

@ -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)
{

View File

@ -5,6 +5,8 @@
#include <string>
#include "MEM_guardedalloc.h"
#include "DNA_ID.h"
#include "DNA_collection_types.h"
#include "DNA_object_types.h"
@ -23,30 +25,21 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
Collection **BKE_light_linking_collection_ptr_get(Object *object, const LightLinkingType link_type)
Collection *BKE_light_linking_collection_get(const Object *object,
const LightLinkingType link_type)
{
LightLinking &light_linking = object->light_linking;
switch (link_type) {
case LIGHT_LINKING_RECEIVER:
return &light_linking.receiver_collection;
case LIGHT_LINKING_BLOCKER:
return &light_linking.blocker_collection;
}
BLI_assert_unreachable();
return nullptr;
}
Collection *BKE_light_linking_collection_get(Object *object, const LightLinkingType link_type)
{
Collection **collection_ptr = BKE_light_linking_collection_ptr_get(object, link_type);
if (!collection_ptr) {
BLI_assert_unreachable();
if (!object->light_linking) {
return nullptr;
}
return *collection_ptr;
switch (link_type) {
case LIGHT_LINKING_RECEIVER:
return object->light_linking->receiver_collection;
case LIGHT_LINKING_BLOCKER:
return object->light_linking->blocker_collection;
}
return nullptr;
}
static std::string get_default_collection_name(const Object *object,
@ -86,17 +79,41 @@ void BKE_light_linking_collection_assign_only(struct Object *object,
struct Collection *new_collection,
const LightLinkingType link_type)
{
Collection **collection_ptr = BKE_light_linking_collection_ptr_get(object, link_type);
/* Unassign old collection if any, */
if (*collection_ptr) {
id_us_min(&(*collection_ptr)->id);
/* Remove user from old collection. */
Collection *old_collection = BKE_light_linking_collection_get(object, link_type);
if (old_collection) {
id_us_min(&old_collection->id);
}
*collection_ptr = new_collection;
/* Allocate light linking on demand. */
if (new_collection && !object->light_linking) {
object->light_linking = MEM_cnew<LightLinking>(__func__);
}
if (new_collection) {
id_us_plus(&new_collection->id);
if (object->light_linking) {
/* Assign and increment user of new collection. */
switch (link_type) {
case LIGHT_LINKING_RECEIVER:
object->light_linking->receiver_collection = new_collection;
break;
case LIGHT_LINKING_BLOCKER:
object->light_linking->blocker_collection = new_collection;
break;
default:
BLI_assert_unreachable();
break;
}
if (new_collection) {
id_us_plus(&new_collection->id);
}
/* Free if empty. */
if (object->light_linking->receiver_collection == nullptr &&
object->light_linking->blocker_collection == nullptr)
{
MEM_SAFE_FREE(object->light_linking);
}
}
}
@ -136,8 +153,8 @@ static CollectionLightLinking *light_linking_collection_add_object(Main *bmain,
/* Add child collection to the light linking collection and return corresponding
* CollectionLightLinking settings.
*
* If the child collection is already in the collection then the content of the collection is not
* modified, and the existing light linking settings are returned. */
* If the child collection is already in the collection then the content of the collection is
* not modified, and the existing light linking settings are returned. */
static CollectionLightLinking *light_linking_collection_add_collection(Main *bmain,
Collection *collection,
Collection *child)

View File

@ -523,7 +523,7 @@ BlendThumbnail *BKE_main_thumbnail_from_imbuf(Main *bmain, ImBuf *img)
IMB_rect_from_float(img); /* Just in case... */
data->width = img->x;
data->height = img->y;
memcpy(data->rect, img->rect, data_size - sizeof(*data));
memcpy(data->rect, img->byte_buffer.data, data_size - sizeof(*data));
}
if (bmain) {
@ -542,7 +542,7 @@ ImBuf *BKE_main_thumbnail_to_imbuf(Main *bmain, BlendThumbnail *data)
if (data) {
img = IMB_allocFromBuffer(
(const uint *)data->rect, NULL, (uint)data->width, (uint)data->height, 4);
(const uint8_t *)data->rect, NULL, (uint)data->width, (uint)data->height, 4);
}
return img;

View File

@ -82,6 +82,8 @@ static void material_init_data(ID *id)
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(material, id));
MEMCPY_STRUCT_AFTER(material, DNA_struct_default_get(Material), id);
*((short *)id->name) = ID_MA;
}
static void material_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
@ -1992,14 +1994,14 @@ static Material *default_materials[] = {&default_material_empty,
static void material_default_gpencil_init(Material *ma)
{
strcpy(ma->id.name, "MADefault GPencil");
BLI_strncpy(ma->id.name + 2, "Default GPencil", MAX_NAME);
BKE_gpencil_material_attr_init(ma);
add_v3_fl(&ma->gp_style->stroke_rgba[0], 0.6f);
}
static void material_default_surface_init(Material *ma)
{
strcpy(ma->id.name, "MADefault Surface");
BLI_strncpy(ma->id.name + 2, "Default Surface", MAX_NAME);
bNodeTree *ntree = blender::bke::ntreeAddTreeEmbedded(
nullptr, &ma->id, "Shader Nodetree", ntreeType_Shader->idname);
@ -2027,7 +2029,7 @@ static void material_default_surface_init(Material *ma)
static void material_default_volume_init(Material *ma)
{
strcpy(ma->id.name, "MADefault Volume");
BLI_strncpy(ma->id.name + 2, "Default Volume", MAX_NAME);
bNodeTree *ntree = blender::bke::ntreeAddTreeEmbedded(
nullptr, &ma->id, "Shader Nodetree", ntreeType_Shader->idname);
@ -2052,7 +2054,7 @@ static void material_default_volume_init(Material *ma)
static void material_default_holdout_init(Material *ma)
{
strcpy(ma->id.name, "MADefault Holdout");
BLI_strncpy(ma->id.name + 2, "Default Holdout", MAX_NAME);
bNodeTree *ntree = blender::bke::ntreeAddTreeEmbedded(
nullptr, &ma->id, "Shader Nodetree", ntreeType_Shader->idname);

View File

@ -257,68 +257,10 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
mesh->poly_offset_indices = nullptr;
}
else {
Set<std::string> names_to_skip;
if (!BLO_write_is_undo(writer)) {
/* When converting to the old mesh format, don't save redundant attributes. */
names_to_skip.add_multiple_new({"position",
".edge_verts",
".corner_vert",
".corner_edge",
".hide_vert",
".hide_edge",
".hide_poly",
".uv_seam",
".select_vert",
".select_edge",
".select_poly",
"material_index",
"sharp_face",
"sharp_edge"});
mesh->mvert = BKE_mesh_legacy_convert_positions_to_verts(
mesh, temp_arrays_for_legacy_format, vert_layers);
mesh->mloop = BKE_mesh_legacy_convert_corners_to_loops(
mesh, temp_arrays_for_legacy_format, loop_layers);
mesh->medge = BKE_mesh_legacy_convert_edges_to_medge(
mesh, temp_arrays_for_legacy_format, edge_layers);
MutableSpan<MPoly> legacy_polys = BKE_mesh_legacy_convert_offsets_to_polys(
mesh, temp_arrays_for_legacy_format, poly_layers);
BKE_mesh_legacy_convert_hide_layers_to_flags(mesh, legacy_polys);
BKE_mesh_legacy_convert_selection_layers_to_flags(mesh, legacy_polys);
BKE_mesh_legacy_convert_material_indices_to_mpoly(mesh, legacy_polys);
BKE_mesh_legacy_sharp_faces_to_flags(mesh, legacy_polys);
BKE_mesh_legacy_bevel_weight_from_layers(mesh);
BKE_mesh_legacy_edge_crease_from_layers(mesh);
BKE_mesh_legacy_sharp_edges_to_flags(mesh);
BKE_mesh_legacy_uv_seam_to_flags(mesh);
BKE_mesh_legacy_attribute_strings_to_flags(mesh);
mesh->active_color_attribute = nullptr;
mesh->default_color_attribute = nullptr;
BKE_mesh_legacy_convert_loose_edges_to_flag(mesh);
mesh->poly_offset_indices = nullptr;
/* Set deprecated mesh data pointers for forward compatibility. */
mesh->mpoly = legacy_polys.data();
mesh->dvert = const_cast<MDeformVert *>(mesh->deform_verts().data());
}
CustomData_blend_write_prepare(mesh->vdata, vert_layers, names_to_skip);
CustomData_blend_write_prepare(mesh->edata, edge_layers, names_to_skip);
CustomData_blend_write_prepare(mesh->ldata, loop_layers, names_to_skip);
CustomData_blend_write_prepare(mesh->pdata, poly_layers, names_to_skip);
if (!BLO_write_is_undo(writer)) {
/* #CustomData expects the layers to be sorted in increasing order based on type. */
std::stable_sort(
poly_layers.begin(),
poly_layers.end(),
[](const CustomDataLayer &a, const CustomDataLayer &b) { return a.type < b.type; });
BKE_mesh_legacy_convert_uvs_to_struct(mesh, temp_arrays_for_legacy_format, loop_layers);
BKE_mesh_legacy_face_set_from_generic(poly_layers);
}
CustomData_blend_write_prepare(mesh->vdata, vert_layers, {});
CustomData_blend_write_prepare(mesh->edata, edge_layers, {});
CustomData_blend_write_prepare(mesh->ldata, loop_layers, {});
CustomData_blend_write_prepare(mesh->pdata, poly_layers, {});
}
mesh->runtime = nullptr;

View File

@ -291,8 +291,9 @@ static IMesh meshes_to_imesh(Span<const Mesh *> meshes,
r_info->mesh_poly_offset[mi] = f;
/* Get matrix that transforms a coordinate in meshes[mi]'s local space
* to the target space. */
const float4x4 objn_mat = (obmats[mi] == nullptr) ? float4x4::identity() :
clean_transform(*obmats[mi]);
const float4x4 objn_mat = (obmats.is_empty() || obmats[mi] == nullptr) ?
float4x4::identity() :
clean_transform(*obmats[mi]);
r_info->to_target_transform[mi] = inv_target_mat * objn_mat;
r_info->has_negative_transform[mi] = math::is_negative(objn_mat);
@ -311,7 +312,7 @@ static IMesh meshes_to_imesh(Span<const Mesh *> meshes,
* Skip the matrix multiplication for each point when there is no transform for a mesh,
* for example when the first mesh is already in the target space. (Note the logic
* directly above, which uses an identity matrix with a null input transform). */
if (obmats[mi] == nullptr) {
if (obmats.is_empty() || obmats[mi] == nullptr) {
threading::parallel_for(vert_positions.index_range(), 2048, [&](IndexRange range) {
for (int i : range) {
float3 co = vert_positions[i];
@ -798,7 +799,7 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
Vector<int> *r_intersecting_edges)
{
#ifdef WITH_GMP
BLI_assert(meshes.size() == transforms.size());
BLI_assert(transforms.is_empty() || meshes.size() == transforms.size());
BLI_assert(material_remaps.size() == 0 || material_remaps.size() == meshes.size());
if (meshes.size() <= 0) {
return nullptr;

View File

@ -231,7 +231,7 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool keep_existing_edges, const bool select
}
/* Create new edges. */
if (!CustomData_get_layer_named(&mesh->ldata, CD_PROP_INT32, ".corner_edge")) {
if (!CustomData_has_layer_named(&mesh->ldata, CD_PROP_INT32, ".corner_edge")) {
CustomData_add_layer_named(
&mesh->ldata, CD_PROP_INT32, CD_CONSTRUCT, mesh->totloop, ".corner_edge");
}
@ -271,7 +271,7 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool keep_existing_edges, const bool select
if (!keep_existing_edges) {
/* All edges are rebuilt from the faces, so there are no loose edges. */
mesh->loose_edges_tag_none();
mesh->tag_loose_edges_none();
}
/* Explicitly clear edge maps, because that way it can be parallelized. */

View File

@ -1236,25 +1236,6 @@ void BKE_mesh_tessface_ensure(struct Mesh *mesh)
/** \name Sharp Edge Conversion
* \{ */
void BKE_mesh_legacy_sharp_faces_to_flags(Mesh *mesh, blender::MutableSpan<MPoly> legacy_polys)
{
using namespace blender;
if (const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face")))
{
threading::parallel_for(legacy_polys.index_range(), 4096, [&](const IndexRange range) {
for (const int i : range) {
SET_FLAG_FROM_TEST(legacy_polys[i].flag_legacy, !sharp_faces[i], ME_SMOOTH);
}
});
}
else {
for (const int i : legacy_polys.index_range()) {
legacy_polys[i].flag_legacy |= ME_SMOOTH;
}
}
}
void BKE_mesh_legacy_sharp_faces_from_flags(Mesh *mesh)
{
using namespace blender;
@ -1289,28 +1270,6 @@ void BKE_mesh_legacy_sharp_faces_from_flags(Mesh *mesh)
/** \name Face Set Conversion
* \{ */
void BKE_mesh_legacy_face_set_from_generic(blender::MutableSpan<CustomDataLayer> poly_layers)
{
using namespace blender;
bool changed = false;
for (CustomDataLayer &layer : poly_layers) {
if (StringRef(layer.name) == ".sculpt_face_set") {
layer.type = CD_SCULPT_FACE_SETS;
layer.name[0] = '\0';
changed = true;
break;
}
}
if (!changed) {
return;
}
/* #CustomData expects the layers to be sorted in increasing order based on type. */
std::stable_sort(
poly_layers.begin(),
poly_layers.end(),
[](const CustomDataLayer &a, const CustomDataLayer &b) { return a.type < b.type; });
}
void BKE_mesh_legacy_face_set_to_generic(Mesh *mesh)
{
using namespace blender;
@ -1349,41 +1308,6 @@ void BKE_mesh_legacy_face_set_to_generic(Mesh *mesh)
/** \name Bevel Weight Conversion
* \{ */
void BKE_mesh_legacy_bevel_weight_from_layers(Mesh *mesh)
{
using namespace blender;
MutableSpan<MVert> verts(mesh->mvert, mesh->totvert);
if (const float *weights = static_cast<const float *>(
CustomData_get_layer(&mesh->vdata, CD_BWEIGHT)))
{
mesh->cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
for (const int i : verts.index_range()) {
verts[i].bweight_legacy = std::clamp(weights[i], 0.0f, 1.0f) * 255.0f;
}
}
else {
mesh->cd_flag &= ~ME_CDFLAG_VERT_BWEIGHT;
for (const int i : verts.index_range()) {
verts[i].bweight_legacy = 0;
}
}
MutableSpan<MEdge> edges(mesh->medge, mesh->totedge);
if (const float *weights = static_cast<const float *>(
CustomData_get_layer(&mesh->edata, CD_BWEIGHT)))
{
mesh->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
for (const int i : edges.index_range()) {
edges[i].bweight_legacy = std::clamp(weights[i], 0.0f, 1.0f) * 255.0f;
}
}
else {
mesh->cd_flag &= ~ME_CDFLAG_EDGE_BWEIGHT;
for (const int i : edges.index_range()) {
edges[i].bweight_legacy = 0;
}
}
}
void BKE_mesh_legacy_bevel_weight_to_layers(Mesh *mesh)
{
using namespace blender;
@ -1410,32 +1334,62 @@ void BKE_mesh_legacy_bevel_weight_to_layers(Mesh *mesh)
}
}
void BKE_mesh_legacy_bevel_weight_to_generic(Mesh *mesh)
{
using namespace blender;
if (!mesh->attributes().contains("bevel_weight_vert")) {
void *data = nullptr;
const ImplicitSharingInfo *sharing_info = nullptr;
for (const int i : IndexRange(mesh->vdata.totlayer)) {
CustomDataLayer &layer = mesh->vdata.layers[i];
if (layer.type == CD_BWEIGHT) {
data = layer.data;
sharing_info = layer.sharing_info;
layer.data = nullptr;
layer.sharing_info = nullptr;
CustomData_free_layer(&mesh->vdata, CD_BWEIGHT, mesh->totvert, i);
break;
}
}
if (data != nullptr) {
CustomData_add_layer_named_with_data(
&mesh->vdata, CD_PROP_FLOAT, data, mesh->totvert, "bevel_weight_vert", sharing_info);
}
if (sharing_info != nullptr) {
sharing_info->remove_user_and_delete_if_last();
}
}
if (!mesh->attributes().contains("bevel_weight_edge")) {
void *data = nullptr;
const ImplicitSharingInfo *sharing_info = nullptr;
for (const int i : IndexRange(mesh->edata.totlayer)) {
CustomDataLayer &layer = mesh->edata.layers[i];
if (layer.type == CD_BWEIGHT) {
data = layer.data;
sharing_info = layer.sharing_info;
layer.data = nullptr;
layer.sharing_info = nullptr;
CustomData_free_layer(&mesh->edata, CD_BWEIGHT, mesh->totedge, i);
break;
}
}
if (data != nullptr) {
CustomData_add_layer_named_with_data(
&mesh->edata, CD_PROP_FLOAT, data, mesh->totedge, "bevel_weight_edge", sharing_info);
}
if (sharing_info != nullptr) {
sharing_info->remove_user_and_delete_if_last();
}
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Edge Crease Conversion
* \{ */
void BKE_mesh_legacy_edge_crease_from_layers(Mesh *mesh)
{
using namespace blender;
MutableSpan<MEdge> edges(mesh->medge, mesh->totedge);
if (const float *creases = static_cast<const float *>(
CustomData_get_layer(&mesh->edata, CD_CREASE)))
{
mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE;
for (const int i : edges.index_range()) {
edges[i].crease_legacy = std::clamp(creases[i], 0.0f, 1.0f) * 255.0f;
}
}
else {
mesh->cd_flag &= ~ME_CDFLAG_EDGE_CREASE;
for (const int i : edges.index_range()) {
edges[i].crease_legacy = 0;
}
}
}
void BKE_mesh_legacy_edge_crease_to_layers(Mesh *mesh)
{
using namespace blender;
@ -1458,26 +1412,6 @@ void BKE_mesh_legacy_edge_crease_to_layers(Mesh *mesh)
/** \name Sharp Edge Conversion
* \{ */
void BKE_mesh_legacy_sharp_edges_to_flags(Mesh *mesh)
{
using namespace blender;
MutableSpan<MEdge> edges(mesh->medge, mesh->totedge);
if (const bool *sharp_edges = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->edata, CD_PROP_BOOL, "sharp_edge")))
{
threading::parallel_for(edges.index_range(), 4096, [&](const IndexRange range) {
for (const int i : range) {
SET_FLAG_FROM_TEST(edges[i].flag_legacy, sharp_edges[i], ME_SHARP);
}
});
}
else {
for (const int i : edges.index_range()) {
edges[i].flag_legacy &= ~ME_SHARP;
}
}
}
void BKE_mesh_legacy_sharp_edges_from_flags(Mesh *mesh)
{
using namespace blender;
@ -1511,26 +1445,6 @@ void BKE_mesh_legacy_sharp_edges_from_flags(Mesh *mesh)
/** \name UV Seam Conversion
* \{ */
void BKE_mesh_legacy_uv_seam_to_flags(Mesh *mesh)
{
using namespace blender;
MutableSpan<MEdge> edges(mesh->medge, mesh->totedge);
if (const bool *uv_seams = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->edata, CD_PROP_BOOL, ".uv_seam")))
{
threading::parallel_for(edges.index_range(), 4096, [&](const IndexRange range) {
for (const int i : range) {
SET_FLAG_FROM_TEST(edges[i].flag_legacy, uv_seams[i], ME_SEAM);
}
});
}
else {
for (const int i : edges.index_range()) {
edges[i].flag_legacy &= ~ME_SEAM;
}
}
}
void BKE_mesh_legacy_uv_seam_from_flags(Mesh *mesh)
{
using namespace blender;
@ -1564,40 +1478,6 @@ void BKE_mesh_legacy_uv_seam_from_flags(Mesh *mesh)
/** \name Hide Attribute and Legacy Flag Conversion
* \{ */
void BKE_mesh_legacy_convert_hide_layers_to_flags(Mesh *mesh,
blender::MutableSpan<MPoly> legacy_polys)
{
using namespace blender;
using namespace blender::bke;
const AttributeAccessor attributes = mesh->attributes();
MutableSpan<MVert> verts(mesh->mvert, mesh->totvert);
const VArray<bool> hide_vert = *attributes.lookup_or_default<bool>(
".hide_vert", ATTR_DOMAIN_POINT, false);
threading::parallel_for(verts.index_range(), 4096, [&](IndexRange range) {
for (const int i : range) {
SET_FLAG_FROM_TEST(verts[i].flag_legacy, hide_vert[i], ME_HIDE);
}
});
MutableSpan<MEdge> edges(mesh->medge, mesh->totedge);
const VArray<bool> hide_edge = *attributes.lookup_or_default<bool>(
".hide_edge", ATTR_DOMAIN_EDGE, false);
threading::parallel_for(edges.index_range(), 4096, [&](IndexRange range) {
for (const int i : range) {
SET_FLAG_FROM_TEST(edges[i].flag_legacy, hide_edge[i], ME_HIDE);
}
});
const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
".hide_poly", ATTR_DOMAIN_FACE, false);
threading::parallel_for(legacy_polys.index_range(), 4096, [&](IndexRange range) {
for (const int i : range) {
SET_FLAG_FROM_TEST(legacy_polys[i].flag_legacy, hide_poly[i], ME_HIDE);
}
});
}
void BKE_mesh_legacy_convert_flags_to_hide_layers(Mesh *mesh)
{
using namespace blender;
@ -1663,21 +1543,6 @@ void BKE_mesh_legacy_convert_flags_to_hide_layers(Mesh *mesh)
/** \name Material Index Conversion
* \{ */
void BKE_mesh_legacy_convert_material_indices_to_mpoly(Mesh *mesh,
blender::MutableSpan<MPoly> legacy_polys)
{
using namespace blender;
using namespace blender::bke;
const AttributeAccessor attributes = mesh->attributes();
const VArray<int> material_indices = *attributes.lookup_or_default<int>(
"material_index", ATTR_DOMAIN_FACE, 0);
threading::parallel_for(legacy_polys.index_range(), 4096, [&](IndexRange range) {
for (const int i : range) {
legacy_polys[i].mat_nr_legacy = material_indices[i];
}
});
}
void BKE_mesh_legacy_convert_mpoly_to_material_indices(Mesh *mesh)
{
using namespace blender;
@ -1708,87 +1573,6 @@ void BKE_mesh_legacy_convert_mpoly_to_material_indices(Mesh *mesh)
/** \name Generic UV Map Conversion
* \{ */
static const bool *layers_find_bool_named(const Span<CustomDataLayer> layers,
const blender::StringRef name)
{
for (const CustomDataLayer &layer : layers) {
if (layer.type == CD_PROP_BOOL) {
if (layer.name == name) {
return static_cast<const bool *>(layer.data);
}
}
}
return nullptr;
}
void BKE_mesh_legacy_convert_uvs_to_struct(
Mesh *mesh,
blender::ResourceScope &temp_mloopuv_for_convert,
blender::Vector<CustomDataLayer, 16> &loop_layers_to_write)
{
using namespace blender;
using namespace blender::bke;
const int loops_num = mesh->totloop;
Vector<CustomDataLayer, 16> new_layer_to_write;
/* Don't write the boolean UV map sublayers which will be written in the legacy #MLoopUV type. */
Set<std::string> uv_sublayers_to_skip;
char vert_name[MAX_CUSTOMDATA_LAYER_NAME];
char edge_name[MAX_CUSTOMDATA_LAYER_NAME];
char pin_name[MAX_CUSTOMDATA_LAYER_NAME];
for (const CustomDataLayer &layer : loop_layers_to_write) {
if (layer.type == CD_PROP_FLOAT2) {
uv_sublayers_to_skip.add_multiple_new(
{BKE_uv_map_vert_select_name_get(layer.name, vert_name),
BKE_uv_map_edge_select_name_get(layer.name, edge_name),
BKE_uv_map_pin_name_get(layer.name, pin_name)});
}
}
for (const CustomDataLayer &layer : loop_layers_to_write) {
if (layer.name[0] && uv_sublayers_to_skip.contains_as(layer.name)) {
continue;
}
if (layer.type != CD_PROP_FLOAT2) {
new_layer_to_write.append(layer);
continue;
}
const Span<float2> coords{static_cast<const float2 *>(layer.data), loops_num};
CustomDataLayer mloopuv_layer = layer;
mloopuv_layer.type = CD_MLOOPUV;
MutableSpan<MLoopUV> mloopuv = temp_mloopuv_for_convert.construct<Array<MLoopUV>>(loops_num);
mloopuv_layer.data = mloopuv.data();
char buffer[MAX_CUSTOMDATA_LAYER_NAME];
const bool *vert_selection = layers_find_bool_named(
loop_layers_to_write, BKE_uv_map_vert_select_name_get(layer.name, buffer));
const bool *edge_selection = layers_find_bool_named(
loop_layers_to_write, BKE_uv_map_edge_select_name_get(layer.name, buffer));
const bool *pin = layers_find_bool_named(loop_layers_to_write,
BKE_uv_map_pin_name_get(layer.name, buffer));
threading::parallel_for(mloopuv.index_range(), 2048, [&](IndexRange range) {
for (const int i : range) {
copy_v2_v2(mloopuv[i].uv, coords[i]);
SET_FLAG_FROM_TEST(mloopuv[i].flag, vert_selection && vert_selection[i], MLOOPUV_VERTSEL);
SET_FLAG_FROM_TEST(mloopuv[i].flag, edge_selection && edge_selection[i], MLOOPUV_EDGESEL);
SET_FLAG_FROM_TEST(mloopuv[i].flag, pin && pin[i], MLOOPUV_PINNED);
}
});
new_layer_to_write.append(mloopuv_layer);
}
/* #CustomData expects the layers to be sorted in increasing order based on type. */
std::stable_sort(
new_layer_to_write.begin(),
new_layer_to_write.end(),
[](const CustomDataLayer &a, const CustomDataLayer &b) { return a.type < b.type; });
loop_layers_to_write = new_layer_to_write;
mesh->ldata.totlayer = new_layer_to_write.size();
mesh->ldata.maxlayer = mesh->ldata.totlayer;
}
void BKE_mesh_legacy_convert_uvs_to_generic(Mesh *mesh)
{
using namespace blender;
@ -1918,40 +1702,6 @@ void BKE_mesh_legacy_convert_uvs_to_generic(Mesh *mesh)
/** \name Selection Attribute and Legacy Flag Conversion
* \{ */
void BKE_mesh_legacy_convert_selection_layers_to_flags(Mesh *mesh,
blender::MutableSpan<MPoly> legacy_polys)
{
using namespace blender;
using namespace blender::bke;
const AttributeAccessor attributes = mesh->attributes();
MutableSpan<MVert> verts(mesh->mvert, mesh->totvert);
const VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
".select_vert", ATTR_DOMAIN_POINT, false);
threading::parallel_for(verts.index_range(), 4096, [&](IndexRange range) {
for (const int i : range) {
SET_FLAG_FROM_TEST(verts[i].flag_legacy, select_vert[i], SELECT);
}
});
MutableSpan<MEdge> edges(mesh->medge, mesh->totedge);
const VArray<bool> select_edge = *attributes.lookup_or_default<bool>(
".select_edge", ATTR_DOMAIN_EDGE, false);
threading::parallel_for(edges.index_range(), 4096, [&](IndexRange range) {
for (const int i : range) {
SET_FLAG_FROM_TEST(edges[i].flag_legacy, select_edge[i], SELECT);
}
});
const VArray<bool> select_poly = *attributes.lookup_or_default<bool>(
".select_poly", ATTR_DOMAIN_FACE, false);
threading::parallel_for(legacy_polys.index_range(), 4096, [&](IndexRange range) {
for (const int i : range) {
SET_FLAG_FROM_TEST(legacy_polys[i].flag_legacy, select_poly[i], ME_FACE_SEL);
}
});
}
void BKE_mesh_legacy_convert_flags_to_selection_layers(Mesh *mesh)
{
using namespace blender;
@ -2013,67 +1763,16 @@ void BKE_mesh_legacy_convert_flags_to_selection_layers(Mesh *mesh)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Loose Edges
* \{ */
void BKE_mesh_legacy_convert_loose_edges_to_flag(Mesh *mesh)
{
using namespace blender;
using namespace blender::bke;
const LooseEdgeCache &loose_edges = mesh->loose_edges();
MutableSpan<MEdge> edges(mesh->medge, mesh->totedge);
threading::parallel_for(edges.index_range(), 4096, [&](const IndexRange range) {
if (loose_edges.count == 0) {
for (const int64_t i : range) {
edges[i].flag_legacy &= ~ME_LOOSEEDGE;
}
}
else {
for (const int64_t i : range) {
SET_FLAG_FROM_TEST(edges[i].flag_legacy, loose_edges.is_loose_bits[i], ME_LOOSEEDGE);
}
}
});
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Vertex and Position Conversion
* \{ */
MVert *BKE_mesh_legacy_convert_positions_to_verts(
Mesh *mesh,
blender::ResourceScope &temp_arrays_for_convert,
blender::Vector<CustomDataLayer, 16> &vert_layers_to_write)
{
using namespace blender;
const Span<float3> positions = mesh->vert_positions();
CustomDataLayer mvert_layer{};
mvert_layer.type = CD_MVERT;
MutableSpan<MVert> verts = temp_arrays_for_convert.construct<Array<MVert>>(mesh->totvert);
mvert_layer.data = verts.data();
threading::parallel_for(verts.index_range(), 2048, [&](IndexRange range) {
for (const int i : range) {
copy_v3_v3(verts[i].co_legacy, positions[i]);
}
});
vert_layers_to_write.append(mvert_layer);
return verts.data();
}
void BKE_mesh_legacy_convert_verts_to_positions(Mesh *mesh)
{
using namespace blender;
using namespace blender::bke;
const MVert *mvert = static_cast<const MVert *>(CustomData_get_layer(&mesh->vdata, CD_MVERT));
if (!mvert || CustomData_get_layer_named(&mesh->vdata, CD_PROP_FLOAT3, "position")) {
if (!mvert || CustomData_has_layer_named(&mesh->vdata, CD_PROP_FLOAT3, "position")) {
return;
}
@ -2098,37 +1797,12 @@ void BKE_mesh_legacy_convert_verts_to_positions(Mesh *mesh)
/** \name MEdge and int2 conversion
* \{ */
MEdge *BKE_mesh_legacy_convert_edges_to_medge(
Mesh *mesh,
blender::ResourceScope &temp_arrays_for_convert,
blender::Vector<CustomDataLayer, 16> &edge_layers_to_write)
{
using namespace blender;
const Span<int2> edges = mesh->edges();
CustomDataLayer medge_layer{};
medge_layer.type = CD_MEDGE;
MutableSpan<MEdge> legacy_edges = temp_arrays_for_convert.construct<Array<MEdge>>(mesh->totedge);
medge_layer.data = legacy_edges.data();
threading::parallel_for(edges.index_range(), 2048, [&](IndexRange range) {
for (const int i : range) {
legacy_edges[i] = {};
legacy_edges[i].v1 = edges[i][0];
legacy_edges[i].v2 = edges[i][1];
}
});
edge_layers_to_write.append(medge_layer);
return legacy_edges.data();
}
void BKE_mesh_legacy_convert_edges_to_generic(Mesh *mesh)
{
using namespace blender;
using namespace blender::bke;
const MEdge *medge = static_cast<const MEdge *>(CustomData_get_layer(&mesh->edata, CD_MEDGE));
if (!medge || CustomData_get_layer_named(&mesh->edata, CD_PROP_INT32_2D, ".edge_verts")) {
if (!medge || CustomData_has_layer_named(&mesh->edata, CD_PROP_INT32_2D, ".edge_verts")) {
return;
}
@ -2217,95 +1891,17 @@ void BKE_mesh_legacy_attribute_flags_to_strings(Mesh *mesh)
default_from_indices(mesh->ldata);
}
void BKE_mesh_legacy_attribute_strings_to_flags(Mesh *mesh)
{
using namespace blender;
CustomData *vdata = &mesh->vdata;
CustomData *ldata = &mesh->ldata;
CustomData_clear_layer_flag(
vdata, CD_PROP_BYTE_COLOR, CD_FLAG_COLOR_ACTIVE | CD_FLAG_COLOR_RENDER);
CustomData_clear_layer_flag(
ldata, CD_PROP_BYTE_COLOR, CD_FLAG_COLOR_ACTIVE | CD_FLAG_COLOR_RENDER);
CustomData_clear_layer_flag(ldata, CD_PROP_COLOR, CD_FLAG_COLOR_ACTIVE | CD_FLAG_COLOR_RENDER);
CustomData_clear_layer_flag(vdata, CD_PROP_COLOR, CD_FLAG_COLOR_ACTIVE | CD_FLAG_COLOR_RENDER);
if (const char *name = mesh->active_color_attribute) {
int i;
if ((i = CustomData_get_named_layer_index(vdata, CD_PROP_BYTE_COLOR, name)) != -1) {
CustomData_set_layer_active_index(vdata, CD_PROP_BYTE_COLOR, i);
vdata->layers[i].flag |= CD_FLAG_COLOR_ACTIVE;
}
else if ((i = CustomData_get_named_layer_index(vdata, CD_PROP_COLOR, name)) != -1) {
CustomData_set_layer_active_index(vdata, CD_PROP_COLOR, i);
vdata->layers[i].flag |= CD_FLAG_COLOR_ACTIVE;
}
else if ((i = CustomData_get_named_layer_index(ldata, CD_PROP_BYTE_COLOR, name)) != -1) {
CustomData_set_layer_active_index(ldata, CD_PROP_BYTE_COLOR, i);
ldata->layers[i].flag |= CD_FLAG_COLOR_ACTIVE;
}
else if ((i = CustomData_get_named_layer_index(ldata, CD_PROP_COLOR, name)) != -1) {
CustomData_set_layer_active_index(ldata, CD_PROP_COLOR, i);
ldata->layers[i].flag |= CD_FLAG_COLOR_ACTIVE;
}
}
if (const char *name = mesh->default_color_attribute) {
int i;
if ((i = CustomData_get_named_layer_index(vdata, CD_PROP_BYTE_COLOR, name)) != -1) {
CustomData_set_layer_render_index(vdata, CD_PROP_BYTE_COLOR, i);
vdata->layers[i].flag |= CD_FLAG_COLOR_RENDER;
}
else if ((i = CustomData_get_named_layer_index(vdata, CD_PROP_COLOR, name)) != -1) {
CustomData_set_layer_render_index(vdata, CD_PROP_COLOR, i);
vdata->layers[i].flag |= CD_FLAG_COLOR_RENDER;
}
else if ((i = CustomData_get_named_layer_index(ldata, CD_PROP_BYTE_COLOR, name)) != -1) {
CustomData_set_layer_render_index(ldata, CD_PROP_BYTE_COLOR, i);
ldata->layers[i].flag |= CD_FLAG_COLOR_RENDER;
}
else if ((i = CustomData_get_named_layer_index(ldata, CD_PROP_COLOR, name)) != -1) {
CustomData_set_layer_render_index(ldata, CD_PROP_COLOR, i);
ldata->layers[i].flag |= CD_FLAG_COLOR_RENDER;
}
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Face Corner Conversion
* \{ */
MLoop *BKE_mesh_legacy_convert_corners_to_loops(
Mesh *mesh,
blender::ResourceScope &temp_arrays_for_convert,
blender::Vector<CustomDataLayer, 16> &loop_layers_to_write)
{
using namespace blender;
const Span<int> corner_verts = mesh->corner_verts();
const Span<int> corner_edges = mesh->corner_edges();
CustomDataLayer mloop_layer{};
mloop_layer.type = CD_MLOOP;
MutableSpan<MLoop> loops = temp_arrays_for_convert.construct<Array<MLoop>>(mesh->totloop);
mloop_layer.data = loops.data();
threading::parallel_for(loops.index_range(), 2048, [&](IndexRange range) {
for (const int i : range) {
loops[i].v = corner_verts[i];
loops[i].e = corner_edges[i];
}
});
loop_layers_to_write.append(mloop_layer);
return loops.data();
}
void BKE_mesh_legacy_convert_loops_to_corners(Mesh *mesh)
{
using namespace blender;
if (CustomData_get_layer_named(&mesh->ldata, CD_PROP_INT32, ".corner_vert") &&
CustomData_get_layer_named(&mesh->ldata, CD_PROP_INT32, ".corner_edge"))
if (CustomData_has_layer_named(&mesh->ldata, CD_PROP_INT32, ".corner_vert") &&
CustomData_has_layer_named(&mesh->ldata, CD_PROP_INT32, ".corner_edge"))
{
return;
}
@ -2335,30 +1931,6 @@ void BKE_mesh_legacy_convert_loops_to_corners(Mesh *mesh)
/** \name Poly Offset Conversion
* \{ */
blender::MutableSpan<MPoly> BKE_mesh_legacy_convert_offsets_to_polys(
const Mesh *mesh,
blender::ResourceScope &temp_arrays_for_convert,
blender::Vector<CustomDataLayer, 16> &poly_layers_to_write)
{
using namespace blender;
const OffsetIndices polys = mesh->polys();
MutableSpan<MPoly> polys_legacy = temp_arrays_for_convert.construct<Array<MPoly>>(mesh->totpoly);
threading::parallel_for(polys_legacy.index_range(), 2048, [&](IndexRange range) {
for (const int i : range) {
polys_legacy[i].loopstart = polys[i].start();
polys_legacy[i].totloop = polys[i].size();
}
});
CustomDataLayer layer{};
layer.type = CD_MPOLY;
layer.data = polys_legacy.data();
poly_layers_to_write.append(layer);
return polys_legacy;
}
static bool poly_loops_orders_match(const Span<MPoly> polys)
{
for (const int i : polys.index_range().drop_back(1)) {

View File

@ -190,7 +190,7 @@ void Mesh::tag_loose_verts_none() const
try_tag_verts_no_face_none(*this);
}
void Mesh::loose_edges_tag_none() const
void Mesh::tag_loose_edges_none() const
{
using namespace blender::bke;
this->runtime->loose_edges_cache.ensure([&](LooseEdgeCache &r_data) {
@ -314,9 +314,21 @@ void BKE_mesh_tag_edges_split(struct Mesh *mesh)
free_bvh_cache(*mesh->runtime);
reset_normals(*mesh->runtime);
free_subdiv_ccg(*mesh->runtime);
mesh->runtime->loose_edges_cache.tag_dirty();
mesh->runtime->loose_verts_cache.tag_dirty();
mesh->runtime->verts_no_face_cache.tag_dirty();
if (mesh->runtime->loose_edges_cache.is_cached() &&
mesh->runtime->loose_edges_cache.data().count != 0)
{
mesh->runtime->loose_edges_cache.tag_dirty();
}
if (mesh->runtime->loose_verts_cache.is_cached() &&
mesh->runtime->loose_verts_cache.data().count != 0)
{
mesh->runtime->loose_verts_cache.tag_dirty();
}
if (mesh->runtime->verts_no_face_cache.is_cached() &&
mesh->runtime->verts_no_face_cache.data().count != 0)
{
mesh->runtime->verts_no_face_cache.tag_dirty();
}
mesh->runtime->subsurf_face_dot_tags.clear_and_shrink();
mesh->runtime->subsurf_optimal_display_edges.clear_and_shrink();
if (mesh->runtime->shrinkwrap_data) {

View File

@ -32,6 +32,24 @@ BLI_NOINLINE static void sample_point_attribute(const Span<int> corner_verts,
}
}
void sample_point_normals(const Span<int> corner_verts,
const Span<MLoopTri> looptris,
const Span<int> looptri_indices,
const Span<float3> bary_coords,
const Span<float3> src,
const IndexMask mask,
const MutableSpan<float3> dst)
{
for (const int i : mask) {
const MLoopTri &tri = looptris[looptri_indices[i]];
const float3 value = attribute_math::mix3(bary_coords[i],
src[corner_verts[tri.tri[0]]],
src[corner_verts[tri.tri[1]]],
src[corner_verts[tri.tri[2]]]);
dst[i] = math::normalize(value);
}
}
void sample_point_attribute(const Span<int> corner_verts,
const Span<MLoopTri> looptris,
const Span<int> looptri_indices,

View File

@ -71,10 +71,6 @@
#include "tracking_private.h"
/* Convert camera object to legacy format where the camera tracks are stored in the MovieTracking
* structure when saving .blend file. */
#define USE_LEGACY_CAMERA_OBJECT_FORMAT_ON_SAVE 1
static void free_buffers(MovieClip *clip);
static void movie_clip_init_data(ID *id)
@ -200,39 +196,6 @@ static void movieclip_blend_write(BlendWriter *writer, ID *id, const void *id_ad
MovieTracking *tracking = &clip->tracking;
#if USE_LEGACY_CAMERA_OBJECT_FORMAT_ON_SAVE
const bool is_undo = BLO_write_is_undo(writer);
/* When using legacy format for camera object assign the list of camera tracks to the
* MovieTracking object. Do it in-place as it simplifies the code a bit, and it is not
* supposed to cause threading issues as no other code is meant to access the legacy fields. */
if (!is_undo) {
MovieTrackingObject *active_tracking_object = BKE_tracking_object_get_active(tracking);
MovieTrackingObject *tracking_camera_object = BKE_tracking_object_get_camera(tracking);
BLI_assert(active_tracking_object != NULL);
BLI_assert(tracking_camera_object != NULL);
tracking->tracks_legacy = tracking_camera_object->tracks;
tracking->plane_tracks_legacy = tracking_camera_object->plane_tracks;
/* The active track in the tracking structure used to be shared across all tracking objects. */
tracking->act_track_legacy = active_tracking_object->active_track;
tracking->act_plane_track_legacy = active_tracking_object->active_plane_track;
tracking->reconstruction_legacy = tracking_camera_object->reconstruction;
}
#endif
/* Assign the pixel-space principal point for forward compatibility. */
/* TODO(sergey): Remove with the next major version update when forward compatibility is allowed
* to be broken. */
if (!is_undo && clip->lastsize[0] != 0 && clip->lastsize[1] != 0) {
tracking_principal_point_normalized_to_pixel(tracking->camera.principal_point,
clip->lastsize[0],
clip->lastsize[1],
tracking->camera.principal_legacy);
}
BLO_write_id_struct(writer, MovieClip, id_address, &clip->id);
BKE_id_blend_write(writer, &clip->id);
@ -241,39 +204,11 @@ static void movieclip_blend_write(BlendWriter *writer, ID *id, const void *id_ad
}
LISTBASE_FOREACH (MovieTrackingObject *, object, &tracking->objects) {
#if USE_LEGACY_CAMERA_OBJECT_FORMAT_ON_SAVE
/* When saving cameras object in the legacy format clear the list of tracks. This is because
* the tracking object code is generic and assumes object owns the tracks in the list. For the
* camera tracks that is not the case in the legacy format. */
if (!is_undo && (object->flag & TRACKING_OBJECT_CAMERA)) {
MovieTrackingObject legacy_object = *object;
BLI_listbase_clear(&legacy_object.tracks);
BLI_listbase_clear(&legacy_object.plane_tracks);
legacy_object.active_track = NULL;
legacy_object.active_plane_track = NULL;
memset(&legacy_object.reconstruction, 0, sizeof(legacy_object.reconstruction));
BLO_write_struct_at_address(writer, MovieTrackingObject, object, &legacy_object);
}
else
#endif
{
BLO_write_struct(writer, MovieTrackingObject, object);
}
BLO_write_struct(writer, MovieTrackingObject, object);
write_movieTracks(writer, &object->tracks);
write_moviePlaneTracks(writer, &object->plane_tracks);
write_movieReconstruction(writer, &object->reconstruction);
}
#if USE_LEGACY_CAMERA_OBJECT_FORMAT_ON_SAVE
if (!is_undo) {
BLI_listbase_clear(&tracking->tracks_legacy);
BLI_listbase_clear(&tracking->plane_tracks_legacy);
tracking->act_track_legacy = NULL;
tracking->act_plane_track_legacy = NULL;
memset(&tracking->reconstruction_legacy, 0, sizeof(tracking->reconstruction_legacy));
}
#endif
}
static void direct_link_movieReconstruction(BlendDataReader *reader,
@ -613,11 +548,9 @@ void BKE_movieclip_convert_multilayer_ibuf(struct ImBuf *ibuf)
movieclip_convert_multilayer_add_layer,
movieclip_convert_multilayer_add_pass);
if (ctx.combined_pass != NULL) {
BLI_assert(ibuf->rect_float == NULL);
ibuf->rect_float = ctx.combined_pass;
BLI_assert(ibuf->float_buffer.data == NULL);
IMB_assign_float_buffer(ibuf, ctx.combined_pass, IB_TAKE_OWNERSHIP);
ibuf->channels = ctx.num_combined_channels;
ibuf->flags |= IB_rectfloat;
ibuf->mall |= IB_rectfloat;
}
IMB_exr_close(ibuf->userdata);
ibuf->userdata = NULL;
@ -1797,7 +1730,7 @@ void BKE_movieclip_update_scopes(MovieClip *clip,
scopes->track_disabled = false;
if (ibuf && (ibuf->rect || ibuf->rect_float)) {
if (ibuf && (ibuf->byte_buffer.data || ibuf->float_buffer.data)) {
MovieTrackingMarker undist_marker = *marker;
if (user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
@ -2114,7 +2047,7 @@ GPUTexture *BKE_movieclip_get_gpu_texture(MovieClip *clip, MovieClipUser *cuser)
/* This only means RGBA16F instead of RGBA32F. */
const bool high_bitdepth = false;
const bool store_premultiplied = ibuf->rect_float ? false : true;
const bool store_premultiplied = ibuf->float_buffer.data ? false : true;
*tex = IMB_create_gpu_texture(clip->id.name + 2, ibuf, high_bitdepth, store_premultiplied);
/* Do not generate mips for movieclips... too slow. */

View File

@ -822,18 +822,15 @@ static void foreach_edge(const SubdivForeachContext *foreach_context,
return;
}
/* Ignore all inner face edges as they have sharpness of zero when using Catmull-Clark mode. In
* simple mode, all edges have maximum sharpness, so they can't be skipped. */
if (coarse_edge_index == ORIGINDEX_NONE &&
reshape_smooth_context->smoothing_type != MULTIRES_SUBDIVIDE_SIMPLE)
{
/* Ignore all inner face edges as they have sharpness of zero. */
if (coarse_edge_index == ORIGINDEX_NONE) {
return;
}
/* Ignore all loose edges as well, as they are not communicated to the OpenSubdiv. */
if (!reshape_smooth_context->loose_base_edges.is_empty() &&
reshape_smooth_context->loose_base_edges[coarse_edge_index])
{
return;
if (!reshape_smooth_context->loose_base_edges.is_empty()) {
if (reshape_smooth_context->loose_base_edges[coarse_edge_index]) {
return;
}
}
/* Edges without crease are to be ignored as well. */
const float crease = get_effective_crease(reshape_smooth_context, coarse_edge_index);

View File

@ -1352,6 +1352,7 @@ namespace blender::bke {
static GHash *nodetreetypes_hash = nullptr;
static GHash *nodetypes_hash = nullptr;
static GHash *nodetypes_alias_hash = nullptr;
static GHash *nodesockettypes_hash = nullptr;
} // namespace blender::bke
@ -1416,6 +1417,19 @@ bNodeType *nodeTypeFind(const char *idname)
return nullptr;
}
const char *nodeTypeFindAlias(const char *alias)
{
if (alias[0]) {
const char *idname = static_cast<const char *>(
BLI_ghash_lookup(blender::bke::nodetypes_alias_hash, alias));
if (idname) {
return idname;
}
}
return alias;
}
static void node_free_type(void *nodetype_v)
{
bNodeType *nodetype = static_cast<bNodeType *>(nodetype_v);
@ -1458,6 +1472,11 @@ void nodeUnregisterType(bNodeType *nt)
BLI_ghash_remove(blender::bke::nodetypes_hash, nt->idname, nullptr, node_free_type);
}
void nodeRegisterAlias(bNodeType *nt, const char *alias)
{
BLI_ghash_insert(blender::bke::nodetypes_alias_hash, BLI_strdup(alias), BLI_strdup(nt->idname));
}
namespace blender::bke {
bool node_type_is_undefined(const bNode *node)
@ -4389,6 +4408,7 @@ void BKE_node_system_init()
{
blender::bke::nodetreetypes_hash = BLI_ghash_str_new("nodetreetypes_hash gh");
blender::bke::nodetypes_hash = BLI_ghash_str_new("nodetypes_hash gh");
blender::bke::nodetypes_alias_hash = BLI_ghash_str_new("nodetypes_alias_hash gh");
blender::bke::nodesockettypes_hash = BLI_ghash_str_new("nodesockettypes_hash gh");
register_nodes();
@ -4396,6 +4416,11 @@ void BKE_node_system_init()
void BKE_node_system_exit()
{
if (blender::bke::nodetypes_alias_hash) {
BLI_ghash_free(blender::bke::nodetypes_alias_hash, MEM_freeN, MEM_freeN);
blender::bke::nodetypes_alias_hash = nullptr;
}
if (blender::bke::nodetypes_hash) {
NODE_TYPES_BEGIN (nt) {
if (nt->rna_ext.free) {

View File

@ -267,6 +267,9 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in
if (ob_src->lightgroup) {
ob_dst->lightgroup = (LightgroupMembership *)MEM_dupallocN(ob_src->lightgroup);
}
if (ob_src->light_linking) {
ob_dst->light_linking = (LightLinking *)MEM_dupallocN(ob_src->light_linking);
}
if ((flag & LIB_ID_COPY_SET_COPIED_ON_WRITE) != 0) {
if (ob_src->lightprobe_cache) {
@ -331,6 +334,7 @@ static void object_free_data(ID *id)
BKE_previewimg_free(&ob->preview);
MEM_SAFE_FREE(ob->lightgroup);
MEM_SAFE_FREE(ob->light_linking);
BKE_lightprobe_cache_free(ob);
}
@ -470,10 +474,12 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data)
}
}
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, object->light_linking.receiver_collection, IDWALK_CB_USER);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, object->light_linking.blocker_collection, IDWALK_CB_USER);
if (object->light_linking) {
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, object->light_linking->receiver_collection, IDWALK_CB_USER);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, object->light_linking->blocker_collection, IDWALK_CB_USER);
}
}
static void object_foreach_path_pointcache(ListBase *ptcache_list,
@ -616,6 +622,9 @@ static void object_blend_write(BlendWriter *writer, ID *id, const void *id_addre
if (ob->lightgroup) {
BLO_write_struct(writer, LightgroupMembership, ob->lightgroup);
}
if (ob->light_linking) {
BLO_write_struct(writer, LightgroupMembership, ob->light_linking);
}
if (ob->lightprobe_cache) {
BLO_write_struct(writer, LightProbeObjectCache, ob->lightprobe_cache);
@ -839,6 +848,7 @@ static void object_blend_read_data(BlendDataReader *reader, ID *id)
BKE_previewimg_blend_read(reader, ob->preview);
BLO_read_data_address(reader, &ob->lightgroup);
BLO_read_data_address(reader, &ob->light_linking);
BLO_read_data_address(reader, &ob->lightprobe_cache);
if (ob->lightprobe_cache) {
@ -1040,8 +1050,10 @@ static void object_blend_read_lib(BlendLibReader *reader, ID *id)
BLO_read_id_address(reader, id, &ob->rigidbody_constraint->ob2);
}
BLO_read_id_address(reader, id, &ob->light_linking.receiver_collection);
BLO_read_id_address(reader, id, &ob->light_linking.blocker_collection);
if (ob->light_linking) {
BLO_read_id_address(reader, id, &ob->light_linking->receiver_collection);
BLO_read_id_address(reader, id, &ob->light_linking->blocker_collection);
}
}
/* XXX deprecated - old animation system */
@ -1160,8 +1172,10 @@ static void object_blend_read_expand(BlendExpander *expander, ID *id)
}
/* Light and shadow linking. */
BLO_expand(expander, ob->light_linking.receiver_collection);
BLO_expand(expander, ob->light_linking.blocker_collection);
if (ob->light_linking) {
BLO_expand(expander, ob->light_linking->receiver_collection);
BLO_expand(expander, ob->light_linking->blocker_collection);
}
}
static void object_lib_override_apply_post(ID *id_dst, ID *id_src)

View File

@ -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);

View File

@ -1286,23 +1286,23 @@ void BKE_ocean_cache_eval_ij(struct OceanCache *och, struct OceanResult *ocr, in
j = j % res_y;
if (och->ibufs_disp[f]) {
copy_v3_v3(ocr->disp, &och->ibufs_disp[f]->rect_float[4 * (res_x * j + i)]);
copy_v3_v3(ocr->disp, &och->ibufs_disp[f]->float_buffer.data[4 * (res_x * j + i)]);
}
if (och->ibufs_foam[f]) {
ocr->foam = och->ibufs_foam[f]->rect_float[4 * (res_x * j + i)];
ocr->foam = och->ibufs_foam[f]->float_buffer.data[4 * (res_x * j + i)];
}
if (och->ibufs_spray[f]) {
copy_v3_v3(ocr->Eplus, &och->ibufs_spray[f]->rect_float[4 * (res_x * j + i)]);
copy_v3_v3(ocr->Eplus, &och->ibufs_spray[f]->float_buffer.data[4 * (res_x * j + i)]);
}
if (och->ibufs_spray_inverse[f]) {
copy_v3_v3(ocr->Eminus, &och->ibufs_spray_inverse[f]->rect_float[4 * (res_x * j + i)]);
copy_v3_v3(ocr->Eminus, &och->ibufs_spray_inverse[f]->float_buffer.data[4 * (res_x * j + i)]);
}
if (och->ibufs_norm[f]) {
copy_v3_v3(ocr->normal, &och->ibufs_norm[f]->rect_float[4 * (res_x * j + i)]);
copy_v3_v3(ocr->normal, &och->ibufs_norm[f]->float_buffer.data[4 * (res_x * j + i)]);
}
}
@ -1435,7 +1435,7 @@ void BKE_ocean_bake(struct Ocean *o,
BKE_ocean_eval_ij(o, &ocr, x, y);
/* add to the image */
rgb_to_rgba_unit_alpha(&ibuf_disp->rect_float[4 * (res_x * y + x)], ocr.disp);
rgb_to_rgba_unit_alpha(&ibuf_disp->float_buffer.data[4 * (res_x * y + x)], ocr.disp);
if (o->_do_jacobian) {
/* TODO(@ideasman42): cleanup unused code. */
@ -1478,18 +1478,19 @@ void BKE_ocean_bake(struct Ocean *o,
// foam_result = min_ff(foam_result, 1.0f);
value_to_rgba_unit_alpha(&ibuf_foam->rect_float[4 * (res_x * y + x)], foam_result);
value_to_rgba_unit_alpha(&ibuf_foam->float_buffer.data[4 * (res_x * y + x)],
foam_result);
/* spray map baking */
if (o->_do_spray) {
rgb_to_rgba_unit_alpha(&ibuf_spray->rect_float[4 * (res_x * y + x)], ocr.Eplus);
rgb_to_rgba_unit_alpha(&ibuf_spray_inverse->rect_float[4 * (res_x * y + x)],
rgb_to_rgba_unit_alpha(&ibuf_spray->float_buffer.data[4 * (res_x * y + x)], ocr.Eplus);
rgb_to_rgba_unit_alpha(&ibuf_spray_inverse->float_buffer.data[4 * (res_x * y + x)],
ocr.Eminus);
}
}
if (o->_do_normals) {
rgb_to_rgba_unit_alpha(&ibuf_normal->rect_float[4 * (res_x * y + x)], ocr.normal);
rgb_to_rgba_unit_alpha(&ibuf_normal->float_buffer.data[4 * (res_x * y + x)], ocr.normal);
}
}
}

View File

@ -637,12 +637,11 @@ static void apply_watertight_check(PBVH *pbvh, Image *image, ImageUser *image_us
int pixel_offset = pixel_row.start_image_coordinate.y * image_buffer->x +
pixel_row.start_image_coordinate.x;
for (int x = 0; x < pixel_row.num_pixels; x++) {
if (image_buffer->rect_float) {
copy_v4_fl(&image_buffer->rect_float[pixel_offset * 4], 1.0);
if (image_buffer->float_buffer.data) {
copy_v4_fl(&image_buffer->float_buffer.data[pixel_offset * 4], 1.0);
}
if (image_buffer->rect) {
uint8_t *dest = static_cast<uint8_t *>(
static_cast<void *>(&image_buffer->rect[pixel_offset]));
if (image_buffer->byte_buffer.data) {
uint8_t *dest = &image_buffer->byte_buffer.data[pixel_offset * 4];
copy_v4_uchar(dest, 255);
}
pixel_offset += 1;

View File

@ -484,7 +484,7 @@ static void studiolight_create_equirect_radiance_gputexture(StudioLight *sl)
1,
GPU_RGBA16F,
GPU_TEXTURE_USAGE_SHADER_READ,
ibuf->rect_float);
ibuf->float_buffer.data);
GPUTexture *tex = sl->equirect_radiance_gputexture;
GPU_texture_filter_mode(tex, true);
GPU_texture_extend_mode(tex, GPU_SAMPLER_EXTEND_MODE_REPEAT);
@ -498,7 +498,7 @@ static void studiolight_create_matcap_gputexture(StudioLightImage *sli)
ImBuf *ibuf = sli->ibuf;
float *gpu_matcap_3components = MEM_callocN(sizeof(float[3]) * ibuf->x * ibuf->y, __func__);
const float(*offset4)[4] = (const float(*)[4])ibuf->rect_float;
const float(*offset4)[4] = (const float(*)[4])ibuf->float_buffer.data;
float(*offset3)[3] = (float(*)[3])gpu_matcap_3components;
for (int i = 0; i < ibuf->x * ibuf->y; i++, offset4++, offset3++) {
copy_v3_v3(*offset3, *offset4);
@ -545,7 +545,7 @@ static void studiolight_create_equirect_irradiance_gputexture(StudioLight *sl)
1,
GPU_RGBA16F,
GPU_TEXTURE_USAGE_SHADER_READ,
ibuf->rect_float);
ibuf->float_buffer.data);
GPUTexture *tex = sl->equirect_irradiance_gputexture;
GPU_texture_filter_mode(tex, true);
GPU_texture_extend_mode(tex, GPU_SAMPLER_EXTEND_MODE_REPEAT);
@ -681,7 +681,7 @@ static void studiolight_spherical_harmonics_calculate_coefficients(StudioLight *
for (int face = 0; face < 6; face++) {
ITER_PIXELS (float,
sl->radiance_cubemap_buffers[face]->rect_float,
sl->radiance_cubemap_buffers[face]->float_buffer.data,
4,
STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE,
STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE)
@ -976,7 +976,7 @@ BLI_INLINE void studiolight_evaluate_specular_radiance_buffer(ImBuf *radiance_bu
float accum[3] = {0.0f, 0.0f, 0.0f};
float accum_weight = 0.00001f;
ITER_PIXELS (float,
radiance_buffer->rect_float,
radiance_buffer->float_buffer.data,
4,
STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE,
STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE)

Some files were not shown because too many files have changed in this diff Show More