Refactor: change light linking object storage be dynamically allocated #108090
|
@ -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",
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -209,6 +209,21 @@ enum_guiding_distribution = (
|
|||
('VMM', "VMM", "Use von Mises-Fisher models as directional distribution", 2),
|
||||
)
|
||||
|
||||
enum_guiding_directional_sampling_types = (
|
||||
('MIS',
|
||||
"Diffuse Product MIS",
|
||||
"Guided diffuse BSDF component based on the incoming light distribution and the cosine product (closed form product)",
|
||||
0),
|
||||
('RIS',
|
||||
"Re-sampled Importance Sampling",
|
||||
"Perform RIS sampling to guided based on the product of the incoming light distribution and the BSDF",
|
||||
1),
|
||||
('ROUGHNESS',
|
||||
"Roughness-based",
|
||||
"Adjust the guiding probability based on the roughness of the material components",
|
||||
2),
|
||||
)
|
||||
|
||||
|
||||
def enum_openimagedenoise_denoiser(self, context):
|
||||
import _cycles
|
||||
|
@ -568,6 +583,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
|||
default='PARALLAX_AWARE_VMM',
|
||||
)
|
||||
|
||||
guiding_directional_sampling_type: EnumProperty(
|
||||
name="Directional Sampling Type",
|
||||
description="Type of the directional sampling used for guiding",
|
||||
items=enum_guiding_directional_sampling_types,
|
||||
default='RIS',
|
||||
)
|
||||
|
||||
use_surface_guiding: BoolProperty(
|
||||
name="Surface Guiding",
|
||||
description="Use guiding when sampling directions on a surface",
|
||||
|
@ -617,6 +639,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
|||
default=True,
|
||||
)
|
||||
|
||||
guiding_roughness_threshold: FloatProperty(
|
||||
name="Guiding Roughness Threshold",
|
||||
description="The minimal roughness value of a material to apply guiding",
|
||||
min=0.0, max=1.0,
|
||||
default=0.05,
|
||||
)
|
||||
|
||||
max_bounces: IntProperty(
|
||||
name="Max Bounces",
|
||||
description="Total maximum number of bounces",
|
||||
|
|
|
@ -337,6 +337,8 @@ class CYCLES_RENDER_PT_sampling_path_guiding_debug(CyclesDebugButtonsPanel, Pane
|
|||
layout.active = cscene.use_guiding
|
||||
|
||||
layout.prop(cscene, "guiding_distribution_type", text="Distribution Type")
|
||||
layout.prop(cscene, "guiding_roughness_threshold")
|
||||
layout.prop(cscene, "guiding_directional_sampling_type", text="Directional Sampling Type")
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(cscene, "surface_guiding_probability")
|
||||
|
|
|
@ -30,6 +30,25 @@ int blender_device_threads(BL::Scene &b_scene)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void adjust_device_info_from_preferences(DeviceInfo &info, PointerRNA cpreferences)
|
||||
{
|
||||
if (!get_boolean(cpreferences, "peer_memory")) {
|
||||
info.has_peer_memory = false;
|
||||
}
|
||||
|
||||
if (info.type == DEVICE_METAL && !get_boolean(cpreferences, "use_metalrt")) {
|
||||
info.use_hardware_raytracing = false;
|
||||
}
|
||||
|
||||
if (info.type == DEVICE_ONEAPI && !get_boolean(cpreferences, "use_oneapirt")) {
|
||||
info.use_hardware_raytracing = false;
|
||||
}
|
||||
|
||||
if (info.type == DEVICE_HIP && !get_boolean(cpreferences, "use_hiprt")) {
|
||||
info.use_hardware_raytracing = false;
|
||||
}
|
||||
}
|
||||
|
||||
DeviceInfo blender_device_info(BL::Preferences &b_preferences,
|
||||
BL::Scene &b_scene,
|
||||
bool background,
|
||||
|
@ -108,35 +127,17 @@ DeviceInfo blender_device_info(BL::Preferences &b_preferences,
|
|||
}
|
||||
}
|
||||
|
||||
if (!get_boolean(cpreferences, "peer_memory")) {
|
||||
device.has_peer_memory = false;
|
||||
}
|
||||
adjust_device_info_from_preferences(device, cpreferences);
|
||||
foreach (DeviceInfo &info, device.multi_devices) {
|
||||
adjust_device_info_from_preferences(info, cpreferences);
|
||||
|
||||
bool accumulated_use_hardware_raytracing = false;
|
||||
foreach (
|
||||
DeviceInfo &info,
|
||||
(device.multi_devices.size() != 0 ? device.multi_devices : vector<DeviceInfo>({device})))
|
||||
{
|
||||
if (info.type == DEVICE_METAL && !get_boolean(cpreferences, "use_metalrt")) {
|
||||
info.use_hardware_raytracing = false;
|
||||
}
|
||||
|
||||
if (info.type == DEVICE_ONEAPI && !get_boolean(cpreferences, "use_oneapirt")) {
|
||||
info.use_hardware_raytracing = false;
|
||||
}
|
||||
|
||||
if (info.type == DEVICE_HIP && !get_boolean(cpreferences, "use_hiprt")) {
|
||||
info.use_hardware_raytracing = false;
|
||||
}
|
||||
|
||||
/* There is an accumulative logic here, because Multi-devices are support only for
|
||||
/* There is an accumulative logic here, because Multi-devices are supported only for
|
||||
* the same backend + CPU in Blender right now, and both oneAPI and Metal have a
|
||||
* global boolean backend setting (see above) for enabling/disabling HW RT,
|
||||
* so all sub-devices in the multi-device should enable (or disable) HW RT
|
||||
* simultaneously (and CPU device are expected to ignore `use_hardware_raytracing` setting). */
|
||||
accumulated_use_hardware_raytracing |= info.use_hardware_raytracing;
|
||||
* global boolean backend setting for enabling/disabling Hardware Ray Tracing,
|
||||
* so all sub-devices in the multi-device should enable (or disable) Hardware Ray Tracing
|
||||
* simultaneously (and CPU device is expected to ignore `use_hardware_raytracing` setting). */
|
||||
device.use_hardware_raytracing |= info.use_hardware_raytracing;
|
||||
}
|
||||
device.use_hardware_raytracing = accumulated_use_hardware_raytracing;
|
||||
|
||||
if (preview) {
|
||||
/* Disable specialization for preview renders. */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -440,6 +440,13 @@ void BlenderSync::sync_integrator(BL::ViewLayer &b_view_layer, bool background)
|
|||
GuidingDistributionType guiding_distribution_type = (GuidingDistributionType)get_enum(
|
||||
cscene, "guiding_distribution_type", GUIDING_NUM_TYPES, GUIDING_TYPE_PARALLAX_AWARE_VMM);
|
||||
integrator->set_guiding_distribution_type(guiding_distribution_type);
|
||||
GuidingDirectionalSamplingType guiding_directional_sampling_type =
|
||||
(GuidingDirectionalSamplingType)get_enum(cscene,
|
||||
"guiding_directional_sampling_type",
|
||||
GUIDING_DIRECTIONAL_SAMPLING_NUM_TYPES,
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS);
|
||||
integrator->set_guiding_directional_sampling_type(guiding_directional_sampling_type);
|
||||
integrator->set_guiding_roughness_threshold(get_float(cscene, "guiding_roughness_threshold"));
|
||||
}
|
||||
|
||||
DenoiseParams denoise_params = get_denoise_params(b_scene, b_view_layer, background);
|
||||
|
|
|
@ -33,12 +33,16 @@ const char *bvh_layout_name(BVHLayout layout)
|
|||
return "METAL";
|
||||
case BVH_LAYOUT_HIPRT:
|
||||
return "HIPRT";
|
||||
case BVH_LAYOUT_EMBREEGPU:
|
||||
return "EMBREEGPU";
|
||||
case BVH_LAYOUT_MULTI_OPTIX:
|
||||
case BVH_LAYOUT_MULTI_METAL:
|
||||
case BVH_LAYOUT_MULTI_HIPRT:
|
||||
case BVH_LAYOUT_MULTI_EMBREEGPU:
|
||||
case BVH_LAYOUT_MULTI_OPTIX_EMBREE:
|
||||
case BVH_LAYOUT_MULTI_METAL_EMBREE:
|
||||
case BVH_LAYOUT_MULTI_HIPRT_EMBREE:
|
||||
case BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE:
|
||||
return "MULTI";
|
||||
case BVH_LAYOUT_ALL:
|
||||
return "ALL";
|
||||
|
@ -88,6 +92,7 @@ BVH *BVH::create(const BVHParams ¶ms,
|
|||
case BVH_LAYOUT_BVH2:
|
||||
return new BVH2(params, geometry, objects);
|
||||
case BVH_LAYOUT_EMBREE:
|
||||
case BVH_LAYOUT_EMBREEGPU:
|
||||
#ifdef WITH_EMBREE
|
||||
return new BVHEmbree(params, geometry, objects);
|
||||
#else
|
||||
|
@ -117,9 +122,11 @@ BVH *BVH::create(const BVHParams ¶ms,
|
|||
case BVH_LAYOUT_MULTI_OPTIX:
|
||||
case BVH_LAYOUT_MULTI_METAL:
|
||||
case BVH_LAYOUT_MULTI_HIPRT:
|
||||
case BVH_LAYOUT_MULTI_EMBREEGPU:
|
||||
case BVH_LAYOUT_MULTI_OPTIX_EMBREE:
|
||||
case BVH_LAYOUT_MULTI_METAL_EMBREE:
|
||||
case BVH_LAYOUT_MULTI_HIPRT_EMBREE:
|
||||
case BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE:
|
||||
return new BVHMulti(params, geometry, objects);
|
||||
case BVH_LAYOUT_NONE:
|
||||
case BVH_LAYOUT_ALL:
|
||||
|
|
|
@ -265,7 +265,8 @@ void CPUDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
|
|||
#ifdef WITH_EMBREE
|
||||
if (bvh->params.bvh_layout == BVH_LAYOUT_EMBREE ||
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE ||
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL_EMBREE)
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL_EMBREE ||
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE)
|
||||
{
|
||||
BVHEmbree *const bvh_embree = static_cast<BVHEmbree *>(bvh);
|
||||
if (refit) {
|
||||
|
|
|
@ -122,6 +122,11 @@ class MultiDevice : public Device {
|
|||
return BVH_LAYOUT_MULTI_HIPRT;
|
||||
}
|
||||
|
||||
/* With multiple oneAPI devices, every device needs its own acceleration structure */
|
||||
if (bvh_layout_mask == BVH_LAYOUT_EMBREEGPU) {
|
||||
return BVH_LAYOUT_MULTI_EMBREEGPU;
|
||||
}
|
||||
|
||||
/* When devices do not share a common BVH layout, fall back to creating one for each */
|
||||
const BVHLayoutMask BVH_LAYOUT_OPTIX_EMBREE = (BVH_LAYOUT_OPTIX | BVH_LAYOUT_EMBREE);
|
||||
if ((bvh_layout_mask_all & BVH_LAYOUT_OPTIX_EMBREE) == BVH_LAYOUT_OPTIX_EMBREE) {
|
||||
|
@ -131,6 +136,10 @@ class MultiDevice : public Device {
|
|||
if ((bvh_layout_mask_all & BVH_LAYOUT_METAL_EMBREE) == BVH_LAYOUT_METAL_EMBREE) {
|
||||
return BVH_LAYOUT_MULTI_METAL_EMBREE;
|
||||
}
|
||||
const BVHLayoutMask BVH_LAYOUT_EMBREEGPU_EMBREE = (BVH_LAYOUT_EMBREEGPU | BVH_LAYOUT_EMBREE);
|
||||
if ((bvh_layout_mask_all & BVH_LAYOUT_EMBREEGPU_EMBREE) == BVH_LAYOUT_EMBREEGPU_EMBREE) {
|
||||
return BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE;
|
||||
}
|
||||
|
||||
return bvh_layout_mask;
|
||||
}
|
||||
|
@ -164,9 +173,11 @@ class MultiDevice : public Device {
|
|||
assert(bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX ||
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL ||
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_HIPRT ||
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_EMBREEGPU ||
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE ||
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL_EMBREE ||
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_HIPRT_EMBREE);
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_HIPRT_EMBREE ||
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE);
|
||||
|
||||
BVHMulti *const bvh_multi = static_cast<BVHMulti *>(bvh);
|
||||
bvh_multi->sub_bvhs.resize(devices.size());
|
||||
|
@ -193,6 +204,8 @@ class MultiDevice : public Device {
|
|||
params.bvh_layout = BVH_LAYOUT_METAL;
|
||||
else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_HIPRT)
|
||||
params.bvh_layout = BVH_LAYOUT_HIPRT;
|
||||
else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_EMBREEGPU)
|
||||
params.bvh_layout = BVH_LAYOUT_EMBREEGPU;
|
||||
else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE)
|
||||
params.bvh_layout = sub.device->info.type == DEVICE_OPTIX ? BVH_LAYOUT_OPTIX :
|
||||
BVH_LAYOUT_EMBREE;
|
||||
|
@ -202,7 +215,9 @@ class MultiDevice : public Device {
|
|||
else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_HIPRT_EMBREE)
|
||||
params.bvh_layout = sub.device->info.type == DEVICE_HIPRT ? BVH_LAYOUT_HIPRT :
|
||||
BVH_LAYOUT_EMBREE;
|
||||
|
||||
else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE)
|
||||
params.bvh_layout = sub.device->info.type == DEVICE_ONEAPI ? BVH_LAYOUT_EMBREEGPU :
|
||||
BVH_LAYOUT_EMBREE;
|
||||
/* Skip building a bottom level acceleration structure for non-instanced geometry on Embree
|
||||
* (since they are put into the top level directly, see bvh_embree.cpp) */
|
||||
if (!params.top_level && params.bvh_layout == BVH_LAYOUT_EMBREE &&
|
||||
|
|
|
@ -122,7 +122,8 @@ bool OneapiDevice::check_peer_access(Device * /*peer_device*/)
|
|||
|
||||
bool OneapiDevice::can_use_hardware_raytracing_for_features(uint requested_features) const
|
||||
{
|
||||
/* MNEE and Raytrace kernels work correctly with Hardware Raytracing starting with Embree 4.1. */
|
||||
/* MNEE and Ray-trace kernels work correctly with Hardware Ray-tracing starting with Embree 4.1.
|
||||
*/
|
||||
# if defined(RTC_VERSION) && RTC_VERSION < 40100
|
||||
return !(requested_features & (KERNEL_FEATURE_MNEE | KERNEL_FEATURE_NODE_RAYTRACE));
|
||||
# else
|
||||
|
@ -135,14 +136,14 @@ BVHLayoutMask OneapiDevice::get_bvh_layout_mask(uint requested_features) const
|
|||
{
|
||||
return (use_hardware_raytracing &&
|
||||
can_use_hardware_raytracing_for_features(requested_features)) ?
|
||||
BVH_LAYOUT_EMBREE :
|
||||
BVH_LAYOUT_EMBREEGPU :
|
||||
BVH_LAYOUT_BVH2;
|
||||
}
|
||||
|
||||
# ifdef WITH_EMBREE_GPU
|
||||
void OneapiDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
|
||||
{
|
||||
if (embree_device && bvh->params.bvh_layout == BVH_LAYOUT_EMBREE) {
|
||||
if (embree_device && bvh->params.bvh_layout == BVH_LAYOUT_EMBREEGPU) {
|
||||
BVHEmbree *const bvh_embree = static_cast<BVHEmbree *>(bvh);
|
||||
if (refit) {
|
||||
bvh_embree->refit(progress);
|
||||
|
@ -435,7 +436,7 @@ void OneapiDevice::const_copy_to(const char *name, void *host, size_t size)
|
|||
<< string_human_readable_size(size) << ")";
|
||||
|
||||
# ifdef WITH_EMBREE_GPU
|
||||
if (strcmp(name, "data") == 0) {
|
||||
if (embree_scene != nullptr && strcmp(name, "data") == 0) {
|
||||
assert(size <= sizeof(KernelData));
|
||||
|
||||
/* Update scene handle(since it is different for each device on multi devices) */
|
||||
|
|
|
@ -15,6 +15,8 @@ struct GuidingParams {
|
|||
bool use_volume_guiding = false;
|
||||
|
||||
GuidingDistributionType type = GUIDING_TYPE_PARALLAX_AWARE_VMM;
|
||||
GuidingDirectionalSamplingType sampling_type = GUIDING_DIRECTIONAL_SAMPLING_TYPE_PRODUCT_MIS;
|
||||
float roughness_threshold = 0.05f;
|
||||
int training_samples = 128;
|
||||
bool deterministic = false;
|
||||
|
||||
|
@ -24,7 +26,9 @@ struct GuidingParams {
|
|||
{
|
||||
return !((use == other.use) && (use_surface_guiding == other.use_surface_guiding) &&
|
||||
(use_volume_guiding == other.use_volume_guiding) && (type == other.type) &&
|
||||
(sampling_type == other.sampling_type) &&
|
||||
(training_samples == other.training_samples) &&
|
||||
(roughness_threshold == other.roughness_threshold) &&
|
||||
(deterministic == other.deterministic));
|
||||
}
|
||||
};
|
||||
|
|
|
@ -207,6 +207,8 @@ KERNEL_STRUCT_MEMBER(integrator, int, direct_light_sampling_type)
|
|||
KERNEL_STRUCT_MEMBER(integrator, float, surface_guiding_probability)
|
||||
KERNEL_STRUCT_MEMBER(integrator, float, volume_guiding_probability)
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, guiding_distribution_type)
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, guiding_directional_sampling_type)
|
||||
KERNEL_STRUCT_MEMBER(integrator, float, guiding_roughness_threshold)
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, use_guiding)
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, train_guiding)
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, use_surface_guiding)
|
||||
|
@ -216,6 +218,8 @@ KERNEL_STRUCT_MEMBER(integrator, int, use_guiding_mis_weights)
|
|||
|
||||
/* Padding. */
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, pad1)
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, pad2)
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, pad3)
|
||||
KERNEL_STRUCT_END(KernelIntegrator)
|
||||
|
||||
/* SVM. For shader specialization. */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)) ==
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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, ¤t_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);
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -116,7 +116,8 @@ bool Geometry::need_build_bvh(BVHLayout layout) const
|
|||
layout == BVH_LAYOUT_METAL || layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE ||
|
||||
layout == BVH_LAYOUT_MULTI_METAL || layout == BVH_LAYOUT_MULTI_METAL_EMBREE ||
|
||||
layout == BVH_LAYOUT_HIPRT || layout == BVH_LAYOUT_MULTI_HIPRT ||
|
||||
layout == BVH_LAYOUT_MULTI_HIPRT_EMBREE;
|
||||
layout == BVH_LAYOUT_MULTI_HIPRT_EMBREE || layout == BVH_LAYOUT_EMBREEGPU ||
|
||||
layout == BVH_LAYOUT_MULTI_EMBREEGPU || layout == BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE;
|
||||
}
|
||||
|
||||
bool Geometry::is_instanced() const
|
||||
|
|
|
@ -60,10 +60,17 @@ NODE_DEFINE(Integrator)
|
|||
SOCKET_INT(volume_max_steps, "Volume Max Steps", 1024);
|
||||
SOCKET_FLOAT(volume_step_rate, "Volume Step Rate", 1.0f);
|
||||
|
||||
static NodeEnum guiding_ditribution_enum;
|
||||
guiding_ditribution_enum.insert("PARALLAX_AWARE_VMM", GUIDING_TYPE_PARALLAX_AWARE_VMM);
|
||||
guiding_ditribution_enum.insert("DIRECTIONAL_QUAD_TREE", GUIDING_TYPE_DIRECTIONAL_QUAD_TREE);
|
||||
guiding_ditribution_enum.insert("VMM", GUIDING_TYPE_VMM);
|
||||
static NodeEnum guiding_distribution_enum;
|
||||
guiding_distribution_enum.insert("PARALLAX_AWARE_VMM", GUIDING_TYPE_PARALLAX_AWARE_VMM);
|
||||
guiding_distribution_enum.insert("DIRECTIONAL_QUAD_TREE", GUIDING_TYPE_DIRECTIONAL_QUAD_TREE);
|
||||
guiding_distribution_enum.insert("VMM", GUIDING_TYPE_VMM);
|
||||
|
||||
static NodeEnum guiding_directional_sampling_type_enum;
|
||||
guiding_directional_sampling_type_enum.insert("MIS",
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_PRODUCT_MIS);
|
||||
guiding_directional_sampling_type_enum.insert("RIS", GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS);
|
||||
guiding_directional_sampling_type_enum.insert("ROUGHNESS",
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_ROUGHNESS);
|
||||
|
||||
SOCKET_BOOLEAN(use_guiding, "Guiding", false);
|
||||
SOCKET_BOOLEAN(deterministic_guiding, "Deterministic Guiding", true);
|
||||
|
@ -76,8 +83,13 @@ NODE_DEFINE(Integrator)
|
|||
SOCKET_BOOLEAN(use_guiding_mis_weights, "Use MIS Weights", true);
|
||||
SOCKET_ENUM(guiding_distribution_type,
|
||||
"Guiding Distribution Type",
|
||||
guiding_ditribution_enum,
|
||||
guiding_distribution_enum,
|
||||
GUIDING_TYPE_PARALLAX_AWARE_VMM);
|
||||
SOCKET_ENUM(guiding_directional_sampling_type,
|
||||
"Guiding Directional Sampling Type",
|
||||
guiding_directional_sampling_type_enum,
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS);
|
||||
SOCKET_FLOAT(guiding_roughness_threshold, "Guiding Roughness Threshold", 0.05f);
|
||||
|
||||
SOCKET_BOOLEAN(caustics_reflective, "Reflective Caustics", true);
|
||||
SOCKET_BOOLEAN(caustics_refractive, "Refractive Caustics", true);
|
||||
|
@ -239,6 +251,8 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
|
|||
kintegrator->use_guiding_direct_light = use_guiding_direct_light;
|
||||
kintegrator->use_guiding_mis_weights = use_guiding_mis_weights;
|
||||
kintegrator->guiding_distribution_type = guiding_params.type;
|
||||
kintegrator->guiding_directional_sampling_type = guiding_params.sampling_type;
|
||||
kintegrator->guiding_roughness_threshold = guiding_params.roughness_threshold;
|
||||
|
||||
kintegrator->seed = seed;
|
||||
|
||||
|
@ -409,7 +423,9 @@ GuidingParams Integrator::get_guiding_params(const Device *device) const
|
|||
guiding_params.type = guiding_distribution_type;
|
||||
guiding_params.training_samples = guiding_training_samples;
|
||||
guiding_params.deterministic = deterministic_guiding;
|
||||
|
||||
guiding_params.sampling_type = guiding_directional_sampling_type;
|
||||
// In Blender/Cycles the user set roughness is squared to behave more linear.
|
||||
guiding_params.roughness_threshold = guiding_roughness_threshold * guiding_roughness_threshold;
|
||||
return guiding_params;
|
||||
}
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
@ -54,6 +54,8 @@ class Integrator : public Node {
|
|||
NODE_SOCKET_API(bool, use_guiding_direct_light);
|
||||
NODE_SOCKET_API(bool, use_guiding_mis_weights);
|
||||
NODE_SOCKET_API(GuidingDistributionType, guiding_distribution_type);
|
||||
NODE_SOCKET_API(GuidingDirectionalSamplingType, guiding_directional_sampling_type);
|
||||
NODE_SOCKET_API(float, guiding_roughness_threshold);
|
||||
|
||||
NODE_SOCKET_API(bool, caustics_reflective)
|
||||
NODE_SOCKET_API(bool, caustics_refractive)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) ==
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -73,6 +73,17 @@ struct WGL_XDG_Decor_Window {
|
|||
struct zxdg_toplevel_decoration_v1 *toplevel_decor = nullptr;
|
||||
struct xdg_toplevel *toplevel = nullptr;
|
||||
enum zxdg_toplevel_decoration_v1_mode mode = (enum zxdg_toplevel_decoration_v1_mode)0;
|
||||
|
||||
/**
|
||||
* Defer calling #xdg_surface_ack_configure.
|
||||
* \note Accessing the members must lock on `win->frame_pending_mutex`.
|
||||
*/
|
||||
struct {
|
||||
/** When set, ACK configure is expected. */
|
||||
bool ack_configure = false;
|
||||
/** The serial to pass to ACK configure. */
|
||||
uint32_t ack_configure_serial = 0;
|
||||
} pending;
|
||||
};
|
||||
|
||||
static void gwl_xdg_decor_window_destroy(WGL_XDG_Decor_Window *decor)
|
||||
|
@ -745,6 +756,18 @@ static void gwl_window_frame_update_from_pending_no_lock(GWL_Window *win)
|
|||
wl_surface_set_buffer_scale(win->wl_surface, win->frame.buffer_scale);
|
||||
}
|
||||
|
||||
if (win->xdg_decor) {
|
||||
WGL_XDG_Decor_Window &decor = *win->xdg_decor;
|
||||
if (decor.pending.ack_configure) {
|
||||
xdg_surface_ack_configure(decor.surface, decor.pending.ack_configure_serial);
|
||||
/* The XDG spec states a commit event is required after ACK configure. */
|
||||
surface_needs_commit = true;
|
||||
|
||||
decor.pending.ack_configure = false;
|
||||
decor.pending.ack_configure_serial = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (surface_needs_commit) {
|
||||
#ifdef USE_EVENT_BACKGROUND_THREAD
|
||||
/* Postponing the commit avoids flickering when moving between monitors of different scale. */
|
||||
|
@ -1179,6 +1202,12 @@ static void xdg_surface_handle_configure(void *data,
|
|||
}
|
||||
CLOG_INFO(LOG, 2, "configure");
|
||||
|
||||
#ifdef USE_EVENT_BACKGROUND_THREAD
|
||||
std::lock_guard lock_frame_guard{static_cast<GWL_Window *>(data)->frame_pending_mutex};
|
||||
#endif
|
||||
win->xdg_decor->pending.ack_configure = true;
|
||||
win->xdg_decor->pending.ack_configure_serial = serial;
|
||||
|
||||
#ifdef USE_EVENT_BACKGROUND_THREAD
|
||||
GHOST_SystemWayland *system = win->ghost_system;
|
||||
const bool is_main_thread = system->main_thread_id == std::this_thread::get_id();
|
||||
|
@ -1190,10 +1219,8 @@ static void xdg_surface_handle_configure(void *data,
|
|||
else
|
||||
#endif
|
||||
{
|
||||
gwl_window_frame_update_from_pending(win);
|
||||
gwl_window_frame_update_from_pending_no_lock(win);
|
||||
}
|
||||
|
||||
xdg_surface_ack_configure(xdg_surface, serial);
|
||||
}
|
||||
|
||||
static const xdg_surface_listener xdg_surface_listener = {
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
# Skipped (see IMPORT_LANGUAGES_SKIP in settings.py). #23:Greek (Ελληνικά):el_GR
|
||||
35:Esperanto (Esperanto):eo
|
||||
# Skipped (see IMPORT_LANGUAGES_SKIP in settings.py). #36:Spanish from Spain (Español de España):es_ES
|
||||
# Skipped (see IMPORT_LANGUAGES_SKIP in settings.py). #34:Estonian (Eestlane):et_EE
|
||||
# Skipped (see IMPORT_LANGUAGES_SKIP in settings.py). #34:Estonian (Eesti keel):et_EE
|
||||
42:Basque (Euskara):eu_EU
|
||||
26:Persian (ﯽﺳﺭﺎﻓ):fa_IR
|
||||
6:Finnish (Suomi):fi_FI
|
||||
|
|
|
@ -68,7 +68,7 @@ LANGUAGES = (
|
|||
(32, "Brazilian Portuguese (Português do Brasil)", "pt_BR"),
|
||||
# Using the utf8 flipped form of Hebrew (עִבְרִית)).
|
||||
(33, "Hebrew (תירִבְעִ)", "he_IL"),
|
||||
(34, "Estonian (Eestlane)", "et_EE"),
|
||||
(34, "Estonian (Eesti keel)", "et_EE"),
|
||||
(35, "Esperanto (Esperanto)", "eo"),
|
||||
(36, "Spanish from Spain (Español de España)", "es_ES"),
|
||||
(37, "Amharic (አማርኛ)", "am_ET"),
|
||||
|
@ -206,7 +206,7 @@ _str_base = (
|
|||
r"(?:(?!<\\)(?:\\\\)*\\(?=(?P={_}2)))|"
|
||||
# The most common case.
|
||||
".(?!(?P={_}2))"
|
||||
")+.)" # Don't forget the last char!
|
||||
")*.)" # Don't forget the last char!
|
||||
"(?P={_}2)" # And closing quote.
|
||||
)
|
||||
str_clean_re = _str_base.format(_="g", capt="P<clean>")
|
||||
|
@ -257,7 +257,8 @@ PYGETTEXT_KEYWORDS = (() +
|
|||
for it in ("modifier_subpanel_register", "gpencil_modifier_subpanel_register")) +
|
||||
|
||||
# Node socket declarations: contextless names
|
||||
tuple((r"\.{}<decl::.*?>\(\s*" + _msg_re + r"(?:,[^),]+)*\s*\)").format(it)
|
||||
tuple((r"\.{}<decl::.*?>\(\s*" + _msg_re + r"(?:,[^),]+)*\s*\)"
|
||||
r"(?![^;]*\.translation_context\()").format(it)
|
||||
for it in ("add_input", "add_output")) +
|
||||
|
||||
# Node socket declarations: names with contexts
|
||||
|
|
|
@ -250,6 +250,15 @@ class Prefs(bpy.types.KeyConfigPreferences):
|
|||
update=update_fn,
|
||||
)
|
||||
|
||||
use_transform_navigation: BoolProperty(
|
||||
name="Navigate during Transform",
|
||||
description=(
|
||||
"Enable view navigation while using transform operators. "
|
||||
"Proportional Influence, Automatic Constraints and Auto IK Chain Length shortcuts will require holding Alt key"),
|
||||
default=False,
|
||||
update=update_fn,
|
||||
)
|
||||
|
||||
def draw(self, layout):
|
||||
from bpy import context
|
||||
|
||||
|
@ -313,6 +322,7 @@ class Prefs(bpy.types.KeyConfigPreferences):
|
|||
sub.prop(self, "use_v3d_tab_menu")
|
||||
sub.prop(self, "use_pie_click_drag")
|
||||
sub.prop(self, "use_v3d_shade_ex_pie")
|
||||
sub.prop(self, "use_transform_navigation")
|
||||
|
||||
# File Browser settings.
|
||||
col = layout.column()
|
||||
|
@ -365,6 +375,7 @@ def load():
|
|||
use_alt_click_leader=kc_prefs.use_alt_click_leader,
|
||||
use_pie_click_drag=kc_prefs.use_pie_click_drag,
|
||||
use_file_single_click=kc_prefs.use_file_single_click,
|
||||
use_transform_navigation=kc_prefs.use_transform_navigation,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
@ -93,6 +93,8 @@ class Params:
|
|||
# Since this means with RMB select enabled in edit-mode for e.g.
|
||||
# `Ctrl-LMB` would be caught by box-select instead of add/extrude.
|
||||
"tool_maybe_tweak_event",
|
||||
# Changes some transformers modal key-map items to avoid conflicts with navigation operations
|
||||
"use_transform_navigation",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
|
@ -119,6 +121,7 @@ class Params:
|
|||
use_file_single_click=False,
|
||||
v3d_tilde_action='VIEW',
|
||||
v3d_alt_mmb_drag_action='RELATIVE',
|
||||
use_transform_navigation=False,
|
||||
):
|
||||
from sys import platform
|
||||
self.apple = (platform == 'darwin')
|
||||
|
@ -209,6 +212,7 @@ class Params:
|
|||
self.pie_value = 'CLICK_DRAG' if use_pie_click_drag else 'PRESS'
|
||||
self.tool_tweak_event = {"type": self.tool_mouse, "value": 'CLICK_DRAG'}
|
||||
self.tool_maybe_tweak_event = {"type": self.tool_mouse, "value": self.tool_maybe_tweak_value}
|
||||
self.use_transform_navigation = use_transform_navigation
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
@ -1312,7 +1316,7 @@ def km_uv_editor(params):
|
|||
{"properties": [("extend", True)]}),
|
||||
])
|
||||
|
||||
# 3D cursor
|
||||
# 2D cursor
|
||||
if params.cursor_tweak_event:
|
||||
items.extend([
|
||||
("uv.cursor_set", params.cursor_set_event, None),
|
||||
|
@ -1581,13 +1585,16 @@ def km_view3d(params):
|
|||
# Transform.
|
||||
("transform.translate", {"type": params.select_mouse, "value": 'CLICK_DRAG'}, None),
|
||||
op_tool_optional(
|
||||
("transform.translate", {"type": 'G', "value": 'PRESS'}, None),
|
||||
("transform.translate", {"type": 'G', "value": 'PRESS'},
|
||||
{"properties": [("allow_navigation", params.use_transform_navigation)]}),
|
||||
(op_tool_cycle, "builtin.move"), params),
|
||||
op_tool_optional(
|
||||
("transform.rotate", {"type": 'R', "value": 'PRESS'}, None),
|
||||
("transform.rotate", {"type": 'R', "value": 'PRESS'},
|
||||
{"properties": [("allow_navigation", params.use_transform_navigation)]}),
|
||||
(op_tool_cycle, "builtin.rotate"), params),
|
||||
op_tool_optional(
|
||||
("transform.resize", {"type": 'S', "value": 'PRESS'}, None),
|
||||
("transform.resize", {"type": 'S', "value": 'PRESS'},
|
||||
{"properties": [("allow_navigation", params.use_transform_navigation)]}),
|
||||
(op_tool_cycle, "builtin.scale"), params),
|
||||
op_tool_optional(
|
||||
("transform.tosphere", {"type": 'S', "value": 'PRESS', "shift": True, "alt": True}, None),
|
||||
|
@ -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),
|
||||
])
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -257,6 +257,7 @@ class TIME_PT_playback(TimelinePanelButtons, Panel):
|
|||
col.prop(screen, "use_play_clip_editors", text="Movie Clip Editor")
|
||||
col.prop(screen, "use_play_node_editors", text="Node Editors")
|
||||
col.prop(screen, "use_play_sequence_editors", text="Video Sequencer")
|
||||
col.prop(screen, "use_play_spreadsheet_editors")
|
||||
|
||||
col = layout.column(heading="Show")
|
||||
col.prop(scene, "show_subframe", text="Subframes")
|
||||
|
|
|
@ -1038,10 +1038,22 @@ class VIEW3D_MT_transform_base:
|
|||
# TODO: get rid of the custom text strings?
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
allow_navigation = getattr(
|
||||
context.window_manager.keyconfigs.active.preferences,
|
||||
"use_transform_navigation",
|
||||
False)
|
||||
|
||||
layout.operator("transform.translate")
|
||||
layout.operator("transform.rotate")
|
||||
layout.operator("transform.resize", text="Scale")
|
||||
props = layout.operator("transform.translate")
|
||||
props.release_confirm = False
|
||||
props.allow_navigation = allow_navigation
|
||||
|
||||
props = layout.operator("transform.rotate")
|
||||
props.release_confirm = False
|
||||
props.allow_navigation = allow_navigation
|
||||
|
||||
props = layout.operator("transform.resize", text="Scale")
|
||||
props.release_confirm = False
|
||||
props.allow_navigation = allow_navigation
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
|
|
@ -155,6 +155,17 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
|
|||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_ui_units_x = 12
|
||||
|
||||
def draw(self, _context):
|
||||
# layout = self.layout
|
||||
pass
|
||||
|
||||
|
||||
class VIEW3D_PT_tools_meshedit_options_transform(View3DPanel, Panel):
|
||||
bl_category = "Tool"
|
||||
bl_context = ".mesh_edit" # dot on purpose (access from topbar)
|
||||
bl_label = "Transform"
|
||||
bl_parent_id = "VIEW3D_PT_tools_meshedit_options"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.active_object
|
||||
|
@ -169,56 +180,47 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
|
|||
ob = context.active_object
|
||||
mesh = ob.data
|
||||
|
||||
row = layout.row(align=True, heading="Transform")
|
||||
row.prop(tool_settings, "use_transform_correct_face_attributes")
|
||||
col = layout.column(align=True)
|
||||
col.prop(tool_settings, "use_transform_correct_face_attributes")
|
||||
sub = col.column(align=True)
|
||||
sub.active = tool_settings.use_transform_correct_face_attributes
|
||||
sub.prop(tool_settings, "use_transform_correct_keep_connected")
|
||||
col.separator()
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.active = tool_settings.use_transform_correct_face_attributes
|
||||
row.prop(tool_settings, "use_transform_correct_keep_connected")
|
||||
|
||||
row = layout.row(align=True, heading="UVs")
|
||||
row.prop(tool_settings, "use_edge_path_live_unwrap")
|
||||
|
||||
row = layout.row(heading="Mirror")
|
||||
sub = row.row(align=True)
|
||||
col = layout.column(heading="Mirror")
|
||||
sub = col.row(align=True)
|
||||
sub.prop(mesh, "use_mirror_x", text="X", toggle=True)
|
||||
sub.prop(mesh, "use_mirror_y", text="Y", toggle=True)
|
||||
sub.prop(mesh, "use_mirror_z", text="Z", toggle=True)
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.active = ob.data.use_mirror_x or ob.data.use_mirror_y or ob.data.use_mirror_z
|
||||
row.prop(mesh, "use_mirror_topology")
|
||||
col = layout.column(align=True)
|
||||
col.active = mesh.use_mirror_x or mesh.use_mirror_y or mesh.use_mirror_z
|
||||
col.prop(mesh, "use_mirror_topology")
|
||||
col.separator()
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(tool_settings, "use_mesh_automerge", text="Auto Merge", toggle=False)
|
||||
sub = col.column(align=True)
|
||||
sub.active = tool_settings.use_mesh_automerge
|
||||
sub.prop(tool_settings, "use_mesh_automerge_and_split", toggle=False)
|
||||
sub.prop(tool_settings, "double_threshold", text="Threshold")
|
||||
|
||||
|
||||
class VIEW3D_PT_tools_meshedit_options_automerge(View3DPanel, Panel):
|
||||
class VIEW3D_PT_tools_meshedit_options_uvs(View3DPanel, Panel):
|
||||
bl_category = "Tool"
|
||||
bl_context = ".mesh_edit" # dot on purpose (access from topbar)
|
||||
bl_label = "Auto Merge"
|
||||
bl_label = "UVs"
|
||||
bl_parent_id = "VIEW3D_PT_tools_meshedit_options"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.active_object
|
||||
|
||||
def draw_header(self, context):
|
||||
tool_settings = context.tool_settings
|
||||
self.layout.use_property_split = False
|
||||
self.layout.prop(tool_settings, "use_mesh_automerge",
|
||||
text=self.bl_label if self.is_popover else "", toggle=False)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.use_property_decorate = False
|
||||
layout.use_property_split = True
|
||||
|
||||
tool_settings = context.tool_settings
|
||||
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.active = tool_settings.use_mesh_automerge
|
||||
col.prop(tool_settings, "use_mesh_automerge_and_split", toggle=False)
|
||||
col.prop(tool_settings, "double_threshold", text="Threshold")
|
||||
layout.prop(tool_settings, "use_edge_path_live_unwrap")
|
||||
|
||||
|
||||
# ********** default tools for editmode_armature ****************
|
||||
|
@ -2368,7 +2370,8 @@ classes = (
|
|||
VIEW3D_PT_tools_object_options,
|
||||
VIEW3D_PT_tools_object_options_transform,
|
||||
VIEW3D_PT_tools_meshedit_options,
|
||||
VIEW3D_PT_tools_meshedit_options_automerge,
|
||||
VIEW3D_PT_tools_meshedit_options_transform,
|
||||
VIEW3D_PT_tools_meshedit_options_uvs,
|
||||
VIEW3D_PT_tools_armatureedit_options,
|
||||
VIEW3D_PT_tools_posemode_options,
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -311,10 +311,11 @@ void BKE_id_delete(struct Main *bmain, void *idv) ATTR_NONNULL();
|
|||
/**
|
||||
* Like BKE_id_delete, but with extra corner-case options.
|
||||
*
|
||||
* \param extra_remapping_flags Additional `ID_REMAP_` flags to pass to remapping code when
|
||||
* \param extra_remapping_flags: Additional `ID_REMAP_` flags to pass to remapping code when
|
||||
* ensuring that deleted IDs are not used by any other ID in given `bmain`. Typical example would
|
||||
* be e.g. `ID_REMAP_FORCE_UI_POINTERS`, required when default UI-handling callbacks of remapping
|
||||
* code won't be working (e.g. from readfile code). */
|
||||
* code won't be working (e.g. from readfile code).
|
||||
*/
|
||||
void BKE_id_delete_ex(struct Main *bmain, void *idv, const int extra_remapping_flags)
|
||||
ATTR_NONNULL(1, 2);
|
||||
/**
|
||||
|
|
|
@ -303,6 +303,27 @@ struct IDOverrideLibraryProperty *BKE_lib_override_library_property_get(
|
|||
*/
|
||||
void BKE_lib_override_library_property_delete(struct IDOverrideLibrary *override,
|
||||
struct IDOverrideLibraryProperty *override_property);
|
||||
/**
|
||||
* Delete a property override from the given ID \a override, if it exists.
|
||||
*
|
||||
* \return True when the property was found (and thus deleted), false if it wasn't found.
|
||||
*/
|
||||
bool BKE_lib_override_library_property_search_and_delete(struct IDOverrideLibrary *override,
|
||||
const char *rna_path);
|
||||
|
||||
/** Change the RNA path of a library override on a property.
|
||||
*
|
||||
* No-op if the property override cannot be found.
|
||||
*
|
||||
* \param from_rna_path The RNA path of the property to change.
|
||||
* \param to_rna_path The new RNA path. The library override system will copy the string to its own
|
||||
* memory; the caller will retain ownership of the passed pointer.
|
||||
* \return True if the property was found (and thus changed), false if it wasn't found.
|
||||
*/
|
||||
bool BKE_lib_override_library_property_rna_path_change(IDOverrideLibrary *liboverride,
|
||||
const char *old_rna_path,
|
||||
const char *new_rna_path);
|
||||
|
||||
/**
|
||||
* Get the RNA-property matching the \a library_prop override property. Used for UI to query
|
||||
* additional data about the overridden property (e.g. UI name).
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2005 Blender Foundation */
|
||||
* Copyright 2023 Blender Foundation */
|
||||
|
||||
#pragma once
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -334,7 +334,7 @@ static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss,
|
|||
0, numEffectedF, &data, ccgSubSurf__calcVertNormals_faces_accumulate_cb, &settings);
|
||||
}
|
||||
|
||||
/* XXX can I reduce the number of normalisations here? */
|
||||
/* XXX can I reduce the number of normalization calls here? */
|
||||
for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) {
|
||||
CCGVert *v = (CCGVert *)effectedV[ptrIdx];
|
||||
float *no = VERT_getNo(v, lvl);
|
||||
|
|
|
@ -641,8 +641,8 @@ static int animsys_quaternion_evaluate_fcurves(PathResolvedRNA quat_rna,
|
|||
}
|
||||
|
||||
if (fcurve_offset < 4) {
|
||||
/* This quaternion was incompletely keyed, so the result is a mixture of the unit quaterion and
|
||||
* values from FCurves. This means that it's almost certainly no longer of unit length. */
|
||||
/* This quaternion was incompletely keyed, so the result is a mixture of the unit quaternion
|
||||
* and values from FCurves. This means that it's almost certainly no longer of unit length. */
|
||||
normalize_qt(r_quaternion);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -1006,7 +1006,7 @@ void BKE_main_view_layers_synced_ensure(const Main *bmain)
|
|||
BKE_scene_view_layers_synced_ensure(scene);
|
||||
}
|
||||
|
||||
/* NOTE: This is not (yet?) covered by the dirty tag and deffered re-sync system. */
|
||||
/* NOTE: This is not (yet?) covered by the dirty tag and deferred re-sync system. */
|
||||
BKE_layer_collection_local_sync_all(bmain);
|
||||
}
|
||||
|
||||
|
|
|
@ -198,8 +198,9 @@ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_f
|
|||
BKE_lib_override_library_init(dst_id, nullptr);
|
||||
}
|
||||
|
||||
/* If source is already overriding data, we copy it but reuse its reference for dest ID.
|
||||
* Otherwise, source is only an override template, it then becomes reference of dest ID. */
|
||||
/* If source is already overriding data, we copy it but reuse its reference for destination ID.
|
||||
* Otherwise, source is only an override template, it then becomes reference of destination ID.
|
||||
*/
|
||||
dst_id->override_library->reference = src_id->override_library->reference ?
|
||||
src_id->override_library->reference :
|
||||
const_cast<ID *>(src_id);
|
||||
|
@ -1776,7 +1777,7 @@ static void lib_override_library_remap(Main *bmain,
|
|||
*
|
||||
* In case linked data keep being modified, these conditions may fail and the mapping may start to
|
||||
* return 'wrong' results. However, this is considered as an acceptable limitation here, since this
|
||||
* is mainly a 'best effort' to recover from situations that should not be hapenning in the first
|
||||
* is mainly a 'best effort' to recover from situations that should not be happening in the first
|
||||
* place.
|
||||
*/
|
||||
|
||||
|
@ -2061,7 +2062,7 @@ static bool lib_override_library_resync(Main *bmain,
|
|||
}
|
||||
|
||||
/* Get a mapping of all missing linked IDs that were liboverrides, to search for 'old
|
||||
* liboverrides' for newly created ones that do not alredy have one, in next step. */
|
||||
* liboverrides' for newly created ones that do not already have one, in next step. */
|
||||
LibOverrideMissingIDsData missing_ids_data = lib_override_library_resync_build_missing_ids_data(
|
||||
bmain);
|
||||
|
||||
|
@ -2638,7 +2639,8 @@ static bool lib_override_library_main_resync_id_skip_check(ID *id,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Clear 'unreachable' tag of existing liboverrides if they are using another reachable liboverride
|
||||
/**
|
||||
* Clear 'unreachable' tag of existing liboverrides if they are using another reachable liboverride
|
||||
* (typical case: Mesh object which only relationship to the rest of the liboverride hierarchy is
|
||||
* though its 'parent' pointer (i.e. rest of the hierarchy has no actual relationship to this mesh
|
||||
* object). Sadge.
|
||||
|
@ -2646,7 +2648,8 @@ static bool lib_override_library_main_resync_id_skip_check(ID *id,
|
|||
* Logic and rational of this function are very similar to these of
|
||||
* #lib_override_hierarchy_dependencies_recursive_tag_from, but withing specific resync context.
|
||||
*
|
||||
* \returns True if it finds a non-isolated 'parent' ID, false otherwise. */
|
||||
* \returns True if it finds a non-isolated 'parent' ID, false otherwise.
|
||||
*/
|
||||
static bool lib_override_resync_tagging_finalize_recursive_check_from(
|
||||
Main *bmain, ID *id, const int library_indirect_level)
|
||||
{
|
||||
|
@ -3527,6 +3530,41 @@ void lib_override_library_property_clear(IDOverrideLibraryProperty *op)
|
|||
BLI_freelistN(&op->operations);
|
||||
}
|
||||
|
||||
bool BKE_lib_override_library_property_search_and_delete(IDOverrideLibrary *override,
|
||||
const char *rna_path)
|
||||
{
|
||||
IDOverrideLibraryProperty *override_property = BKE_lib_override_library_property_find(override,
|
||||
rna_path);
|
||||
if (override_property == nullptr) {
|
||||
return false;
|
||||
}
|
||||
BKE_lib_override_library_property_delete(override, override_property);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BKE_lib_override_library_property_rna_path_change(IDOverrideLibrary *override,
|
||||
const char *old_rna_path,
|
||||
const char *new_rna_path)
|
||||
{
|
||||
/* Find the override property by its old RNA path. */
|
||||
GHash *override_runtime = override_library_rna_path_mapping_ensure(override);
|
||||
IDOverrideLibraryProperty *override_property = static_cast<IDOverrideLibraryProperty *>(
|
||||
BLI_ghash_popkey(override_runtime, old_rna_path, nullptr));
|
||||
|
||||
if (override_property == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Switch over the RNA path. */
|
||||
MEM_SAFE_FREE(override_property->rna_path);
|
||||
override_property->rna_path = BLI_strdup(new_rna_path);
|
||||
|
||||
/* Put property back into the lookup mapping, using the new RNA path. */
|
||||
BLI_ghash_insert(override_runtime, override_property->rna_path, override_property);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BKE_lib_override_library_property_delete(IDOverrideLibrary *override,
|
||||
IDOverrideLibraryProperty *override_property)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue