Cleanup: Move BKE_node.h to C++ #107790

Merged
Hans Goudey merged 16 commits from mod_moder/blender:tmp_move_node_on_cpp into main 2023-05-15 15:14:30 +02:00
169 changed files with 1779 additions and 1119 deletions
Showing only changes of commit 8cb0f623af - Show all commits

View File

@ -503,7 +503,7 @@ if(NOT APPLE)
mark_as_advanced(WITH_CYCLES_DEVICE_CUDA)
option(WITH_CYCLES_CUDA_BINARIES "Build Cycles NVIDIA CUDA binaries" OFF)
set(CYCLES_CUDA_BINARIES_ARCH sm_30 sm_35 sm_37 sm_50 sm_52 sm_60 sm_61 sm_70 sm_75 sm_86 compute_75 CACHE STRING "CUDA architectures to build binaries for")
set(CYCLES_CUDA_BINARIES_ARCH sm_30 sm_35 sm_37 sm_50 sm_52 sm_60 sm_61 sm_70 sm_75 sm_86 sm_89 compute_75 CACHE STRING "CUDA architectures to build binaries for")
option(WITH_CYCLES_CUDA_BUILD_SERIAL "Build cubins one after another (useful on machines with limited RAM)" OFF)
option(WITH_CUDA_DYNLOAD "Dynamically load CUDA libraries at runtime (for developers, makes cuda-gdb work)" ON)

View File

@ -14,6 +14,7 @@ set(EMBREE_EXTRA_ARGS
-DEMBREE_BACKFACE_CULLING=OFF
-DEMBREE_BACKFACE_CULLING_CURVES=ON
-DEMBREE_BACKFACE_CULLING_SPHERES=ON
-DEMBREE_NO_SPLASH=ON
-DEMBREE_TASKING_SYSTEM=TBB
-DEMBREE_TBB_ROOT=${LIBDIR}/tbb
-DTBB_ROOT=${LIBDIR}/tbb

View File

@ -477,9 +477,9 @@ set(SQLITE_HASH_TYPE SHA1)
set(SQLITE_FILE sqlite-autoconf-${SQLLITE_LONG_VERSION}.tar.gz)
set(SQLITE_CPE "cpe:2.3:a:sqlite:sqlite:${SQLITE_VERSION}:*:*:*:*:*:*:*")
set(EMBREE_VERSION 4.0.1)
set(EMBREE_VERSION 4.1.0)
set(EMBREE_URI https://github.com/embree/embree/archive/v${EMBREE_VERSION}.zip)
set(EMBREE_HASH dd26617719a587e126b341d1b32f7fd0)
set(EMBREE_HASH 4b525955b08e1249a700dea5b5ffc8b2)
set(EMBREE_HASH_TYPE MD5)
set(EMBREE_FILE embree-v${EMBREE_VERSION}.zip)

View File

@ -24,144 +24,3 @@ index 7c2f43d..106b1d5 100644
DISABLE_STACK_PROTECTOR_FOR_INTERSECTORS(${EMBREE_LIBRARY_FILES_AVX2})
ADD_LIBRARY(embree_avx2 STATIC ${EMBREE_LIBRARY_FILES_AVX2})
TARGET_LINK_LIBRARIES(embree_avx2 PRIVATE tasking)
diff --git a/include/embree4/rtcore_device.h b/include/embree4/rtcore_device.h
index 45bf95583..62ee7787d 100644
--- a/include/embree4/rtcore_device.h
+++ b/include/embree4/rtcore_device.h
@@ -55,6 +55,7 @@ enum RTCDeviceProperty
RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED = 66,
RTC_DEVICE_PROPERTY_IGNORE_INVALID_RAYS_ENABLED = 67,
RTC_DEVICE_PROPERTY_COMPACT_POLYS_ENABLED = 68,
+ RTC_DEVICE_PROPERTY_BACKFACE_CULLING_SPHERES_ENABLED = 69,
RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED = 96,
RTC_DEVICE_PROPERTY_QUAD_GEOMETRY_SUPPORTED = 97,
diff --git a/kernels/common/device.cpp b/kernels/common/device.cpp
index 3ffac7e37..215ccc961 100644
--- a/kernels/common/device.cpp
+++ b/kernels/common/device.cpp
@@ -170,6 +170,9 @@ namespace embree
#if defined (EMBREE_BACKFACE_CULLING_CURVES)
v += "backfacecullingcurves ";
#endif
+#if defined (EMBREE_BACKFACE_CULLING_SPHERES)
+ v += "backfacecullingspheres ";
+#endif
#if defined(EMBREE_FILTER_FUNCTION)
v += "intersection_filter ";
#endif
@@ -477,6 +480,12 @@ namespace embree
case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_CURVES_ENABLED: return 0;
#endif
+#if defined(EMBREE_BACKFACE_CULLING_SPHERES)
+ case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_SPHERES_ENABLED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_SPHERES_ENABLED: return 0;
+#endif
+
#if defined(EMBREE_COMPACT_POLYS)
case RTC_DEVICE_PROPERTY_COMPACT_POLYS_ENABLED: return 1;
#else
diff --git a/kernels/config.h.in b/kernels/config.h.in
index f02c90360..ba9acde56 100644
--- a/kernels/config.h.in
+++ b/kernels/config.h.in
@@ -5,6 +5,7 @@
#cmakedefine EMBREE_STAT_COUNTERS
#cmakedefine EMBREE_BACKFACE_CULLING
#cmakedefine EMBREE_BACKFACE_CULLING_CURVES
+#cmakedefine EMBREE_BACKFACE_CULLING_SPHERES
#cmakedefine EMBREE_FILTER_FUNCTION
#cmakedefine EMBREE_IGNORE_INVALID_RAYS
#cmakedefine EMBREE_GEOMETRY_TRIANGLE
diff --git a/kernels/geometry/sphere_intersector.h b/kernels/geometry/sphere_intersector.h
index 074f910a2..30f490818 100644
--- a/kernels/geometry/sphere_intersector.h
+++ b/kernels/geometry/sphere_intersector.h
@@ -106,8 +106,13 @@ namespace embree
const vbool<M> valid_front = valid & (ray.tnear() <= t_front) & (t_front <= ray.tfar);
const vbool<M> valid_back = valid & (ray.tnear() <= t_back ) & (t_back <= ray.tfar);
+#if defined (EMBREE_BACKFACE_CULLING_SPHERES)
+ /* check if there is a first hit */
+ const vbool<M> valid_first = valid_front;
+#else
/* check if there is a first hit */
const vbool<M> valid_first = valid_front | valid_back;
+#endif
if (unlikely(none(valid_first)))
return false;
@@ -120,7 +125,8 @@ namespace embree
/* invoke intersection filter for first hit */
const bool is_hit_first = epilog(valid_first, hit);
-
+
+#if !defined (EMBREE_BACKFACE_CULLING_SPHERES)
/* check for possible second hits before potentially accepted hit */
const vfloat<M> t_second = t_back;
const vbool<M> valid_second = valid_front & valid_back & (t_second <= ray.tfar);
@@ -131,7 +137,9 @@ namespace embree
const Vec3vf<M> Ng_second = td_back * ray_dir - perp;
hit = SphereIntersectorHitM<M> (t_second, Ng_second);
const bool is_hit_second = epilog(valid_second, hit);
-
+#else
+ constexpr bool is_hit_second = false;
+#endif
return is_hit_first | is_hit_second;
}
@@ -186,8 +194,13 @@ namespace embree
const vbool<M> valid_front = valid & (ray.tnear()[k] <= t_front) & (t_front <= ray.tfar[k]);
const vbool<M> valid_back = valid & (ray.tnear()[k] <= t_back ) & (t_back <= ray.tfar[k]);
+#if defined (EMBREE_BACKFACE_CULLING_SPHERES)
+ /* check if there is a first hit */
+ const vbool<M> valid_first = valid_front;
+#else
/* check if there is a first hit */
const vbool<M> valid_first = valid_front | valid_back;
+#endif
if (unlikely(none(valid_first)))
return false;
@@ -200,7 +213,8 @@ namespace embree
/* invoke intersection filter for first hit */
const bool is_hit_first = epilog(valid_first, hit);
-
+
+#if !defined (EMBREE_BACKFACE_CULLING_SPHERES)
/* check for possible second hits before potentially accepted hit */
const vfloat<M> t_second = t_back;
const vbool<M> valid_second = valid_front & valid_back & (t_second <= ray.tfar[k]);
@@ -211,7 +225,9 @@ namespace embree
const Vec3vf<M> Ng_second = td_back * ray_dir - perp;
hit = SphereIntersectorHitM<M> (t_second, Ng_second);
const bool is_hit_second = epilog(valid_second, hit);
-
+#else
+ constexpr bool is_hit_second = false;
+#endif
return is_hit_first | is_hit_second;
}
};
diff -ruN a/kernels/sycl/rthwif_embree_builder.cpp b/kernels/sycl/rthwif_embree_builder.cpp
--- a/kernels/sycl/rthwif_embree_builder.cpp 2023-03-28 17:23:06.429190200 +0200
+++ b/kernels/sycl/rthwif_embree_builder.cpp 2023-03-28 17:35:01.291938600 +0200
@@ -540,7 +540,12 @@
assert(offset <= geomDescrData.size());
}
+ /* Force running BVH building sequentially from the calling thread if using TBB < 2021, as it otherwise leads to runtime issues. */
+#if TBB_VERSION_MAJOR<2021
+ RTHWIF_PARALLEL_OPERATION parallelOperation = nullptr;
+#else
RTHWIF_PARALLEL_OPERATION parallelOperation = rthwifNewParallelOperation();
+#endif
/* estimate static accel size */
BBox1f time_range(0,1);

View File

@ -31,7 +31,8 @@ IF(NOT PYTHON_ROOT_DIR AND NOT $ENV{PYTHON_ROOT_DIR} STREQUAL "")
SET(PYTHON_ROOT_DIR $ENV{PYTHON_ROOT_DIR})
ENDIF()
SET(PYTHON_VERSION 3.10 CACHE STRING "Python Version (major and minor only)")
SET(_PYTHON_VERSION_SUPPORTED 3.10)
SET(PYTHON_VERSION ${_PYTHON_VERSION_SUPPORTED} CACHE STRING "Python Version (major and minor only)")
MARK_AS_ADVANCED(PYTHON_VERSION)
@ -178,8 +179,24 @@ UNSET(_IS_LIB_PATH_DEF)
# handle the QUIETLY and REQUIRED arguments and SET PYTHONLIBSUNIX_FOUND to TRUE IF
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(PythonLibsUnix DEFAULT_MSG
PYTHON_LIBRARY PYTHON_LIBPATH PYTHON_INCLUDE_DIR PYTHON_INCLUDE_CONFIG_DIR)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(PythonLibsUnix
# NOTE(@ideasman42): Instead of `DEFAULT_MSG` use a custom message because users
# may have newer versions Python and not be using pre-compiled libraries
# (on other UNIX systems or using an esoteric architecture).
# Some Python developers might want to use the newer features of Python too.
# While we could automatically detect and use newer versions but this would result in
# developers using a configuration which isn't officially supported without realizing it.
# So warn that the officially supported Python version is not found and let the developer
# explicitly set the newer version if they wish.
# From a maintenance perspective it's typically not a problem to support newer versions,
# doing so can help ease the process of upgrading too, nevertheless these versions don't
# have the same level of testing & support.
"\
'PYTHON_VERSION=${_PYTHON_VERSION_SUPPORTED}' not found! \
This is the only officially supported version. \
If you wish to use a newer Python version you may set 'PYTHON_VERSION' \
however we do not guarantee full compatibility in this case."
PYTHON_LIBRARY PYTHON_LIBPATH PYTHON_INCLUDE_DIR PYTHON_INCLUDE_CONFIG_DIR)
IF(PYTHONLIBSUNIX_FOUND)
# Assign cache items
@ -215,6 +232,7 @@ IF(PYTHONLIBSUNIX_FOUND)
ENDIF()
UNSET(_PYTHON_ABI_FLAGS)
UNSET(_PYTHON_VERSION_SUPPORTED)
UNSET(_python_SEARCH_DIRS)
MARK_AS_ADVANCED(

View File

@ -8,6 +8,8 @@ buildbot:
version: '10.1.243'
cuda11:
version: '11.4.1'
cuda12:
version: '12.1.1'
hip:
version: '5.5.30571'
hiprt:

View File

@ -302,10 +302,6 @@
* \ingroup imbuf
*/
/** \defgroup imbdds DDS
* \ingroup imbuf
*/
/** \defgroup openexr OpenEXR
* \ingroup imbuf
*/

View File

@ -389,7 +389,7 @@ static float4 LerpCurveSegmentMotionCV(ParticleCurveData *CData, int sys, int cu
}
const float4 mP = CurveSegmentMotionCV(CData, sys, curve, first_curve_key + curvekey);
const float4 mP2 = CurveSegmentMotionCV(CData, sys, curve, first_curve_key + curvekey2);
return lerp(mP, mP2, remainder);
return mix(mP, mP2, remainder);
}
static void export_hair_motion_validate_attribute(Hair *hair,
@ -899,9 +899,9 @@ static float4 interpolate_curve_points(const float (*b_attr_position)[3],
const int point_a = clamp((int)curve_t, 0, num_points - 1);
const int point_b = min(point_a + 1, num_points - 1);
const float t = curve_t - (float)point_a;
return lerp(curve_point_as_float4(b_attr_position, b_attr_radius, first_point_index + point_a),
curve_point_as_float4(b_attr_position, b_attr_radius, first_point_index + point_b),
t);
return mix(curve_point_as_float4(b_attr_position, b_attr_radius, first_point_index + point_a),
curve_point_as_float4(b_attr_position, b_attr_radius, first_point_index + point_b),
t);
}
static void export_hair_curves(Scene *scene,

View File

@ -515,6 +515,7 @@ void BlenderSession::render_frame_finish()
static bool bake_setup_pass(Scene *scene, const string &bake_type_str, const int bake_filter)
{
Integrator *integrator = scene->integrator;
Film *film = scene->film;
const char *bake_type = bake_type_str.c_str();
PassType type = PASS_NONE;
@ -542,13 +543,29 @@ static bool bake_setup_pass(Scene *scene, const string &bake_type_str, const int
else if (strcmp(bake_type, "ENVIRONMENT") == 0) {
type = PASS_BACKGROUND;
}
/* AO passes. */
/* AO pass. */
else if (strcmp(bake_type, "AO") == 0) {
type = PASS_AO;
}
/* Shadow pass. */
else if (strcmp(bake_type, "SHADOW") == 0) {
/* Bake as combined pass, together with marking the object as a shadow catcher. */
type = PASS_SHADOW_CATCHER;
film->set_use_approximate_shadow_catcher(true);
use_direct_light = true;
use_indirect_light = true;
include_albedo = true;
integrator->set_use_diffuse(true);
integrator->set_use_glossy(true);
integrator->set_use_transmission(true);
integrator->set_use_emission(true);
}
/* Combined pass. */
else if (strcmp(bake_type, "COMBINED") == 0) {
type = PASS_COMBINED;
film->set_use_approximate_shadow_catcher(true);
use_direct_light = (bake_filter & BL::BakeSettings::pass_filter_DIRECT) != 0;
use_indirect_light = (bake_filter & BL::BakeSettings::pass_filter_INDIRECT) != 0;
@ -683,17 +700,23 @@ void BlenderSession::bake(BL::Depsgraph &b_depsgraph_,
/* Object might have been disabled for rendering or excluded in some
* other way, in that case Blender will report a warning afterwards. */
bool object_found = false;
Object *bake_object = nullptr;
if (!session->progress.get_cancel()) {
foreach (Object *ob, scene->objects) {
if (ob->name == b_object.name()) {
object_found = true;
bake_object = ob;
break;
}
}
}
if (object_found && !session->progress.get_cancel()) {
/* For the shadow pass, temporarily mark the object as a shadow catcher. */
const bool was_shadow_catcher = (bake_object) ? bake_object->get_is_shadow_catcher() : false;
if (bake_object && bake_type == "SHADOW") {
bake_object->set_is_shadow_catcher(true);
}
if (bake_object && !session->progress.get_cancel()) {
/* Get session and buffer parameters. */
const SessionParams session_params = BlenderSync::get_session_params(
b_engine, b_userpref, b_scene, background);
@ -714,10 +737,15 @@ void BlenderSession::bake(BL::Depsgraph &b_depsgraph_,
}
/* Perform bake. Check cancel to avoid crash with incomplete scene data. */
if (object_found && !session->progress.get_cancel()) {
if (bake_object && !session->progress.get_cancel()) {
session->start();
session->wait();
}
/* Restore object state. */
if (bake_object) {
bake_object->set_is_shadow_catcher(was_shadow_catcher);
}
}
void BlenderSession::synchronize(BL::Depsgraph &b_depsgraph_)

View File

@ -360,7 +360,7 @@ void BVHSpatialSplit::split_triangle_primitive(const Mesh *mesh,
/* edge intersects the plane => insert intersection to both boxes. */
if ((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) {
float3 t = lerp(v0, v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
float3 t = mix(v0, v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
left_bounds.grow(t);
right_bounds.grow(t);
}
@ -408,7 +408,7 @@ void BVHSpatialSplit::split_curve_primitive(const Hair *hair,
/* edge intersects the plane => insert intersection to both boxes. */
if ((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) {
float3 t = lerp(v0, v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
float3 t = mix(v0, v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
left_bounds.grow(t);
right_bounds.grow(t);
}

View File

@ -122,8 +122,12 @@ bool OneapiDevice::check_peer_access(Device * /*peer_device*/)
bool OneapiDevice::can_use_hardware_raytracing_for_features(uint requested_features) const
{
/* MNEE and Ray-trace kernels currently don't work correctly with HWRT. */
/* MNEE and Raytrace kernels work correctly with Hardware Raytracing starting with Embree 4.1. */
# if defined(RTC_VERSION) && RTC_VERSION < 40100
return !(requested_features & (KERNEL_FEATURE_MNEE | KERNEL_FEATURE_NODE_RAYTRACE));
# else
return true;
# endif
}
BVHLayoutMask OneapiDevice::get_bvh_layout_mask(uint requested_features) const

View File

@ -62,7 +62,7 @@ bool work_balance_do_rebalance(vector<WorkBalanceInfo> &work_balance_infos)
bool has_big_difference = false;
for (const WorkBalanceInfo &info : work_balance_infos) {
const double time_target = lerp(info.time_spent, time_average, lerp_weight);
const double time_target = mix(info.time_spent, time_average, lerp_weight);
const double new_weight = info.weight * time_target / info.time_spent;
new_weights.push_back(new_weight);
total_weight += new_weight;

View File

@ -540,12 +540,12 @@ if(WITH_CYCLES_CUDA_BINARIES)
elseif(${arch} MATCHES ".*_7." AND "${CUDA_VERSION}" LESS 100)
message(STATUS "CUDA binaries for ${arch} require CUDA 10.0+, skipped.")
elseif(${arch} MATCHES ".*_8.")
if(DEFINED CUDA11_NVCC_EXECUTABLE)
set(cuda_nvcc_executable ${CUDA11_NVCC_EXECUTABLE})
set(cuda_toolkit_root_dir ${CUDA11_TOOLKIT_ROOT_DIR})
elseif("${CUDA_VERSION}" GREATER_EQUAL 111) # Support for sm_86 was introduced in CUDA 11
if("${CUDA_VERSION}" GREATER_EQUAL 111) # Support for sm_86 was introduced in CUDA 11
set(cuda_nvcc_executable ${CUDA_NVCC_EXECUTABLE})
set(cuda_toolkit_root_dir ${CUDA_TOOLKIT_ROOT_DIR})
elseif(DEFINED CUDA11_NVCC_EXECUTABLE)
set(cuda_nvcc_executable ${CUDA11_NVCC_EXECUTABLE})
set(cuda_toolkit_root_dir ${CUDA11_TOOLKIT_ROOT_DIR})
else()
message(STATUS "CUDA binaries for ${arch} require CUDA 11.1+, skipped.")
endif()

View File

@ -96,7 +96,7 @@ ccl_device_forceinline Spectrum interpolate_fresnel_color(float3 L,
{
/* Compute the real Fresnel term and remap it from real_F0..1 to F0..1.
* The reason why we use this remapping instead of directly doing the
* Schlick approximation lerp(F0, 1.0, (1.0-cosLH)^5) is that for cases
* Schlick approximation mix(F0, 1.0, (1.0-cosLH)^5) is that for cases
* with similar IORs (e.g. ice in water), the relative IOR can be close
* enough to 1.0 that the Schlick approximation becomes inaccurate. */
float real_F = fresnel_dielectric_cos(dot(L, H), ior);

View File

@ -174,27 +174,30 @@ bool oneapi_kernel_is_required_for_features(const std::string &kernel_name,
return true;
}
bool oneapi_kernel_is_raytrace_or_mnee(const std::string &kernel_name)
bool oneapi_kernel_is_compatible_with_hardware_raytracing(const std::string &kernel_name)
{
return (kernel_name.find(device_kernel_as_string(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE)) !=
std::string::npos) ||
/* MNEE and Raytrace kernels work correctly with Hardware Raytracing 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)) ==
std::string::npos) &&
(kernel_name.find(device_kernel_as_string(
DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE)) != std::string::npos);
DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE)) == std::string::npos);
# else
return true;
# endif
}
bool oneapi_kernel_is_using_embree(const std::string &kernel_name)
bool oneapi_kernel_has_intersections(const std::string &kernel_name)
{
# ifdef WITH_EMBREE_GPU
/* MNEE and Ray-trace kernels aren't yet enabled to use Embree. */
for (int i = 0; i < (int)DEVICE_KERNEL_NUM; i++) {
DeviceKernel kernel = (DeviceKernel)i;
if (device_kernel_has_intersection(kernel)) {
if (kernel_name.find(device_kernel_as_string(kernel)) != std::string::npos) {
return !oneapi_kernel_is_raytrace_or_mnee(kernel_name);
return true;
}
}
}
# endif
return false;
}
@ -217,7 +220,8 @@ bool oneapi_load_kernels(SyclQueue *queue_,
const std::string &kernel_name = kernel_id.get_name();
if (!oneapi_kernel_is_required_for_features(kernel_name, kernel_features) ||
!oneapi_kernel_is_using_embree(kernel_name))
!(oneapi_kernel_has_intersections(kernel_name) &&
oneapi_kernel_is_compatible_with_hardware_raytracing(kernel_name)))
{
continue;
}
@ -260,14 +264,14 @@ bool oneapi_load_kernels(SyclQueue *queue_,
/* In case HWRT is on, compilation of kernels using Embree is already handled in previous
* block. */
if (!oneapi_kernel_is_required_for_features(kernel_name, kernel_features) ||
(use_hardware_raytracing && oneapi_kernel_is_using_embree(kernel_name)))
(use_hardware_raytracing && oneapi_kernel_has_intersections(kernel_name) &&
oneapi_kernel_is_compatible_with_hardware_raytracing(kernel_name)))
{
continue;
}
# ifdef WITH_EMBREE_GPU
if (oneapi_kernel_is_using_embree(kernel_name) ||
oneapi_kernel_is_raytrace_or_mnee(kernel_name)) {
if (oneapi_kernel_has_intersections(kernel_name)) {
sycl::kernel_bundle<sycl::bundle_state::input> one_kernel_bundle_input =
sycl::get_kernel_bundle<sycl::bundle_state::input>(queue->get_context(), {kernel_id});
one_kernel_bundle_input

View File

@ -8,6 +8,7 @@
#include "kernel/film/adaptive_sampling.h"
#include "kernel/film/light_passes.h"
#include "kernel/integrator/intersect_closest.h"
#include "kernel/integrator/path_state.h"
#include "kernel/sample/pattern.h"
@ -327,6 +328,8 @@ ccl_device bool integrator_init_from_bake(KernelGlobals kg,
else {
integrator_path_init_sorted(kg, state, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader_index);
}
integrator_split_shadow_catcher(kg, state, &isect, render_buffer);
}
return true;

View File

@ -398,6 +398,7 @@ ccl_device_forceinline bool mnee_newton_solver(KernelGlobals kg,
ccl_private const ShaderData *sd,
ccl_private ShaderData *sd_vtx,
ccl_private const LightSample *ls,
const bool light_fixed_direction,
int vertex_count,
ccl_private ManifoldVertex *vertices)
{
@ -413,7 +414,6 @@ ccl_device_forceinline bool mnee_newton_solver(KernelGlobals kg,
projection_ray.time = sd->time;
Intersection projection_isect;
const bool light_fixed_direction = (ls->t == FLT_MAX);
const float3 light_sample = light_fixed_direction ? ls->D : ls->P;
/* We start gently, potentially ramping up to beta = 1, since target configurations
@ -639,6 +639,7 @@ ccl_device_forceinline Spectrum mnee_eval_bsdf_contribution(ccl_private ShaderCl
/* Compute transfer matrix determinant |T1| = |dx1/dxn| (and |dh/dx| in the process) */
ccl_device_forceinline bool mnee_compute_transfer_matrix(ccl_private const ShaderData *sd,
ccl_private const LightSample *ls,
const bool light_fixed_direction,
int vertex_count,
ccl_private ManifoldVertex *vertices,
ccl_private float *dx1_dxlight,
@ -692,7 +693,7 @@ ccl_device_forceinline bool mnee_compute_transfer_matrix(ccl_private const Shade
float dxn_dwn;
float4 dc_dlight;
if (ls->t == FLT_MAX) {
if (light_fixed_direction) {
/* Constant direction toward light sample. */
float3 wo = ls->D;
@ -764,6 +765,7 @@ ccl_device_forceinline bool mnee_path_contribution(KernelGlobals kg,
ccl_private ShaderData *sd,
ccl_private ShaderData *sd_mnee,
ccl_private LightSample *ls,
const bool light_fixed_direction,
int vertex_count,
ccl_private ManifoldVertex *vertices,
ccl_private BsdfEval *throughput)
@ -807,7 +809,8 @@ ccl_device_forceinline bool mnee_path_contribution(KernelGlobals kg,
float dh_dx;
float dx1_dxlight;
if (!mnee_compute_transfer_matrix(sd, ls, vertex_count, vertices, &dx1_dxlight, &dh_dx))
if (!mnee_compute_transfer_matrix(
sd, ls, light_fixed_direction, vertex_count, vertices, &dx1_dxlight, &dh_dx))
return false;
/* Receiver bsdf eval above already contains |n.wo|. */
@ -882,7 +885,7 @@ ccl_device_forceinline bool mnee_path_contribution(KernelGlobals kg,
kg, state, sd_mnee, NULL, PATH_RAY_DIFFUSE, true);
/* Set light looking dir. */
wo = (vi == vertex_count - 1) ? (ls->t == FLT_MAX ? ls->D : ls->P - v.p) :
wo = (vi == vertex_count - 1) ? (light_fixed_direction ? ls->D : ls->P - v.p) :
vertices[vi + 1].p - v.p;
wo = normalize_len(wo, &wo_len);
@ -1039,12 +1042,22 @@ ccl_device_forceinline int kernel_path_mnee_sample(KernelGlobals kg,
* discontinuity is visible between direct and indirect contributions */
INTEGRATOR_STATE_WRITE(state, path, mnee) |= PATH_MNEE_VALID;
/* 2. Walk on the specular manifold to find vertices on the
* casters that satisfy snell's law for each interface
*/
if (mnee_newton_solver(kg, sd, sd_mnee, ls, vertex_count, vertices)) {
/* Distant or environment light. */
bool light_fixed_direction = (ls->t == FLT_MAX);
if (ls->type == LIGHT_AREA) {
const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ls->lamp);
if (klight->area.tan_half_spread == 0.0f) {
/* Area light with zero spread also has fixed direction. */
light_fixed_direction = true;
}
}
/* 2. Walk on the specular manifold to find vertices on the casters that satisfy snell's law for
* each interface. */
if (mnee_newton_solver(kg, sd, sd_mnee, ls, light_fixed_direction, vertex_count, vertices)) {
/* 3. If a solution exists, calculate contribution of the corresponding path */
if (!mnee_path_contribution(kg, state, sd, sd_mnee, ls, vertex_count, vertices, throughput))
if (!mnee_path_contribution(
kg, state, sd, sd_mnee, ls, light_fixed_direction, vertex_count, vertices, throughput))
return 0;
return vertex_count;

View File

@ -227,55 +227,43 @@ ccl_device bool area_light_spread_clamp_light(const float3 P,
}
/* Common API. */
/* Compute `eval_fac` and `pdf`. Also sample a new position on the light if `sample_coord`. */
template<bool in_volume_segment>
ccl_device_inline bool area_light_sample(const ccl_global KernelLight *klight,
const float randu,
const float randv,
const float3 P,
ccl_private LightSample *ls)
ccl_device_inline bool area_light_eval(const ccl_global KernelLight *klight,
const float3 ray_P,
ccl_private float3 *light_P,
ccl_private LightSample *ccl_restrict ls,
float randu,
float randv,
bool sample_coord)
{
ls->P = klight->co;
float3 axis_u = klight->area.axis_u;
float3 axis_v = klight->area.axis_v;
float len_u = klight->area.len_u;
float len_v = klight->area.len_v;
float3 Ng = klight->area.dir;
const float3 Ng = klight->area.dir;
const float invarea = fabsf(klight->area.invarea);
bool sample_rectangle = (klight->area.invarea > 0.0f);
if (!in_volume_segment) {
if (dot(ls->P - P, Ng) > 0.0f) {
return false;
}
}
const float3 axis_u = klight->area.axis_u;
const float3 axis_v = klight->area.axis_v;
const float len_u = klight->area.len_u;
const float len_v = klight->area.len_v;
float invarea = fabsf(klight->area.invarea);
bool is_ellipse = (klight->area.invarea < 0.0f);
bool sample_rectangle = !is_ellipse;
float3 inplane;
float3 light_P_new = *light_P;
if (in_volume_segment) {
inplane = sample_rectangle ?
rectangle_sample(axis_u * len_u * 0.5f, axis_v * len_v * 0.5f, randu, randv) :
ellipse_sample(axis_u * len_u * 0.5f, axis_v * len_v * 0.5f, randu, randv);
ls->P += inplane;
light_P_new += sample_rectangle ?
rectangle_sample(
axis_u * len_u * 0.5f, axis_v * len_v * 0.5f, randu, randv) :
ellipse_sample(axis_u * len_u * 0.5f, axis_v * len_v * 0.5f, randu, randv);
ls->pdf = invarea;
}
else {
float3 old_P = ls->P;
float3 sample_axis_u = axis_u;
float3 sample_axis_v = axis_v;
float sample_len_u = len_u;
float sample_len_v = len_v;
if (klight->area.normalize_spread > 0) {
if (!area_light_spread_clamp_light(P,
if (!area_light_spread_clamp_light(ray_P,
Ng,
&ls->P,
&sample_axis_u,
&sample_len_u,
&sample_axis_v,
&sample_len_v,
&light_P_new,
&axis_u,
&len_u,
&axis_v,
&len_v,
klight->area.tan_half_spread,
&sample_rectangle))
{
@ -285,53 +273,82 @@ ccl_device_inline bool area_light_sample(const ccl_global KernelLight *klight,
if (sample_rectangle) {
ls->pdf = area_light_rect_sample(
P, &ls->P, sample_axis_u, sample_len_u, sample_axis_v, sample_len_v, randu, randv, true);
ray_P, &light_P_new, axis_u, len_u, axis_v, len_v, randu, randv, sample_coord);
}
else {
if (klight->area.tan_half_spread == 0.0f) {
ls->pdf = 1.0f;
}
else {
ls->P += ellipse_sample(sample_axis_u * sample_len_u * 0.5f,
sample_axis_v * sample_len_v * 0.5f,
randu,
randv);
ls->pdf = 4.0f * M_1_PI_F / (sample_len_u * sample_len_v);
if (sample_coord) {
light_P_new += ellipse_sample(
axis_u * len_u * 0.5f, axis_v * len_v * 0.5f, randu, randv);
}
ls->pdf = 4.0f * M_1_PI_F / (len_u * len_v);
}
}
inplane = ls->P - old_P;
}
const float light_u = dot(inplane, axis_u) / len_u;
const float light_v = dot(inplane, axis_v) / len_v;
/* Sampled point lies outside of the area light. */
if (is_ellipse && (sqr(light_u) + sqr(light_v) > 0.25f)) {
return false;
if (sample_coord) {
*light_P = light_P_new;
ls->D = normalize_len(*light_P - ray_P, &ls->t);
}
if (!is_ellipse && (fabsf(light_u) > 0.5f || fabsf(light_v) > 0.5f)) {
return false;
}
/* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */
ls->u = light_v + 0.5f;
ls->v = -light_u - light_v;
ls->Ng = Ng;
ls->D = normalize_len(ls->P - P, &ls->t);
ls->eval_fac = 0.25f * invarea;
if (klight->area.normalize_spread > 0) {
/* Area Light spread angle attenuation */
ls->eval_fac *= area_light_spread_attenuation(
ls->D, ls->Ng, klight->area.tan_half_spread, klight->area.normalize_spread);
ls->D, Ng, klight->area.tan_half_spread, klight->area.normalize_spread);
}
if (!sample_rectangle && klight->area.tan_half_spread > 0) {
if (in_volume_segment || (!sample_rectangle && klight->area.tan_half_spread > 0)) {
ls->pdf *= lamp_light_pdf(Ng, -ls->D, ls->t);
}
return ls->eval_fac > 0;
}
template<bool in_volume_segment>
ccl_device_inline bool area_light_sample(const ccl_global KernelLight *klight,
const float randu,
const float randv,
const float3 P,
ccl_private LightSample *ls)
{
ls->P = klight->co;
ls->Ng = klight->area.dir;
if (!in_volume_segment) {
if (dot(ls->P - P, ls->Ng) > 0.0f) {
return false;
}
}
if (!area_light_eval<in_volume_segment>(klight, P, &ls->P, ls, randu, randv, true)) {
return false;
}
const float3 inplane = ls->P - klight->co;
const float light_u = dot(inplane, klight->area.axis_u) / klight->area.len_u;
const float light_v = dot(inplane, klight->area.axis_v) / klight->area.len_v;
if (!in_volume_segment) {
const bool is_ellipse = (klight->area.invarea < 0.0f);
/* Sampled point lies outside of the area light. */
if (is_ellipse && (sqr(light_u) + sqr(light_v) > 0.25f)) {
return false;
}
if (!is_ellipse && (fabsf(light_u) > 0.5f || fabsf(light_v) > 0.5f)) {
return false;
}
}
/* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */
ls->u = light_v + 0.5f;
ls->v = -light_u - light_v;
return true;
}
@ -339,14 +356,15 @@ ccl_device_forceinline void area_light_update_position(const ccl_global KernelLi
ccl_private LightSample *ls,
const float3 P)
{
const float invarea = fabsf(klight->area.invarea);
ls->D = normalize_len(ls->P - P, &ls->t);
ls->pdf = invarea;
if (klight->area.normalize_spread > 0) {
ls->eval_fac = 0.25f * invarea;
ls->eval_fac *= area_light_spread_attenuation(
ls->D, ls->Ng, klight->area.tan_half_spread, klight->area.normalize_spread);
if (klight->area.tan_half_spread == 0) {
/* Update position on the light to keep the direction fixed. */
area_light_eval<false>(klight, P, &ls->P, ls, 0, 0, true);
}
else {
ls->D = normalize_len(ls->P - P, &ls->t);
area_light_eval<false>(klight, P, &ls->P, ls, 0, 0, false);
/* Convert pdf to be in area measure. */
ls->pdf /= lamp_light_pdf(ls->Ng, -ls->D, ls->t);
}
}
@ -397,60 +415,13 @@ ccl_device_inline bool area_light_sample_from_intersection(
const float3 ray_D,
ccl_private LightSample *ccl_restrict ls)
{
/* area light */
float invarea = fabsf(klight->area.invarea);
float3 Ng = klight->area.dir;
float3 light_P = klight->co;
ls->u = isect->u;
ls->v = isect->v;
ls->D = ray_D;
ls->Ng = Ng;
ls->Ng = klight->area.dir;
float3 sample_axis_u = klight->area.axis_u;
float3 sample_axis_v = klight->area.axis_v;
float sample_len_u = klight->area.len_u;
float sample_len_v = klight->area.len_v;
bool is_ellipse = (klight->area.invarea < 0.0f);
bool sample_rectangle = !is_ellipse;
if (klight->area.normalize_spread > 0) {
if (!area_light_spread_clamp_light(ray_P,
Ng,
&light_P,
&sample_axis_u,
&sample_len_u,
&sample_axis_v,
&sample_len_v,
klight->area.tan_half_spread,
&sample_rectangle))
{
return false;
}
}
if (sample_rectangle) {
ls->pdf = area_light_rect_sample(
ray_P, &light_P, sample_axis_u, sample_len_u, sample_axis_v, sample_len_v, 0, 0, false);
}
else {
ls->pdf = klight->area.tan_half_spread == 0.0f ?
1.0f :
4.0f * M_1_PI_F / (sample_len_u * sample_len_v) *
lamp_light_pdf(Ng, -ray_D, ls->t);
}
ls->eval_fac = 0.25f * invarea;
if (klight->area.normalize_spread > 0) {
/* Area Light spread angle attenuation */
ls->eval_fac *= area_light_spread_attenuation(
ls->D, ls->Ng, klight->area.tan_half_spread, klight->area.normalize_spread);
}
return ls->eval_fac > 0;
float3 light_P = klight->co;
return area_light_eval<false>(klight, ray_P, &light_P, ls, 0, 0, false);
}
template<bool in_volume_segment>

View File

@ -36,7 +36,7 @@ static float shutter_curve_eval(float x, array<float> &shutter_curve)
int index = (int)x;
float frac = x - index;
if (index < shutter_curve.size() - 1) {
return lerp(shutter_curve[index], shutter_curve[index + 1], frac);
return mix(shutter_curve[index], shutter_curve[index + 1], frac);
}
else {
return shutter_curve[shutter_curve.size() - 1];

View File

@ -1291,7 +1291,7 @@ template<class T> void init_test_curve(array<T> &buffer, T start, T end, int ste
buffer.resize(steps);
for (int i = 0; i < steps; i++) {
buffer[i] = lerp(start, end, float(i) / (steps - 1));
buffer[i] = mix(start, end, float(i) / (steps - 1));
}
}

View File

@ -555,16 +555,6 @@ CCL_NAMESPACE_END
CCL_NAMESPACE_BEGIN
#if !defined(__KERNEL_METAL__)
/* Interpolation */
template<class A, class B> A lerp(const A &a, const A &b, const B &t)
{
return (A)(a * ((B)1 - t) + b * t);
}
#endif /* __KERNEL_METAL__ */
/* Triangle */
ccl_device_inline float triangle_area(ccl_private const float3 &v1,

View File

@ -379,7 +379,7 @@ ccl_device_inline Transform transform_empty()
ccl_device_inline float4 quat_interpolate(float4 q1, float4 q2, float t)
{
/* Optix and MetalRT are using lerp to interpolate motion transformations. */
/* Optix and MetalRT are using linear interpolation to interpolate motion transformations. */
#if defined(__KERNEL_GPU_RAYTRACING__)
return normalize((1.0f - t) * q1 + t * q2);
#else /* defined(__KERNEL_GPU_RAYTRACING__) */

View File

@ -1018,9 +1018,44 @@ class WM_OT_url_open(Operator):
description="URL to open",
)
@staticmethod
def _add_utm_param_to_url(url, utm_source):
import urllib
# Make sure we have a scheme otherwise we can't parse the url.
if not url.startswith(("http://", "https://")):
url = "https://" + url
# Parse the URL to get its domain and query parameters.
parsed_url = urllib.parse.urlparse(url)
domain = parsed_url.netloc
# Only add a utm source if it points to a blender.org domain.
if not (domain.endswith(".blender.org") or domain == "blender.org"):
return url
# Parse the query parameters and add or update the utm_source parameter.
query_params = urllib.parse.parse_qs(parsed_url.query)
query_params["utm_source"] = utm_source
new_query = urllib.parse.urlencode(query_params, doseq=True)
# Create a new URL with the updated query parameters.
new_url_parts = list(parsed_url)
new_url_parts[4] = new_query
new_url = urllib.parse.urlunparse(new_url_parts)
return new_url
@staticmethod
def _get_utm_source():
version = bpy.app.version_string
formatted_version = version.replace(' ', '-').lower()
return f"blender-{formatted_version}"
def execute(self, _context):
import webbrowser
webbrowser.open(self.url)
complete_url = self._add_utm_param_to_url(self.url, self._get_utm_source())
webbrowser.open(complete_url)
return {'FINISHED'}
@ -1102,10 +1137,7 @@ class WM_OT_url_open_preset(Operator):
url = url(self, context)
break
import webbrowser
webbrowser.open(url)
return {'FINISHED'}
return bpy.ops.wm.url_open(url=url)
class WM_OT_path_open(Operator):
@ -1307,9 +1339,7 @@ class WM_OT_doc_view_manual(Operator):
)
return {'CANCELLED'}
else:
import webbrowser
webbrowser.open(url)
return {'FINISHED'}
return bpy.ops.wm.url_open(url=url)
class WM_OT_doc_view(Operator):
@ -1325,10 +1355,7 @@ class WM_OT_doc_view(Operator):
if url is None:
return {'CANCELLED'}
import webbrowser
webbrowser.open(url)
return {'FINISHED'}
return bpy.ops.wm.url_open(url=url)
rna_path = StringProperty(

View File

@ -435,7 +435,9 @@ class IMAGE_MT_uvs(Menu):
layout.separator()
layout.operator_context = 'INVOKE_DEFAULT'
layout.operator("uv.pack_islands")
layout.operator_context = 'EXEC_REGION_WIN'
layout.operator("uv.average_islands_scale")
layout.separator()

View File

@ -168,6 +168,7 @@ class TIME_MT_cache(Menu):
col.prop(st, "cache_softbody")
col.prop(st, "cache_particles")
col.prop(st, "cache_cloth")
col.prop(st, "cache_simulation_nodes")
col.prop(st, "cache_smoke")
col.prop(st, "cache_dynamicpaint")
col.prop(st, "cache_rigidbody")

View File

@ -5,6 +5,8 @@
#include "BLI_array.hh"
#include "BLI_color.hh"
#include "BLI_cpp_type.hh"
#include "BLI_generic_span.hh"
#include "BLI_generic_virtual_array.hh"
#include "BLI_math_color.hh"
#include "BLI_math_vector.h"
#include "BLI_math_vector.hh"
@ -587,4 +589,16 @@ template<typename T> using DefaultMixer = typename DefaultMixerStruct<T>::type;
/** \} */
/* -------------------------------------------------------------------- */
/** \name Generic Array Utils Implementations
*
* Extra implementations of functions from #BLI_array_utils.hh for all attribute types,
* used to avoid templating the same logic for each type in many places.
* \{ */
void gather(GSpan src, Span<int> map, GMutableSpan dst);
void gather(const GVArray &src, Span<int> map, GMutableSpan dst);
/** \} */
} // namespace blender::bke::attribute_math

View File

@ -31,7 +31,7 @@ extern "C" {
* 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_SUBVERSION 10
/** User readable version string. */
const char *BKE_blender_version_string(void);

View File

@ -303,6 +303,12 @@ void BKE_collection_parent_relations_rebuild(struct Collection *collection);
*/
void BKE_main_collections_parent_relations_rebuild(struct Main *bmain);
/**
* Perform some validation on integrity of the data of this collection.
*
* \return `true` if everything is OK, false if some errors are detected. */
bool BKE_collection_validate(struct Collection *collection);
/* .blend file I/O */
void BKE_collection_blend_write_nolib(struct BlendWriter *writer, struct Collection *collection);

View File

@ -47,7 +47,7 @@ float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash);
bool BKE_cryptomatte_find_name(const struct CryptomatteSession *session,
float encoded_hash,
char *r_name,
int name_len);
int name_maxncpy);
char *BKE_cryptomatte_entries_to_matte_id(struct NodeCryptomatte *node_storage);
void BKE_cryptomatte_matte_id_to_entries(struct NodeCryptomatte *node_storage,

View File

@ -118,9 +118,15 @@ struct CryptomatteStampDataCallbackData {
static blender::StringRef extract_layer_hash(blender::StringRefNull key);
/* C type callback function (StampCallback). */
static void extract_layer_names(void *_data, const char *propname, char *propvalue, int len);
static void extract_layer_names(void *_data,
const char *propname,
char *propvalue,
int propvalue_maxncpy);
/* C type callback function (StampCallback). */
static void extract_layer_manifest(void *_data, const char *propname, char *propvalue, int len);
static void extract_layer_manifest(void *_data,
const char *propname,
char *propvalue,
int propvalue_maxncpy);
};
const blender::Vector<std::string> &BKE_cryptomatte_layer_names_get(

View File

@ -50,7 +50,10 @@ void BKE_image_free_gputextures(struct Image *ima);
*/
void BKE_image_free_data(struct Image *image);
typedef void(StampCallback)(void *data, const char *propname, char *propvalue, int len);
typedef void(StampCallback)(void *data,
const char *propname,
char *propvalue,
int propvalue_maxncpy);
void BKE_render_result_stamp_info(struct Scene *scene,
struct Object *camera,

View File

@ -422,7 +422,7 @@ bActionGroup *action_groups_add_new(bAction *act, const char name[])
/* make it selected, with default name */
agrp->flag = AGRP_SELECTED;
STRNCPY(agrp->name, name[0] ? name : DATA_("Group"));
STRNCPY_UTF8(agrp->name, name[0] ? name : DATA_("Group"));
/* add to action, and validate */
BLI_addtail(&act->groups, agrp);

View File

@ -169,7 +169,7 @@ static void action_flip_pchan(Object *ob_arm,
BLI_str_escape(pchan_name_esc, pchan->name, sizeof(pchan_name_esc));
const int path_xform_prefix_len = SNPRINTF(path_xform, "pose.bones[\"%s\"]", pchan_name_esc);
char *path_xform_suffix = path_xform + path_xform_prefix_len;
const int path_xform_suffix_len = sizeof(path_xform) - path_xform_prefix_len;
const int path_xform_suffix_maxncpy = sizeof(path_xform) - path_xform_prefix_len;
/* Lookup and assign all available #FCurve channels,
* unavailable channels are left NULL. */
@ -191,11 +191,11 @@ static void action_flip_pchan(Object *ob_arm,
} fkc_pchan = {{{NULL}}};
#define FCURVE_ASSIGN_VALUE(id, path_test_suffix, index) \
BLI_strncpy(path_xform_suffix, path_test_suffix, path_xform_suffix_len); \
BLI_strncpy(path_xform_suffix, path_test_suffix, path_xform_suffix_maxncpy); \
action_flip_pchan_cache_fcurve_assign_value(&fkc_pchan.id, index, path_xform, fcache)
#define FCURVE_ASSIGN_ARRAY(id, path_test_suffix) \
BLI_strncpy(path_xform_suffix, path_test_suffix, path_xform_suffix_len); \
BLI_strncpy(path_xform_suffix, path_test_suffix, path_xform_suffix_maxncpy); \
action_flip_pchan_cache_fcurve_assign_array( \
fkc_pchan.id, ARRAY_SIZE(fkc_pchan.id), path_xform, fcache)

View File

@ -131,8 +131,8 @@ KeyingSet *BKE_keyingset_add(
/* allocate new KeyingSet */
ks = MEM_callocN(sizeof(KeyingSet), "KeyingSet");
STRNCPY(ks->idname, (idname) ? idname : (name) ? name : DATA_("KeyingSet"));
STRNCPY(ks->name, (name) ? name : (idname) ? idname : DATA_("Keying Set"));
STRNCPY_UTF8(ks->idname, (idname) ? idname : (name) ? name : DATA_("KeyingSet"));
STRNCPY_UTF8(ks->name, (name) ? name : (idname) ? idname : DATA_("Keying Set"));
ks->flag = flag;
ks->keyingflag = keyingflag;

View File

@ -173,10 +173,10 @@ bool BKE_id_attribute_rename(ID *id,
* is clamped to it's maximum length, otherwise assigning an over-long name multiple times
* will add `.001` suffix unnecessarily. */
{
const int maxlength = CustomData_name_max_length_calc(new_name);
const int new_name_maxncpy = CustomData_name_max_length_calc(new_name);
/* NOTE: A function that performs a clamped comparison without copying would be handy here. */
char new_name_clamped[MAX_CUSTOMDATA_LAYER_NAME];
BLI_strncpy_utf8(new_name_clamped, new_name, maxlength);
BLI_strncpy_utf8(new_name_clamped, new_name, new_name_maxncpy);
if (STREQ(old_name, new_name_clamped)) {
return false;
}
@ -254,19 +254,14 @@ static bool unique_name_cb(void *arg, const char *name)
bool BKE_id_attribute_calc_unique_name(ID *id, const char *name, char *outname)
{
AttrUniqueData data{id};
const int maxlength = CustomData_name_max_length_calc(name);
const int name_maxncpy = CustomData_name_max_length_calc(name);
/* Set default name if none specified.
* NOTE: We only call IFACE_() if needed to avoid locale lookup overhead. */
if (!name || name[0] == '\0') {
BLI_strncpy(outname, IFACE_("Attribute"), maxlength);
}
else {
BLI_strncpy_utf8(outname, name, maxlength);
}
BLI_strncpy_utf8(outname, (name && name[0]) ? name : IFACE_("Attribute"), name_maxncpy);
const char *defname = ""; /* Dummy argument, never used as `name` is never zero length. */
return BLI_uniquename_cb(unique_name_cb, &data, defname, '.', outname, maxlength);
return BLI_uniquename_cb(unique_name_cb, &data, defname, '.', outname, name_maxncpy);
}
CustomDataLayer *BKE_id_attribute_new(ID *id,

View File

@ -1,5 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_array_utils.hh"
#include "BKE_attribute_math.hh"
namespace blender::bke::attribute_math {
@ -128,4 +130,20 @@ void ColorGeometry4bMixer::finalize(const IndexMask mask)
});
}
void gather(const GSpan src, const Span<int> map, GMutableSpan dst)
{
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
array_utils::gather(src.typed<T>(), map, dst.typed<T>());
});
}
void gather(const GVArray &src, const Span<int> map, GMutableSpan dst)
{
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
array_utils::gather(src.typed<T>(), map, dst.typed<T>());
});
}
} // namespace blender::bke::attribute_math

View File

@ -1617,7 +1617,7 @@ BoidRule *boid_new_rule(int type)
rule->type = type;
rule->flag |= BOIDRULE_IN_AIR | BOIDRULE_ON_LAND;
STRNCPY(rule->name, DATA_(rna_enum_boidrule_type_items[type - 1].name));
STRNCPY_UTF8(rule->name, DATA_(rna_enum_boidrule_type_items[type - 1].name));
return rule;
}

View File

@ -1944,6 +1944,49 @@ void BKE_main_collections_parent_relations_rebuild(Main *bmain)
}
}
bool BKE_collection_validate(struct Collection *collection)
{
if (!BLI_listbase_validate(&collection->children)) {
return false;
}
if (!BLI_listbase_validate(&collection->runtime.parents)) {
return false;
}
if (BKE_collection_cycle_find(collection, NULL)) {
return false;
}
bool is_ok = true;
/* Check that children have each collection used/referenced only once. */
GSet *processed_collections = BLI_gset_ptr_new(__func__);
for (CollectionChild *child = collection->children.first; child; child = child->next) {
void **r_key;
if (BLI_gset_ensure_p_ex(processed_collections, child->collection, &r_key)) {
is_ok = false;
}
else {
*r_key = child->collection;
}
}
/* Check that parents have each collection used/referenced only once. */
BLI_gset_clear(processed_collections, NULL);
for (CollectionParent *parent = collection->runtime.parents.first; parent; parent = parent->next)
{
void **r_key;
if (BLI_gset_ensure_p_ex(processed_collections, parent->collection, &r_key)) {
is_ok = false;
}
else {
*r_key = parent->collection;
}
}
BLI_gset_free(processed_collections, NULL);
return is_ok;
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -219,14 +219,14 @@ float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash)
bool BKE_cryptomatte_find_name(const CryptomatteSession *session,
const float encoded_hash,
char *r_name,
int name_len)
int name_maxncpy)
{
std::optional<std::string> name = (*session)[encoded_hash];
if (!name) {
return false;
}
BLI_strncpy(r_name, name->c_str(), name_len);
BLI_strncpy(r_name, name->c_str(), name_maxncpy);
return true;
}
@ -580,7 +580,7 @@ blender::StringRef CryptomatteStampDataCallbackData::extract_layer_hash(blender:
void CryptomatteStampDataCallbackData::extract_layer_names(void *_data,
const char *propname,
char *propvalue,
int /*len*/)
int /*propvalue_maxncpy*/)
{
CryptomatteStampDataCallbackData *data = static_cast<CryptomatteStampDataCallbackData *>(_data);
@ -598,7 +598,7 @@ void CryptomatteStampDataCallbackData::extract_layer_names(void *_data,
void CryptomatteStampDataCallbackData::extract_layer_manifest(void *_data,
const char *propname,
char *propvalue,
int /*len*/)
int /*propvalue_maxncpy*/)
{
CryptomatteStampDataCallbackData *data = static_cast<CryptomatteStampDataCallbackData *>(_data);

View File

@ -91,7 +91,7 @@ TEST(cryptomatte, extract_layer_hash_from_metadata_key)
static void validate_cryptomatte_session_from_stamp_data(void * /*data*/,
const char *propname,
char *propvalue,
int /*len*/)
int /*propvalue_maxncpy*/)
{
blender::StringRefNull prop_name(propname);
if (!prop_name.startswith("cryptomatte/")) {

View File

@ -1124,14 +1124,6 @@ static void copy_construct_data(const GSpan src, GMutableSpan dst)
src.type().copy_construct_n(src.data(), dst.data(), src.size());
}
static void copy_with_map(const GSpan src, const Span<int> map, GMutableSpan dst)
{
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
array_utils::gather(src.typed<T>(), map, dst.typed<T>());
});
}
static CurvesGeometry copy_with_removed_points(
const CurvesGeometry &curves,
const IndexMask points_to_delete,
@ -1216,7 +1208,7 @@ static CurvesGeometry copy_with_removed_points(
attribute.dst.span.copy_from(attribute.src);
}
else {
copy_with_map(attribute.src, new_curve_orig_indices, attribute.dst.span);
bke::attribute_math::gather(attribute.src, new_curve_orig_indices, attribute.dst.span);
}
}
});

View File

@ -30,6 +30,7 @@
#include "BLI_span.hh"
#include "BLI_string.h"
#include "BLI_string_ref.hh"
#include "BLI_string_utf8.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
@ -4413,7 +4414,7 @@ void CustomData_set_layer_unique_name(CustomData *data, const int index)
/* Set default name if none specified. Note we only call DATA_() when
* needed to avoid overhead of locale lookups in the depsgraph. */
if (nlayer->name[0] == '\0') {
STRNCPY(nlayer->name, DATA_(typeInfo->defaultname));
STRNCPY_UTF8(nlayer->name, DATA_(typeInfo->defaultname));
}
const char *defname = ""; /* Dummy argument, never used as `name` is never zero length. */
@ -4437,10 +4438,10 @@ void CustomData_validate_layer_name(const CustomData *data,
* deleted, so assign the active layer to name
*/
index = CustomData_get_active_layer_index(data, type);
BLI_strncpy(outname, data->layers[index].name, MAX_CUSTOMDATA_LAYER_NAME);
BLI_strncpy_utf8(outname, data->layers[index].name, MAX_CUSTOMDATA_LAYER_NAME);
}
else {
BLI_strncpy(outname, name, MAX_CUSTOMDATA_LAYER_NAME);
BLI_strncpy_utf8(outname, name, MAX_CUSTOMDATA_LAYER_NAME);
}
}

View File

@ -405,7 +405,7 @@ static bool surface_duplicateNameExists(void *arg, const char *name)
void dynamicPaintSurface_setUniqueName(DynamicPaintSurface *surface, const char *basename)
{
char name[64];
STRNCPY(name, basename); /* in case basename is surface->name use a copy */
STRNCPY_UTF8(name, basename); /* in case basename is surface->name use a copy */
BLI_uniquename_cb(
surface_duplicateNameExists, surface, name, '.', surface->name, sizeof(surface->name));
}

View File

@ -16,6 +16,7 @@
#include "BLI_expr_pylike_eval.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string_utf8.h"
#include "BLI_string_utils.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@ -955,7 +956,7 @@ DriverVar *driver_add_new_variable(ChannelDriver *driver)
BLI_addtail(&driver->variables, dvar);
/* Give the variable a 'unique' name. */
strcpy(dvar->name, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"));
STRNCPY_UTF8(dvar->name, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"));
BLI_uniquename(&driver->variables,
dvar,
CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"),

View File

@ -675,7 +675,7 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd,
}
/* auto-name */
STRNCPY(gpl->info, DATA_(name));
STRNCPY_UTF8(gpl->info, DATA_(name));
BLI_uniquename(&gpd->layers,
gpl,
(gpd->flag & GP_DATA_ANNOTATIONS) ? DATA_("Note") : DATA_("GP_Layer"),

View File

@ -356,7 +356,7 @@ GpencilModifierData *BKE_gpencil_modifier_new(int type)
GpencilModifierData *md = MEM_callocN(mti->struct_size, mti->struct_name);
/* NOTE: this name must be made unique later. */
STRNCPY(md->name, DATA_(mti->name));
STRNCPY_UTF8(md->name, DATA_(mti->name));
md->type = type;
md->mode = eGpencilModifierMode_Realtime | eGpencilModifierMode_Render;

View File

@ -2486,18 +2486,24 @@ void BKE_stamp_data_free(StampData *stamp_data)
}
/* wrap for callback only */
static void metadata_set_field(void *data, const char *propname, char *propvalue, int /*len*/)
static void metadata_set_field(void *data,
const char *propname,
char *propvalue,
int /*propvalue_maxncpy*/)
{
/* We know it is an ImBuf* because that's what we pass to BKE_stamp_info_callback. */
ImBuf *imbuf = static_cast<ImBuf *>(data);
IMB_metadata_set_field(imbuf->metadata, propname, propvalue);
}
static void metadata_get_field(void *data, const char *propname, char *propvalue, int len)
static void metadata_get_field(void *data,
const char *propname,
char *propvalue,
int propvalue_maxncpy)
{
/* We know it is an ImBuf* because that's what we pass to BKE_stamp_info_callback. */
ImBuf *imbuf = static_cast<ImBuf *>(data);
IMB_metadata_get_field(imbuf->metadata, propname, propvalue, len);
IMB_metadata_get_field(imbuf->metadata, propname, propvalue, propvalue_maxncpy);
}
void BKE_imbuf_stamp_info(const RenderResult *rr, ImBuf *ibuf)

View File

@ -1845,7 +1845,7 @@ KeyBlock *BKE_keyblock_add(Key *key, const char *name)
}
else {
if (tot == 1) {
STRNCPY(kb->name, DATA_("Basis"));
STRNCPY_UTF8(kb->name, DATA_("Basis"));
}
else {
SNPRINTF(kb->name, DATA_("Key %d"), tot - 1);

View File

@ -787,7 +787,7 @@ void BKE_layer_collection_resync_allow(void)
}
struct LayerCollectionResync {
LayerCollectionResync *prev, *next;
LayerCollectionResync *next, *prev;
/* Temp data used to generate a queue during valid layer search. See
* #layer_collection_resync_find. */
@ -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 differed re-sync system */
/* NOTE: This is not (yet?) covered by the dirty tag and deffered re-sync system. */
BKE_layer_collection_local_sync_all(bmain);
}
@ -2522,7 +2522,7 @@ ViewLayerAOV *BKE_view_layer_add_aov(ViewLayer *view_layer)
ViewLayerAOV *aov;
aov = MEM_cnew<ViewLayerAOV>(__func__);
aov->type = AOV_TYPE_COLOR;
STRNCPY(aov->name, DATA_("AOV"));
STRNCPY_UTF8(aov->name, DATA_("AOV"));
BLI_addtail(&view_layer->aovs, aov);
viewlayer_aov_active_set(view_layer, aov);
viewlayer_aov_make_name_unique(view_layer);
@ -2642,12 +2642,7 @@ ViewLayerLightgroup *BKE_view_layer_add_lightgroup(ViewLayer *view_layer, const
{
ViewLayerLightgroup *lightgroup;
lightgroup = MEM_cnew<ViewLayerLightgroup>(__func__);
if (name && name[0]) {
STRNCPY(lightgroup->name, name);
}
else {
STRNCPY(lightgroup->name, DATA_("Lightgroup"));
}
STRNCPY_UTF8(lightgroup->name, (name && name[0]) ? name : DATA_("Lightgroup"));
BLI_addtail(&view_layer->lightgroups, lightgroup);
viewlayer_lightgroup_active_set(view_layer, lightgroup);
viewlayer_lightgroup_make_name_unique(view_layer, lightgroup);

View File

@ -1603,7 +1603,7 @@ bool BKE_id_new_name_validate(
if (name[0] == '\0') {
/* Disallow empty names. */
STRNCPY(name, DATA_(BKE_idtype_idcode_to_name(GS(id->name))));
STRNCPY_UTF8(name, DATA_(BKE_idtype_idcode_to_name(GS(id->name))));
}
else {
/* disallow non utf8 chars,

View File

@ -404,6 +404,11 @@ uint64_t BKE_library_id_can_use_filter_id(const ID *id_owner, const bool include
return FILTER_ID_ALL;
}
if (ID_IS_OVERRIDE_LIBRARY_REAL(id_owner)) {
/* LibOverride data 'hierarchy root' can virtually point back to any type of ID. */
return FILTER_ID_ALL;
}
switch ((ID_Type)id_type_owner) {
case ID_LI:
return FILTER_ID_LI;

View File

@ -37,6 +37,7 @@
#include "BLI_path_util.h"
#include "BLI_session_uuid.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
@ -137,7 +138,7 @@ static ModifierData *modifier_allocate_and_init(ModifierType type)
ModifierData *md = static_cast<ModifierData *>(MEM_callocN(mti->structSize, mti->structName));
/* NOTE: this name must be made unique later. */
STRNCPY(md->name, DATA_(mti->name));
STRNCPY_UTF8(md->name, DATA_(mti->name));
md->type = type;
md->mode = eModifierMode_Realtime | eModifierMode_Render;

View File

@ -1521,8 +1521,10 @@ void multires_ensure_external_read(struct Mesh *mesh, int top_level)
return;
}
MDisps *mdisps = static_cast<MDisps *>(
CustomData_get_layer_for_write(&mesh->ldata, CD_MDISPS, mesh->totloop));
/* Modify the data array from the original mesh, not the evaluated mesh.
* When multiple objects share the same mesh, this can lead to memory leaks. */
MDisps *mdisps = const_cast<MDisps *>(
static_cast<const MDisps *>(CustomData_get_layer(&mesh->ldata, CD_MDISPS)));
if (mdisps == nullptr) {
mdisps = static_cast<MDisps *>(
CustomData_add_layer(&mesh->ldata, CD_MDISPS, CD_SET_DEFAULT, mesh->totloop));

View File

@ -40,6 +40,7 @@
#include "BLI_set.hh"
#include "BLI_stack.hh"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_string_utils.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@ -1161,7 +1162,7 @@ static void node_init(const bContext *C, bNodeTree *ntree, bNode *node)
* Data have their own translation option!
* This solution may be a bit rougher than nodeLabel()'s returned string, but it's simpler
* than adding "do_translate" flags to this func (and labelfunc() as well). */
STRNCPY(node->name, DATA_(ntype->ui_name));
STRNCPY_UTF8(node->name, DATA_(ntype->ui_name));
nodeUniqueName(ntree, node);
/* Generally sockets should be added after the initialization, because the set of sockets might

View File

@ -481,9 +481,9 @@ char *BKE_packedfile_unpack_to_file(ReportList *reports,
static void unpack_generate_paths(const char *filepath,
ID *id,
char *r_abspath,
size_t abspath_maxncpy,
char *r_relpath,
size_t abspathlen,
size_t relpathlen)
size_t relpath_maxncpy)
{
const short id_type = GS(id->name);
char temp_filename[FILE_MAX];
@ -545,13 +545,13 @@ static void unpack_generate_paths(const char *filepath,
break;
}
if (dir_name) {
BLI_path_join(r_relpath, relpathlen, "//", dir_name, temp_filename);
BLI_path_join(r_relpath, relpath_maxncpy, "//", dir_name, temp_filename);
}
}
{
size_t len = BLI_strncpy_rlen(r_abspath, temp_dirname, abspathlen);
BLI_strncpy(r_abspath + len, temp_filename, abspathlen - len);
size_t len = BLI_strncpy_rlen(r_abspath, temp_dirname, abspath_maxncpy);
BLI_strncpy(r_abspath + len, temp_filename, abspath_maxncpy - len);
}
}
@ -567,7 +567,7 @@ char *BKE_packedfile_unpack(Main *bmain,
if (id != NULL) {
unpack_generate_paths(
orig_file_path, id, absname, localname, sizeof(absname), sizeof(localname));
orig_file_path, id, absname, sizeof(absname), localname, sizeof(localname));
new_name = BKE_packedfile_unpack_to_file(
reports, BKE_main_blendfile_path(bmain), absname, localname, pf, how);
}

View File

@ -910,7 +910,7 @@ static bool seq_foreach_path_callback(Sequence *seq, void *user_data)
BPathForeachPathData *bpath_data = (BPathForeachPathData *)user_data;
if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM) && se) {
BKE_bpath_foreach_path_dirfile_fixed_process(bpath_data, seq->strip->dir, se->name);
BKE_bpath_foreach_path_dirfile_fixed_process(bpath_data, seq->strip->dirpath, se->filename);
}
else if ((seq->type == SEQ_TYPE_IMAGE) && se) {
/* NOTE: An option not to loop over all strips could be useful? */
@ -923,12 +923,13 @@ static bool seq_foreach_path_callback(Sequence *seq, void *user_data)
}
for (i = 0; i < len; i++, se++) {
BKE_bpath_foreach_path_dirfile_fixed_process(bpath_data, seq->strip->dir, se->name);
BKE_bpath_foreach_path_dirfile_fixed_process(
bpath_data, seq->strip->dirpath, se->filename);
}
}
else {
/* simple case */
BKE_bpath_foreach_path_fixed_process(bpath_data, seq->strip->dir);
BKE_bpath_foreach_path_fixed_process(bpath_data, seq->strip->dirpath);
}
}
return true;

View File

@ -65,7 +65,7 @@ ShaderFxData *BKE_shaderfx_new(int type)
ShaderFxData *fx = MEM_callocN(fxi->struct_size, fxi->struct_name);
/* NOTE: this name must be made unique later. */
STRNCPY(fx->name, DATA_(fxi->name));
STRNCPY_UTF8(fx->name, DATA_(fxi->name));
fx->type = type;
fx->mode = eShaderFxMode_Realtime | eShaderFxMode_Render;

View File

@ -68,7 +68,7 @@ void ModifierSimulationCache::try_discover_bake(const StringRefNull meta_dir,
if (!dir_entry_path.endswith(".json")) {
continue;
}
char modified_file_name[FILENAME_MAX];
char modified_file_name[FILE_MAX];
STRNCPY(modified_file_name, dir_entry.relname);
BLI_str_replace_char(modified_file_name, '_', '.');

View File

@ -1081,7 +1081,7 @@ static void ffmpeg_dict_set_int(AVDictionary **dict, const char *key, int value)
static void ffmpeg_add_metadata_callback(void *data,
const char *propname,
char *propvalue,
int UNUSED(len))
int UNUSED(propvalue_maxncpy))
{
AVDictionary **metadata = (AVDictionary **)data;
av_dict_set(metadata, propname, propvalue, 0);

View File

@ -285,6 +285,10 @@ BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
lb->first = lb->last = (void *)0;
}
/** Validate the integrity of a given ListBase, returns `true` if evrything is OK, false otherwise.
*/
bool BLI_listbase_validate(struct ListBase *lb);
/**
* Equality check for ListBase.
*

View File

@ -560,7 +560,7 @@ static bool delete_recursive(const char *dir)
char path[FILE_MAXDIR];
/* dir listing produces dir path without trailing slash... */
BLI_strncpy(path, fl->path, sizeof(path));
STRNCPY(path, fl->path);
BLI_path_slash_ensure(path, sizeof(path));
if (delete_recursive(path)) {
@ -627,7 +627,7 @@ int BLI_path_move(const char *file, const char *to)
* it has to be 'mv filepath filepath' and not
* 'mv filepath destination_directory' */
BLI_strncpy(str, to, sizeof(str));
STRNCPY(str, to);
/* points 'to' to a directory ? */
if (BLI_path_slash_rfind(str) == (str + strlen(str) - 1)) {
if (BLI_path_slash_rfind(file) != NULL) {
@ -658,7 +658,7 @@ int BLI_copy(const char *file, const char *to)
* it has to be 'cp filepath filepath' and not
* 'cp filepath destdir' */
BLI_strncpy(str, to, sizeof(str));
STRNCPY(str, to);
/* points 'to' to a directory ? */
if (BLI_path_slash_rfind(str) == (str + strlen(str) - 1)) {
if (BLI_path_slash_rfind(file) != NULL) {
@ -741,9 +741,9 @@ static void join_dirfile_alloc(char **dst, size_t *alloc_len, const char *dir, c
BLI_path_join(*dst, len + 1, dir, file);
}
static char *strip_last_slash(const char *dir)
static char *strip_last_slash(const char *dirpath)
{
char *result = BLI_strdup(dir);
char *result = BLI_strdup(dirpath);
BLI_path_slash_rstrip(result);
return result;

View File

@ -871,6 +871,47 @@ void BLI_listbase_rotate_last(ListBase *lb, void *vlink)
((Link *)lb->last)->next = nullptr;
}
bool BLI_listbase_validate(ListBase *lb)
{
if (lb->first == nullptr && lb->last == nullptr) {
/* Empty list. */
return true;
}
if (ELEM(nullptr, lb->first, lb->last)) {
/* If one of the pointer is null, but not this other, this is a corrupted listbase. */
return false;
}
/* Walk the list in bot directions to ensure all next & prev pointers are valid and consistent.
*/
for (Link *lb_link = static_cast<Link *>(lb->first); lb_link; lb_link = lb_link->next) {
if (lb_link == lb->first) {
if (lb_link->prev != nullptr) {
return false;
}
}
if (lb_link == lb->last) {
if (lb_link->next != nullptr) {
return false;
}
}
}
for (Link *lb_link = static_cast<Link *>(lb->last); lb_link; lb_link = lb_link->prev) {
if (lb_link == lb->last) {
if (lb_link->next != nullptr) {
return false;
}
}
if (lb_link == lb->first) {
if (lb_link->prev != nullptr) {
return false;
}
}
}
return true;
}
LinkData *BLI_genericNodeN(void *data)
{
LinkData *ld;

View File

@ -43,6 +43,9 @@
* - 254..255: invalid.
*
* Invalid values fall back to 1 byte or -1 (for an error value).
*
* \note From testing string copying via #BLI_strncpy_utf8 with large (multi-megabyte) strings,
* using a function instead of a lookup-table is between 2 & 3 times faster.
* \{ */
BLI_INLINE int utf8_char_compute_skip(const char c)
@ -310,7 +313,7 @@ int BLI_str_utf8_invalid_strip(char *str, size_t length)
BLI_INLINE char *str_utf8_copy_max_bytes_impl(char *dst, const char *src, size_t dst_maxncpy)
{
/* Cast to `uint8_t` is a no-op, quiets array subscript of type `char` warning.
* No need to check `src` points to a nil byte, this will break out of the switch statement. */
* No need to check `src` points to a nil byte as this will return from the switch statement. */
size_t utf8_size;
while ((utf8_size = (size_t)utf8_char_compute_skip(*src)) < dst_maxncpy) {
dst_maxncpy -= utf8_size;
@ -318,12 +321,12 @@ BLI_INLINE char *str_utf8_copy_max_bytes_impl(char *dst, const char *src, size_t
/* NOLINTBEGIN: bugprone-assignment-in-if-condition */
/* clang-format off */
switch (utf8_size) {
case 6: if (UNLIKELY(!(*dst = *src++))) { return dst; } dst++; ATTR_FALLTHROUGH;
case 5: if (UNLIKELY(!(*dst = *src++))) { return dst; } dst++; ATTR_FALLTHROUGH;
case 4: if (UNLIKELY(!(*dst = *src++))) { return dst; } dst++; ATTR_FALLTHROUGH;
case 3: if (UNLIKELY(!(*dst = *src++))) { return dst; } dst++; ATTR_FALLTHROUGH;
case 2: if (UNLIKELY(!(*dst = *src++))) { return dst; } dst++; ATTR_FALLTHROUGH;
case 1: if (UNLIKELY(!(*dst = *src++))) { return dst; } dst++;
case 6: if (UNLIKELY(!(*dst = *src++))) { return dst; } dst++; ATTR_FALLTHROUGH;
case 5: if (UNLIKELY(!(*dst = *src++))) { return dst; } dst++; ATTR_FALLTHROUGH;
case 4: if (UNLIKELY(!(*dst = *src++))) { return dst; } dst++; ATTR_FALLTHROUGH;
case 3: if (UNLIKELY(!(*dst = *src++))) { return dst; } dst++; ATTR_FALLTHROUGH;
case 2: if (UNLIKELY(!(*dst = *src++))) { return dst; } dst++; ATTR_FALLTHROUGH;
case 1: if (UNLIKELY(!(*dst = *src++))) { return dst; } dst++;
}
/* clang-format on */
/* NOLINTEND: bugprone-assignment-in-if-condition */

View File

@ -112,7 +112,7 @@ bool BLI_windows_register_blend_extension(const bool background)
&hkey,
&dwd);
if (lresult == ERROR_SUCCESS) {
BLI_snprintf(buffer, sizeof(buffer), "\"%s\" \"%%1\"", BlPath);
SNPRINTF(buffer, "\"%s\" \"%%1\"", BlPath);
lresult = RegSetValueEx(hkey, NULL, 0, REG_SZ, (BYTE *)buffer, strlen(buffer) + 1);
RegCloseKey(hkey);
}
@ -131,7 +131,7 @@ bool BLI_windows_register_blend_extension(const bool background)
&hkey,
&dwd);
if (lresult == ERROR_SUCCESS) {
BLI_snprintf(buffer, sizeof(buffer), "\"%s\", 1", BlPath);
SNPRINTF(buffer, "\"%s\", 1", BlPath);
lresult = RegSetValueEx(hkey, NULL, 0, REG_SZ, (BYTE *)buffer, strlen(buffer) + 1);
RegCloseKey(hkey);
}
@ -169,12 +169,10 @@ bool BLI_windows_register_blend_extension(const bool background)
RegCloseKey(root);
printf("success (%s)\n", usr_mode ? "user" : "system");
if (!background) {
BLI_snprintf(MBox,
sizeof(MBox),
"File extension registered for %s.",
usr_mode ?
"the current user. To register for all users, run as an administrator" :
"all users");
SNPRINTF(MBox,
"File extension registered for %s.",
usr_mode ? "the current user. To register for all users, run as an administrator" :
"all users");
MessageBox(0, MBox, "Blender", MB_OK | MB_ICONINFORMATION);
}
return true;

View File

@ -107,7 +107,7 @@ TEST(listbase, FindLinkOrIndex)
TEST(listbase, FindLinkFromStringOrPointer)
{
struct TestLink {
struct TestLink *prev, *next;
struct TestLink *next, *prev;
char name[64];
const void *ptr;
};

View File

@ -335,7 +335,7 @@ static void polyfill_to_obj(const char *id,
FILE *f;
uint i;
BLI_snprintf(path, sizeof(path), "%s.obj", id);
SNPRINTF(path, "%s.obj", id);
f = fopen(path, "w");
if (!f) {

View File

@ -632,7 +632,7 @@ static bool seq_sound_proxy_update_cb(Sequence *seq, void *user_data)
Main *bmain = (Main *)user_data;
if (seq->type == SEQ_TYPE_SOUND_HD) {
char str[FILE_MAX];
BLI_path_join(str, sizeof(str), seq->strip->dir, seq->strip->stripdata->name);
BLI_path_join(str, sizeof(str), seq->strip->dirpath, seq->strip->stripdata->filename);
BLI_path_abs(str, BKE_main_blendfile_path(bmain));
seq->sound = BKE_sound_new_file(bmain, str);
}
@ -640,7 +640,7 @@ static bool seq_sound_proxy_update_cb(Sequence *seq, void *user_data)
#define SEQ_USE_PROXY_CUSTOM_FILE (1 << 21)
/* don't know, if anybody used that this way, but just in case, upgrade to new way... */
if ((seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) && !(seq->flag & SEQ_USE_PROXY_CUSTOM_DIR)) {
SNPRINTF(seq->strip->proxy->dir, "%s" SEP_STR "BL_proxy", seq->strip->dir);
SNPRINTF(seq->strip->proxy->dirpath, "%s" SEP_STR "BL_proxy", seq->strip->dirpath);
}
#undef SEQ_USE_PROXY_CUSTOM_DIR
#undef SEQ_USE_PROXY_CUSTOM_FILE

View File

@ -4355,6 +4355,27 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 306, 9)) {
/* Fix sound strips with speed factor set to 0. See #107289. */
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
Editing *ed = SEQ_editing_get(scene);
if (ed != nullptr) {
SEQ_for_each_callback(&ed->seqbase, version_seq_fix_broken_sound_strips, nullptr);
}
}
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_ACTION) {
SpaceAction *saction = reinterpret_cast<SpaceAction *>(sl);
saction->cache_display |= TIME_CACHE_SIMULATION_NODES;
}
}
}
}
}
/**
* Versioning code until next subversion bump goes here.
*
@ -4366,13 +4387,5 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
*/
{
/* Keep this block, even when empty. */
/* Fix sound strips with speed factor set to 0. See #107289. */
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
Editing *ed = SEQ_editing_get(scene);
if (ed != nullptr) {
SEQ_for_each_callback(&ed->seqbase, version_seq_fix_broken_sound_strips, nullptr);
}
}
}
}

View File

@ -11,6 +11,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
@ -812,7 +813,7 @@ void blo_do_versions_userdef(UserDef *userdef)
"Versioning user script path");
STRNCPY(script_dir->dir_path, userdef->pythondir_legacy);
STRNCPY(script_dir->name, DATA_("Untitled"));
STRNCPY_UTF8(script_dir->name, DATA_("Untitled"));
BLI_addhead(&userdef->script_directories, script_dir);
}
}

View File

@ -1063,7 +1063,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
#ifdef WITH_BUILDINFO
/* TODO(sergey): Add branch name to file as well? */
fg.build_commit_timestamp = build_commit_timestamp;
BLI_strncpy(fg.build_hash, build_hash, sizeof(fg.build_hash));
STRNCPY(fg.build_hash, build_hash);
#else
fg.build_commit_timestamp = 0;
STRNCPY(fg.build_hash, "unknown");

View File

@ -2,13 +2,15 @@
* Copyright 2019 Blender Foundation. */
#include "blendfile_loading_base_test.h"
#include "BLI_path_util.h"
class BlendfileLoadingTest : public BlendfileLoadingBaseTest {
};
TEST_F(BlendfileLoadingTest, CanaryTest)
{
/* Load the smallest blend file we have in the SVN lib/tests directory. */
if (!blendfile_load("modifier_stack/array_test.blend")) {
if (!blendfile_load("modifier_stack" SEP_STR "array_test.blend")) {
return;
}
depsgraph_create(DAG_EVAL_RENDER);

View File

@ -116,7 +116,7 @@ bool BlendfileLoadingBaseTest::blendfile_load(const char *filepath)
return false;
}
char abspath[FILENAME_MAX];
char abspath[FILE_MAX];
BLI_path_join(abspath, sizeof(abspath), test_assets_dir.c_str(), filepath);
BlendFileReadReport bf_reports = {nullptr};

View File

@ -453,15 +453,14 @@ void OutputOpenExrMultiLayerOperation::update_memory_buffer_partial(MemoryBuffer
const rcti &area,
Span<MemoryBuffer *> inputs)
{
const MemoryBuffer *input_image = inputs[0];
for (int i = 0; i < layers_.size(); i++) {
OutputOpenExrLayer &layer = layers_[i];
int layer_num_channels = COM_data_type_num_channels(layer.datatype);
if (layer.output_buffer) {
MemoryBuffer output_buf(layer.output_buffer,
COM_data_type_num_channels(layer.datatype),
this->get_width(),
this->get_height());
output_buf.copy_from(input_image, area);
MemoryBuffer output_buf(
layer.output_buffer, layer_num_channels, this->get_width(), this->get_height());
/* Input node always has 4 channels. Not all are needed depending on datatype. */
output_buf.copy_from(inputs[i], area, 0, layer_num_channels, 0);
}
}
}

View File

@ -139,7 +139,7 @@ static void extract_tan_init_common(const MeshRenderData *mr,
char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
const char *layer_name = CustomData_get_layer_name(r_loop_data, CD_TANGENT, 0);
GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
BLI_snprintf(attr_name, sizeof(*attr_name), "t%s", attr_safe_name);
SNPRINTF(attr_name, "t%s", attr_safe_name);
GPU_vertformat_attr_add(format, attr_name, comp_type, 4, fetch_mode);
GPU_vertformat_alias_add(format, "t");
GPU_vertformat_alias_add(format, "at");

View File

@ -368,7 +368,7 @@ static void acf_generic_idblock_name(bAnimListElem *ale, char *name)
/* just copy the name... */
if (id && name) {
BLI_strncpy(name, id->name + 2, ANIM_CHAN_NAME_SIZE);
BLI_strncpy_utf8(name, id->name + 2, ANIM_CHAN_NAME_SIZE);
}
}
@ -476,7 +476,7 @@ static void acf_summary_backdrop(bAnimContext *ac, bAnimListElem *ale, float ymi
static void acf_summary_name(bAnimListElem *UNUSED(ale), char *name)
{
if (name) {
BLI_strncpy(name, IFACE_("Summary"), ANIM_CHAN_NAME_SIZE);
BLI_strncpy_utf8(name, IFACE_("Summary"), ANIM_CHAN_NAME_SIZE);
}
}
@ -1178,7 +1178,7 @@ static void acf_nla_controls_backdrop(bAnimContext *ac,
/* name for nla controls expander entries */
static void acf_nla_controls_name(bAnimListElem *UNUSED(ale), char *name)
{
BLI_strncpy(name, IFACE_("NLA Strip Controls"), ANIM_CHAN_NAME_SIZE);
BLI_strncpy_utf8(name, IFACE_("NLA Strip Controls"), ANIM_CHAN_NAME_SIZE);
}
/* check if some setting exists for this channel */
@ -1393,7 +1393,7 @@ static int acf_filldrivers_icon(bAnimListElem *UNUSED(ale))
static void acf_filldrivers_name(bAnimListElem *UNUSED(ale), char *name)
{
BLI_strncpy(name, IFACE_("Drivers"), ANIM_CHAN_NAME_SIZE);
BLI_strncpy_utf8(name, IFACE_("Drivers"), ANIM_CHAN_NAME_SIZE);
}
/* check if some setting exists for this channel */
@ -4468,6 +4468,10 @@ void ANIM_channel_draw(
/* just skip - drawn as widget now */
offset += ICON_WIDTH;
}
else {
/* A bit of padding when there is no expand widget. */
offset += (short)(0.2f * U.widget_unit);
}
/* step 3) draw icon ............................................... */
if (acf->icon) {
@ -4522,10 +4526,6 @@ void ANIM_channel_draw(
offset += ICON_WIDTH;
}
}
else if ((ac->spacetype == SPACE_NLA) && acf->has_setting(ac, ale, ACHANNEL_SETTING_SOLO)) {
/* just skip - drawn as widget now */
offset += ICON_WIDTH;
}
}
/* step 5) draw name ............................................... */
@ -5252,11 +5252,6 @@ void ANIM_channel_draw_widgets(const bContext *C,
offset += ICON_WIDTH;
}
}
else if ((ac->spacetype == SPACE_NLA) && acf->has_setting(ac, ale, ACHANNEL_SETTING_SOLO)) {
/* 'solo' setting for NLA Tracks */
draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_SOLO);
offset += ICON_WIDTH;
}
}
/* step 4) draw text - check if renaming widget is in use... */
@ -5338,6 +5333,13 @@ void ANIM_channel_draw_widgets(const bContext *C,
/* check if there's enough space for the toggles if the sliders are drawn too */
if (!(draw_sliders) || (BLI_rcti_size_x(&v2d->mask) > ANIM_UI_get_channel_button_width() / 2))
{
/* solo... */
if ((ac->spacetype == SPACE_NLA) && acf->has_setting(ac, ale, ACHANNEL_SETTING_SOLO)) {
offset -= ICON_WIDTH;
draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_SOLO);
/* A touch of padding because the star icon is so wide. */
offset -= (short)(0.2f * ICON_WIDTH);
}
/* protect... */
if (acf->has_setting(ac, ale, ACHANNEL_SETTING_PROTECT)) {
offset -= ICON_WIDTH;

View File

@ -327,6 +327,7 @@ void postEditBoneDuplicate(struct ListBase *editbones, Object *ob)
if (!ebone_dst) {
ebone_dst = ED_armature_ebone_get_mirrored(editbones, ebone_src);
}
if (ebone_dst) {
BLI_ghash_insert(name_map, ebone_src->name, ebone_dst->name);
}
@ -334,22 +335,28 @@ void postEditBoneDuplicate(struct ListBase *editbones, Object *ob)
LISTBASE_FOREACH (EditBone *, ebone_src, editbones) {
EditBone *ebone_dst = ebone_src->temp.ebone;
if (ebone_dst) {
bPoseChannel *pchan_src = BKE_pose_channel_find_name(ob->pose, ebone_src->name);
if (pchan_src) {
bPoseChannel *pchan_dst = BKE_pose_channel_find_name(ob->pose, ebone_dst->name);
if (pchan_dst) {
if (pchan_src->custom_tx) {
pchan_dst->custom_tx = pchan_duplicate_map(ob->pose, name_map, pchan_src->custom_tx);
}
if (pchan_src->bbone_prev) {
pchan_dst->bbone_prev = pchan_duplicate_map(ob->pose, name_map, pchan_src->bbone_prev);
}
if (pchan_src->bbone_next) {
pchan_dst->bbone_next = pchan_duplicate_map(ob->pose, name_map, pchan_src->bbone_next);
}
}
}
if (!ebone_dst) {
continue;
}
bPoseChannel *pchan_src = BKE_pose_channel_find_name(ob->pose, ebone_src->name);
if (!pchan_src) {
continue;
}
bPoseChannel *pchan_dst = BKE_pose_channel_find_name(ob->pose, ebone_dst->name);
if (!pchan_dst) {
continue;
}
if (pchan_src->custom_tx) {
pchan_dst->custom_tx = pchan_duplicate_map(ob->pose, name_map, pchan_src->custom_tx);
}
if (pchan_src->bbone_prev) {
pchan_dst->bbone_prev = pchan_duplicate_map(ob->pose, name_map, pchan_src->bbone_prev);
}
if (pchan_src->bbone_next) {
pchan_dst->bbone_next = pchan_duplicate_map(ob->pose, name_map, pchan_src->bbone_next);
}
}
@ -1120,71 +1127,80 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
scene, view_layer, CTX_wm_view3d(C), &objects_len);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
bArmature *arm = obedit->data;
EditBone *ebone_iter;
/* The beginning of the duplicated mirrored bones in the edbo list */
EditBone *ebone_first_dupe = NULL;
Object *obedit = objects[ob_index];
bArmature *arm = obedit->data;
ED_armature_edit_sync_selection(arm->edbo); /* XXX why is this needed? */
preEditBoneDuplicate(arm->edbo);
/* Select mirrored bones */
/* Deselect ebones depending on input axis and direction.
* A symmetrizable selection contains selected ebones of the input direction
* and unique selected bones with an unique flippable name.
*
* Storing temp ptrs to mirrored unselected ebones. */
for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
if (EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED)) {
char name_flip[MAXBONENAME];
if (!(EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED))) {
/* Skipping invisible selected bones. */
continue;
}
BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
char name_flip[MAXBONENAME];
if (ebone_iter == NULL) {
continue;
}
if (STREQ(name_flip, ebone_iter->name)) {
/* if the name matches, we don't have the potential to be mirrored, just skip */
ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
}
else {
EditBone *ebone = ED_armature_ebone_find_name(arm->edbo, name_flip);
BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
if (ebone) {
if ((ebone->flag & BONE_SELECTED) == 0) {
/* simple case, we're selected, the other bone isn't! */
ebone_iter->temp.ebone = ebone;
}
else {
/* complicated - choose which direction to copy */
float axis_delta;
if (STREQ(name_flip, ebone_iter->name)) {
/* Skipping ebones without flippable as they don't have the potential to be mirrored. */
ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
continue;
}
axis_delta = ebone->head[axis] - ebone_iter->head[axis];
if (axis_delta == 0.0f) {
axis_delta = ebone->tail[axis] - ebone_iter->tail[axis];
}
EditBone *ebone = ED_armature_ebone_find_name(arm->edbo, name_flip);
if (axis_delta == 0.0f) {
/* Both mirrored bones exist and point to each other and overlap exactly.
*
* in this case there's no well defined solution, so de-select both and skip.
*/
ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
}
else {
EditBone *ebone_src, *ebone_dst;
if (((axis_delta < 0.0f) ? -1 : 1) == direction) {
ebone_src = ebone;
ebone_dst = ebone_iter;
}
else {
ebone_src = ebone_iter;
ebone_dst = ebone;
}
if (!ebone) {
/* The ebone_iter is unique and mirrorable. */
continue;
}
ebone_src->temp.ebone = ebone_dst;
ebone_dst->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
}
}
if (ebone->flag & BONE_SELECTED) {
/* The mirrored ebone and the ebone_iter are selected.
* Deselect based on the input direction and axis. */
float axis_delta;
axis_delta = ebone->head[axis] - ebone_iter->head[axis];
if (axis_delta == 0.0f) {
/* The ebone heads are overlapping. */
axis_delta = ebone->tail[axis] - ebone_iter->tail[axis];
if (axis_delta == 0.0f) {
/* Both mirrored bones point to each other and overlap exactly.
* In this case there's no well defined solution, so de-select both and skip. */
ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
continue;
}
}
/* Deselect depending on direction. */
if (((axis_delta < 0.0f) ? -1 : 1) == direction) {
/* Don't store temp ptr if the iter_bone gets deselected.
* In this case, the ebone.temp should point to the ebone_iter. */
ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
continue;
}
ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
}
/* Set temp pointer to mirrored ebones */
ebone_iter->temp.ebone = ebone;
}
/* Find the selected bones and duplicate them as needed, with mirrored name. */
@ -1206,11 +1222,12 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
ebone_iter->temp.ebone->inherit_scale_mode = ebone_iter->inherit_scale_mode;
continue;
}
char name_flip[MAXBONENAME];
BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
/* bones must have a side-suffix */
/* mirrored bones must have a side-suffix */
if (!STREQ(name_flip, ebone_iter->name)) {
EditBone *ebone;
@ -1254,8 +1271,8 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
*/
if (ebone->head[axis] != 0.0f) {
/* The mirrored bone doesn't start on the mirror axis, so assume that this one should
* not be connected to the old parent */
/* The mirrored bone doesn't start on the mirror axis, so assume that this one
* should not be connected to the old parent */
ebone->flag &= ~BONE_CONNECTED;
}
}

View File

@ -3388,7 +3388,7 @@ void ED_gpencil_layer_merge(bGPdata *gpd,
}
}
static void gpencil_layer_new_name_get(bGPdata *gpd, char *rname)
static void gpencil_layer_new_name_get(bGPdata *gpd, char *r_name, size_t name_maxncpy)
{
int index = 0;
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
@ -3398,12 +3398,10 @@ static void gpencil_layer_new_name_get(bGPdata *gpd, char *rname)
}
if (index == 0) {
BLI_strncpy(rname, "GP_Layer", 128);
BLI_strncpy(r_name, "GP_Layer", name_maxncpy);
return;
}
char *name = BLI_sprintfN("%.*s.%03d", 128, "GP_Layer", index);
BLI_strncpy(rname, name, 128);
MEM_freeN(name);
BLI_snprintf(r_name, name_maxncpy, "GP_Layer.%03d", index);
}
int ED_gpencil_new_layer_dialog(bContext *C, wmOperator *op)
@ -3415,7 +3413,7 @@ int ED_gpencil_new_layer_dialog(bContext *C, wmOperator *op)
if (!RNA_property_is_set(op->ptr, prop)) {
char name[MAX_NAME];
bGPdata *gpd = ob->data;
gpencil_layer_new_name_get(gpd, name);
gpencil_layer_new_name_get(gpd, name, sizeof(name));
RNA_property_string_set(op->ptr, prop, name);
return WM_operator_props_dialog_popup(C, op, 200);
}

View File

@ -3937,11 +3937,11 @@ static void ui_but_update_ex(uiBut *but, const bool validate)
(void)str; /* UNUSED */
}
else {
STRNCPY(but->drawstr, IFACE_("Press a key"));
STRNCPY_UTF8(but->drawstr, IFACE_("Press a key"));
}
}
else {
STRNCPY(but->drawstr, but->str);
STRNCPY_UTF8(but->drawstr, but->str);
}
break;

View File

@ -36,6 +36,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_utildefines.h"
#include "BLI_vector.hh"
@ -2021,7 +2022,7 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op)
BKE_nlatrack_add_strip(nlt, strip, is_liboverride);
/* Auto-name the strip, and give the track an interesting name. */
STRNCPY(nlt->name, DATA_("SoundTrack"));
STRNCPY_UTF8(nlt->name, DATA_("SoundTrack"));
BKE_nlastrip_validate_name(adt, strip);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_ADDED, nullptr);

View File

@ -779,6 +779,9 @@ static bConstraint *edit_constraint_property_get(bContext *C, wmOperator *op, Ob
if (owner == EDIT_CONSTRAINT_OWNER_BONE) {
list = ED_object_pose_constraint_list(C);
if (!list) {
return NULL;
}
}
else {
list = &ob->constraints;

View File

@ -758,23 +758,25 @@ void timeline_draw_cache(const SpaceAction *saction, const Object *ob, const Sce
y_offset += cache_draw_height;
}
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type != eModifierType_Nodes) {
continue;
if (saction->cache_display & TIME_CACHE_SIMULATION_NODES) {
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type != eModifierType_Nodes) {
continue;
}
const NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
if (nmd->node_group == nullptr) {
continue;
}
if (nmd->simulation_cache == nullptr) {
continue;
}
if ((nmd->node_group->runtime->runtime_flag & NTREE_RUNTIME_FLAG_HAS_SIMULATION_ZONE) == 0) {
continue;
}
timeline_cache_draw_simulation_nodes(
*scene, *nmd->simulation_cache, y_offset, cache_draw_height, pos_id);
y_offset += cache_draw_height;
}
const NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
if (nmd->node_group == nullptr) {
continue;
}
if (nmd->simulation_cache == nullptr) {
continue;
}
if ((nmd->node_group->runtime->runtime_flag & NTREE_RUNTIME_FLAG_HAS_SIMULATION_ZONE) == 0) {
continue;
}
timeline_cache_draw_simulation_nodes(
*scene, *nmd->simulation_cache, y_offset, cache_draw_height, pos_id);
y_offset += cache_draw_height;
}
GPU_blend(GPU_BLEND_NONE);

View File

@ -67,11 +67,9 @@ static SpaceLink *action_create(const ScrArea *area, const Scene *scene)
saction->ads.filterflag |= ADS_FILTER_SUMMARY;
/* enable all cache display */
saction->cache_display |= TIME_CACHE_DISPLAY;
saction->cache_display |= (TIME_CACHE_SOFTBODY | TIME_CACHE_PARTICLES);
saction->cache_display |= (TIME_CACHE_CLOTH | TIME_CACHE_SMOKE | TIME_CACHE_DYNAMICPAINT);
saction->cache_display |= TIME_CACHE_RIGIDBODY;
saction->cache_display = TIME_CACHE_DISPLAY | TIME_CACHE_SOFTBODY | TIME_CACHE_PARTICLES |
TIME_CACHE_CLOTH | TIME_CACHE_SMOKE | TIME_CACHE_DYNAMICPAINT |
TIME_CACHE_RIGIDBODY | TIME_CACHE_SIMULATION_NODES;
/* header */
region = MEM_cnew<ARegion>("header for action");

View File

@ -2841,7 +2841,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
else if (!can_create_dir(params->dir)) {
const char *lastdir = folderlist_peeklastdir(sfile->folders_prev);
if (lastdir) {
BLI_strncpy(params->dir, lastdir, sizeof(params->dir));
STRNCPY(params->dir, lastdir);
}
}
#endif

View File

@ -982,7 +982,7 @@ typedef struct tGaussOperatorData {
/* Store data to smooth an FCurve segment. */
typedef struct tFCurveSegmentLink {
struct tFCurveSegmentLink *prev, *next;
struct tFCurveSegmentLink *next, *prev;
FCurve *fcu;
FCurveSegment *segment;
float *samples; /* Array of y-values of the FCurve segment. */

View File

@ -249,7 +249,7 @@ static int unpack_all_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
}
if (count == 1) {
STRNCPY(title, IFACE_("Unpack 1 File"));
STRNCPY_UTF8(title, IFACE_("Unpack 1 File"));
}
else {
SNPRINTF(title, IFACE_("Unpack %d Files"), count);

View File

@ -25,6 +25,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_timecode.h"
#include "BLI_utildefines.h"
@ -748,18 +749,18 @@ void ED_info_draw_stats(
};
char labels[MAX_LABELS_COUNT][64];
STRNCPY(labels[OBJ], IFACE_("Objects"));
STRNCPY(labels[VERTS], IFACE_("Vertices"));
STRNCPY(labels[EDGES], IFACE_("Edges"));
STRNCPY(labels[FACES], IFACE_("Faces"));
STRNCPY(labels[TRIS], IFACE_("Triangles"));
STRNCPY(labels[JOINTS], IFACE_("Joints"));
STRNCPY(labels[BONES], IFACE_("Bones"));
STRNCPY(labels[LAYERS], IFACE_("Layers"));
STRNCPY(labels[FRAMES], IFACE_("Frames"));
STRNCPY(labels[STROKES], IFACE_("Strokes"));
STRNCPY(labels[POINTS], IFACE_("Points"));
STRNCPY(labels[LIGHTS], IFACE_("Lights"));
STRNCPY_UTF8(labels[OBJ], IFACE_("Objects"));
STRNCPY_UTF8(labels[VERTS], IFACE_("Vertices"));
STRNCPY_UTF8(labels[EDGES], IFACE_("Edges"));
STRNCPY_UTF8(labels[FACES], IFACE_("Faces"));
STRNCPY_UTF8(labels[TRIS], IFACE_("Triangles"));
STRNCPY_UTF8(labels[JOINTS], IFACE_("Joints"));
STRNCPY_UTF8(labels[BONES], IFACE_("Bones"));
STRNCPY_UTF8(labels[LAYERS], IFACE_("Layers"));
STRNCPY_UTF8(labels[FRAMES], IFACE_("Frames"));
STRNCPY_UTF8(labels[STROKES], IFACE_("Strokes"));
STRNCPY_UTF8(labels[POINTS], IFACE_("Points"));
STRNCPY_UTF8(labels[LIGHTS], IFACE_("Lights"));
int longest_label = 0;
int i;

View File

@ -31,6 +31,8 @@
#include "BKE_workspace.h"
#include "BLI_set.hh"
#include "BLI_string_utf8.h"
#include "BLT_translation.h"
#include "DEG_depsgraph.h"
@ -507,7 +509,7 @@ void ED_node_shader_default(const bContext *C, ID *id)
ma->nodetree = ntreeCopyTree(bmain, ma_default->nodetree);
ma->nodetree->owner_id = &ma->id;
for (bNode *node_iter : ma->nodetree->all_nodes()) {
STRNCPY(node_iter->name, DATA_(node_iter->name));
STRNCPY_UTF8(node_iter->name, DATA_(node_iter->name));
nodeUniqueName(ma->nodetree, node_iter);
}

View File

@ -16,6 +16,7 @@
#include "BLI_array.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_vector.hh"
#include "BLT_translation.h"
@ -474,14 +475,14 @@ static void ui_node_sock_name(const bNodeTree *ntree,
name, UI_MAX_NAME_STR, "%s | %s", IFACE_(node_name), IFACE_(sock->link->fromsock->name));
}
else {
BLI_strncpy(name, IFACE_(node_name), UI_MAX_NAME_STR);
BLI_strncpy_utf8(name, IFACE_(node_name), UI_MAX_NAME_STR);
}
}
else if (sock->type == SOCK_SHADER) {
BLI_strncpy(name, IFACE_("None"), UI_MAX_NAME_STR);
BLI_strncpy_utf8(name, IFACE_("None"), UI_MAX_NAME_STR);
}
else {
BLI_strncpy(name, IFACE_("Default"), UI_MAX_NAME_STR);
BLI_strncpy_utf8(name, IFACE_("Default"), UI_MAX_NAME_STR);
}
}
@ -604,7 +605,7 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
icon = ICON_BLANK1;
}
else {
STRNCPY(name, IFACE_(item.node_name));
STRNCPY_UTF8(name, IFACE_(item.node_name));
icon = ICON_NONE;
}

View File

@ -726,13 +726,13 @@ static void tree_element_sequence_dup_activate(Scene *scene, TreeElement * /*te*
#endif
Sequence *p = static_cast<Sequence *>(ed->seqbasep->first);
while (p) {
if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->name[0] == '\0')) {
if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->filename[0] == '\0')) {
p = p->next;
continue;
}
#if 0
if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) {
if (STREQ(p->strip->stripdata->filename, seq->strip->stripdata->filename)) {
select_single_seq(p, 0);
}
#endif

View File

@ -69,7 +69,7 @@ SequenceAddOp TreeDisplaySequencer::need_add_seq_dup(Sequence *seq) const
continue;
}
if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) {
if (STREQ(p->strip->stripdata->filename, seq->strip->stripdata->filename)) {
return SEQUENCE_DUPLICATE_NOOP;
}
p = p->prev;
@ -82,7 +82,7 @@ SequenceAddOp TreeDisplaySequencer::need_add_seq_dup(Sequence *seq) const
continue;
}
if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) {
if (STREQ(p->strip->stripdata->filename, seq->strip->stripdata->filename)) {
return SEQUENCE_DUPLICATE_ADD;
}
p = p->next;
@ -95,12 +95,12 @@ void TreeDisplaySequencer::add_seq_dup(Sequence *seq, TreeElement *te, short ind
{
Sequence *p = seq;
while (p) {
if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->name[0] == '\0')) {
if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->filename[0] == '\0')) {
p = p->next;
continue;
}
if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) {
if (STREQ(p->strip->stripdata->filename, seq->strip->stripdata->filename)) {
outliner_add_element(&space_outliner_, &te->subtree, (void *)p, te, TSE_SEQUENCE, index);
}
p = p->next;

View File

@ -68,8 +68,8 @@ TreeElementSequenceStrip::TreeElementSequenceStrip(TreeElement &legacy_te, Strip
{
BLI_assert(legacy_te.store_elem->type == TSE_SEQ_STRIP);
if (strip.dir[0] != '\0') {
legacy_te_.name = strip.dir;
if (strip.dirpath[0] != '\0') {
legacy_te_.name = strip.dirpath;
}
else {
legacy_te_.name = IFACE_("Strip None");
@ -86,7 +86,7 @@ TreeElementSequenceStripDuplicate::TreeElementSequenceStripDuplicate(TreeElement
BLI_assert(legacy_te.store_elem->type == TSE_SEQUENCE_DUP);
legacy_te_.idcode = sequence.type;
legacy_te_.name = sequence.strip->stripdata->name;
legacy_te_.name = sequence.strip->stripdata->filename;
}
Sequence &TreeElementSequenceStripDuplicate::getSequence() const

View File

@ -179,7 +179,7 @@ static void sequencer_generic_invoke_path__internal(bContext *C,
if (last_seq && last_seq->strip && SEQ_HAS_PATH(last_seq)) {
Main *bmain = CTX_data_main(C);
char path[FILE_MAX];
STRNCPY(path, last_seq->strip->dir);
STRNCPY(path, last_seq->strip->dirpath);
BLI_path_abs(path, BKE_main_blendfile_path(bmain));
RNA_string_set(op->ptr, identifier, path);
}
@ -1254,7 +1254,7 @@ void sequencer_image_seq_reserve_frames(
for (int i = 0; i < len; i++, se++) {
STRNCPY(filename_stripped, filename);
BLI_path_frame(filename_stripped, sizeof(filename_stripped), minframe + i, numdigits);
SNPRINTF(se->name, "%s%s", filename_stripped, ext);
SNPRINTF(se->filename, "%s%s", filename_stripped, ext);
}
MEM_freeN(filename);
@ -1282,10 +1282,9 @@ static void sequencer_add_image_strip_load_files(wmOperator *op,
const int numdigits)
{
const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders");
/* size of Strip->dir. */
char directory[FILE_MAXDIR];
BLI_path_split_dir_part(load_data->path, directory, sizeof(directory));
SEQ_add_image_set_directory(seq, directory);
char dirpath[sizeof(seq->strip->dirpath)];
BLI_path_split_dir_part(load_data->path, dirpath, sizeof(dirpath));
SEQ_add_image_set_directory(seq, dirpath);
if (use_placeholders) {
sequencer_image_seq_reserve_frames(

View File

@ -806,7 +806,8 @@ static void draw_seq_text_get_source(Sequence *seq, char *r_source, size_t sourc
switch (seq->type) {
case SEQ_TYPE_IMAGE:
case SEQ_TYPE_MOVIE: {
BLI_path_join(r_source, source_maxncpy, seq->strip->dir, seq->strip->stripdata->name);
BLI_path_join(
r_source, source_maxncpy, seq->strip->dirpath, seq->strip->stripdata->filename);
break;
}
case SEQ_TYPE_SOUND_RAM: {

View File

@ -1879,7 +1879,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
/* Note this assume all elements (images) have the same dimension,
* since we only copy the name here. */
se_new = MEM_reallocN(strip_new->stripdata, sizeof(*se_new));
STRNCPY(se_new->name, se->name);
STRNCPY(se_new->filename, se->filename);
strip_new->stripdata = se_new;
if (step > 1) {
@ -2920,7 +2920,7 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
* but look into changing after 2.60. */
BLI_path_rel(directory, BKE_main_blendfile_path(bmain));
}
STRNCPY(seq->strip->dir, directory);
STRNCPY(seq->strip->dirpath, directory);
if (seq->strip->stripdata) {
MEM_freeN(seq->strip->stripdata);
@ -2933,7 +2933,7 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
else {
RNA_BEGIN (op->ptr, itemptr, "files") {
char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0, NULL);
STRNCPY(se->name, filename);
STRNCPY(se->filename, filename);
MEM_freeN(filename);
se++;
}
@ -2991,9 +2991,9 @@ static int sequencer_change_path_invoke(bContext *C, wmOperator *op, const wmEve
Sequence *seq = SEQ_select_active_get(scene);
char filepath[FILE_MAX];
BLI_path_join(filepath, sizeof(filepath), seq->strip->dir, seq->strip->stripdata->name);
BLI_path_join(filepath, sizeof(filepath), seq->strip->dirpath, seq->strip->stripdata->filename);
RNA_string_set(op->ptr, "directory", seq->strip->dir);
RNA_string_set(op->ptr, "directory", seq->strip->dirpath);
RNA_string_set(op->ptr, "filepath", filepath);
/* Set default display depending on seq type. */

View File

@ -235,12 +235,12 @@ void ED_sequencer_select_sequence_single(Scene *scene, Sequence *seq, bool desel
if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE)) {
if (seq->strip) {
BLI_strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR);
BLI_strncpy(ed->act_imagedir, seq->strip->dirpath, FILE_MAXDIR);
}
}
else if (seq->type == SEQ_TYPE_SOUND_RAM) {
if (seq->strip) {
BLI_strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR);
BLI_strncpy(ed->act_sounddir, seq->strip->dirpath, FILE_MAXDIR);
}
}
seq->flag |= SELECT;
@ -570,12 +570,12 @@ static void sequencer_select_set_active(Scene *scene, Sequence *seq)
if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE)) {
if (seq->strip) {
BLI_strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR);
BLI_strncpy(ed->act_imagedir, seq->strip->dirpath, FILE_MAXDIR);
}
}
else if (seq->type == SEQ_TYPE_SOUND_RAM) {
if (seq->strip) {
BLI_strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR);
BLI_strncpy(ed->act_sounddir, seq->strip->dirpath, FILE_MAXDIR);
}
}
recurs_sel_seq(seq);
@ -1893,7 +1893,7 @@ static bool select_grouped_data(SeqCollection *strips,
const int channel)
{
bool changed = false;
const char *dir = actseq->strip ? actseq->strip->dir : NULL;
const char *dirpath = actseq->strip ? actseq->strip->dirpath : NULL;
if (!SEQ_USE_DATA(actseq)) {
return changed;
@ -1901,10 +1901,10 @@ static bool select_grouped_data(SeqCollection *strips,
Sequence *seq;
if (SEQ_HAS_PATH(actseq) && dir) {
if (SEQ_HAS_PATH(actseq) && dirpath) {
SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && SEQ_HAS_PATH(seq) && seq->strip &&
STREQ(seq->strip->dir, dir))
STREQ(seq->strip->dirpath, dirpath))
{
seq->flag |= SELECT;
changed = true;

View File

@ -1980,8 +1980,7 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
Object *ob = base->object;
/* if hidden but in edit mode, we still display, can happen with animation */
if ((base->flag & BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT) != 0 ||
(ob->mode != OB_MODE_OBJECT))
{
(ob->mode != OB_MODE_OBJECT)) {
CTX_data_id_pointer_set(result, &ob->id);
}
}

View File

@ -1327,7 +1327,7 @@ void calculatePropRatio(TransInfo *t)
}
if (pet_id) {
STRNCPY(t->proptext, IFACE_(pet_id));
STRNCPY_UTF8(t->proptext, IFACE_(pet_id));
}
}
else {

View File

@ -585,7 +585,7 @@ static void handle_armature_parent_orientation(Object *ob, float r_mat[3][3])
bPoseChannel *active_pchan = BKE_pose_channel_active(ob, false);
/* Check if target bone is a child. */
if (active_pchan->parent) {
if (active_pchan && active_pchan->parent) {
/* For child, show parent local regardless if "local location" is set for parent bone. */
transform_orientations_create_from_axis(r_mat, UNPACK3(active_pchan->parent->pose_mat));
return;

View File

@ -18,6 +18,8 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BKE_global.h"
#include "BLI_array.hh"
#include "BLI_convexhull_2d.h"
#include "BLI_linklist.h"
@ -59,6 +61,7 @@
#include "ED_image.h"
#include "ED_mesh.h"
#include "ED_screen.h"
#include "ED_undo.h"
#include "ED_uvedit.h"
#include "ED_view3d.h"
@ -169,6 +172,14 @@ void blender::geometry::UVPackIsland_Params::setUDIMOffsetFromSpaceImage(const S
}
/** \} */
bool blender::geometry::UVPackIsland_Params::isCancelled() const
{
if (stop) {
return *stop;
}
return false;
}
/* -------------------------------------------------------------------- */
/** \name Parametrizer Conversion
* \{ */
@ -1141,6 +1152,7 @@ static bool island_has_pins(const Scene *scene,
* This is needed to perform UV packing on objects that aren't in edit-mode.
* \param udim_source_closest: UDIM source SpaceImage.
* \param original_selection: Pack to original selection.
* \param notify_wm: Notify the WM of any changes. (UI thread only.)
* \param params: Parameters and options to pass to the packing engine.
*/
static void uvedit_pack_islands_multi(const Scene *scene,
@ -1149,6 +1161,7 @@ static void uvedit_pack_islands_multi(const Scene *scene,
BMesh **bmesh_override,
const SpaceImage *udim_source_closest,
const bool original_selection,
const bool notify_wm,
blender::geometry::UVPackIsland_Params *params)
{
blender::Vector<FaceIsland *> island_vector;
@ -1271,6 +1284,7 @@ static void uvedit_pack_islands_multi(const Scene *scene,
BLI_memarena_free(arena);
const float scale = pack_islands(pack_island_vector, *params);
const bool is_cancelled = params->isCancelled();
float base_offset[2] = {0.0f, 0.0f};
copy_v2_v2(base_offset, params->udim_base_offset);
@ -1309,7 +1323,10 @@ static void uvedit_pack_islands_multi(const Scene *scene,
float matrix[2][2];
float matrix_inverse[2][2];
float pre_translate[2];
for (int64_t i : pack_island_vector.index_range()) {
for (const int64_t i : pack_island_vector.index_range()) {
if (is_cancelled) {
continue;
}
blender::geometry::PackIsland *pack_island = pack_island_vector[i];
FaceIsland *island = island_vector[pack_island->caller_index];
const float island_scale = pack_island->can_scale_(*params) ? scale : 1.0f;
@ -1339,16 +1356,21 @@ static void uvedit_pack_islands_multi(const Scene *scene,
pre_translate[1] = selection_min_co[1] / rescale;
island_uv_transform(island, matrix, pre_translate);
}
}
for (const int64_t i : pack_island_vector.index_range()) {
blender::geometry::PackIsland *pack_island = pack_island_vector[i];
/* Cleanup memory. */
pack_island_vector[i] = nullptr;
delete pack_island;
}
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data);
if (notify_wm && !is_cancelled) {
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data);
}
}
for (FaceIsland *island : island_vector) {
@ -1361,6 +1383,9 @@ static void uvedit_pack_islands_multi(const Scene *scene,
/** \name Pack UV Islands Operator
* \{ */
/* TODO: support this, interaction with the job-system needs to be handled carefully. */
// #define USE_INTERACTIVE_PACK
/* Packing targets. */
enum {
PACK_UDIM_SRC_CLOSEST = 0,
@ -1368,6 +1393,70 @@ enum {
PACK_ORIGINAL_AABB,
};
struct UVPackIslandsData {
wmWindowManager *wm;
const Scene *scene;
Object **objects;
uint objects_len;
const SpaceImage *sima;
int udim_source;
bContext *undo_context;
const char *undo_str;
bool use_job;
blender::geometry::UVPackIsland_Params pack_island_params;
};
static void pack_islands_startjob(void *pidv, bool *stop, bool *do_update, float *progress)
{
*progress = 0.02f;
UVPackIslandsData *pid = static_cast<UVPackIslandsData *>(pidv);
pid->pack_island_params.stop = stop;
pid->pack_island_params.do_update = do_update;
pid->pack_island_params.progress = progress;
uvedit_pack_islands_multi(pid->scene,
pid->objects,
pid->objects_len,
nullptr,
(pid->udim_source == PACK_UDIM_SRC_CLOSEST) ? pid->sima : nullptr,
(pid->udim_source == PACK_ORIGINAL_AABB),
!pid->use_job,
&pid->pack_island_params);
*progress = 0.99f;
*do_update = true;
}
static void pack_islands_endjob(void *pidv)
{
UVPackIslandsData *pid = static_cast<UVPackIslandsData *>(pidv);
for (uint ob_index = 0; ob_index < pid->objects_len; ob_index++) {
Object *obedit = pid->objects[ob_index];
DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data);
}
WM_main_add_notifier(NC_SPACE | ND_SPACE_IMAGE, NULL);
if (pid->undo_str) {
ED_undo_push(pid->undo_context, pid->undo_str);
}
}
static void pack_islands_freejob(void *pidv)
{
WM_cursor_wait(false);
UVPackIslandsData *pid = static_cast<UVPackIslandsData *>(pidv);
MEM_freeN(pid->objects);
WM_set_locked_interface(pid->wm, false);
MEM_freeN(pid);
}
static int pack_islands_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@ -1400,7 +1489,23 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin);
}
blender::geometry::UVPackIsland_Params pack_island_params;
UVPackIslandsData *pid = static_cast<UVPackIslandsData *>(
MEM_callocN(sizeof(UVPackIslandsData), "pack_islands_data"));
pid->use_job = op->flag & OP_IS_INVOKE;
pid->scene = scene;
pid->objects = objects;
pid->objects_len = objects_len;
pid->sima = sima;
pid->udim_source = udim_source;
pid->wm = CTX_wm_manager(C);
blender::geometry::UVPackIsland_Params &pack_island_params = pid->pack_island_params;
{
/* Call default constructor and copy the defaults. */
blender::geometry::UVPackIsland_Params default_params;
pack_island_params = default_params;
}
pack_island_params.setFromUnwrapOptions(options);
pack_island_params.rotate = RNA_boolean_get(op->ptr, "rotate");
pack_island_params.scale_to_fit = RNA_boolean_get(op->ptr, "scale");
@ -1416,15 +1521,31 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
pack_island_params.setUDIMOffsetFromSpaceImage(sima);
}
uvedit_pack_islands_multi(scene,
objects,
objects_len,
nullptr,
(udim_source == PACK_UDIM_SRC_CLOSEST) ? sima : nullptr,
(udim_source == PACK_ORIGINAL_AABB),
&pack_island_params);
if (pid->use_job) {
/* Setup job. */
if (pid->wm->op_undo_depth == 0) {
/* The job must do it's own undo push. */
pid->undo_context = C;
pid->undo_str = op->type->name;
}
MEM_freeN(objects);
wmJob *wm_job = WM_jobs_get(
pid->wm, CTX_wm_window(C), scene, "Packing UVs", WM_JOB_PROGRESS, WM_JOB_TYPE_UV_PACK);
WM_jobs_customdata_set(wm_job, pid, pack_islands_freejob);
WM_jobs_timer(wm_job, 0.1, 0, 0);
WM_set_locked_interface(pid->wm, true);
WM_jobs_callbacks(wm_job, pack_islands_startjob, nullptr, nullptr, pack_islands_endjob);
WM_cursor_wait(true);
G.is_break = false;
WM_jobs_start(CTX_wm_manager(C), wm_job);
return OPERATOR_FINISHED;
}
pack_islands_startjob(pid, nullptr, nullptr, nullptr);
pack_islands_endjob(pid);
MEM_freeN(pid);
return OPERATOR_FINISHED;
}
@ -1452,7 +1573,7 @@ static const EnumPropertyItem pack_shape_method_items[] = {
};
static const EnumPropertyItem pinned_islands_method_items[] = {
{ED_UVPACK_PIN_NORMAL, "NORMAL", 0, "Normal", "Pin information is not used"},
{ED_UVPACK_PIN_DEFAULT, "DEFAULT", 0, "Default", "Pin information is not used"},
{ED_UVPACK_PIN_IGNORED, "IGNORED", 0, "Ignored", "Pinned islands are not packed"},
{ED_UVPACK_PIN_LOCK_SCALE, "SCALE", 0, "Locked scale", "Pinned islands won't rescale"},
{ED_UVPACK_PIN_LOCK_ROTATION, "ROTATION", 0, "Locked rotation", "Pinned islands won't rotate"},
@ -1487,10 +1608,21 @@ void UV_OT_pack_islands(wmOperatorType *ot)
ot->description =
"Transform all islands so that they fill up the UV/UDIM space as much as possible";
#ifdef USE_INTERACTIVE_PACK
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
#else
/* The operator will handle undo, so the job system can push() it after the job completes. */
ot->flag = OPTYPE_REGISTER;
#endif
/* api callbacks */
ot->exec = pack_islands_exec;
#ifdef USE_INTERACTIVE_PACK
ot->invoke = WM_operator_props_popup_call;
#else
ot->invoke = WM_operator_props_popup_confirm;
#endif
ot->poll = ED_operator_uvedit;
/* properties */
@ -1510,7 +1642,7 @@ void UV_OT_pack_islands(wmOperatorType *ot)
RNA_def_enum(ot->srna,
"pin_method",
pinned_islands_method_items,
ED_UVPACK_PIN_NORMAL,
ED_UVPACK_PIN_DEFAULT,
"Pinned Islands",
"");
RNA_def_enum(ot->srna,
@ -2234,7 +2366,7 @@ void ED_uvedit_live_unwrap(const Scene *scene, Object **objects, int objects_len
pack_island_params.margin = scene->toolsettings->uvcalc_margin;
uvedit_pack_islands_multi(
scene, objects, objects_len, nullptr, nullptr, false, &pack_island_params);
scene, objects, objects_len, nullptr, nullptr, false, true, &pack_island_params);
}
}
@ -2377,7 +2509,7 @@ static int unwrap_exec(bContext *C, wmOperator *op)
pack_island_params.margin = RNA_float_get(op->ptr, "margin");
uvedit_pack_islands_multi(
scene, objects, objects_len, nullptr, nullptr, false, &pack_island_params);
scene, objects, objects_len, nullptr, nullptr, false, true, &pack_island_params);
MEM_freeN(objects);
@ -2759,7 +2891,7 @@ static int smart_project_exec(bContext *C, wmOperator *op)
params.margin = RNA_float_get(op->ptr, "island_margin");
uvedit_pack_islands_multi(
scene, objects_changed, object_changed_len, nullptr, nullptr, false, &params);
scene, objects_changed, object_changed_len, nullptr, nullptr, false, true, &params);
/* #uvedit_pack_islands_multi only supports `per_face_aspect = false`. */
const bool per_face_aspect = false;
@ -3747,7 +3879,7 @@ void ED_uvedit_add_simple_uvs(Main *bmain, const Scene *scene, Object *ob)
params.margin_method = ED_UVPACK_MARGIN_SCALED;
params.margin = 0.001f;
uvedit_pack_islands_multi(scene, &ob, 1, &bm, nullptr, false, &params);
uvedit_pack_islands_multi(scene, &ob, 1, &bm, nullptr, false, true, &params);
/* Write back from BMesh to Mesh. */
BMeshToMeshParams bm_to_me_params{};

View File

@ -37,7 +37,7 @@ enum eUVPackIsland_ShapeMethod {
enum eUVPackIsland_PinMethod {
ED_UVPACK_PIN_IGNORED = 0,
ED_UVPACK_PIN_NORMAL,
ED_UVPACK_PIN_DEFAULT,
ED_UVPACK_PIN_LOCK_ROTATION,
ED_UVPACK_PIN_LOCK_ROTATION_SCALE,
ED_UVPACK_PIN_LOCK_SCALE,
@ -55,6 +55,7 @@ class UVPackIsland_Params {
void setFromUnwrapOptions(const UnwrapOptions &options);
void setUDIMOffsetFromSpaceImage(const SpaceImage *sima);
bool isCancelled() const;
/** Islands can be rotated to improve packing. */
bool rotate;
@ -84,6 +85,12 @@ class UVPackIsland_Params {
float target_aspect_y;
/** Which shape to use when packing. */
eUVPackIsland_ShapeMethod shape_method;
/** Abandon packing early when set by the job system. */
bool *stop;
bool *do_update;
/** How much progress we have made. From wmJob. */
float *progress;
};
class uv_phi;

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