diff --git a/extern/hipew/include/hiprtew.h b/extern/hipew/include/hiprtew.h index a5472896dd97..5f967e7c99c6 100644 --- a/extern/hipew/include/hiprtew.h +++ b/extern/hipew/include/hiprtew.h @@ -79,6 +79,7 @@ typedef hiprtError(thiprtSetFuncTable)(hiprtContext context, hiprtFuncDataSet set); typedef hiprtError(thiprtDestroyFuncTable)(hiprtContext context, hiprtFuncTable funcTable); +typedef void(thiprtSetLogLevel)( hiprtLogLevel level ); /* Function declarations. */ extern thiprtCreateContext *hiprtCreateContext; @@ -94,6 +95,7 @@ extern thiprtGetSceneBuildTemporaryBufferSize *hiprtGetSceneBuildTemporaryBuffer extern thiprtCreateFuncTable *hiprtCreateFuncTable; extern thiprtSetFuncTable *hiprtSetFuncTable; extern thiprtDestroyFuncTable *hiprtDestroyFuncTable; +extern thiprtSetLogLevel *hiprtSetLogLevel; /* HIPEW API. */ diff --git a/extern/hipew/src/hiprtew.cc b/extern/hipew/src/hiprtew.cc index 84403bb22834..5844d6466b33 100644 --- a/extern/hipew/src/hiprtew.cc +++ b/extern/hipew/src/hiprtew.cc @@ -41,6 +41,7 @@ thiprtGetSceneBuildTemporaryBufferSize *hiprtGetSceneBuildTemporaryBufferSize; thiprtCreateFuncTable *hiprtCreateFuncTable; thiprtSetFuncTable *hiprtSetFuncTable; thiprtDestroyFuncTable *hiprtDestroyFuncTable; +thiprtSetLogLevel *hiprtSetLogLevel; static void hipewHipRtExit(void) { @@ -89,6 +90,7 @@ bool hiprtewInit() HIPRT_LIBRARY_FIND(hiprtCreateFuncTable) HIPRT_LIBRARY_FIND(hiprtSetFuncTable) HIPRT_LIBRARY_FIND(hiprtDestroyFuncTable) + HIPRT_LIBRARY_FIND(hiprtSetLogLevel) result = true; #endif diff --git a/extern/xdnd/xdnd.c b/extern/xdnd/xdnd.c index e8c51377e278..afd7156978fe 100644 --- a/extern/xdnd/xdnd.c +++ b/extern/xdnd/xdnd.c @@ -464,8 +464,9 @@ static char *concat_string_list (char **t, int *bytes) break; if (!(t[n][0])) break; - strcpy (s + l, t[n]); - l += strlen (t[n]) + 1; + int t_size = strlen (t[n]) + 1; + memcpy (s + l, t[n], t_size); + l += t_size; } *bytes = l; s[l] = '\0'; diff --git a/intern/cycles/device/hiprt/device_impl.cpp b/intern/cycles/device/hiprt/device_impl.cpp index a70a92be3a5b..bbdb7f403553 100644 --- a/intern/cycles/device/hiprt/device_impl.cpp +++ b/intern/cycles/device/hiprt/device_impl.cpp @@ -96,6 +96,8 @@ HIPRTDevice::HIPRTDevice(const DeviceInfo &info, Stats &stats, Profiler &profile set_error(string_printf("Failed to create HIPRT Function Table")); return; } + + hiprtSetLogLevel(hiprtLogLevelNone); } HIPRTDevice::~HIPRTDevice() @@ -261,8 +263,7 @@ string HIPRTDevice::compile_kernel(const uint kernel_features, const char *name, linker_options.append(" --offload-arch=").append(arch); linker_options.append(" -fgpu-rdc --hip-link --cuda-device-only "); string hiprt_ver(HIPRT_VERSION_STR); - string hiprt_bc; - hiprt_bc = hiprt_path + "\\hiprt" + hiprt_ver + "_amd_lib_win.bc"; + string hiprt_bc = hiprt_path + "\\dist\\bin\\Release\\hiprt" + hiprt_ver + "_amd_lib_win.bc"; string linker_command = string_printf("clang++ %s \"%s\" %s -o \"%s\"", linker_options.c_str(), diff --git a/intern/cycles/device/hiprt/queue.cpp b/intern/cycles/device/hiprt/queue.cpp index 8a37e8706541..a37aafe234c0 100644 --- a/intern/cycles/device/hiprt/queue.cpp +++ b/intern/cycles/device/hiprt/queue.cpp @@ -61,6 +61,8 @@ bool HIPRTDeviceQueue::enqueue(DeviceKernel kernel, 0), "enqueue"); + debug_enqueue_end(); + return !(hiprt_device_->have_error()); } diff --git a/intern/cycles/kernel/device/hiprt/bvh.h b/intern/cycles/kernel/device/hiprt/bvh.h index 656689ae686e..a7242d99c7b3 100644 --- a/intern/cycles/kernel/device/hiprt/bvh.h +++ b/intern/cycles/kernel/device/hiprt/bvh.h @@ -46,11 +46,11 @@ ccl_device_intersect bool scene_intersect(KernelGlobals kg, GET_TRAVERSAL_STACK() if (visibility & PATH_RAY_SHADOW_OPAQUE) { - GET_TRAVERSAL_ANY_HIT(table_closest_intersect, 0) + GET_TRAVERSAL_ANY_HIT(table_closest_intersect, 0, ray->time) hit = traversal.getNextHit(); } else { - GET_TRAVERSAL_CLOSEST_HIT(table_closest_intersect, 0) + GET_TRAVERSAL_CLOSEST_HIT(table_closest_intersect, 0, ray->time) hit = traversal.getNextHit(); } if (hit.hasHit()) { @@ -157,13 +157,13 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg, payload.in_state = state; payload.max_hits = max_hits; payload.visibility = visibility; - payload.prim_type = PRIMITIVE_TRIANGLE; + payload.prim_type = PRIMITIVE_NONE; payload.ray_time = ray->time; payload.num_hits = 0; payload.r_num_recorded_hits = num_recorded_hits; payload.r_throughput = throughput; GET_TRAVERSAL_STACK() - GET_TRAVERSAL_ANY_HIT(table_shadow_intersect, 1) + GET_TRAVERSAL_ANY_HIT(table_shadow_intersect, 1, ray->time) hiprtHit hit = traversal.getNextHit(); num_recorded_hits = payload.r_num_recorded_hits; throughput = payload.r_throughput; @@ -201,7 +201,7 @@ ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg, GET_TRAVERSAL_STACK() - GET_TRAVERSAL_CLOSEST_HIT(table_volume_intersect, 3) + GET_TRAVERSAL_CLOSEST_HIT(table_volume_intersect, 3, ray->time) hiprtHit hit = traversal.getNextHit(); // return hit.hasHit(); if (hit.hasHit()) { diff --git a/intern/cycles/kernel/device/hiprt/common.h b/intern/cycles/kernel/device/hiprt/common.h index a65061647ae3..045502bec4d5 100644 --- a/intern/cycles/kernel/device/hiprt/common.h +++ b/intern/cycles/kernel/device/hiprt/common.h @@ -53,7 +53,7 @@ struct LocalPayload { # endif # ifdef HIPRT_SHARED_STACK -# define GET_TRAVERSAL_ANY_HIT(FUNCTION_TABLE, RAY_TYPE) \ +# define GET_TRAVERSAL_ANY_HIT(FUNCTION_TABLE, RAY_TYPE, RAY_TIME) \ hiprtSceneTraversalAnyHitCustomStack traversal(kernel_data.device_bvh, \ ray_hip, \ stack, \ @@ -61,10 +61,10 @@ struct LocalPayload { hiprtTraversalHintDefault, \ &payload, \ kernel_params.FUNCTION_TABLE, \ - RAY_TYPE); \ - hiprtSceneTraversalAnyHitCustomStack traversal_simple( \ - kernel_data.device_bvh, ray_hip, stack, visibility); -# define GET_TRAVERSAL_CLOSEST_HIT(FUNCTION_TABLE, RAY_TYPE) \ + RAY_TYPE, \ + RAY_TIME); + +# define GET_TRAVERSAL_CLOSEST_HIT(FUNCTION_TABLE, RAY_TYPE, RAY_TIME) \ hiprtSceneTraversalClosestCustomStack traversal(kernel_data.device_bvh, \ ray_hip, \ stack, \ @@ -72,9 +72,8 @@ struct LocalPayload { hiprtTraversalHintDefault, \ &payload, \ kernel_params.FUNCTION_TABLE, \ - RAY_TYPE); \ - hiprtSceneTraversalClosestCustomStack traversal_simple( \ - kernel_data.device_bvh, ray_hip, stack, visibility); + RAY_TYPE, \ + RAY_TIME); # else # define GET_TRAVERSAL_ANY_HIT(FUNCTION_TABLE) \ hiprtSceneTraversalAnyHit traversal(kernel_data.device_bvh, \ @@ -82,16 +81,14 @@ struct LocalPayload { visibility, \ FUNCTION_TABLE, \ hiprtTraversalHintDefault, \ - &payload); \ - hiprtSceneTraversalAnyHit traversal_simple(kernel_data.device_bvh, ray_hip, visibility); + &payload); # define GET_TRAVERSAL_CLOSEST_HIT(FUNCTION_TABLE) \ hiprtSceneTraversalClosest traversal(kernel_data.device_bvh, \ ray_hip, \ visibility, \ FUNCTION_TABLE, \ hiprtTraversalHintDefault, \ - &payload); \ - hiprtSceneTraversalClosest traversal_simple(kernel_data.device_bvh, ray_hip, visibility); + &payload); # endif ccl_device_inline void set_intersect_point(KernelGlobals kg, diff --git a/intern/cycles/kernel/integrator/mnee.h b/intern/cycles/kernel/integrator/mnee.h index f6c8d20247dc..7af104f6096c 100644 --- a/intern/cycles/kernel/integrator/mnee.h +++ b/intern/cycles/kernel/integrator/mnee.h @@ -775,7 +775,9 @@ ccl_device_forceinline bool mnee_path_contribution(KernelGlobals kg, surface_shader_bsdf_eval(kg, state, sd, wo, throughput, ls->shader); /* Update light sample with new position / direction and keep pdf in vertex area measure. */ - light_sample_update(kg, ls, vertices[vertex_count - 1].p); + const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); + light_sample_update( + kg, ls, vertices[vertex_count - 1].p, vertices[vertex_count - 1].n, path_flag); /* Save state path bounce info in case a light path node is used in the refractive interface or * light shader graph. */ diff --git a/intern/cycles/kernel/integrator/shade_dedicated_light.h b/intern/cycles/kernel/integrator/shade_dedicated_light.h index 9c6b2e3045b7..3e91d6e29963 100644 --- a/intern/cycles/kernel/integrator/shade_dedicated_light.h +++ b/intern/cycles/kernel/integrator/shade_dedicated_light.h @@ -20,6 +20,8 @@ ccl_device_inline bool shadow_linking_light_sample_from_intersection( KernelGlobals kg, ccl_private const Intersection &ccl_restrict isect, ccl_private const Ray &ccl_restrict ray, + const float3 N, + const uint32_t path_flag, ccl_private LightSample *ccl_restrict ls) { const int lamp = isect.prim; @@ -31,7 +33,7 @@ ccl_device_inline bool shadow_linking_light_sample_from_intersection( return distant_light_sample_from_intersection(kg, ray.D, lamp, ls); } - return light_sample_from_intersection(kg, &isect, ray.P, ray.D, ls); + return light_sample_from_intersection(kg, &isect, ray.P, ray.D, N, path_flag, ls); } ccl_device_inline float shadow_linking_light_sample_mis_weight(KernelGlobals kg, @@ -88,8 +90,11 @@ ccl_device bool shadow_linking_shade_light(KernelGlobals kg, ccl_private float &mis_weight, ccl_private int &ccl_restrict light_group) { + const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); + const float3 N = INTEGRATOR_STATE(state, path, mis_origin_n); LightSample ls ccl_optional_struct_init; - const bool use_light_sample = shadow_linking_light_sample_from_intersection(kg, isect, ray, &ls); + const bool use_light_sample = shadow_linking_light_sample_from_intersection( + kg, isect, ray, N, path_flag, &ls); if (!use_light_sample) { /* No light to be sampled, so no direct light contribution either. */ return false; @@ -100,7 +105,6 @@ ccl_device bool shadow_linking_shade_light(KernelGlobals kg, return false; } - const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); if (!is_light_shader_visible_to_path(ls.shader, path_flag)) { return false; } diff --git a/intern/cycles/kernel/integrator/shade_light.h b/intern/cycles/kernel/integrator/shade_light.h index fb9c53ffdd1a..8bcf55a96ffe 100644 --- a/intern/cycles/kernel/integrator/shade_light.h +++ b/intern/cycles/kernel/integrator/shade_light.h @@ -24,12 +24,15 @@ ccl_device_inline void integrate_light(KernelGlobals kg, float3 ray_P = INTEGRATOR_STATE(state, ray, P); const float3 ray_D = INTEGRATOR_STATE(state, ray, D); const float ray_time = INTEGRATOR_STATE(state, ray, time); + const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); + const float3 N = INTEGRATOR_STATE(state, path, mis_origin_n); /* Advance ray to new start distance. */ INTEGRATOR_STATE_WRITE(state, ray, tmin) = intersection_t_offset(isect.t); LightSample ls ccl_optional_struct_init; - const bool use_light_sample = light_sample_from_intersection(kg, &isect, ray_P, ray_D, &ls); + const bool use_light_sample = light_sample_from_intersection( + kg, &isect, ray_P, ray_D, N, path_flag, &ls); if (!use_light_sample) { return; @@ -37,7 +40,6 @@ ccl_device_inline void integrate_light(KernelGlobals kg, /* Use visibility flag to skip lights. */ #ifdef __PASSES__ - const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); if (!is_light_shader_visible_to_path(ls.shader, path_flag)) { return; } diff --git a/intern/cycles/kernel/light/distribution.h b/intern/cycles/kernel/light/distribution.h index 9ca6856d94dd..23cdaa6dff5b 100644 --- a/intern/cycles/kernel/light/distribution.h +++ b/intern/cycles/kernel/light/distribution.h @@ -46,7 +46,9 @@ ccl_device_noinline bool light_distribution_sample(KernelGlobals kg, const float3 rand, const float time, const float3 P, + const float3 N, const int object_receiver, + const int shader_flags, const int bounce, const uint32_t path_flag, ccl_private LightSample *ls) @@ -56,8 +58,19 @@ ccl_device_noinline bool light_distribution_sample(KernelGlobals kg, const int index = light_distribution_sample(kg, rand.z); const float pdf_selection = kernel_data.integrator.distribution_pdf_lights; const float2 rand_uv = float3_to_float2(rand); - return light_sample( - kg, rand_uv, time, P, object_receiver, bounce, path_flag, index, 0, pdf_selection, ls); + return light_sample(kg, + rand_uv, + time, + P, + N, + object_receiver, + shader_flags, + bounce, + path_flag, + index, + 0, + pdf_selection, + ls); } ccl_device_inline float light_distribution_pdf_lamp(KernelGlobals kg) diff --git a/intern/cycles/kernel/light/light.h b/intern/cycles/kernel/light/light.h index 22dbdb3a318e..87596a0abef2 100644 --- a/intern/cycles/kernel/light/light.h +++ b/intern/cycles/kernel/light/light.h @@ -96,6 +96,8 @@ ccl_device_inline bool light_sample(KernelGlobals kg, const int lamp, const float2 rand, const float3 P, + const float3 N, + const int shader_flags, const uint32_t path_flag, ccl_private LightSample *ls) { @@ -150,7 +152,7 @@ ccl_device_inline bool light_sample(KernelGlobals kg, } } else if (type == LIGHT_POINT) { - if (!point_light_sample(klight, rand, P, ls)) { + if (!point_light_sample(klight, rand, P, N, shader_flags, ls)) { return false; } } @@ -171,7 +173,9 @@ ccl_device_noinline bool light_sample(KernelGlobals kg, const float2 rand, const float time, const float3 P, + const float3 N, const int object_receiver, + const int shader_flags, const int bounce, const uint32_t path_flag, const int emitter_index, @@ -233,7 +237,7 @@ ccl_device_noinline bool light_sample(KernelGlobals kg, return false; } - if (!light_sample(kg, light, rand, P, path_flag, ls)) { + if (!light_sample(kg, light, rand, P, N, shader_flags, path_flag, ls)) { return false; } } @@ -446,6 +450,8 @@ ccl_device bool light_sample_from_intersection(KernelGlobals kg, ccl_private const Intersection *ccl_restrict isect, const float3 ray_P, const float3 ray_D, + const float3 N, + const uint32_t path_flag, ccl_private LightSample *ccl_restrict ls) { const int lamp = isect->prim; @@ -468,7 +474,7 @@ ccl_device bool light_sample_from_intersection(KernelGlobals kg, } } else if (type == LIGHT_POINT) { - if (!point_light_sample_from_intersection(klight, isect, ray_P, ray_D, ls)) { + if (!point_light_sample_from_intersection(klight, isect, ray_P, ray_D, N, path_flag, ls)) { return false; } } diff --git a/intern/cycles/kernel/light/point.h b/intern/cycles/kernel/light/point.h index bac53ff58ccf..a4dbd1850fe5 100644 --- a/intern/cycles/kernel/light/point.h +++ b/intern/cycles/kernel/light/point.h @@ -8,68 +8,123 @@ CCL_NAMESPACE_BEGIN -template ccl_device_inline bool point_light_sample(const ccl_global KernelLight *klight, const float2 rand, const float3 P, + const float3 N, + const int shader_flags, ccl_private LightSample *ls) { - float3 center = klight->co; - float radius = klight->spot.radius; - /* disk oriented normal */ - const float3 lightN = normalize(P - center); - ls->P = center; - - if (radius > 0.0f) { - ls->P += disk_light_sample(lightN, rand) * radius; + float3 lightN = P - klight->co; + const float d_sq = len_squared(lightN); + const float d = sqrtf(d_sq); + lightN /= d; + + const float r_sq = sqr(klight->spot.radius); + + float cos_theta; + if (d_sq > r_sq) { + const float one_minus_cos = sin_sqr_to_one_minus_cos(r_sq / d_sq); + sample_uniform_cone_concentric(-lightN, one_minus_cos, rand, &cos_theta, &ls->D, &ls->pdf); + } + else { + const bool has_transmission = (shader_flags & SD_BSDF_HAS_TRANSMISSION); + if (has_transmission) { + ls->D = sample_uniform_sphere(rand); + ls->pdf = M_1_2PI_F * 0.5f; + } + else { + sample_cos_hemisphere(N, rand, &ls->D, &ls->pdf); + } + cos_theta = -dot(ls->D, lightN); } - ls->pdf = klight->spot.invarea; - ls->D = normalize_len(ls->P - P, &ls->t); - /* we set the light normal to the outgoing direction to support texturing */ - ls->Ng = -ls->D; + /* Law of cosines. */ + ls->t = d * cos_theta - copysignf(safe_sqrtf(r_sq - d_sq + d_sq * sqr(cos_theta)), d_sq - r_sq); + + ls->P = P + ls->D * ls->t; ls->eval_fac = M_1_PI_F * 0.25f * klight->spot.invarea; + if (r_sq == 0) { + /* Use intensity instead of radiance for point light. */ + ls->eval_fac /= sqr(ls->t); + /* `ls->Ng` is not well-defined for point light, so use the incoming direction instead. */ + ls->Ng = -ls->D; + } + else { + ls->Ng = normalize(ls->P - klight->co); + /* Remap sampled point onto the sphere to prevent precision issues with small radius. */ + ls->P = ls->Ng * klight->spot.radius + klight->co; + } + + const Transform itfm = klight->itfm; + const float2 uv = map_to_sphere(transform_direction(&itfm, ls->Ng)); + /* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */ + ls->u = uv.y; + ls->v = 1.0f - uv.x - uv.y; - float2 uv = map_to_sphere(ls->Ng); - ls->u = uv.x; - ls->v = uv.y; - ls->pdf *= lamp_light_pdf(lightN, -ls->D, ls->t); return true; } +ccl_device_forceinline float point_light_pdf( + const float d_sq, const float r_sq, const float3 N, const float3 D, const uint32_t path_flag) +{ + if (d_sq > r_sq) { + return M_1_2PI_F / sin_sqr_to_one_minus_cos(r_sq / d_sq); + } + + const bool has_transmission = (path_flag & PATH_RAY_MIS_HAD_TRANSMISSION); + return has_transmission ? M_1_2PI_F * 0.5f : pdf_cos_hemisphere(N, D); +} + ccl_device_forceinline void point_light_mnee_sample_update(const ccl_global KernelLight *klight, ccl_private LightSample *ls, - const float3 P) + const float3 P, + const float3 N, + const uint32_t path_flag) { ls->D = normalize_len(ls->P - P, &ls->t); - ls->Ng = -ls->D; - float2 uv = map_to_sphere(ls->Ng); - ls->u = uv.x; - ls->v = uv.y; + const float radius = klight->spot.radius; - float invarea = klight->spot.invarea; - ls->eval_fac = (0.25f * M_1_PI_F) * invarea; - /* NOTE : preserve pdf in area measure. */ - ls->pdf = invarea; + if (radius > 0) { + const float d_sq = len_squared(P - klight->co); + const float r_sq = sqr(radius); + const float t_sq = sqr(ls->t); + + ls->pdf = point_light_pdf(d_sq, r_sq, N, ls->D, path_flag); + + /* NOTE : preserve pdf in area measure. */ + ls->pdf *= 0.5f * fabsf(d_sq - r_sq - t_sq) / (radius * ls->t * t_sq); + + ls->Ng = normalize(ls->P - klight->co); + } + else { + ls->eval_fac = M_1_PI_F * 0.25f * klight->spot.invarea; + + ls->Ng = -ls->D; + + /* PDF does not change. */ + } + + const Transform itfm = klight->itfm; + const float2 uv = map_to_sphere(transform_direction(&itfm, ls->Ng)); + /* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */ + ls->u = uv.y; + ls->v = 1.0f - uv.x - uv.y; } ccl_device_inline bool point_light_intersect(const ccl_global KernelLight *klight, const ccl_private Ray *ccl_restrict ray, ccl_private float *t) { - /* Sphere light (aka, aligned disk light). */ - const float3 lightP = klight->co; const float radius = klight->spot.radius; if (radius == 0.0f) { return false; } - /* disk oriented normal */ - const float3 lightN = normalize(ray->P - lightP); float3 P; - return ray_disk_intersect(ray->P, ray->D, ray->tmin, ray->tmax, lightP, lightN, radius, &P, t); + return ray_sphere_intersect(ray->P, ray->D, ray->tmin, ray->tmax, klight->co, radius, &P, t); } ccl_device_inline bool point_light_sample_from_intersection( @@ -77,27 +132,27 @@ ccl_device_inline bool point_light_sample_from_intersection( ccl_private const Intersection *ccl_restrict isect, const float3 ray_P, const float3 ray_D, + const float3 N, + const uint32_t path_flag, ccl_private LightSample *ccl_restrict ls) { - const float3 lighN = normalize(ray_P - klight->co); + ls->eval_fac = M_1_PI_F * 0.25f * klight->spot.invarea; - /* We set the light normal to the outgoing direction to support texturing. */ - ls->Ng = -ls->D; + const float radius = klight->spot.radius; - float invarea = klight->spot.invarea; - ls->eval_fac = (0.25f * M_1_PI_F) * invarea; - ls->pdf = invarea; + ls->Ng = radius > 0 ? normalize(ls->P - klight->co) : -ray_D; - float2 uv = map_to_sphere(ls->Ng); - ls->u = uv.x; - ls->v = uv.y; + const Transform itfm = klight->itfm; + const float2 uv = map_to_sphere(transform_direction(&itfm, ls->Ng)); + /* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */ + ls->u = uv.y; + ls->v = 1.0f - uv.x - uv.y; - /* compute pdf */ - if (ls->t != FLT_MAX) { - ls->pdf *= lamp_light_pdf(lighN, -ls->D, ls->t); + if (ls->t == FLT_MAX) { + ls->pdf = 0.0f; } else { - ls->pdf = 0.f; + ls->pdf = point_light_pdf(len_squared(ray_P - klight->co), sqr(radius), N, ray_D, path_flag); } return true; @@ -115,14 +170,22 @@ ccl_device_forceinline bool point_light_tree_parameters(const ccl_global KernelL cos_theta_u = 1.0f; /* Any value in [-1, 1], irrelevant since theta = 0 */ return true; } - float min_distance; - point_to_centroid = safe_normalize_len(centroid - P, &min_distance); - const float radius = klight->spot.radius; - const float hypotenus = sqrtf(sqr(radius) + sqr(min_distance)); - cos_theta_u = min_distance / hypotenus; + float dist_point_to_centroid; + point_to_centroid = safe_normalize_len(centroid - P, &dist_point_to_centroid); - distance = make_float2(hypotenus, min_distance); + const float radius = klight->spot.radius; + if (dist_point_to_centroid > radius) { + /* Equivalent to a disk light with the same angular span. */ + cos_theta_u = cos_from_sin(radius / dist_point_to_centroid); + distance = dist_point_to_centroid * make_float2(1.0f / cos_theta_u, 1.0f); + } + else { + /* Similar to background light. */ + cos_theta_u = -1.0f; + /* HACK: pack radiance scaling in the distance. */ + distance = one_float2() * radius / M_SQRT2_F; + } return true; } diff --git a/intern/cycles/kernel/light/sample.h b/intern/cycles/kernel/light/sample.h index 2a2fce850344..96d6474e7af0 100644 --- a/intern/cycles/kernel/light/sample.h +++ b/intern/cycles/kernel/light/sample.h @@ -338,7 +338,7 @@ ccl_device_inline bool light_sample_from_volume_segment(KernelGlobals kg, #endif { return light_distribution_sample( - kg, rand, time, P, object_receiver, bounce, path_flag, ls); + kg, rand, time, P, D, object_receiver, SD_BSDF_HAS_TRANSMISSION, bounce, path_flag, ls); } } @@ -363,7 +363,7 @@ ccl_device bool light_sample_from_position(KernelGlobals kg, #endif { return light_distribution_sample( - kg, rand, time, P, object_receiver, bounce, path_flag, ls); + kg, rand, time, P, N, object_receiver, shader_flags, bounce, path_flag, ls); } } @@ -371,12 +371,14 @@ ccl_device bool light_sample_from_position(KernelGlobals kg, * except for directional light. */ ccl_device_forceinline void light_sample_update(KernelGlobals kg, ccl_private LightSample *ls, - const float3 P) + const float3 P, + const float3 N, + const uint32_t path_flag) { const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ls->lamp); if (ls->type == LIGHT_POINT) { - point_light_mnee_sample_update(klight, ls, P); + point_light_mnee_sample_update(klight, ls, P, N, path_flag); } else if (ls->type == LIGHT_SPOT) { spot_light_mnee_sample_update(klight, ls, P); diff --git a/intern/cycles/kernel/light/tree.h b/intern/cycles/kernel/light/tree.h index 52ff88a35213..55788f064cd2 100644 --- a/intern/cycles/kernel/light/tree.h +++ b/intern/cycles/kernel/light/tree.h @@ -761,7 +761,9 @@ ccl_device_noinline bool light_tree_sample(KernelGlobals kg, float3_to_float2(rand), time, P, + N_or_D, object_receiver, + shader_flags, bounce, path_flag, selected_emitter, diff --git a/intern/cycles/kernel/sample/mapping.h b/intern/cycles/kernel/sample/mapping.h index 43c84a409458..6ae8fb9f95ae 100644 --- a/intern/cycles/kernel/sample/mapping.h +++ b/intern/cycles/kernel/sample/mapping.h @@ -19,6 +19,29 @@ ccl_device void to_unit_disk(ccl_private float2 *rand) rand->y = r * sinf(phi); } +/* Distribute 2D uniform random samples on [0, 1] over unit disk [-1, 1], with concentric mapping + * to better preserve stratification for some RNG sequences. */ +ccl_device float2 concentric_sample_disk(const float2 rand) +{ + float phi, r; + float a = 2.0f * rand.x - 1.0f; + float b = 2.0f * rand.y - 1.0f; + + if (a == 0.0f && b == 0.0f) { + return zero_float2(); + } + else if (a * a > b * b) { + r = a; + phi = M_PI_4_F * (b / a); + } + else { + r = b; + phi = M_PI_2_F - M_PI_4_F * (a / b); + } + + return make_float2(r * cosf(phi), r * sinf(phi)); +} + /* return an orthogonal tangent and bitangent given a normal and tangent that * may not be exactly orthogonal */ ccl_device void make_orthonormals_tangent(const float3 N, @@ -45,6 +68,12 @@ ccl_device_inline void sample_cos_hemisphere(const float3 N, *pdf = costheta * M_1_PI_F; } +ccl_device_inline float pdf_cos_hemisphere(const float3 N, const float3 D) +{ + const float cos_theta = dot(N, D); + return cos_theta > 0 ? cos_theta * M_1_PI_F : 0.0f; +} + /* sample direction uniformly distributed in hemisphere */ ccl_device_inline void sample_uniform_hemisphere(const float3 N, const float2 rand, @@ -91,6 +120,42 @@ ccl_device_inline float pdf_uniform_cone(const float3 N, float3 D, float angle) return 0.0f; } +/* Uniformly sample a direction in a cone of given angle around `N`. Use concentric mapping to + * better preserve stratification. Return the angle between `N` and the sampled direction as + * `cos_theta`. + * Pass `1 - cos(angle)` as argument instead of `angle` to alleviate precision issues at small + * angles (see sphere light for reference). */ +ccl_device_inline void sample_uniform_cone_concentric(const float3 N, + const float one_minus_cos_angle, + const float2 rand, + ccl_private float *cos_theta, + ccl_private float3 *wo, + ccl_private float *pdf) +{ + if (one_minus_cos_angle > 0) { + /* Map random number from 2D to 1D. */ + float2 xy = concentric_sample_disk(rand); + const float r2 = len_squared(xy); + + /* Equivalent to `mix(cos_angle, 1.0f, 1.0f - r2)` */ + *cos_theta = 1.0f - r2 * one_minus_cos_angle; + + /* Equivalent to `xy *= sin_theta / sqrt(r2); */ + xy *= safe_sqrtf(one_minus_cos_angle * (2.0f - one_minus_cos_angle * r2)); + + float3 T, B; + make_orthonormals(N, &T, &B); + + *wo = xy.x * T + xy.y * B + *cos_theta * N; + *pdf = M_1_2PI_F / one_minus_cos_angle; + } + else { + *cos_theta = 1.0f; + *wo = N; + *pdf = 1.0f; + } +} + /* sample uniform point on the surface of a sphere */ ccl_device float3 sample_uniform_sphere(const float2 rand) { @@ -103,29 +168,6 @@ ccl_device float3 sample_uniform_sphere(const float2 rand) return make_float3(x, y, z); } -/* distribute uniform xy on [0,1] over unit disk [-1,1], with concentric mapping - * to better preserve stratification for some RNG sequences */ -ccl_device float2 concentric_sample_disk(const float2 rand) -{ - float phi, r; - float a = 2.0f * rand.x - 1.0f; - float b = 2.0f * rand.y - 1.0f; - - if (a == 0.0f && b == 0.0f) { - return zero_float2(); - } - else if (a * a > b * b) { - r = a; - phi = M_PI_4_F * (b / a); - } - else { - r = b; - phi = M_PI_2_F - M_PI_4_F * (a / b); - } - - return make_float2(r * cosf(phi), r * sinf(phi)); -} - /* sample point in unit polygon with given number of corners and rotation */ ccl_device float2 regular_polygon_sample(float corners, float rotation, const float2 rand) { diff --git a/intern/cycles/scene/light.cpp b/intern/cycles/scene/light.cpp index bc7a41a5824d..f6728f023668 100644 --- a/intern/cycles/scene/light.cpp +++ b/intern/cycles/scene/light.cpp @@ -1214,6 +1214,9 @@ void LightManager::device_update_lights(Device *device, DeviceScene *dscene, Sce shader_id &= ~SHADER_AREA_LIGHT; float radius = light->size; + /* TODO: `invarea` was used for disk sampling, with the current solid angle sampling this + * becomes unnecessary. We could store `eval_fac` instead, but currently it shares the same + * #KernelSpotLight type with #LIGHT_SPOT, so keep it know until refactor for spot light. */ float invarea = (light->normalize && radius > 0.0f) ? 1.0f / (M_PI_F * radius * radius) : 1.0f; diff --git a/intern/cycles/util/math.h b/intern/cycles/util/math.h index a29abe51e7a2..394e56ea9268 100644 --- a/intern/cycles/util/math.h +++ b/intern/cycles/util/math.h @@ -748,6 +748,12 @@ ccl_device_inline float cos_from_sin(const float s) return safe_sqrtf(1.0f - sqr(s)); } +ccl_device_inline float sin_sqr_to_one_minus_cos(const float s_sq) +{ + /* Using second-order Taylor expansion at small angles for better accuracy. */ + return s_sq > 0.0004f ? 1.0f - safe_sqrtf(1.0f - s_sq) : 0.5f * s_sq; +} + ccl_device_inline float pow20(float a) { return sqr(sqr(sqr(sqr(a)) * a)); diff --git a/intern/cycles/util/math_intersect.h b/intern/cycles/util/math_intersect.h index 0e1ed3de6083..c7277f38f25b 100644 --- a/intern/cycles/util/math_intersect.h +++ b/intern/cycles/util/math_intersect.h @@ -18,29 +18,32 @@ ccl_device bool ray_sphere_intersect(float3 ray_P, ccl_private float3 *isect_P, ccl_private float *isect_t) { - const float3 d = sphere_P - ray_P; - const float radiussq = sphere_radius * sphere_radius; - const float tsq = dot(d, d); - - if (tsq > radiussq) { - /* Ray origin outside sphere. */ - const float tp = dot(d, ray_D); - if (tp < 0.0f) { - /* Ray points away from sphere. */ - return false; - } - const float dsq = tsq - tp * tp; /* Pythagoras. */ - if (dsq > radiussq) { - /* Closest point on ray outside sphere. */ - return false; - } - const float t = tp - sqrtf(radiussq - dsq); /* pythagoras */ - if (t > ray_tmin && t < ray_tmax) { - *isect_t = t; - *isect_P = ray_P + ray_D * t; - return true; - } + const float3 d_vec = sphere_P - ray_P; + const float r_sq = sphere_radius * sphere_radius; + const float d_sq = dot(d_vec, d_vec); + const float d_cos_theta = dot(d_vec, ray_D); + + if (d_sq > r_sq && d_cos_theta < 0.0f) { + /* Ray origin outside sphere and points away from sphere. */ + return false; } + + const float d_sin_theta_sq = d_sq - d_cos_theta * d_cos_theta; + + if (d_sin_theta_sq > r_sq) { + /* Closest point on ray outside sphere. */ + return false; + } + + /* Law of cosines. */ + const float t = d_cos_theta - copysignf(sqrtf(r_sq - d_sin_theta_sq), d_sq - r_sq); + + if (t > ray_tmin && t < ray_tmax) { + *isect_t = t; + *isect_P = ray_P + ray_D * t; + return true; + } + return false; } diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.cc b/intern/ghost/intern/GHOST_DropTargetWin32.cc index a7f642cdbb04..513f61b0b552 100644 --- a/intern/ghost/intern/GHOST_DropTargetWin32.cc +++ b/intern/ghost/intern/GHOST_DropTargetWin32.cc @@ -270,10 +270,11 @@ void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *p_data_object) if (p_data_object->QueryGetData(&fmtetc) == S_OK) { if (p_data_object->GetData(&fmtetc, &stgmed) == S_OK) { char *str = (char *)::GlobalLock(stgmed.hGlobal); + int str_size = ::strlen(str) + 1; - tmp_string = (char *)::malloc(::strlen(str) + 1); + tmp_string = (char *)::malloc(str_size); if (tmp_string) { - ::strcpy(tmp_string, str); + ::memcpy(tmp_string, str, str_size); } /* Free memory. */ ::GlobalUnlock(stgmed.hGlobal); diff --git a/release/license/THIRD-PARTY-LICENSES.txt b/release/license/THIRD-PARTY-LICENSES.txt index 268399287f80..cd43f71f2a9b 100644 --- a/release/license/THIRD-PARTY-LICENSES.txt +++ b/release/license/THIRD-PARTY-LICENSES.txt @@ -22,11 +22,10 @@ PERFORMANCE OF THIS SOFTWARE. ** Audaspace; version 1.3.0 -- https://audaspace.github.io/ ** Cuda Wrangler; version cbf465b -- https://github.com/CudaWrangler/cuew ** Draco; version 1.3.6 -- https://google.github.io/draco/ -** Embree; version 3.13.4 -- https://github.com/embree/embree -** Intel(R) oneAPI DPC++ compiler; version 20221019 -- +** Embree; version 4.1.0 -- https://github.com/embree/embree +** Intel(R) oneAPI DPC++ compiler; version 2022-12 -- https://github.com/intel/llvm#oneapi-dpc-compiler -** Intel® Open Path Guiding Library; version v0.4.1-beta -- -http://www.openpgl.org/ +** Intel® Open Path Guiding Library; version 0.5.0 -- http://www.openpgl.org/ ** Mantaflow; version 0.13 -- http://mantaflow.com/ ** materialX; version 1.38.6 -- https://github.com/AcademySoftwareFoundation/MaterialX @@ -40,6 +39,8 @@ https://software.intel.com/en-us/oneapi/onetbb ** SDL Extension Wrangler; version 15edf8e -- https://github.com/SDLWrangler/sdlew ** ShaderC; version 2022.3 -- https://github.com/google/shaderc +** SYCL Unified Runtime ; version fd711c920acc4434cb52ff18b078c082d9d7f44d -- +https://github.com/oneapi-src/unified-runtime ** Vulkan Loader; version 1.2.198 -- https://github.com/KhronosGroup/Vulkan-Loader @@ -279,6 +280,8 @@ limitations under the License. Copyright 2014 Blender Foundation * For ShaderC see also this required NOTICE: Copyright 2015 The Shaderc Authors. All rights reserved. +* For SYCL Unified Runtime see also this required NOTICE: + Copyright (C) 2022-2023 Intel Corporation * For Vulkan Loader see also this required NOTICE: Copyright (c) 2019 The Khronos Group Inc. Copyright (c) 2019 Valve Corporation @@ -378,7 +381,7 @@ All rights reserved. ** Google Logging; version 4.4.0 -- https://github.com/google/glog Copyright (c) 2006, Google Inc. All rights reserved. -** Imath; version 3.1.5 -- https://github.com/AcademySoftwareFoundation/Imath +** Imath; version 3.1.7 -- https://github.com/AcademySoftwareFoundation/Imath Copyright Contributors to the OpenEXR Project. All rights reserved. ** ISPC; version 1.17.0 -- https://github.com/ispc/ispc Copyright Intel Corporation @@ -395,10 +398,10 @@ Copyright Contributors to the Open Shading Language project. ** OpenColorIO; version 2.2.0 -- https://github.com/AcademySoftwareFoundation/OpenColorIO Copyright Contributors to the OpenColorIO Project. -** OpenEXR; version 3.1.5 -- +** OpenEXR; version 3.1.7 -- https://github.com/AcademySoftwareFoundation/openexr Copyright Contributors to the OpenEXR Project. All rights reserved. -** OpenImageIO; version 2.4.9.0 -- http://www.openimageio.org +** OpenImageIO; version 2.4.11.0 -- http://www.openimageio.org Copyright (c) 2008-present by Contributors to the OpenImageIO project. All Rights Reserved. ** Pystring; version 1.1.3 -- https://github.com/imageworks/pystring @@ -571,7 +574,7 @@ effect of CC0 on those rights. ------ -** FLAC; version 1.3.4 -- https://xiph.org/flac/ +** FLAC; version 1.4.2 -- https://xiph.org/flac/ Copyright (C) 2001-2009 Josh Coalson Copyright (C) 2011-2016 Xiph.Org Foundation ** Potrace; version 1.16 -- http://potrace.sourceforge.net/ @@ -1242,7 +1245,7 @@ Copyright (C) 2003-2021 x264 project ** miniLZO; version 2.08 -- http://www.oberhumer.com/opensource/lzo/ LZO and miniLZO are Copyright (C) 1996-2014 Markus Franz Xaver Oberhumer All Rights Reserved. -** The FreeType Project; version 2.12.1 -- +** The FreeType Project; version 2.13.0 -- https://sourceforge.net/projects/freetype Copyright (C) 1996-2020 by David Turner, Robert Wilhelm, and Werner Lemberg. ** X Drag and Drop; version 2000-08-08 -- @@ -2796,7 +2799,7 @@ That's all there is to it! ------ -** FFmpeg; version 5.1.2 -- http://ffmpeg.org/ +** FFmpeg; version 6.0 -- http://ffmpeg.org/ Copyright: The FFmpeg contributors https://github.com/FFmpeg/FFmpeg/blob/master/CREDITS ** Libsndfile; version 1.1.0 -- http://libsndfile.github.io/libsndfile/ @@ -3425,7 +3428,35 @@ December 9, 2010 ------ -** {fmt}; version 8.0.0 -- https://github.com/fmtlib/fmt +** vcintrinsics; version 782fbf7301dc73acaa049a4324c976ad94f587f7 -- +https://github.com/intel/vc-intrinsics +Copyright (c) 2019 Intel Corporation + +MIT License + +Copyright (c) 2019 Intel Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------ + +** {fmt}; version 9.1.0 -- https://github.com/fmtlib/fmt Copyright (c) 2012 - present, Victor Zverovich ** Brotli; version 1.0.9 -- https://github.com/google/brotli Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. @@ -3454,11 +3485,11 @@ Copyright (c) 2006, 2008 Junio C Hamano Copyright © 2017-2018 Red Hat Inc. Copyright © 2012 Collabora, Ltd. Copyright © 2008 Kristian Høgsberg -** Libxml2; version 2.10.3 -- http://xmlsoft.org/ +** Libxml2; version 2.10.4 -- http://xmlsoft.org/ Copyright (C) 1998-2012 Daniel Veillard. All Rights Reserved. ** Mesa 3D; version 21.1.5 -- https://www.mesa3d.org/ Copyright (C) 1999-2007 Brian Paul All Rights Reserved. -** oneAPI Level Zero; version v1.8.5 -- +** oneAPI Level Zero; version v1.8.8 -- https://github.com/oneapi-src/level-zero Copyright (C) 2019-2021 Intel Corporation ** OPENCollada; version 1.6.68 -- https://github.com/KhronosGroup/OpenCOLLADA @@ -3470,12 +3501,11 @@ Copyright (c) 2018 Jingwei Huang, Yichao Zhou, Matthias Niessner, Jonathan Shewchuk and Leonidas Guibas. All rights reserved. ** robin-map; version 0.6.2 -- https://github.com/Tessil/robin-map Copyright (c) 2017 Thibaut Goetghebuer-Planchon -** sse2neon; version fe5ff00bb8d19b327714a3c290f3e2ce81ba3525 -- -https://github.com/DLTcollab/sse2neon +** sse2neon; version 1.6.0 -- https://github.com/DLTcollab/sse2neon Copyright sse2neon contributors ** TinyGLTF; version 2.5.0 -- https://github.com/syoyo/tinygltf Copyright (c) 2017 Syoyo Fujita, Aurélien Chatelain and many contributors -** Wayland protocols; version 1.21 -- +** Wayland protocols; version 1.31 -- https://gitlab.freedesktop.org/wayland/wayland-protocols Copyright © 2008-2013 Kristian Høgsberg Copyright © 2010-2013 Intel Corporation @@ -3973,7 +4003,7 @@ the following restrictions: ------ -** LibTIFF; version 4.4.0 -- http://www.libtiff.org/ +** LibTIFF; version 4.5.1 -- http://www.libtiff.org/ Copyright (c) 1988-1997 Sam Leffler Copyright (c) 1991-1997 Silicon Graphics, Inc. @@ -4029,7 +4059,7 @@ Software. ** OpenSubdiv; version 3.5.0 -- http://graphics.pixar.com/opensubdiv Copyright 2013 Pixar -** Universal Scene Description; version 22.11 -- http://www.openusd.org/ +** Universal Scene Description; version 23.05 -- http://www.openusd.org/ Copyright 2016 Pixar Licensed under the Apache License, Version 2.0 (the "Apache License") with the @@ -4215,7 +4245,7 @@ disclaims all warranties with regard to this software. ------ -** Wayland; version 1.21.0 -- https://gitlab.freedesktop.org/wayland/wayland +** Wayland; version 1.22.0 -- https://gitlab.freedesktop.org/wayland/wayland Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. Copyright © 2011 Kristian Høgsberg Copyright © 2011 Benjamin Franzke @@ -4240,7 +4270,7 @@ MIT Expat ------ -** OpenSSL; version 1.1.1q -- https://www.openssl.org/ +** OpenSSL; version 3.1.1 -- https://www.openssl.org/ Copyright (c) 1998-2021 The OpenSSL Project Copyright (c) 1995-1998 Eric A. Young, Tim J. Hudson @@ -4363,7 +4393,7 @@ OpenSSL License ------ -** Python; version 3.10.9 -- https://www.python.org +** Python; version 3.10.12 -- https://www.python.org Copyright (c) 2001-2021 Python Software Foundation. All rights reserved. A. HISTORY OF THE SOFTWARE diff --git a/scripts/modules/bpy_types.py b/scripts/modules/bpy_types.py index 7564b006e0e3..4e588c6d99cf 100644 --- a/scripts/modules/bpy_types.py +++ b/scripts/modules/bpy_types.py @@ -566,7 +566,7 @@ def _name_convention_attribute_remove(attributes, name): class Mesh(bpy_types.ID): __slots__ = () - def from_pydata(self, vertices, edges, faces): + def from_pydata(self, vertices, edges, faces, shade_flat=True): """ Make a mesh from a list of vertices/edges/faces Until we have a nicer way to make geometry, use this. @@ -623,6 +623,9 @@ def from_pydata(self, vertices, edges, faces): self.polygons.foreach_set("loop_start", loop_starts) self.polygons.foreach_set("vertices", vertex_indices) + if shade_flat: + self.shade_flat() + if edges_len or faces_len: self.update( # Needed to either: @@ -663,6 +666,22 @@ def edge_creases_ensure(self): def edge_creases_remove(self): _name_convention_attribute_remove(self.attributes, "crease_edge") + def shade_flat(self): + """ + Render and display faces uniform, using face normals, + setting the "sharp_face" attribute true for every face + """ + sharp_faces = _name_convention_attribute_ensure(self.attributes, "sharp_face", 'FACE', 'BOOLEAN') + for value in sharp_faces.data: + value.value = True + + def shade_smooth(self): + """ + Render and display faces smooth, using interpolated vertex normals, + removing the "sharp_face" attribute + """ + _name_convention_attribute_remove(self.attributes, "sharp_face") + class MeshEdge(StructRNA): __slots__ = () diff --git a/scripts/startup/bl_operators/add_mesh_torus.py b/scripts/startup/bl_operators/add_mesh_torus.py index 21a672c273aa..602826581c92 100644 --- a/scripts/startup/bl_operators/add_mesh_torus.py +++ b/scripts/startup/bl_operators/add_mesh_torus.py @@ -246,6 +246,7 @@ def execute(self, context): mesh.vertices.foreach_set("co", verts_loc) mesh.polygons.foreach_set("loop_start", range(0, nbr_loops, 4)) mesh.loops.foreach_set("vertex_index", faces) + mesh.shade_flat() if self.generate_uvs: add_uvs(mesh, self.minor_segments, self.major_segments) diff --git a/scripts/startup/bl_ui/generic_ui_list.py b/scripts/startup/bl_ui/generic_ui_list.py index 76de60204af8..83ece19a473b 100644 --- a/scripts/startup/bl_ui/generic_ui_list.py +++ b/scripts/startup/bl_ui/generic_ui_list.py @@ -31,7 +31,7 @@ def draw_ui_list( context, class_name="UI_UL_list", *, - unique_id="", + unique_id, list_path, active_index_path, insertion_operators=True, @@ -48,7 +48,7 @@ def draw_ui_list( :type context: :class:`Context` :arg class_name: Name of the UIList class to draw. The default is the UIList class that ships with Blender. :type class_name: str - :arg unique_id: Optional identifier, in case wanting to draw multiple unique copies of a list. + :arg unique_id: Unique identifier to differentiate this from other UI lists. :type unique_id: str :arg list_path: Data path of the list relative to context, eg. "object.vertex_groups". :type list_path: str diff --git a/scripts/startup/bl_ui/space_spreadsheet.py b/scripts/startup/bl_ui/space_spreadsheet.py index 3ba713e019e1..a4997ceda183 100644 --- a/scripts/startup/bl_ui/space_spreadsheet.py +++ b/scripts/startup/bl_ui/space_spreadsheet.py @@ -87,8 +87,12 @@ def draw_spreadsheet_context(self, layout, ctx): layout.label(text="Invalid id") elif ctx.type == 'MODIFIER': layout.label(text=ctx.modifier_name, icon='MODIFIER') - elif ctx.type == 'NODE': - layout.label(text=ctx.node_name, icon='NODE') + elif ctx.type == 'GROUP_NODE': + layout.label(text=ctx.ui_name, icon='NODE') + elif ctx.type == 'SIMULATION_ZONE': + layout.label(text="Simulation Zone") + elif ctx.type == 'VIEWER_NODE': + layout.label(text=ctx.ui_name) def draw_spreadsheet_viewer_path_icon(self, layout, space, icon='RIGHTARROW_THIN'): layout.prop(space, "display_viewer_path_collapsed", icon_only=True, emboss=False, icon=icon) diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index b263a076ee11..064b48173548 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -3070,8 +3070,8 @@ class VIEW3D_MT_object_convert(Menu): def draw(self, context): layout = self.layout ob = context.active_object - - if ob and ob.type == 'GPENCIL' and context.gpencil_data: + + if ob and ob.type == 'GPENCIL' and context.gpencil_data and not context.preferences.experimental.use_grease_pencil_version3: layout.operator_enum("gpencil.convert", "type") else: layout.operator_enum("object.convert", "target") diff --git a/scripts/templates_py/ui_list_generic.py b/scripts/templates_py/ui_list_generic.py index d33075ddd650..4113a99d6811 100644 --- a/scripts/templates_py/ui_list_generic.py +++ b/scripts/templates_py/ui_list_generic.py @@ -18,8 +18,9 @@ def draw(self, context): draw_ui_list( layout, context, - list_context_path="scene.my_list", - active_index_context_path="scene.my_list_active_index" + list_path="scene.my_list", + active_index_path="scene.my_list_active_index", + unique_id="my_list_id", ) diff --git a/source/blender/blenkernel/BKE_compute_contexts.hh b/source/blender/blenkernel/BKE_compute_contexts.hh index fb4702b27152..a1015c7b7f22 100644 --- a/source/blender/blenkernel/BKE_compute_contexts.hh +++ b/source/blender/blenkernel/BKE_compute_contexts.hh @@ -59,4 +59,23 @@ class NodeGroupComputeContext : public ComputeContext { void print_current_in_line(std::ostream &stream) const override; }; +class SimulationZoneComputeContext : public ComputeContext { + private: + static constexpr const char *s_static_type = "SIMULATION_ZONE"; + + int32_t output_node_id_; + + public: + SimulationZoneComputeContext(const ComputeContext *parent, int output_node_id); + SimulationZoneComputeContext(const ComputeContext *parent, const bNode &node); + + int32_t output_node_id() const + { + return output_node_id_; + } + + private: + void print_current_in_line(std::ostream &stream) const override; +}; + } // namespace blender::bke diff --git a/source/blender/blenkernel/BKE_mesh.hh b/source/blender/blenkernel/BKE_mesh.hh index 2d580eea8aed..96924441bd96 100644 --- a/source/blender/blenkernel/BKE_mesh.hh +++ b/source/blender/blenkernel/BKE_mesh.hh @@ -93,13 +93,15 @@ void normals_calc_poly_vert(Span vert_positions, * a regular #float3 format. */ struct CornerNormalSpace { - /** Reference vector, orthogonal to corner normal. */ + /** The automatically computed face corner normal, not including influence of custom normals. */ + float3 vec_lnor; + /** Reference vector, orthogonal to #vec_lnor. */ float3 vec_ref; - /** Third vector, orthogonal to corner normal and #vec_ref. */ + /** Third vector, orthogonal to #vec_lnor and #vec_ref. */ float3 vec_ortho; /** Reference angle around #vec_ortho, in [0, pi] range (0.0 marks space as invalid). */ float ref_alpha; - /** Reference angle around corner normal, in [0, 2pi] range (0.0 marks space as invalid). */ + /** Reference angle around #vec_lnor, in [0, 2pi] range (0.0 marks space as invalid). */ float ref_beta; }; @@ -131,7 +133,6 @@ struct CornerNormalSpaceArray { }; void lnor_space_custom_normal_to_data(const CornerNormalSpace *lnor_space, - float3 lnor_no_custom, const float custom_lnor[3], short r_clnor_data[2]); diff --git a/source/blender/blenkernel/BKE_node_runtime.hh b/source/blender/blenkernel/BKE_node_runtime.hh index 122a5ac819b0..aacd2ed4e919 100644 --- a/source/blender/blenkernel/BKE_node_runtime.hh +++ b/source/blender/blenkernel/BKE_node_runtime.hh @@ -33,8 +33,8 @@ struct RelationsInNode; } namespace aal = anonymous_attribute_lifetime; } // namespace blender::nodes -namespace blender::bke::node_tree_zones { -class TreeZones; +namespace blender::bke { +class bNodeTreeZones; } namespace blender::bke::anonymous_attribute_inferencing { struct AnonymousAttributeInferencingResult; @@ -149,7 +149,7 @@ class bNodeTreeRuntime : NonCopyable, NonMovable { mutable std::atomic allow_use_dirty_topology_cache = 0; CacheMutex tree_zones_cache_mutex; - std::unique_ptr tree_zones; + std::unique_ptr tree_zones; /** Only valid when #topology_cache_is_dirty is false. */ Vector links; diff --git a/source/blender/blenkernel/BKE_node_tree_zones.hh b/source/blender/blenkernel/BKE_node_tree_zones.hh index bbc8770ff1cd..c1915bfe74eb 100644 --- a/source/blender/blenkernel/BKE_node_tree_zones.hh +++ b/source/blender/blenkernel/BKE_node_tree_zones.hh @@ -12,10 +12,13 @@ #include "BLI_vector.hh" -namespace blender::bke::node_tree_zones { +namespace blender::bke { -struct TreeZone { - TreeZones *owner = nullptr; +class bNodeTreeZones; + +class bNodeTreeZone { + public: + bNodeTreeZones *owner = nullptr; /** Index of the zone in the array of all zones in a node tree. */ int index = -1; /** Zero for top level zones, one for a nested zone, and so on. */ @@ -25,22 +28,22 @@ struct TreeZone { /** Output node of the zone. */ const bNode *output_node = nullptr; /** Direct parent of the zone. If this is null, this is a top level zone. */ - TreeZone *parent_zone = nullptr; + bNodeTreeZone *parent_zone = nullptr; /** Direct children zones. Does not contain recursively nested zones. */ - Vector child_zones; + Vector child_zones; /** Direct children nodes excluding nodes that belong to child zones. */ Vector child_nodes; /** Links that enter the zone through the zone border. */ Vector border_links; bool contains_node_recursively(const bNode &node) const; - bool contains_zone_recursively(const TreeZone &other_zone) const; + bool contains_zone_recursively(const bNodeTreeZone &other_zone) const; }; -class TreeZones { +class bNodeTreeZones { public: - Vector> zones; - Vector root_zones; + Vector> zones; + Vector root_zones; Vector nodes_outside_zones; /** * Zone index by node. Nodes that are in no zone, are not included. Nodes that are at the border @@ -52,9 +55,26 @@ class TreeZones { * Get the deepest zone that a socket is in. Note that the inputs of a Simulation Input node are * in a different zone than its output sockets. */ - const TreeZone *get_zone_by_socket(const bNodeSocket &socket) const; + const bNodeTreeZone *get_zone_by_socket(const bNodeSocket &socket) const; + + /** + * Get the deepest zone that the node is in. Note that the e.g. Simulation Input and Output nodes + * are considered to be inside of the zone they create. + */ + const bNodeTreeZone *get_zone_by_node(const int32_t node_id) const; + + /** + * Get a sorted list of zones that the node is in. First comes the root zone and last the most + * nested zone. For nodes that are at the root level, the returned list is empty. + */ + Vector get_zone_stack_for_node(const int32_t node_id) const; }; -const TreeZones *get_tree_zones(const bNodeTree &tree); +const bNodeTreeZones *get_tree_zones(const bNodeTree &tree); + +} // namespace blender::bke -} // namespace blender::bke::node_tree_zones +inline const blender::bke::bNodeTreeZones *bNodeTree::zones() const +{ + return blender::bke::get_tree_zones(*this); +} diff --git a/source/blender/blenkernel/BKE_viewer_path.h b/source/blender/blenkernel/BKE_viewer_path.h index 230caefebe58..8707e2c96c33 100644 --- a/source/blender/blenkernel/BKE_viewer_path.h +++ b/source/blender/blenkernel/BKE_viewer_path.h @@ -50,7 +50,9 @@ void BKE_viewer_path_id_remap(ViewerPath *viewer_path, const struct IDRemapper * ViewerPathElem *BKE_viewer_path_elem_new(ViewerPathElemType type); IDViewerPathElem *BKE_viewer_path_elem_new_id(void); ModifierViewerPathElem *BKE_viewer_path_elem_new_modifier(void); -NodeViewerPathElem *BKE_viewer_path_elem_new_node(void); +GroupNodeViewerPathElem *BKE_viewer_path_elem_new_group_node(void); +SimulationZoneViewerPathElem *BKE_viewer_path_elem_new_simulation_zone(void); +ViewerNodeViewerPathElem *BKE_viewer_path_elem_new_viewer_node(void); ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src); bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, const ViewerPathElem *b); void BKE_viewer_path_elem_free(ViewerPathElem *elem); diff --git a/source/blender/blenkernel/intern/action_test.cc b/source/blender/blenkernel/intern/action_test.cc index 58c144057925..7f46f2c8cd83 100644 --- a/source/blender/blenkernel/intern/action_test.cc +++ b/source/blender/blenkernel/intern/action_test.cc @@ -2,6 +2,8 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BLI_string.h" + #include "BKE_action.h" #include "DNA_action_types.h" @@ -53,10 +55,10 @@ TEST(action_groups, ReconstructGroupsWithReordering) bActionGroup groupB = {nullptr}; bActionGroup groupC = {nullptr}; bActionGroup groupD = {nullptr}; - strcpy(groupA.name, "groupA"); - strcpy(groupB.name, "groupB"); - strcpy(groupC.name, "groupC"); - strcpy(groupD.name, "groupD"); + STRNCPY(groupA.name, "groupA"); + STRNCPY(groupB.name, "groupB"); + STRNCPY(groupC.name, "groupC"); + STRNCPY(groupD.name, "groupD"); BLI_addtail(&action.groups, &groupA); BLI_addtail(&action.groups, &groupB); diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 75f95c20998c..c0b551e684d6 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -703,7 +703,7 @@ bool bone_autoside_name( { uint len; char basename[MAXBONENAME] = ""; - char extension[5] = ""; + const char *extension = NULL; len = strlen(name); if (len == 0) { @@ -723,18 +723,18 @@ bool bone_autoside_name( /* z-axis - vertical (top/bottom) */ if (IS_EQF(head, 0.0f)) { if (tail < 0) { - strcpy(extension, "Bot"); + extension = "Bot"; } else if (tail > 0) { - strcpy(extension, "Top"); + extension = "Top"; } } else { if (head < 0) { - strcpy(extension, "Bot"); + extension = "Bot"; } else { - strcpy(extension, "Top"); + extension = "Top"; } } } @@ -742,18 +742,18 @@ bool bone_autoside_name( /* y-axis - depth (front/back) */ if (IS_EQF(head, 0.0f)) { if (tail < 0) { - strcpy(extension, "Fr"); + extension = "Fr"; } else if (tail > 0) { - strcpy(extension, "Bk"); + extension = "Bk"; } } else { if (head < 0) { - strcpy(extension, "Fr"); + extension = "Fr"; } else { - strcpy(extension, "Bk"); + extension = "Bk"; } } } @@ -761,19 +761,19 @@ bool bone_autoside_name( /* x-axis - horizontal (left/right) */ if (IS_EQF(head, 0.0f)) { if (tail < 0) { - strcpy(extension, "R"); + extension = "R"; } else if (tail > 0) { - strcpy(extension, "L"); + extension = "L"; } } else { if (head < 0) { - strcpy(extension, "R"); + extension = "R"; /* XXX Shouldn't this be simple else, as for z and y axes? */ } else if (head > 0) { - strcpy(extension, "L"); + extension = "L"; } } } @@ -782,7 +782,7 @@ bool bone_autoside_name( * - truncate if there is an extension and it wouldn't be able to fit * - otherwise, just append to end */ - if (extension[0]) { + if (extension) { bool changed = true; while (changed) { /* remove extensions */ diff --git a/source/blender/blenkernel/intern/compute_contexts.cc b/source/blender/blenkernel/intern/compute_contexts.cc index e8b4304bf63c..b943aefcfebb 100644 --- a/source/blender/blenkernel/intern/compute_contexts.cc +++ b/source/blender/blenkernel/intern/compute_contexts.cc @@ -62,4 +62,30 @@ void NodeGroupComputeContext::print_current_in_line(std::ostream &stream) const stream << "Node ID: " << node_id_; } +SimulationZoneComputeContext::SimulationZoneComputeContext(const ComputeContext *parent, + const int32_t output_node_id) + : ComputeContext(s_static_type, parent), output_node_id_(output_node_id) +{ + /* Mix static type and node id into a single buffer so that only a single call to #mix_in is + * necessary. */ + const int type_size = strlen(s_static_type); + const int buffer_size = type_size + 1 + sizeof(int32_t); + DynamicStackBuffer<64, 8> buffer_owner(buffer_size, 8); + char *buffer = static_cast(buffer_owner.buffer()); + memcpy(buffer, s_static_type, type_size + 1); + memcpy(buffer + type_size + 1, &output_node_id_, sizeof(int32_t)); + hash_.mix_in(buffer, buffer_size); +} + +SimulationZoneComputeContext::SimulationZoneComputeContext(const ComputeContext *parent, + const bNode &node) + : SimulationZoneComputeContext(parent, node.identifier) +{ +} + +void SimulationZoneComputeContext::print_current_in_line(std::ostream &stream) const +{ + stream << "Simulation Zone ID: " << output_node_id_; +} + } // namespace blender::bke diff --git a/source/blender/blenkernel/intern/mesh_mirror.cc b/source/blender/blenkernel/intern/mesh_mirror.cc index c3e9b2587b34..11a9ba45e418 100644 --- a/source/blender/blenkernel/intern/mesh_mirror.cc +++ b/source/blender/blenkernel/intern/mesh_mirror.cc @@ -432,15 +432,12 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, mirrorj += result_polys[mirror_i].size() - (j - src_poly.start()); } - const blender::float3 orig_normal = loop_normals[mirrorj]; copy_v3_v3(loop_normals[mirrorj], loop_normals[j]); mul_m4_v3(mtx_nor, loop_normals[mirrorj]); const int space_index = lnors_spacearr.corner_space_indices[mirrorj]; - blender::bke::mesh::lnor_space_custom_normal_to_data(&lnors_spacearr.spaces[space_index], - orig_normal, - loop_normals[mirrorj], - clnors[mirrorj]); + blender::bke::mesh::lnor_space_custom_normal_to_data( + &lnors_spacearr.spaces[space_index], loop_normals[mirrorj], clnors[mirrorj]); } } } diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 4e54ca2ad093..e45ae48c3b06 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -472,6 +472,8 @@ static void lnor_space_define(CornerNormalSpace *lnor_space, return; } + lnor_space->vec_lnor = lnor; + /* Compute ref alpha, average angle of all available edge vectors to lnor. */ if (!edge_vectors.is_empty()) { float alpha = 0.0f; @@ -526,7 +528,7 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space, using namespace blender::bke::mesh; CornerNormalSpace space{}; lnor_space_define(&space, lnor, vec_ref, vec_other, edge_vectors); - copy_v3_v3(lnor_space->vec_lnor, lnor); + copy_v3_v3(lnor_space->vec_lnor, space.vec_lnor); copy_v3_v3(lnor_space->vec_ref, space.vec_ref); copy_v3_v3(lnor_space->vec_ortho, space.vec_ortho); lnor_space->ref_alpha = space.ref_alpha; @@ -570,13 +572,12 @@ MINLINE short unit_float_to_short(const float val) namespace blender::bke::mesh { static void lnor_space_custom_data_to_normal(const CornerNormalSpace *lnor_space, - const float3 lnor_no_custom, const short clnor_data[2], float r_custom_lnor[3]) { /* NOP custom normal data or invalid lnor space, return. */ if (clnor_data[0] == 0 || lnor_space->ref_alpha == 0.0f || lnor_space->ref_beta == 0.0f) { - copy_v3_v3(r_custom_lnor, lnor_no_custom); + copy_v3_v3(r_custom_lnor, lnor_space->vec_lnor); return; } @@ -589,7 +590,7 @@ static void lnor_space_custom_data_to_normal(const CornerNormalSpace *lnor_space alphafac; const float betafac = unit_short_to_float(clnor_data[1]); - mul_v3_v3fl(r_custom_lnor, lnor_no_custom, cosf(alpha)); + mul_v3_v3fl(r_custom_lnor, lnor_space->vec_lnor, cosf(alpha)); if (betafac == 0.0f) { madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinf(alpha)); @@ -611,29 +612,29 @@ void BKE_lnor_space_custom_data_to_normal(const MLoopNorSpace *lnor_space, { using namespace blender::bke::mesh; CornerNormalSpace space; + space.vec_lnor = lnor_space->vec_lnor; space.vec_ref = lnor_space->vec_ref; space.vec_ortho = lnor_space->vec_ortho; space.ref_alpha = lnor_space->ref_alpha; space.ref_beta = lnor_space->ref_beta; - lnor_space_custom_data_to_normal(&space, lnor_space->vec_lnor, clnor_data, r_custom_lnor); + lnor_space_custom_data_to_normal(&space, clnor_data, r_custom_lnor); } namespace blender::bke::mesh { void lnor_space_custom_normal_to_data(const CornerNormalSpace *lnor_space, - const float3 lnor_no_custom, const float custom_lnor[3], short r_clnor_data[2]) { /* We use nullptr vector as NOP custom normal (can be simpler than giving auto-computed `lnor`). */ - if (is_zero_v3(custom_lnor) || compare_v3v3(lnor_no_custom, custom_lnor, 1e-4f)) { + if (is_zero_v3(custom_lnor) || compare_v3v3(lnor_space->vec_lnor, custom_lnor, 1e-4f)) { r_clnor_data[0] = r_clnor_data[1] = 0; return; } { const float pi2 = float(M_PI * 2.0); - const float cos_alpha = dot_v3v3(lnor_no_custom, custom_lnor); + const float cos_alpha = dot_v3v3(lnor_space->vec_lnor, custom_lnor); float vec[3], cos_beta; float alpha; @@ -648,7 +649,7 @@ void lnor_space_custom_normal_to_data(const CornerNormalSpace *lnor_space, } /* Project custom lnor on (vec_ref, vec_ortho) plane. */ - mul_v3_v3fl(vec, lnor_no_custom, -cos_alpha); + mul_v3_v3fl(vec, lnor_space->vec_lnor, -cos_alpha); add_v3_v3(vec, custom_lnor); normalize_v3(vec); @@ -680,11 +681,12 @@ void BKE_lnor_space_custom_normal_to_data(const MLoopNorSpace *lnor_space, { using namespace blender::bke::mesh; CornerNormalSpace space; + space.vec_lnor = lnor_space->vec_lnor; space.vec_ref = lnor_space->vec_ref; space.vec_ortho = lnor_space->vec_ortho; space.ref_alpha = lnor_space->ref_alpha; space.ref_beta = lnor_space->ref_beta; - lnor_space_custom_normal_to_data(&space, lnor_space->vec_lnor, custom_lnor, r_clnor_data); + lnor_space_custom_normal_to_data(&space, custom_lnor, r_clnor_data); } namespace blender::bke::mesh { @@ -901,10 +903,8 @@ static void lnor_space_for_single_fan(LoopSplitTaskDataCommon *common_data, lnors_spacearr->corner_space_indices[ml_curr_index] = space_index; if (!clnors_data.is_empty()) { - lnor_space_custom_data_to_normal(lnor_space, - loop_normals[ml_curr_index], - clnors_data[ml_curr_index], - loop_normals[ml_curr_index]); + lnor_space_custom_data_to_normal( + lnor_space, clnors_data[ml_curr_index], loop_normals[ml_curr_index]); } if (!lnors_spacearr->corners_by_space.is_empty()) { @@ -1084,7 +1084,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, /* Extra bonus: since small-stack is local to this function, * no more need to empty it at all cost! */ - lnor_space_custom_data_to_normal(lnor_space, lnor, *clnor_ref, lnor); + lnor_space_custom_data_to_normal(lnor_space, *clnor_ref, lnor); } } @@ -1600,8 +1600,7 @@ static void mesh_normals_loop_custom_set(Span positions, float *nor = r_custom_loop_normals[nidx]; const int space_index = lnors_spacearr.corner_space_indices[i]; - lnor_space_custom_normal_to_data( - &lnors_spacearr.spaces[space_index], loop_normals[i], nor, r_clnors_data[i]); + lnor_space_custom_normal_to_data(&lnors_spacearr.spaces[space_index], nor, r_clnors_data[i]); done_loops[i].reset(); } else { @@ -1618,7 +1617,7 @@ static void mesh_normals_loop_custom_set(Span positions, mul_v3_fl(avg_nor, 1.0f / float(fan_corners.size())); short2 clnor_data_tmp; lnor_space_custom_normal_to_data( - &lnors_spacearr.spaces[space_index], loop_normals[i], avg_nor, clnor_data_tmp); + &lnors_spacearr.spaces[space_index], avg_nor, clnor_data_tmp); r_clnors_data.fill_indices(fan_corners, clnor_data_tmp); } diff --git a/source/blender/blenkernel/intern/node_tree_zones.cc b/source/blender/blenkernel/intern/node_tree_zones.cc index 785a38a9ddbc..1240c0366f81 100644 --- a/source/blender/blenkernel/intern/node_tree_zones.cc +++ b/source/blender/blenkernel/intern/node_tree_zones.cc @@ -11,9 +11,9 @@ #include "BLI_task.hh" #include "BLI_timeit.hh" -namespace blender::bke::node_tree_zones { +namespace blender::bke { -static void update_zone_depths(TreeZone &zone) +static void update_zone_depths(bNodeTreeZone &zone) { if (zone.depth >= 0) { return; @@ -26,12 +26,14 @@ static void update_zone_depths(TreeZone &zone) zone.depth = zone.parent_zone->depth + 1; } -static Vector> find_zone_nodes( - const bNodeTree &tree, TreeZones &owner, Map &r_zone_by_inout_node) +static Vector> find_zone_nodes( + const bNodeTree &tree, + bNodeTreeZones &owner, + Map &r_zone_by_inout_node) { - Vector> zones; + Vector> zones; for (const bNode *node : tree.nodes_by_type("GeometryNodeSimulationOutput")) { - auto zone = std::make_unique(); + auto zone = std::make_unique(); zone->owner = &owner; zone->index = zones.size(); zone->output_node = node; @@ -41,7 +43,7 @@ static Vector> find_zone_nodes( for (const bNode *node : tree.nodes_by_type("GeometryNodeSimulationInput")) { const auto &storage = *static_cast(node->storage); if (const bNode *sim_output_node = tree.node_by_id(storage.output_node_id)) { - if (TreeZone *zone = r_zone_by_inout_node.lookup_default(sim_output_node, nullptr)) { + if (bNodeTreeZone *zone = r_zone_by_inout_node.lookup_default(sim_output_node, nullptr)) { zone->input_node = node; r_zone_by_inout_node.add(node, zone); } @@ -51,18 +53,18 @@ static Vector> find_zone_nodes( } struct ZoneRelation { - TreeZone *parent; - TreeZone *child; + bNodeTreeZone *parent; + bNodeTreeZone *child; }; static Vector get_direct_zone_relations( - const Span> all_zones, + const Span> all_zones, const BitGroupVector<> &depend_on_input_flag_array) { Vector zone_relations; /* Gather all relations, even the transitive once. */ - for (const std::unique_ptr &zone : all_zones) { + for (const std::unique_ptr &zone : all_zones) { const int zone_i = zone->index; for (const bNode *node : {zone->output_node}) { if (node == nullptr) { @@ -108,18 +110,18 @@ static Vector get_direct_zone_relations( } static void update_zone_per_node(const Span all_nodes, - const Span> all_zones, + const Span> all_zones, const BitGroupVector<> &depend_on_input_flag_array, - const Map &zone_by_inout_node, + const Map &zone_by_inout_node, Map &r_zone_by_node_id, Vector &r_node_outside_zones) { for (const int node_i : all_nodes.index_range()) { const bNode &node = *all_nodes[node_i]; const BoundedBitSpan depend_on_input_flags = depend_on_input_flag_array[node_i]; - TreeZone *parent_zone = nullptr; + bNodeTreeZone *parent_zone = nullptr; bits::foreach_1_index(depend_on_input_flags, [&](const int parent_zone_i) { - TreeZone *zone = all_zones[parent_zone_i].get(); + bNodeTreeZone *zone = all_zones[parent_zone_i].get(); if (ELEM(&node, zone->input_node, zone->output_node)) { return; } @@ -136,12 +138,12 @@ static void update_zone_per_node(const Span all_nodes, r_zone_by_node_id.add(node.identifier, parent_zone->index); } } - for (const MapItem item : zone_by_inout_node.items()) { + for (const MapItem item : zone_by_inout_node.items()) { r_zone_by_node_id.add_overwrite(item.key->identifier, item.value->index); } } -static void update_zone_border_links(const bNodeTree &tree, TreeZones &tree_zones) +static void update_zone_border_links(const bNodeTree &tree, bNodeTreeZones &tree_zones) { for (const bNodeLink *link : tree.all_links()) { if (!link->is_available()) { @@ -150,28 +152,30 @@ static void update_zone_border_links(const bNodeTree &tree, TreeZones &tree_zone if (link->is_muted()) { continue; } - TreeZone *from_zone = const_cast(tree_zones.get_zone_by_socket(*link->fromsock)); - TreeZone *to_zone = const_cast(tree_zones.get_zone_by_socket(*link->tosock)); + bNodeTreeZone *from_zone = const_cast( + tree_zones.get_zone_by_socket(*link->fromsock)); + bNodeTreeZone *to_zone = const_cast( + tree_zones.get_zone_by_socket(*link->tosock)); if (from_zone == to_zone) { continue; } BLI_assert(from_zone == nullptr || from_zone->contains_zone_recursively(*to_zone)); - for (TreeZone *zone = to_zone; zone != from_zone; zone = zone->parent_zone) { + for (bNodeTreeZone *zone = to_zone; zone != from_zone; zone = zone->parent_zone) { zone->border_links.append(link); } } } -static std::unique_ptr discover_tree_zones(const bNodeTree &tree) +static std::unique_ptr discover_tree_zones(const bNodeTree &tree) { if (tree.has_available_link_cycle()) { return {}; } - std::unique_ptr tree_zones = std::make_unique(); + std::unique_ptr tree_zones = std::make_unique(); const Span all_nodes = tree.all_nodes(); - Map zone_by_inout_node; + Map zone_by_inout_node; tree_zones->zones = find_zone_nodes(tree, *tree_zones, zone_by_inout_node); const int zones_num = tree_zones->zones.size(); @@ -203,13 +207,13 @@ static std::unique_ptr discover_tree_zones(const bNodeTree &tree) } } if (node->type == GEO_NODE_SIMULATION_INPUT) { - if (const TreeZone *zone = zone_by_inout_node.lookup_default(node, nullptr)) { + if (const bNodeTreeZone *zone = zone_by_inout_node.lookup_default(node, nullptr)) { /* Now entering a zone, so set the corresponding bit. */ depend_on_input_flags[zone->index].set(); } } else if (node->type == GEO_NODE_SIMULATION_OUTPUT) { - if (const TreeZone *zone = zone_by_inout_node.lookup_default(node, nullptr)) { + if (const bNodeTreeZone *zone = zone_by_inout_node.lookup_default(node, nullptr)) { /* The output is implicitly linked to the input, so also propagate the bits from there. */ if (const bNode *zone_input_node = zone->input_node) { const int input_node_i = zone_input_node->index(); @@ -239,11 +243,11 @@ static std::unique_ptr discover_tree_zones(const bNodeTree &tree) } /* Update depths. */ - for (std::unique_ptr &zone : tree_zones->zones) { + for (std::unique_ptr &zone : tree_zones->zones) { update_zone_depths(*zone); } - for (std::unique_ptr &zone : tree_zones->zones) { + for (std::unique_ptr &zone : tree_zones->zones) { if (zone->depth == 0) { tree_zones->root_zones.append(zone.get()); } @@ -262,7 +266,7 @@ static std::unique_ptr discover_tree_zones(const bNodeTree &tree) if (zone_i == -1) { continue; } - const TreeZone &zone = *tree_zones->zones[zone_i]; + const bNodeTreeZone &zone = *tree_zones->zones[zone_i]; if (ELEM(node, zone.input_node, zone.output_node)) { continue; } @@ -274,21 +278,21 @@ static std::unique_ptr discover_tree_zones(const bNodeTree &tree) return tree_zones; } -const TreeZones *get_tree_zones(const bNodeTree &tree) +const bNodeTreeZones *get_tree_zones(const bNodeTree &tree) { tree.runtime->tree_zones_cache_mutex.ensure( [&]() { tree.runtime->tree_zones = discover_tree_zones(tree); }); return tree.runtime->tree_zones.get(); } -bool TreeZone::contains_node_recursively(const bNode &node) const +bool bNodeTreeZone::contains_node_recursively(const bNode &node) const { - const TreeZones *zones = this->owner; + const bNodeTreeZones *zones = this->owner; const int zone_i = zones->zone_by_node_id.lookup_default(node.identifier, -1); if (zone_i == -1) { return false; } - for (const TreeZone *zone = zones->zones[zone_i].get(); zone; zone = zone->parent_zone) { + for (const bNodeTreeZone *zone = zones->zones[zone_i].get(); zone; zone = zone->parent_zone) { if (zone == this) { return true; } @@ -296,9 +300,9 @@ bool TreeZone::contains_node_recursively(const bNode &node) const return false; } -bool TreeZone::contains_zone_recursively(const TreeZone &other_zone) const +bool bNodeTreeZone::contains_zone_recursively(const bNodeTreeZone &other_zone) const { - for (const TreeZone *zone = other_zone.parent_zone; zone; zone = zone->parent_zone) { + for (const bNodeTreeZone *zone = other_zone.parent_zone; zone; zone = zone->parent_zone) { if (zone == this) { return true; } @@ -306,25 +310,47 @@ bool TreeZone::contains_zone_recursively(const TreeZone &other_zone) const return false; } -const TreeZone *TreeZones::get_zone_by_socket(const bNodeSocket &socket) const +const bNodeTreeZone *bNodeTreeZones::get_zone_by_socket(const bNodeSocket &socket) const { const bNode &node = socket.owner_node(); - const int zone_i = this->zone_by_node_id.lookup_default(node.identifier, -1); - if (zone_i == -1) { - return nullptr; + const bNodeTreeZone *zone = this->get_zone_by_node(node.identifier); + if (zone == nullptr) { + return zone; } - const TreeZone &zone = *this->zones[zone_i]; - if (zone.input_node == &node) { + if (zone->input_node == &node) { if (socket.is_input()) { - return zone.parent_zone; + return zone->parent_zone; } } - if (zone.output_node == &node) { + if (zone->output_node == &node) { if (socket.is_output()) { - return zone.parent_zone; + return zone->parent_zone; } } - return &zone; + return zone; +} + +const bNodeTreeZone *bNodeTreeZones::get_zone_by_node(const int32_t node_id) const +{ + const int zone_i = this->zone_by_node_id.lookup_default(node_id, -1); + if (zone_i == -1) { + return nullptr; + } + return this->zones[zone_i].get(); +} + +Vector bNodeTreeZones::get_zone_stack_for_node(const int node_id) const +{ + const bNodeTreeZone *zone = this->get_zone_by_node(node_id); + if (zone == nullptr) { + return {}; + } + Vector zone_stack; + for (; zone; zone = zone->parent_zone) { + zone_stack.append(zone); + } + std::reverse(zone_stack.begin(), zone_stack.end()); + return zone_stack; } -} // namespace blender::bke::node_tree_zones +} // namespace blender::bke diff --git a/source/blender/blenkernel/intern/viewer_path.cc b/source/blender/blenkernel/intern/viewer_path.cc index e7b3b5d6e57c..04cd874d5679 100644 --- a/source/blender/blenkernel/intern/viewer_path.cc +++ b/source/blender/blenkernel/intern/viewer_path.cc @@ -73,13 +73,23 @@ void BKE_viewer_path_blend_write(BlendWriter *writer, const ViewerPath *viewer_p BLO_write_string(writer, typed_elem->modifier_name); break; } - case VIEWER_PATH_ELEM_TYPE_NODE: { - const auto *typed_elem = reinterpret_cast(elem); - BLO_write_struct(writer, NodeViewerPathElem, typed_elem); - BLO_write_string(writer, typed_elem->node_name); + case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: { + const auto *typed_elem = reinterpret_cast(elem); + BLO_write_struct(writer, GroupNodeViewerPathElem, typed_elem); + break; + } + case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: { + const auto *typed_elem = reinterpret_cast(elem); + BLO_write_struct(writer, SimulationZoneViewerPathElem, typed_elem); + break; + } + case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: { + const auto *typed_elem = reinterpret_cast(elem); + BLO_write_struct(writer, ViewerNodeViewerPathElem, typed_elem); break; } } + BLO_write_string(writer, elem->ui_name); } } @@ -87,7 +97,11 @@ void BKE_viewer_path_blend_read_data(BlendDataReader *reader, ViewerPath *viewer { BLO_read_list(reader, &viewer_path->path); LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) { + BLO_read_data_address(reader, &elem->ui_name); switch (ViewerPathElemType(elem->type)) { + case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: + case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: + case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: case VIEWER_PATH_ELEM_TYPE_ID: { break; } @@ -96,11 +110,6 @@ void BKE_viewer_path_blend_read_data(BlendDataReader *reader, ViewerPath *viewer BLO_read_data_address(reader, &typed_elem->modifier_name); break; } - case VIEWER_PATH_ELEM_TYPE_NODE: { - auto *typed_elem = reinterpret_cast(elem); - BLO_read_data_address(reader, &typed_elem->node_name); - break; - } } } } @@ -115,7 +124,9 @@ void BKE_viewer_path_blend_read_lib(BlendLibReader *reader, ID *self_id, ViewerP break; } case VIEWER_PATH_ELEM_TYPE_MODIFIER: - case VIEWER_PATH_ELEM_TYPE_NODE: { + case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: + case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: + case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: { break; } } @@ -132,7 +143,9 @@ void BKE_viewer_path_foreach_id(LibraryForeachIDData *data, ViewerPath *viewer_p break; } case VIEWER_PATH_ELEM_TYPE_MODIFIER: - case VIEWER_PATH_ELEM_TYPE_NODE: { + case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: + case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: + case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: { break; } } @@ -149,30 +162,39 @@ void BKE_viewer_path_id_remap(ViewerPath *viewer_path, const IDRemapper *mapping break; } case VIEWER_PATH_ELEM_TYPE_MODIFIER: - case VIEWER_PATH_ELEM_TYPE_NODE: { + case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: + case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: + case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: { break; } } } } +template static T *make_elem(const ViewerPathElemType type) +{ + T *elem = MEM_cnew(__func__); + elem->base.type = type; + return elem; +} + ViewerPathElem *BKE_viewer_path_elem_new(const ViewerPathElemType type) { switch (type) { case VIEWER_PATH_ELEM_TYPE_ID: { - IDViewerPathElem *elem = MEM_cnew(__func__); - elem->base.type = type; - return &elem->base; + return &make_elem(type)->base; } case VIEWER_PATH_ELEM_TYPE_MODIFIER: { - ModifierViewerPathElem *elem = MEM_cnew(__func__); - elem->base.type = type; - return &elem->base; + return &make_elem(type)->base; + } + case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: { + return &make_elem(type)->base; } - case VIEWER_PATH_ELEM_TYPE_NODE: { - NodeViewerPathElem *elem = MEM_cnew(__func__); - elem->base.type = type; - return &elem->base; + case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: { + return &make_elem(type)->base; + } + case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: { + return &make_elem(type)->base; } } BLI_assert_unreachable(); @@ -190,15 +212,30 @@ ModifierViewerPathElem *BKE_viewer_path_elem_new_modifier() BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_MODIFIER)); } -NodeViewerPathElem *BKE_viewer_path_elem_new_node() +GroupNodeViewerPathElem *BKE_viewer_path_elem_new_group_node() +{ + return reinterpret_cast( + BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_GROUP_NODE)); +} + +SimulationZoneViewerPathElem *BKE_viewer_path_elem_new_simulation_zone() { - return reinterpret_cast( - BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_NODE)); + return reinterpret_cast( + BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE)); +} + +ViewerNodeViewerPathElem *BKE_viewer_path_elem_new_viewer_node() +{ + return reinterpret_cast( + BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_VIEWER_NODE)); } ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src) { ViewerPathElem *dst = BKE_viewer_path_elem_new(ViewerPathElemType(src->type)); + if (src->ui_name) { + dst->ui_name = BLI_strdup(src->ui_name); + } switch (ViewerPathElemType(src->type)) { case VIEWER_PATH_ELEM_TYPE_ID: { const auto *old_elem = reinterpret_cast(src); @@ -214,13 +251,22 @@ ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src) } break; } - case VIEWER_PATH_ELEM_TYPE_NODE: { - const auto *old_elem = reinterpret_cast(src); - auto *new_elem = reinterpret_cast(dst); + case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: { + const auto *old_elem = reinterpret_cast(src); + auto *new_elem = reinterpret_cast(dst); + new_elem->node_id = old_elem->node_id; + break; + } + case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: { + const auto *old_elem = reinterpret_cast(src); + auto *new_elem = reinterpret_cast(dst); + new_elem->sim_output_node_id = old_elem->sim_output_node_id; + break; + } + case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: { + const auto *old_elem = reinterpret_cast(src); + auto *new_elem = reinterpret_cast(dst); new_elem->node_id = old_elem->node_id; - if (old_elem->node_name != nullptr) { - new_elem->node_name = BLI_strdup(old_elem->node_name); - } break; } } @@ -243,9 +289,19 @@ bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, const ViewerPathElem *b const auto *b_elem = reinterpret_cast(b); return StringRef(a_elem->modifier_name) == StringRef(b_elem->modifier_name); } - case VIEWER_PATH_ELEM_TYPE_NODE: { - const auto *a_elem = reinterpret_cast(a); - const auto *b_elem = reinterpret_cast(b); + case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: { + const auto *a_elem = reinterpret_cast(a); + const auto *b_elem = reinterpret_cast(b); + return a_elem->node_id == b_elem->node_id; + } + case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: { + const auto *a_elem = reinterpret_cast(a); + const auto *b_elem = reinterpret_cast(b); + return a_elem->sim_output_node_id == b_elem->sim_output_node_id; + } + case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: { + const auto *a_elem = reinterpret_cast(a); + const auto *b_elem = reinterpret_cast(b); return a_elem->node_id == b_elem->node_id; } } @@ -255,7 +311,10 @@ bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, const ViewerPathElem *b void BKE_viewer_path_elem_free(ViewerPathElem *elem) { switch (ViewerPathElemType(elem->type)) { - case VIEWER_PATH_ELEM_TYPE_ID: { + case VIEWER_PATH_ELEM_TYPE_ID: + case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: + case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: + case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: { break; } case VIEWER_PATH_ELEM_TYPE_MODIFIER: { @@ -263,11 +322,9 @@ void BKE_viewer_path_elem_free(ViewerPathElem *elem) MEM_SAFE_FREE(typed_elem->modifier_name); break; } - case VIEWER_PATH_ELEM_TYPE_NODE: { - auto *typed_elem = reinterpret_cast(elem); - MEM_SAFE_FREE(typed_elem->node_name); - break; - } + } + if (elem->ui_name) { + MEM_freeN(elem->ui_name); } MEM_freeN(elem); } diff --git a/source/blender/blenlib/BLI_span.hh b/source/blender/blenlib/BLI_span.hh index 608ef8e2e551..93dbd9756815 100644 --- a/source/blender/blenlib/BLI_span.hh +++ b/source/blender/blenlib/BLI_span.hh @@ -599,7 +599,8 @@ template class MutableSpan { constexpr T &operator[](const int64_t index) const { - BLI_assert(index < this->size()); + BLI_assert(index >= 0); + BLI_assert(index < size_); return data_[index]; } diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 7d3b6f4c095d..cf6f2dab6cbd 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -196,8 +196,8 @@ static int path_normalize_impl(char *path, bool check_blend_relative_prefix) /* NOTE(@ideasman42): * `memmove(start, eind, strlen(eind) + 1);` * is the same as - * `strcpy(start, eind);` - * except `strcpy` should not be used because there is overlap, + * `BLI_strncpy(start, eind, ...);` + * except string-copy should not be used because there is overlap, * so use `memmove` 's slightly more obscure syntax. */ /* Inline replacement: diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c index aa752046b27b..aef289a5718a 100644 --- a/source/blender/blenlib/intern/rct.c +++ b/source/blender/blenlib/intern/rct.c @@ -825,10 +825,10 @@ bool BLI_rcti_clamp(rcti *rect, const rcti *rect_bounds, int r_xy[2]) bool BLI_rctf_compare(const rctf *rect_a, const rctf *rect_b, const float limit) { - if (fabsf(rect_a->xmin - rect_b->xmin) < limit) { - if (fabsf(rect_a->xmax - rect_b->xmax) < limit) { - if (fabsf(rect_a->ymin - rect_b->ymin) < limit) { - if (fabsf(rect_a->ymax - rect_b->ymax) < limit) { + if (fabsf(rect_a->xmin - rect_b->xmin) <= limit) { + if (fabsf(rect_a->xmax - rect_b->xmax) <= limit) { + if (fabsf(rect_a->ymin - rect_b->ymin) <= limit) { + if (fabsf(rect_a->ymax - rect_b->ymax) <= limit) { return true; } } diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c index f9d918663be8..efc098c16f80 100644 --- a/source/blender/blenlib/intern/string_utils.c +++ b/source/blender/blenlib/intern/string_utils.c @@ -133,14 +133,14 @@ size_t BLI_string_flip_side_name(char *name_dst, BLI_string_debug_size(name_dst, name_dst_maxncpy); size_t len; - char *prefix = alloca(name_dst_maxncpy); /* The part before the facing */ - char *suffix = alloca(name_dst_maxncpy); /* The part after the facing */ - char *replace = alloca(name_dst_maxncpy); /* The replacement string */ - char *number = alloca(name_dst_maxncpy); /* The number extension string */ + char *prefix = alloca(name_dst_maxncpy); /* The part before the facing */ + char *suffix = alloca(name_dst_maxncpy); /* The part after the facing */ + char *number = alloca(name_dst_maxncpy); /* The number extension string */ + const char *replace = NULL; char *index = NULL; bool is_set = false; - *prefix = *suffix = *replace = *number = '\0'; + *prefix = *suffix = *number = '\0'; /* always copy the name, since this can be called with an uninitialized string */ len = BLI_strncpy_rlen(name_dst, name_src, name_dst_maxncpy); @@ -169,19 +169,19 @@ size_t BLI_string_flip_side_name(char *name_dst, switch (name_dst[len - 1]) { case 'l': prefix[len - 1] = 0; - strcpy(replace, "r"); + replace = "r"; break; case 'r': prefix[len - 1] = 0; - strcpy(replace, "l"); + replace = "l"; break; case 'L': prefix[len - 1] = 0; - strcpy(replace, "R"); + replace = "R"; break; case 'R': prefix[len - 1] = 0; - strcpy(replace, "L"); + replace = "L"; break; default: is_set = false; @@ -193,22 +193,22 @@ size_t BLI_string_flip_side_name(char *name_dst, is_set = true; switch (name_dst[0]) { case 'l': - strcpy(replace, "r"); + replace = "r"; BLI_strncpy(suffix, name_dst + 1, name_dst_maxncpy); prefix[0] = 0; break; case 'r': - strcpy(replace, "l"); + replace = "l"; BLI_strncpy(suffix, name_dst + 1, name_dst_maxncpy); prefix[0] = 0; break; case 'L': - strcpy(replace, "R"); + replace = "R"; BLI_strncpy(suffix, name_dst + 1, name_dst_maxncpy); prefix[0] = 0; break; case 'R': - strcpy(replace, "L"); + replace = "L"; BLI_strncpy(suffix, name_dst + 1, name_dst_maxncpy); prefix[0] = 0; break; @@ -222,10 +222,10 @@ size_t BLI_string_flip_side_name(char *name_dst, if (((index = BLI_strcasestr(prefix, "right")) == prefix) || (index == prefix + len - 5)) { is_set = true; if (index[0] == 'r') { - strcpy(replace, "left"); + replace = "left"; } else { - strcpy(replace, (index[1] == 'I') ? "LEFT" : "Left"); + replace = (index[1] == 'I' ? "LEFT" : "Left"); } *index = 0; BLI_strncpy(suffix, index + 5, name_dst_maxncpy); @@ -233,10 +233,10 @@ size_t BLI_string_flip_side_name(char *name_dst, else if (((index = BLI_strcasestr(prefix, "left")) == prefix) || (index == prefix + len - 4)) { is_set = true; if (index[0] == 'l') { - strcpy(replace, "right"); + replace = "right"; } else { - strcpy(replace, (index[1] == 'E') ? "RIGHT" : "Right"); + replace = (index[1] == 'E' ? "RIGHT" : "Right"); } *index = 0; BLI_strncpy(suffix, index + 4, name_dst_maxncpy); @@ -244,7 +244,7 @@ size_t BLI_string_flip_side_name(char *name_dst, } return BLI_snprintf_rlen( - name_dst, name_dst_maxncpy, "%s%s%s%s", prefix, replace, suffix, number); + name_dst, name_dst_maxncpy, "%s%s%s%s", prefix, replace ? replace : "", suffix, number); } /* Unique name utils. */ diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c index 87ce59269755..a017a0e930a8 100644 --- a/source/blender/blenloader/intern/versioning_260.c +++ b/source/blender/blenloader/intern/versioning_260.c @@ -83,22 +83,18 @@ static void do_versions_nodetree_image_default_alpha_output(bNodeTree *ntree) { - bNode *node; - bNodeSocket *sock; - - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS)) { /* default Image output value should have 0 alpha */ - sock = node->outputs.first; - ((bNodeSocketValueRGBA *)(sock->default_value))->value[3] = 0.0f; + bNodeSocket *sock = node->outputs.first; + ((bNodeSocketValueRGBA *)sock->default_value)->value[3] = 0.0f; } } } static void do_versions_nodetree_convert_angle(bNodeTree *ntree) { - bNode *node; - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == CMP_NODE_ROTATE) { /* Convert degrees to radians. */ bNodeSocket *sock = ((bNodeSocket *)node->inputs.first)->next; @@ -225,26 +221,22 @@ static void do_versions_image_settings_2_60(Scene *sce) /* socket use flags were only temporary before */ static void do_versions_nodetree_socket_use_flags_2_62(bNodeTree *ntree) { - bNode *node; - bNodeSocket *sock; - bNodeLink *link; - - for (node = ntree->nodes.first; node; node = node->next) { - for (sock = node->inputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { sock->flag &= ~SOCK_IS_LINKED; } - for (sock = node->outputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { sock->flag &= ~SOCK_IS_LINKED; } } - for (sock = ntree->inputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) { sock->flag &= ~SOCK_IS_LINKED; } - for (sock = ntree->outputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { sock->flag &= ~SOCK_IS_LINKED; } - for (link = ntree->links.first; link; link = link->next) { + LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { link->fromsock->flag |= SOCK_IS_LINKED; link->tosock->flag |= SOCK_IS_LINKED; } @@ -252,16 +244,14 @@ static void do_versions_nodetree_socket_use_flags_2_62(bNodeTree *ntree) static void do_versions_nodetree_multi_file_output_format_2_62_1(Scene *sce, bNodeTree *ntree) { - bNode *node; - - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == CMP_NODE_OUTPUT_FILE) { /* previous CMP_NODE_OUTPUT_FILE nodes get converted to multi-file outputs */ NodeImageFile *old_data = node->storage; NodeImageMultiFile *nimf = MEM_callocN(sizeof(NodeImageMultiFile), "node image multi file"); bNodeSocket *old_image = BLI_findlink(&node->inputs, 0); bNodeSocket *old_z = BLI_findlink(&node->inputs, 1); - bNodeSocket *sock; + char filename[FILE_MAXFILE]; /* ugly, need to remove the old inputs list to avoid bad pointer @@ -296,7 +286,7 @@ static void do_versions_nodetree_multi_file_output_format_2_62_1(Scene *sce, bNo nimf->format.imtype = R_IMF_IMTYPE_MULTILAYER; SNPRINTF(sockpath, "%s_Image", filename); - sock = ntreeCompositOutputFileAddSocket(ntree, node, sockpath, &nimf->format); + bNodeSocket *sock = ntreeCompositOutputFileAddSocket(ntree, node, sockpath, &nimf->format); /* XXX later do_versions copies path from socket name, need to set this explicitly */ STRNCPY(sock->name, sockpath); if (old_image->link) { @@ -314,7 +304,7 @@ static void do_versions_nodetree_multi_file_output_format_2_62_1(Scene *sce, bNo } } else { - sock = ntreeCompositOutputFileAddSocket(ntree, node, filename, &nimf->format); + bNodeSocket *sock = ntreeCompositOutputFileAddSocket(ntree, node, filename, &nimf->format); /* XXX later do_versions copies path from socket name, need to set this explicitly */ STRNCPY(sock->name, filename); if (old_image->link) { @@ -331,7 +321,6 @@ static void do_versions_nodetree_multi_file_output_format_2_62_1(Scene *sce, bNo } else if (node->type == CMP_NODE_OUTPUT_MULTI_FILE__DEPRECATED) { NodeImageMultiFile *nimf = node->storage; - bNodeSocket *sock; /* CMP_NODE_OUTPUT_MULTI_FILE has been re-declared as CMP_NODE_OUTPUT_FILE */ node->type = CMP_NODE_OUTPUT_FILE; @@ -342,7 +331,7 @@ static void do_versions_nodetree_multi_file_output_format_2_62_1(Scene *sce, bNo } /* transfer render format toggle to node format toggle */ - for (sock = node->inputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { NodeImageMultiFileSocket *simf = sock->storage; simf->use_node_format = simf->use_render_format; } @@ -356,17 +345,12 @@ static void do_versions_nodetree_multi_file_output_format_2_62_1(Scene *sce, bNo /* blue and red are swapped pre 2.62.1, be sane (red == red) now! */ static void do_versions_mesh_mloopcol_swap_2_62_1(Mesh *me) { - CustomDataLayer *layer; - MLoopCol *mloopcol; - int a; - int i; - - for (a = 0; a < me->ldata.totlayer; a++) { - layer = &me->ldata.layers[a]; + for (int a = 0; a < me->ldata.totlayer; a++) { + CustomDataLayer *layer = &me->ldata.layers[a]; if (layer->type == CD_PROP_BYTE_COLOR) { - mloopcol = (MLoopCol *)layer->data; - for (i = 0; i < me->totloop; i++, mloopcol++) { + MLoopCol *mloopcol = layer->data; + for (int i = 0; i < me->totloop; i++, mloopcol++) { SWAP(uchar, mloopcol->r, mloopcol->b); } } @@ -375,12 +359,9 @@ static void do_versions_mesh_mloopcol_swap_2_62_1(Mesh *me) static void do_versions_nodetree_multi_file_output_path_2_63_1(bNodeTree *ntree) { - bNode *node; - - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == CMP_NODE_OUTPUT_FILE) { - bNodeSocket *sock; - for (sock = node->inputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { NodeImageMultiFileSocket *input = sock->storage; /* input file path is stored in dedicated struct now instead socket name */ STRNCPY(input->path, sock->name); @@ -391,12 +372,9 @@ static void do_versions_nodetree_multi_file_output_path_2_63_1(bNodeTree *ntree) static void do_versions_nodetree_file_output_layers_2_64_5(bNodeTree *ntree) { - bNode *node; - - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == CMP_NODE_OUTPUT_FILE) { - bNodeSocket *sock; - for (sock = node->inputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { NodeImageMultiFileSocket *input = sock->storage; /* Multi-layer names are stored as separate strings now, @@ -413,12 +391,9 @@ static void do_versions_nodetree_file_output_layers_2_64_5(bNodeTree *ntree) static void do_versions_nodetree_image_layer_2_64_5(bNodeTree *ntree) { - bNode *node; - - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == CMP_NODE_IMAGE) { - bNodeSocket *sock; - for (sock = node->outputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { NodeImageLayer *output = MEM_callocN(sizeof(NodeImageLayer), "node image layer"); /* take pass index both from current storage ptr (actually an int) */ @@ -433,13 +408,11 @@ static void do_versions_nodetree_image_layer_2_64_5(bNodeTree *ntree) static void do_versions_nodetree_frame_2_64_6(bNodeTree *ntree) { - bNode *node; - - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == NODE_FRAME) { /* initialize frame node storage data */ if (node->storage == NULL) { - NodeFrame *data = (NodeFrame *)MEM_callocN(sizeof(NodeFrame), "frame node storage"); + NodeFrame *data = MEM_callocN(sizeof(NodeFrame), "frame node storage"); node->storage = data; /* copy current flags */ @@ -475,9 +448,7 @@ static void do_version_logic_264(ListBase *regionbase) static void do_versions_affine_tracker_track(MovieTrackingTrack *track) { - int i; - - for (i = 0; i < track->markersnr; i++) { + for (int i = 0; i < track->markersnr; i++) { MovieTrackingMarker *marker = &track->markers[i]; if (is_zero_v2(marker->pattern_corners[0]) && is_zero_v2(marker->pattern_corners[1]) && @@ -566,9 +537,6 @@ static void do_versions_nodetree_customnodes(bNodeTree *ntree, int UNUSED(is_gro { /* initialize node tree type idname */ { - bNode *node; - bNodeSocket *sock; - ntree->typeinfo = NULL; /* tree type idname */ @@ -585,7 +553,7 @@ static void do_versions_nodetree_customnodes(bNodeTree *ntree, int UNUSED(is_gro } /* node type idname */ - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { BLI_strncpy( node->idname, node_get_static_idname(node->type, ntree->type), sizeof(node->idname)); @@ -593,80 +561,53 @@ static void do_versions_nodetree_customnodes(bNodeTree *ntree, int UNUSED(is_gro node->flag |= NODE_INIT; /* sockets idname */ - for (sock = node->inputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { STRNCPY(sock->idname, node_socket_get_static_idname(sock)); } - for (sock = node->outputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { STRNCPY(sock->idname, node_socket_get_static_idname(sock)); } } /* tree sockets idname */ - for (sock = ntree->inputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) { STRNCPY(sock->idname, node_socket_get_static_idname(sock)); } - for (sock = ntree->outputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { STRNCPY(sock->idname, node_socket_get_static_idname(sock)); } } /* initialize socket in_out values */ - { - bNode *node; - bNodeSocket *sock; - - for (node = ntree->nodes.first; node; node = node->next) { - for (sock = node->inputs.first; sock; sock = sock->next) { - sock->in_out = SOCK_IN; - } - for (sock = node->outputs.first; sock; sock = sock->next) { - sock->in_out = SOCK_OUT; - } - } - for (sock = ntree->inputs.first; sock; sock = sock->next) { - sock->in_out = SOCK_IN; - } - for (sock = ntree->outputs.first; sock; sock = sock->next) { - sock->in_out = SOCK_OUT; - } - } + {LISTBASE_FOREACH (bNode *, node, &ntree->nodes){ + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs){sock->in_out = SOCK_IN; +} +LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { + sock->in_out = SOCK_OUT; +} +} +LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) { + sock->in_out = SOCK_IN; +} +LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { + sock->in_out = SOCK_OUT; +} +} - /* initialize socket identifier strings */ - { - bNode *node; - bNodeSocket *sock; - - for (node = ntree->nodes.first; node; node = node->next) { - for (sock = node->inputs.first; sock; sock = sock->next) { - STRNCPY(sock->identifier, sock->name); - BLI_uniquename(&node->inputs, - sock, - "socket", - '.', - offsetof(bNodeSocket, identifier), - sizeof(sock->identifier)); - } - for (sock = node->outputs.first; sock; sock = sock->next) { - STRNCPY(sock->identifier, sock->name); - BLI_uniquename(&node->outputs, - sock, - "socket", - '.', - offsetof(bNodeSocket, identifier), - sizeof(sock->identifier)); - } - } - for (sock = ntree->inputs.first; sock; sock = sock->next) { +/* initialize socket identifier strings */ +{ + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { STRNCPY(sock->identifier, sock->name); - BLI_uniquename(&ntree->inputs, + BLI_uniquename(&node->inputs, sock, "socket", '.', offsetof(bNodeSocket, identifier), sizeof(sock->identifier)); } - for (sock = ntree->outputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { STRNCPY(sock->identifier, sock->name); - BLI_uniquename(&ntree->outputs, + BLI_uniquename(&node->outputs, sock, "socket", '.', @@ -674,6 +615,25 @@ static void do_versions_nodetree_customnodes(bNodeTree *ntree, int UNUSED(is_gro sizeof(sock->identifier)); } } + LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) { + STRNCPY(sock->identifier, sock->name); + BLI_uniquename(&ntree->inputs, + sock, + "socket", + '.', + offsetof(bNodeSocket, identifier), + sizeof(sock->identifier)); + } + LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { + STRNCPY(sock->identifier, sock->name); + BLI_uniquename(&ntree->outputs, + sock, + "socket", + '.', + offsetof(bNodeSocket, identifier), + sizeof(sock->identifier)); + } +} } static bool seq_colorbalance_update_cb(Sequence *seq, void *UNUSED(user_data)) @@ -681,11 +641,8 @@ static bool seq_colorbalance_update_cb(Sequence *seq, void *UNUSED(user_data)) Strip *strip = seq->strip; if (strip && strip->color_balance) { - SequenceModifierData *smd; - ColorBalanceModifierData *cbmd; - - smd = SEQ_modifier_new(seq, NULL, seqModifierType_ColorBalance); - cbmd = (ColorBalanceModifierData *)smd; + SequenceModifierData *smd = SEQ_modifier_new(seq, NULL, seqModifierType_ColorBalance); + ColorBalanceModifierData *cbmd = (ColorBalanceModifierData *)smd; cbmd->color_balance = *strip->color_balance; @@ -727,676 +684,603 @@ static bool seq_set_wipe_angle_cb(Sequence *seq, void *UNUSED(user_data)) void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain) { if (bmain->versionfile < 260) { - { - /* set default alpha value of Image outputs in image and render layer nodes to 0 */ - Scene *sce; - bNodeTree *ntree; - - for (sce = bmain->scenes.first; sce; sce = sce->id.next) { - /* there are files with invalid audio_channels value, the real cause - * is unknown, but we fix it here anyway to avoid crashes */ - if (sce->r.ffcodecdata.audio_channels == 0) { - sce->r.ffcodecdata.audio_channels = 2; - } - - if (sce->nodetree) { - do_versions_nodetree_image_default_alpha_output(sce->nodetree); - } - } - - for (ntree = bmain->nodetrees.first; ntree; ntree = ntree->id.next) { - do_versions_nodetree_image_default_alpha_output(ntree); - } - } - - { - /* support old particle dupliobject rotation settings */ - ParticleSettings *part; - - for (part = bmain->particles.first; part; part = part->id.next) { - if (ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) { - part->draw |= PART_DRAW_ROTATE_OB; - - if (part->rotmode == 0) { - part->rotmode = PART_ROT_VEL; - } - } - } - } + {/* set default alpha value of Image outputs in image and render layer nodes to 0 */ + LISTBASE_FOREACH (Scene *, sce, &bmain->scenes){ + /* there are files with invalid audio_channels value, the real cause + * is unknown, but we fix it here anyway to avoid crashes */ + if (sce->r.ffcodecdata.audio_channels == 0){sce->r.ffcodecdata.audio_channels = 2; } - if (!MAIN_VERSION_ATLEAST(bmain, 260, 1)) { - Object *ob; + if (sce->nodetree) { + do_versions_nodetree_image_default_alpha_output(sce->nodetree); + } +} - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - ob->collision_boundtype = ob->boundtype; - } +LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { + do_versions_nodetree_image_default_alpha_output(ntree); +} +} - { - Camera *cam; - for (cam = bmain->cameras.first; cam; cam = cam->id.next) { - if (cam->sensor_x < 0.01f) { - cam->sensor_x = DEFAULT_SENSOR_WIDTH; - } +{ + /* support old particle dupliobject rotation settings */ + LISTBASE_FOREACH (ParticleSettings *, part, &bmain->particles) { + if (ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) { + part->draw |= PART_DRAW_ROTATE_OB; - if (cam->sensor_y < 0.01f) { - cam->sensor_y = DEFAULT_SENSOR_HEIGHT; - } + if (part->rotmode == 0) { + part->rotmode = PART_ROT_VEL; } } } +} +} - if (!MAIN_VERSION_ATLEAST(bmain, 260, 2)) { - FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - if (ntree->type == NTREE_SHADER) { - bNode *node; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == SH_NODE_MAPPING) { - TexMapping *tex_mapping; - - tex_mapping = node->storage; - tex_mapping->projx = PROJ_X; - tex_mapping->projy = PROJ_Y; - tex_mapping->projz = PROJ_Z; - } - } - } - } - FOREACH_NODETREE_END; +if (!MAIN_VERSION_ATLEAST(bmain, 260, 1)) { + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + ob->collision_boundtype = ob->boundtype; } - if (!MAIN_VERSION_ATLEAST(bmain, 260, 4)) { - { - /* Convert node angles to radians! */ - Scene *sce; - Material *mat; - bNodeTree *ntree; - - for (sce = bmain->scenes.first; sce; sce = sce->id.next) { - if (sce->nodetree) { - do_versions_nodetree_convert_angle(sce->nodetree); - } - } - - for (mat = bmain->materials.first; mat; mat = mat->id.next) { - if (mat->nodetree) { - do_versions_nodetree_convert_angle(mat->nodetree); - } + { + LISTBASE_FOREACH (Camera *, cam, &bmain->cameras) { + if (cam->sensor_x < 0.01f) { + cam->sensor_x = DEFAULT_SENSOR_WIDTH; } - for (ntree = bmain->nodetrees.first; ntree; ntree = ntree->id.next) { - do_versions_nodetree_convert_angle(ntree); + if (cam->sensor_y < 0.01f) { + cam->sensor_y = DEFAULT_SENSOR_HEIGHT; } } + } +} - { - /* Tomato compatibility code. */ - bScreen *screen; - MovieClip *clip; - - for (screen = bmain->screens.first; screen; screen = screen->id.next) { - ScrArea *area; - for (area = screen->areabase.first; area; area = area->next) { - SpaceLink *sl; - for (sl = area->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_VIEW3D) { - View3D *v3d = (View3D *)sl; - if (v3d->bundle_size == 0.0f) { - v3d->bundle_size = 0.2f; - v3d->flag2 |= V3D_SHOW_RECONSTRUCTION; - } +if (!MAIN_VERSION_ATLEAST(bmain, 260, 2)) { + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_SHADER) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == SH_NODE_MAPPING) { + TexMapping *tex_mapping; - if (v3d->bundle_drawtype == 0) { - v3d->bundle_drawtype = OB_PLAINAXES; - } - } - else if (sl->spacetype == SPACE_CLIP) { - SpaceClip *sclip = (SpaceClip *)sl; - if (sclip->scopes.track_preview_height == 0) { - sclip->scopes.track_preview_height = 120; - } - } - } + tex_mapping = node->storage; + tex_mapping->projx = PROJ_X; + tex_mapping->projy = PROJ_Y; + tex_mapping->projz = PROJ_Z; } } + } + } + FOREACH_NODETREE_END; +} - for (clip = bmain->movieclips.first; clip; clip = clip->id.next) { - MovieTrackingTrack *track; - - if (clip->aspx < 1.0f) { - clip->aspx = 1.0f; - clip->aspy = 1.0f; - } +if (!MAIN_VERSION_ATLEAST(bmain, 260, 4)) { + {/* Convert node angles to radians! */ + LISTBASE_FOREACH (Scene *, sce, &bmain->scenes){ + if (sce->nodetree){do_versions_nodetree_convert_angle(sce->nodetree); +} +} - clip->proxy.build_tc_flag = IMB_TC_RECORD_RUN | IMB_TC_FREE_RUN | - IMB_TC_INTERPOLATED_REC_DATE_FREE_RUN; +LISTBASE_FOREACH (Material *, mat, &bmain->materials) { + if (mat->nodetree) { + do_versions_nodetree_convert_angle(mat->nodetree); + } +} - if (clip->proxy.build_size_flag == 0) { - clip->proxy.build_size_flag = IMB_PROXY_25; - } +LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { + do_versions_nodetree_convert_angle(ntree); +} +} - if (clip->proxy.quality == 0) { - clip->proxy.quality = 90; - } +{ + /* Tomato compatibility code. */ + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + if (v3d->bundle_size == 0.0f) { + v3d->bundle_size = 0.2f; + v3d->flag2 |= V3D_SHOW_RECONSTRUCTION; + } - if (clip->tracking.camera.pixel_aspect < 0.01f) { - clip->tracking.camera.pixel_aspect = 1.0f; + if (v3d->bundle_drawtype == 0) { + v3d->bundle_drawtype = OB_PLAINAXES; + } } - - track = clip->tracking.tracks_legacy.first; - while (track) { - if (track->minimum_correlation == 0.0f) { - track->minimum_correlation = 0.75f; + else if (sl->spacetype == SPACE_CLIP) { + SpaceClip *sclip = (SpaceClip *)sl; + if (sclip->scopes.track_preview_height == 0) { + sclip->scopes.track_preview_height = 120; } - - track = track->next; } } } } - if (!MAIN_VERSION_ATLEAST(bmain, 260, 6)) { - Scene *sce; - MovieClip *clip; + LISTBASE_FOREACH (MovieClip *, clip, &bmain->movieclips) { + if (clip->aspx < 1.0f) { + clip->aspx = 1.0f; + clip->aspy = 1.0f; + } + + clip->proxy.build_tc_flag = IMB_TC_RECORD_RUN | IMB_TC_FREE_RUN | + IMB_TC_INTERPOLATED_REC_DATE_FREE_RUN; - for (sce = bmain->scenes.first; sce; sce = sce->id.next) { - do_versions_image_settings_2_60(sce); + if (clip->proxy.build_size_flag == 0) { + clip->proxy.build_size_flag = IMB_PROXY_25; } - for (clip = bmain->movieclips.first; clip; clip = clip->id.next) { - MovieTrackingSettings *settings = &clip->tracking.settings; + if (clip->proxy.quality == 0) { + clip->proxy.quality = 90; + } - if (settings->default_pattern_size == 0.0f) { - settings->default_motion_model = TRACK_MOTION_MODEL_TRANSLATION; - settings->default_minimum_correlation = 0.75; - settings->default_pattern_size = 11; - settings->default_search_size = 51; - } + if (clip->tracking.camera.pixel_aspect < 0.01f) { + clip->tracking.camera.pixel_aspect = 1.0f; } - { - Object *ob; - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - /* convert delta addition into delta scale */ - int i; - for (i = 0; i < 3; i++) { - if ((ob->dsize[i] == 0.0f) || /* simple case, user never touched dsize */ - (ob->scale[i] == 0.0f)) /* can't scale the dsize to give a non zero result, - * so fallback to 1.0f */ - { - ob->dscale[i] = 1.0f; - } - else { - ob->dscale[i] = (ob->scale[i] + ob->dsize[i]) / ob->scale[i]; - } - } + MovieTrackingTrack *track = clip->tracking.tracks_legacy.first; + while (track) { + if (track->minimum_correlation == 0.0f) { + track->minimum_correlation = 0.75f; } + + track = track->next; } } - /* sigh, this dscale vs dsize version patching was not done right, fix for fix, - * this intentionally checks an exact subversion, also note this was never in a release, - * at some point this could be removed. */ - else if (bmain->versionfile == 260 && bmain->subversionfile == 6) { - Object *ob; - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - if (is_zero_v3(ob->dscale)) { - copy_vn_fl(ob->dscale, 3, 1.0f); - } - } +} +} + +if (!MAIN_VERSION_ATLEAST(bmain, 260, 6)) { + LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) { + do_versions_image_settings_2_60(sce); } - if (!MAIN_VERSION_ATLEAST(bmain, 260, 8)) { - Brush *brush; + LISTBASE_FOREACH (MovieClip *, clip, &bmain->movieclips) { + MovieTrackingSettings *settings = &clip->tracking.settings; - for (brush = bmain->brushes.first; brush; brush = brush->id.next) { - if (brush->sculpt_tool == SCULPT_TOOL_ROTATE) { - brush->alpha = 1.0f; - } + if (settings->default_pattern_size == 0.0f) { + settings->default_motion_model = TRACK_MOTION_MODEL_TRANSLATION; + settings->default_minimum_correlation = 0.75; + settings->default_pattern_size = 11; + settings->default_search_size = 51; } } - if (!MAIN_VERSION_ATLEAST(bmain, 261, 1)) { - { - /* update use flags for node sockets (was only temporary before) */ - Scene *sce; - Material *mat; - Tex *tex; - World *world; - bNodeTree *ntree; - - for (sce = bmain->scenes.first; sce; sce = sce->id.next) { - if (sce->nodetree) { - do_versions_nodetree_socket_use_flags_2_62(sce->nodetree); + { + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + /* convert delta addition into delta scale */ + int i; + for (i = 0; i < 3; i++) { + if ((ob->dsize[i] == 0.0f) || /* simple case, user never touched dsize */ + (ob->scale[i] == 0.0f)) /* can't scale the dsize to give a non zero result, + * so fallback to 1.0f */ + { + ob->dscale[i] = 1.0f; } - } - - for (mat = bmain->materials.first; mat; mat = mat->id.next) { - if (mat->nodetree) { - do_versions_nodetree_socket_use_flags_2_62(mat->nodetree); + else { + ob->dscale[i] = (ob->scale[i] + ob->dsize[i]) / ob->scale[i]; } } + } + } +} +/* sigh, this dscale vs dsize version patching was not done right, fix for fix, + * this intentionally checks an exact subversion, also note this was never in a release, + * at some point this could be removed. */ +else if (bmain->versionfile == 260 && bmain->subversionfile == 6) { + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + if (is_zero_v3(ob->dscale)) { + copy_vn_fl(ob->dscale, 3, 1.0f); + } + } +} - for (tex = bmain->textures.first; tex; tex = tex->id.next) { - if (tex->nodetree) { - do_versions_nodetree_socket_use_flags_2_62(tex->nodetree); - } - } +if (!MAIN_VERSION_ATLEAST(bmain, 260, 8)) { + LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { + if (brush->sculpt_tool == SCULPT_TOOL_ROTATE) { + brush->alpha = 1.0f; + } + } +} - for (Light *la = bmain->lights.first; la; la = la->id.next) { - if (la->nodetree) { - do_versions_nodetree_socket_use_flags_2_62(la->nodetree); - } - } +if (!MAIN_VERSION_ATLEAST(bmain, 261, 1)) { + {/* update use flags for node sockets (was only temporary before) */ + LISTBASE_FOREACH (Scene *, sce, &bmain->scenes){ + if (sce->nodetree){do_versions_nodetree_socket_use_flags_2_62(sce->nodetree); +} +} - for (world = bmain->worlds.first; world; world = world->id.next) { - if (world->nodetree) { - do_versions_nodetree_socket_use_flags_2_62(world->nodetree); - } - } +LISTBASE_FOREACH (Material *, mat, &bmain->materials) { + if (mat->nodetree) { + do_versions_nodetree_socket_use_flags_2_62(mat->nodetree); + } +} - for (ntree = bmain->nodetrees.first; ntree; ntree = ntree->id.next) { - do_versions_nodetree_socket_use_flags_2_62(ntree); - } - } - { - MovieClip *clip; - Object *ob; +LISTBASE_FOREACH (Tex *, tex, &bmain->textures) { + if (tex->nodetree) { + do_versions_nodetree_socket_use_flags_2_62(tex->nodetree); + } +} + +LISTBASE_FOREACH (Light *, la, &bmain->lights) { + if (la->nodetree) { + do_versions_nodetree_socket_use_flags_2_62(la->nodetree); + } +} - for (clip = bmain->movieclips.first; clip; clip = clip->id.next) { - MovieTracking *tracking = &clip->tracking; - MovieTrackingObject *tracking_object = tracking->objects.first; +LISTBASE_FOREACH (World *, world, &bmain->worlds) { + if (world->nodetree) { + do_versions_nodetree_socket_use_flags_2_62(world->nodetree); + } +} - clip->proxy.build_tc_flag |= IMB_TC_RECORD_RUN_NO_GAPS; +LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { + do_versions_nodetree_socket_use_flags_2_62(ntree); +} +} +{ + LISTBASE_FOREACH (MovieClip *, clip, &bmain->movieclips) { + MovieTracking *tracking = &clip->tracking; + MovieTrackingObject *tracking_object = tracking->objects.first; - if (!tracking->settings.object_distance) { - tracking->settings.object_distance = 1.0f; - } + clip->proxy.build_tc_flag |= IMB_TC_RECORD_RUN_NO_GAPS; - if (BLI_listbase_is_empty(&tracking->objects)) { - BKE_tracking_object_add(tracking, "Camera"); - } + if (!tracking->settings.object_distance) { + tracking->settings.object_distance = 1.0f; + } - while (tracking_object) { - if (!tracking_object->scale) { - tracking_object->scale = 1.0f; - } + if (BLI_listbase_is_empty(&tracking->objects)) { + BKE_tracking_object_add(tracking, "Camera"); + } - tracking_object = tracking_object->next; - } + while (tracking_object) { + if (!tracking_object->scale) { + tracking_object->scale = 1.0f; } - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - bConstraint *con; - for (con = ob->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_OBJECTSOLVER) { - bObjectSolverConstraint *data = (bObjectSolverConstraint *)con->data; + tracking_object = tracking_object->next; + } + } - if (data->invmat[3][3] == 0.0f) { - unit_m4(data->invmat); - } - } + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (bConstraint *, con, &ob->constraints) { + if (con->type == CONSTRAINT_TYPE_OBJECTSOLVER) { + bObjectSolverConstraint *data = con->data; + + if (data->invmat[3][3] == 0.0f) { + unit_m4(data->invmat); } } } } +} +} - if (!MAIN_VERSION_ATLEAST(bmain, 261, 2)) { - { - /* convert deprecated sculpt_paint_unified_* fields to - * UnifiedPaintSettings */ - Scene *scene; - for (scene = bmain->scenes.first; scene; scene = scene->id.next) { - ToolSettings *ts = scene->toolsettings; - UnifiedPaintSettings *ups = &ts->unified_paint_settings; - ups->size = ts->sculpt_paint_unified_size; - ups->unprojected_radius = ts->sculpt_paint_unified_unprojected_radius; - ups->alpha = ts->sculpt_paint_unified_alpha; - ups->flag = ts->sculpt_paint_settings; - } +if (!MAIN_VERSION_ATLEAST(bmain, 261, 2)) { + { + /* convert deprecated sculpt_paint_unified_* fields to + * UnifiedPaintSettings */ + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + ToolSettings *ts = scene->toolsettings; + UnifiedPaintSettings *ups = &ts->unified_paint_settings; + ups->size = ts->sculpt_paint_unified_size; + ups->unprojected_radius = ts->sculpt_paint_unified_unprojected_radius; + ups->alpha = ts->sculpt_paint_unified_alpha; + ups->flag = ts->sculpt_paint_settings; } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 261, 3)) { - { - /* convert extended ascii to utf-8 for text editor */ - Text *text; - for (text = bmain->texts.first; text; text = text->id.next) { - if (!(text->flags & TXT_ISEXT)) { - TextLine *tl; - - for (tl = text->lines.first; tl; tl = tl->next) { - int added = txt_extended_ascii_as_utf8(&tl->line); - tl->len += added; - - /* reset cursor position if line was changed */ - if (added && tl == text->curl) { - text->curc = 0; - } +if (!MAIN_VERSION_ATLEAST(bmain, 261, 3)) { + {/* convert extended ascii to utf-8 for text editor */ + LISTBASE_FOREACH (Text *, text, &bmain->texts){ + if (!(text->flags & TXT_ISEXT)){LISTBASE_FOREACH (TextLine *, tl, &text->lines){ + int added = txt_extended_ascii_as_utf8(&tl->line); + tl->len += added; + + /* reset cursor position if line was changed */ + if (added && tl == text->curl) { + text->curc = 0; + } +} +} +} +} +{ + /* set new dynamic paint values */ + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_DynamicPaint) { + DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md; + if (pmd->canvas) { + DynamicPaintSurface *surface = pmd->canvas->surfaces.first; + for (; surface; surface = surface->next) { + surface->color_dry_threshold = 1.0f; + surface->influence_scale = 1.0f; + surface->radius_scale = 1.0f; + surface->flags |= MOD_DPAINT_USE_DRYING; } } } } - { - /* set new dynamic paint values */ - Object *ob; - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - ModifierData *md; - for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_DynamicPaint) { - DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md; - if (pmd->canvas) { - DynamicPaintSurface *surface = pmd->canvas->surfaces.first; - for (; surface; surface = surface->next) { - surface->color_dry_threshold = 1.0f; - surface->influence_scale = 1.0f; - surface->radius_scale = 1.0f; - surface->flags |= MOD_DPAINT_USE_DRYING; - } - } - } + } +} +} + +if (bmain->versionfile < 262) { + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_Cloth) { + ClothModifierData *clmd = (ClothModifierData *)md; + if (clmd->sim_parms) { + clmd->sim_parms->vel_damping = 1.0f; } } } } +} - if (bmain->versionfile < 262) { - Object *ob; - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - ModifierData *md; - - for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Cloth) { - ClothModifierData *clmd = (ClothModifierData *)md; - if (clmd->sim_parms) { - clmd->sim_parms->vel_damping = 1.0f; - } +if (bmain->versionfile < 263) { + /* set fluidsim rate. the version patch for this in 2.62 was wrong, so + * try to correct it, if rate is 0.0 that's likely not intentional */ + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_Fluidsim) { + FluidsimModifierData *fmd = (FluidsimModifierData *)md; + if (fmd->fss->animRate == 0.0f) { + fmd->fss->animRate = 1.0f; } } } } +} - if (bmain->versionfile < 263) { - /* set fluidsim rate. the version patch for this in 2.62 was wrong, so - * try to correct it, if rate is 0.0 that's likely not intentional */ - Object *ob; - - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - ModifierData *md; - for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Fluidsim) { - FluidsimModifierData *fmd = (FluidsimModifierData *)md; - if (fmd->fss->animRate == 0.0f) { - fmd->fss->animRate = 1.0f; - } - } - } +if (!MAIN_VERSION_ATLEAST(bmain, 262, 1)) { + /* update use flags for node sockets (was only temporary before) */ + LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) { + if (sce->nodetree) { + do_versions_nodetree_multi_file_output_format_2_62_1(sce, sce->nodetree); } } - if (!MAIN_VERSION_ATLEAST(bmain, 262, 1)) { - /* update use flags for node sockets (was only temporary before) */ - Scene *sce; - bNodeTree *ntree; + /* XXX can't associate with scene for group nodes, image format will stay uninitialized */ + LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { + do_versions_nodetree_multi_file_output_format_2_62_1(NULL, ntree); + } +} - for (sce = bmain->scenes.first; sce; sce = sce->id.next) { - if (sce->nodetree) { - do_versions_nodetree_multi_file_output_format_2_62_1(sce, sce->nodetree); - } +/* only swap for pre-release bmesh merge which had MLoopCol red/blue swap */ +if (bmain->versionfile == 262 && bmain->subversionfile == 1) { + { + LISTBASE_FOREACH (Mesh *, me, &bmain->meshes) { + do_versions_mesh_mloopcol_swap_2_62_1(me); } + } +} - /* XXX can't associate with scene for group nodes, image format will stay uninitialized */ - for (ntree = bmain->nodetrees.first; ntree; ntree = ntree->id.next) { - do_versions_nodetree_multi_file_output_format_2_62_1(NULL, ntree); +if (!MAIN_VERSION_ATLEAST(bmain, 262, 2)) { + /* Set new idname of keyingsets from their now "label-only" name. */ + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + LISTBASE_FOREACH (KeyingSet *, ks, &scene->keyingsets) { + if (!ks->idname[0]) { + STRNCPY(ks->idname, ks->name); + } } } +} - /* only swap for pre-release bmesh merge which had MLoopCol red/blue swap */ - if (bmain->versionfile == 262 && bmain->subversionfile == 1) { - { - Mesh *me; - for (me = bmain->meshes.first; me; me = me->id.next) { - do_versions_mesh_mloopcol_swap_2_62_1(me); +if (!MAIN_VERSION_ATLEAST(bmain, 262, 3)) { + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_Lattice) { + LatticeModifierData *lmd = (LatticeModifierData *)md; + lmd->strength = 1.0f; } } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 262, 2)) { - /* Set new idname of keyingsets from their now "label-only" name. */ - Scene *scene; - for (scene = bmain->scenes.first; scene; scene = scene->id.next) { - KeyingSet *ks; - for (ks = scene->keyingsets.first; ks; ks = ks->next) { - if (!ks->idname[0]) { - STRNCPY(ks->idname, ks->name); +if (!MAIN_VERSION_ATLEAST(bmain, 262, 4)) { + /* Read Viscosity presets from older files */ + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_Fluidsim) { + FluidsimModifierData *fmd = (FluidsimModifierData *)md; + if (fmd->fss->viscosityMode == 3) { + fmd->fss->viscosityValue = 5.0; + fmd->fss->viscosityExponent = 5; + } + else if (fmd->fss->viscosityMode == 4) { + fmd->fss->viscosityValue = 2.0; + fmd->fss->viscosityExponent = 3; } } } } +} + +if (bmain->versionfile < 263) { + /* Default for old files is to save particle rotations to pointcache */ + LISTBASE_FOREACH (ParticleSettings *, part, &bmain->particles) { + part->flag |= PART_ROTATIONS; + } +} - if (!MAIN_VERSION_ATLEAST(bmain, 262, 3)) { - Object *ob; - ModifierData *md; +if (!MAIN_VERSION_ATLEAST(bmain, 263, 1)) { + /* file output node paths are now stored in the file info struct instead socket name */ + LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) { + if (sce->nodetree) { + do_versions_nodetree_multi_file_output_path_2_63_1(sce->nodetree); + } + } + LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { + do_versions_nodetree_multi_file_output_path_2_63_1(ntree); + } +} - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Lattice) { - LatticeModifierData *lmd = (LatticeModifierData *)md; - lmd->strength = 1.0f; - } - } +if (!MAIN_VERSION_ATLEAST(bmain, 263, 3)) { + /* For weight paint, each brush now gets its own weight; + * unified paint settings also have weight. Update unified + * paint settings and brushes with a default weight value. */ + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + ToolSettings *ts = scene->toolsettings; + if (ts) { + ts->unified_paint_settings.weight = ts->vgroup_weight; + ts->unified_paint_settings.flag |= UNIFIED_PAINT_WEIGHT; } } - if (!MAIN_VERSION_ATLEAST(bmain, 262, 4)) { - /* Read Viscosity presets from older files */ - Object *ob; + LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { + brush->weight = 0.5; + } +} - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - ModifierData *md; - for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Fluidsim) { - FluidsimModifierData *fmd = (FluidsimModifierData *)md; - if (fmd->fss->viscosityMode == 3) { - fmd->fss->viscosityValue = 5.0; - fmd->fss->viscosityExponent = 5; +if (!MAIN_VERSION_ATLEAST(bmain, 263, 2)) { + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (sl->spacetype == SPACE_CLIP) { + SpaceClip *sclip = (SpaceClip *)sl; + bool hide = false; + + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { + if (region->regiontype == RGN_TYPE_PREVIEW) { + if (region->alignment != RGN_ALIGN_NONE) { + region->flag |= RGN_FLAG_HIDDEN; + region->v2d.flag &= ~V2D_IS_INIT; + region->alignment = RGN_ALIGN_NONE; + + hide = true; + } + } } - else if (fmd->fss->viscosityMode == 4) { - fmd->fss->viscosityValue = 2.0; - fmd->fss->viscosityExponent = 3; + + if (hide) { + sclip->view = SC_VIEW_CLIP; } } } } } +} - if (bmain->versionfile < 263) { - /* Default for old files is to save particle rotations to pointcache */ - ParticleSettings *part; - for (part = bmain->particles.first; part; part = part->id.next) { - part->flag |= PART_ROTATIONS; +if (!MAIN_VERSION_ATLEAST(bmain, 263, 4)) { + LISTBASE_FOREACH (Camera *, cam, &bmain->cameras) { + if (cam->flag & CAM_PANORAMA) { + cam->type = CAM_PANO; + cam->flag &= ~CAM_PANORAMA; } } - if (!MAIN_VERSION_ATLEAST(bmain, 263, 1)) { - /* file output node paths are now stored in the file info struct instead socket name */ - Scene *sce; - bNodeTree *ntree; + LISTBASE_FOREACH (Curve *, cu, &bmain->curves) { + if (cu->bevfac2 == 0.0f) { + cu->bevfac1 = 0.0f; + cu->bevfac2 = 1.0f; + } + } +} - for (sce = bmain->scenes.first; sce; sce = sce->id.next) { +if (!MAIN_VERSION_ATLEAST(bmain, 263, 5)) { + { + /* file output node paths are now stored in the file info struct instead socket name */ + LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) { if (sce->nodetree) { - do_versions_nodetree_multi_file_output_path_2_63_1(sce->nodetree); + do_versions_nodetree_file_output_layers_2_64_5(sce->nodetree); + do_versions_nodetree_image_layer_2_64_5(sce->nodetree); } } - for (ntree = bmain->nodetrees.first; ntree; ntree = ntree->id.next) { - do_versions_nodetree_multi_file_output_path_2_63_1(ntree); + LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { + do_versions_nodetree_file_output_layers_2_64_5(ntree); + do_versions_nodetree_image_layer_2_64_5(ntree); } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 263, 3)) { - Scene *scene; - Brush *brush; - - /* For weight paint, each brush now gets its own weight; - * unified paint settings also have weight. Update unified - * paint settings and brushes with a default weight value. */ +if (!MAIN_VERSION_ATLEAST(bmain, 263, 6)) { + /* update use flags for node sockets (was only temporary before) */ + LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) { + if (sce->nodetree) { + do_versions_nodetree_frame_2_64_6(sce->nodetree); + } + } - for (scene = bmain->scenes.first; scene; scene = scene->id.next) { - ToolSettings *ts = scene->toolsettings; - if (ts) { - ts->unified_paint_settings.weight = ts->vgroup_weight; - ts->unified_paint_settings.flag |= UNIFIED_PAINT_WEIGHT; - } + LISTBASE_FOREACH (Material *, mat, &bmain->materials) { + if (mat->nodetree) { + do_versions_nodetree_frame_2_64_6(mat->nodetree); } + } - for (brush = bmain->brushes.first; brush; brush = brush->id.next) { - brush->weight = 0.5; + LISTBASE_FOREACH (Tex *, tex, &bmain->textures) { + if (tex->nodetree) { + do_versions_nodetree_frame_2_64_6(tex->nodetree); } } - if (!MAIN_VERSION_ATLEAST(bmain, 263, 2)) { - bScreen *screen; + LISTBASE_FOREACH (Light *, la, &bmain->lights) { + if (la->nodetree) { + do_versions_nodetree_frame_2_64_6(la->nodetree); + } + } - for (screen = bmain->screens.first; screen; screen = screen->id.next) { - ScrArea *area; - for (area = screen->areabase.first; area; area = area->next) { - SpaceLink *sl; + LISTBASE_FOREACH (World *, world, &bmain->worlds) { + if (world->nodetree) { + do_versions_nodetree_frame_2_64_6(world->nodetree); + } + } - for (sl = area->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_CLIP) { - SpaceClip *sclip = (SpaceClip *)sl; - ARegion *region; - bool hide = false; - - for (region = area->regionbase.first; region; region = region->next) { - if (region->regiontype == RGN_TYPE_PREVIEW) { - if (region->alignment != RGN_ALIGN_NONE) { - region->flag |= RGN_FLAG_HIDDEN; - region->v2d.flag &= ~V2D_IS_INIT; - region->alignment = RGN_ALIGN_NONE; - - hide = true; - } - } - } + LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { + do_versions_nodetree_frame_2_64_6(ntree); + } +} - if (hide) { - sclip->view = SC_VIEW_CLIP; - } - } +if (!MAIN_VERSION_ATLEAST(bmain, 263, 7)) { + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_Fluid) { + FluidModifierData *fmd = (FluidModifierData *)md; + if ((fmd->type & MOD_FLUID_TYPE_DOMAIN) && fmd->domain) { + int maxres = max_iii(fmd->domain->res[0], fmd->domain->res[1], fmd->domain->res[2]); + fmd->domain->scale = fmd->domain->dx * maxres; + fmd->domain->dx = 1.0f / fmd->domain->scale; } } } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 263, 4)) { - Camera *cam; - Curve *cu; - - for (cam = bmain->cameras.first; cam; cam = cam->id.next) { - if (cam->flag & CAM_PANORAMA) { - cam->type = CAM_PANO; - cam->flag &= ~CAM_PANORAMA; - } - } +if (!MAIN_VERSION_ATLEAST(bmain, 263, 9)) { + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_SHADER) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT)) { + NodeTexImage *tex = node->storage; - for (cu = bmain->curves.first; cu; cu = cu->id.next) { - if (cu->bevfac2 == 0.0f) { - cu->bevfac1 = 0.0f; - cu->bevfac2 = 1.0f; + tex->iuser.frames = 1; + tex->iuser.sfra = 1; + } } } } + FOREACH_NODETREE_END; +} - if (!MAIN_VERSION_ATLEAST(bmain, 263, 5)) { - { - /* file output node paths are now stored in the file info struct instead socket name */ - Scene *sce; - bNodeTree *ntree; - - for (sce = bmain->scenes.first; sce; sce = sce->id.next) { - if (sce->nodetree) { - do_versions_nodetree_file_output_layers_2_64_5(sce->nodetree); - do_versions_nodetree_image_layer_2_64_5(sce->nodetree); +if (!MAIN_VERSION_ATLEAST(bmain, 263, 10)) { + { + /* composite redesign */ + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->nodetree) { + if (scene->nodetree->chunksize == 0) { + scene->nodetree->chunksize = 256; } } - for (ntree = bmain->nodetrees.first; ntree; ntree = ntree->id.next) { - do_versions_nodetree_file_output_layers_2_64_5(ntree); - do_versions_nodetree_image_layer_2_64_5(ntree); - } } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 263, 6)) { - /* update use flags for node sockets (was only temporary before) */ - Scene *sce; - Material *mat; - Tex *tex; - World *world; - bNodeTree *ntree; - - for (sce = bmain->scenes.first; sce; sce = sce->id.next) { - if (sce->nodetree) { - do_versions_nodetree_frame_2_64_6(sce->nodetree); - } - } - - for (mat = bmain->materials.first; mat; mat = mat->id.next) { - if (mat->nodetree) { - do_versions_nodetree_frame_2_64_6(mat->nodetree); - } - } - - for (tex = bmain->textures.first; tex; tex = tex->id.next) { - if (tex->nodetree) { - do_versions_nodetree_frame_2_64_6(tex->nodetree); - } - } - - for (Light *la = bmain->lights.first; la; la = la->id.next) { - if (la->nodetree) { - do_versions_nodetree_frame_2_64_6(la->nodetree); - } - } - - for (world = bmain->worlds.first; world; world = world->id.next) { - if (world->nodetree) { - do_versions_nodetree_frame_2_64_6(world->nodetree); - } - } - - for (ntree = bmain->nodetrees.first; ntree; ntree = ntree->id.next) { - do_versions_nodetree_frame_2_64_6(ntree); - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 263, 7)) { - Object *ob; - - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - ModifierData *md; - for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Fluid) { - FluidModifierData *fmd = (FluidModifierData *)md; - if ((fmd->type & MOD_FLUID_TYPE_DOMAIN) && fmd->domain) { - int maxres = max_iii(fmd->domain->res[0], fmd->domain->res[1], fmd->domain->res[2]); - fmd->domain->scale = fmd->domain->dx * maxres; - fmd->domain->dx = 1.0f / fmd->domain->scale; - } - } - } - } - } - if (!MAIN_VERSION_ATLEAST(bmain, 263, 9)) { FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - if (ntree->type == NTREE_SHADER) { - bNode *node; - for (node = ntree->nodes.first; node; node = node->next) { - if (ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT)) { - NodeTexImage *tex = node->storage; - - tex->iuser.frames = 1; - tex->iuser.sfra = 1; + if (ntree->type == NTREE_COMPOSIT) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == CMP_NODE_DEFOCUS) { + NodeDefocus *data = node->storage; + if (data->maxblur == 0.0f) { + data->maxblur = 16.0f; + } } } } @@ -1404,746 +1288,630 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain) FOREACH_NODETREE_END; } - if (!MAIN_VERSION_ATLEAST(bmain, 263, 10)) { - { - Scene *scene; - /* composite redesign */ - for (scene = bmain->scenes.first; scene; scene = scene->id.next) { - if (scene->nodetree) { - if (scene->nodetree->chunksize == 0) { - scene->nodetree->chunksize = 256; - } - } - } - - FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - if (ntree->type == NTREE_COMPOSIT) { - bNode *node; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == CMP_NODE_DEFOCUS) { - NodeDefocus *data = node->storage; - if (data->maxblur == 0.0f) { - data->maxblur = 16.0f; - } - } - } - } - } - FOREACH_NODETREE_END; - } - - { - bScreen *screen; - - for (screen = bmain->screens.first; screen; screen = screen->id.next) { - ScrArea *area; - - for (area = screen->areabase.first; area; area = area->next) { - SpaceLink *sl; - - for (sl = area->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_CLIP) { - SpaceClip *sclip = (SpaceClip *)sl; - - if (sclip->around == 0) { - sclip->around = V3D_AROUND_CENTER_MEDIAN; - } - } - } - } - } - } - - { - MovieClip *clip; + {LISTBASE_FOREACH (bScreen *, screen, &bmain->screens){LISTBASE_FOREACH ( + ScrArea *, area, &screen->areabase){LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata){ + if (sl->spacetype == SPACE_CLIP){SpaceClip *sclip = (SpaceClip *)sl; - for (clip = bmain->movieclips.first; clip; clip = clip->id.next) { - clip->start_frame = 1; - } - } + if (sclip->around == 0) { + sclip->around = V3D_AROUND_CENTER_MEDIAN; } +} +} +} +} +} - if (!MAIN_VERSION_ATLEAST(bmain, 263, 11)) { - MovieClip *clip; - - for (clip = bmain->movieclips.first; clip; clip = clip->id.next) { - MovieTrackingTrack *track; +{ + LISTBASE_FOREACH (MovieClip *, clip, &bmain->movieclips) { + clip->start_frame = 1; + } +} +} - track = clip->tracking.tracks_legacy.first; - while (track) { - do_versions_affine_tracker_track(track); +if (!MAIN_VERSION_ATLEAST(bmain, 263, 11)) { + LISTBASE_FOREACH (MovieClip *, clip, &bmain->movieclips) { + MovieTrackingTrack *track = clip->tracking.tracks_legacy.first; + while (track) { + do_versions_affine_tracker_track(track); - track = track->next; - } + track = track->next; } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 263, 13)) { - FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - if (ntree->type == NTREE_COMPOSIT) { - bNode *node; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == CMP_NODE_DILATEERODE) { - if (node->storage == NULL) { - NodeDilateErode *data = MEM_callocN(sizeof(NodeDilateErode), __func__); - data->falloff = PROP_SMOOTH; - node->storage = data; - } +if (!MAIN_VERSION_ATLEAST(bmain, 263, 13)) { + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_COMPOSIT) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == CMP_NODE_DILATEERODE) { + if (node->storage == NULL) { + NodeDilateErode *data = MEM_callocN(sizeof(NodeDilateErode), __func__); + data->falloff = PROP_SMOOTH; + node->storage = data; } } } } - FOREACH_NODETREE_END; } + FOREACH_NODETREE_END; +} - if (!MAIN_VERSION_ATLEAST(bmain, 263, 14)) { - ParticleSettings *part; - - FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - if (ntree->type == NTREE_COMPOSIT) { - bNode *node; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == CMP_NODE_KEYING) { - NodeKeyingData *data = node->storage; +if (!MAIN_VERSION_ATLEAST(bmain, 263, 14)) { + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_COMPOSIT) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == CMP_NODE_KEYING) { + NodeKeyingData *data = node->storage; - if (data->despill_balance == 0.0f) { - data->despill_balance = 0.5f; - } + if (data->despill_balance == 0.0f) { + data->despill_balance = 0.5f; } } } } - FOREACH_NODETREE_END; + } + FOREACH_NODETREE_END; - /* keep compatibility for dupliobject particle size */ - for (part = bmain->particles.first; part; part = part->id.next) { - if (ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) { - if ((part->draw & PART_DRAW_ROTATE_OB) == 0) { - part->draw |= PART_DRAW_NO_SCALE_OB; - } + /* keep compatibility for dupliobject particle size */ + LISTBASE_FOREACH (ParticleSettings *, part, &bmain->particles) { + if (ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) { + if ((part->draw & PART_DRAW_ROTATE_OB) == 0) { + part->draw |= PART_DRAW_NO_SCALE_OB; } } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 263, 17)) { - FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - if (ntree->type == NTREE_COMPOSIT) { - bNode *node; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == CMP_NODE_MASK) { - if (node->storage == NULL) { - NodeMask *data = MEM_callocN(sizeof(NodeMask), __func__); - /* move settings into own struct */ - data->size_x = (int)node->custom3; - data->size_y = (int)node->custom4; - node->custom3 = 0.5f; /* default shutter */ - node->storage = data; - } +if (!MAIN_VERSION_ATLEAST(bmain, 263, 17)) { + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_COMPOSIT) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == CMP_NODE_MASK) { + if (node->storage == NULL) { + NodeMask *data = MEM_callocN(sizeof(NodeMask), __func__); + /* move settings into own struct */ + data->size_x = (int)node->custom3; + data->size_y = (int)node->custom4; + node->custom3 = 0.5f; /* default shutter */ + node->storage = data; } } } } - FOREACH_NODETREE_END; } + FOREACH_NODETREE_END; +} - if (!MAIN_VERSION_ATLEAST(bmain, 263, 18)) { - Scene *scene; - - for (scene = bmain->scenes.first; scene; scene = scene->id.next) { - if (scene->ed) { - SEQ_for_each_callback(&scene->ed->seqbase, seq_colorbalance_update_cb, NULL); - } +if (!MAIN_VERSION_ATLEAST(bmain, 263, 18)) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->ed) { + SEQ_for_each_callback(&scene->ed->seqbase, seq_colorbalance_update_cb, NULL); } } +} - /* color management pipeline changes compatibility code */ - if (!MAIN_VERSION_ATLEAST(bmain, 263, 19)) { - Scene *scene; - Image *ima; - bool colormanagement_disabled = false; - - /* make scenes which are not using color management have got None as display device, - * so they wouldn't perform linear-to-sRGB conversion on display - */ - for (scene = bmain->scenes.first; scene; scene = scene->id.next) { - if ((scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) == 0) { - ColorManagedDisplaySettings *display_settings = &scene->display_settings; +/* color management pipeline changes compatibility code */ +if (!MAIN_VERSION_ATLEAST(bmain, 263, 19)) { + bool colormanagement_disabled = false; - if (display_settings->display_device[0] == 0) { - BKE_scene_disable_color_management(scene); - } + /* make scenes which are not using color management have got None as display device, + * so they wouldn't perform linear-to-sRGB conversion on display + */ + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if ((scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) == 0) { + ColorManagedDisplaySettings *display_settings = &scene->display_settings; - colormanagement_disabled = true; + if (display_settings->display_device[0] == 0) { + BKE_scene_disable_color_management(scene); } + + colormanagement_disabled = true; } + } - for (ima = bmain->images.first; ima; ima = ima->id.next) { - if (ima->source == IMA_SRC_VIEWER) { - ima->flag |= IMA_VIEW_AS_RENDER; - } - else if (colormanagement_disabled) { - /* if color-management not used, set image's color space to raw, so no sRGB->linear - * conversion would happen on display and render there's no clear way to check whether - * color management is enabled or not in render engine so set all images to raw if there's - * at least one scene with color management disabled this would still behave incorrect in - * cases when color management was used for only some of scenes, but such a setup is - * crazy anyway and think it's fair enough to break compatibility in that cases. - */ + LISTBASE_FOREACH (Image *, ima, &bmain->images) { + if (ima->source == IMA_SRC_VIEWER) { + ima->flag |= IMA_VIEW_AS_RENDER; + } + else if (colormanagement_disabled) { + /* if color-management not used, set image's color space to raw, so no sRGB->linear + * conversion would happen on display and render there's no clear way to check whether + * color management is enabled or not in render engine so set all images to raw if there's + * at least one scene with color management disabled this would still behave incorrect in + * cases when color management was used for only some of scenes, but such a setup is + * crazy anyway and think it's fair enough to break compatibility in that cases. + */ - STRNCPY(ima->colorspace_settings.name, "Raw"); - } + STRNCPY(ima->colorspace_settings.name, "Raw"); } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 263, 20)) { - Key *key; - for (key = bmain->shapekeys.first; key; key = key->id.next) { - blo_do_versions_key_uidgen(key); - } +if (!MAIN_VERSION_ATLEAST(bmain, 263, 20)) { + LISTBASE_FOREACH (Key *, key, &bmain->shapekeys) { + blo_do_versions_key_uidgen(key); } +} - if (!MAIN_VERSION_ATLEAST(bmain, 263, 21)) { - { - Mesh *me; - for (me = bmain->meshes.first; me; me = me->id.next) { - CustomData_update_typemap(&me->vdata); - CustomData_free_layers(&me->vdata, CD_MSTICKY, me->totvert); - } +if (!MAIN_VERSION_ATLEAST(bmain, 263, 21)) { + { + LISTBASE_FOREACH (Mesh *, me, &bmain->meshes) { + CustomData_update_typemap(&me->vdata); + CustomData_free_layers(&me->vdata, CD_MSTICKY, me->totvert); } } +} - /* correction for files saved in blender version when BKE_pose_copy_data - * didn't copy animation visualization, which lead to deadlocks on motion - * path calculation for proxied armatures, see #32742. - */ - if (bmain->versionfile < 264) { - Object *ob; - - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - if (ob->pose) { - if (ob->pose->avs.path_step == 0) { - animviz_settings_init(&ob->pose->avs); - } +/* correction for files saved in blender version when BKE_pose_copy_data + * didn't copy animation visualization, which lead to deadlocks on motion + * path calculation for proxied armatures, see #32742. + */ +if (bmain->versionfile < 264) { + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + if (ob->pose) { + if (ob->pose->avs.path_step == 0) { + animviz_settings_init(&ob->pose->avs); } } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 264, 1)) { - FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - if (ntree->type == NTREE_SHADER) { - bNode *node; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == SH_NODE_TEX_COORD) { - node->flag |= NODE_OPTIONS; - } +if (!MAIN_VERSION_ATLEAST(bmain, 264, 1)) { + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_SHADER) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == SH_NODE_TEX_COORD) { + node->flag |= NODE_OPTIONS; } } } - FOREACH_NODETREE_END; } + FOREACH_NODETREE_END; +} - if (!MAIN_VERSION_ATLEAST(bmain, 264, 2)) { - MovieClip *clip; - - for (clip = bmain->movieclips.first; clip; clip = clip->id.next) { - MovieTracking *tracking = &clip->tracking; - MovieTrackingObject *tracking_object; - - for (tracking_object = tracking->objects.first; tracking_object; - tracking_object = tracking_object->next) - { - if (tracking_object->keyframe1 == 0 && tracking_object->keyframe2 == 0) { - tracking_object->keyframe1 = tracking->settings.keyframe1_legacy; - tracking_object->keyframe2 = tracking->settings.keyframe2_legacy; - } +if (!MAIN_VERSION_ATLEAST(bmain, 264, 2)) { + LISTBASE_FOREACH (MovieClip *, clip, &bmain->movieclips) { + MovieTracking *tracking = &clip->tracking; + LISTBASE_FOREACH (MovieTrackingObject *, tracking_object, &tracking->objects) { + if (tracking_object->keyframe1 == 0 && tracking_object->keyframe2 == 0) { + tracking_object->keyframe1 = tracking->settings.keyframe1_legacy; + tracking_object->keyframe2 = tracking->settings.keyframe2_legacy; } } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 264, 3)) { - /* smoke branch */ - { - Object *ob; - - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - ModifierData *md; - for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Fluid) { - FluidModifierData *fmd = (FluidModifierData *)md; - if ((fmd->type & MOD_FLUID_TYPE_DOMAIN) && fmd->domain) { - /* keep branch saves if possible */ - if (!fmd->domain->flame_max_temp) { - fmd->domain->burning_rate = 0.75f; - fmd->domain->flame_smoke = 1.0f; - fmd->domain->flame_vorticity = 0.5f; - fmd->domain->flame_ignition = 1.25f; - fmd->domain->flame_max_temp = 1.75f; - fmd->domain->adapt_threshold = 0.02f; - fmd->domain->adapt_margin = 4; - fmd->domain->flame_smoke_color[0] = 0.7f; - fmd->domain->flame_smoke_color[1] = 0.7f; - fmd->domain->flame_smoke_color[2] = 0.7f; - } - } - else if ((fmd->type & MOD_FLUID_TYPE_FLOW) && fmd->flow) { - if (!fmd->flow->texture_size) { - fmd->flow->fuel_amount = 1.0; - fmd->flow->surface_distance = 1.5; - fmd->flow->color[0] = 0.7f; - fmd->flow->color[1] = 0.7f; - fmd->flow->color[2] = 0.7f; - fmd->flow->texture_size = 1.0f; - } - } - } - } - } +if (!MAIN_VERSION_ATLEAST(bmain, 264, 3)) { + /* smoke branch */ + {LISTBASE_FOREACH (Object *, ob, &bmain->objects){ + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers){ + if (md->type == eModifierType_Fluid){FluidModifierData *fmd = (FluidModifierData *)md; + if ((fmd->type & MOD_FLUID_TYPE_DOMAIN) && fmd->domain) { + /* keep branch saves if possible */ + if (!fmd->domain->flame_max_temp) { + fmd->domain->burning_rate = 0.75f; + fmd->domain->flame_smoke = 1.0f; + fmd->domain->flame_vorticity = 0.5f; + fmd->domain->flame_ignition = 1.25f; + fmd->domain->flame_max_temp = 1.75f; + fmd->domain->adapt_threshold = 0.02f; + fmd->domain->adapt_margin = 4; + fmd->domain->flame_smoke_color[0] = 0.7f; + fmd->domain->flame_smoke_color[1] = 0.7f; + fmd->domain->flame_smoke_color[2] = 0.7f; + } + } + else if ((fmd->type & MOD_FLUID_TYPE_FLOW) && fmd->flow) { + if (!fmd->flow->texture_size) { + fmd->flow->fuel_amount = 1.0; + fmd->flow->surface_distance = 1.5; + fmd->flow->color[0] = 0.7f; + fmd->flow->color[1] = 0.7f; + fmd->flow->color[2] = 0.7f; + fmd->flow->texture_size = 1.0f; } + } +} +} +} +} - /* render border for viewport */ - { - bScreen *screen; - - for (screen = bmain->screens.first; screen; screen = screen->id.next) { - ScrArea *area; - for (area = screen->areabase.first; area; area = area->next) { - SpaceLink *sl; - for (sl = area->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_VIEW3D) { - View3D *v3d = (View3D *)sl; - if (v3d->render_border.xmin == 0.0f && v3d->render_border.ymin == 0.0f && - v3d->render_border.xmax == 0.0f && v3d->render_border.ymax == 0.0f) - { - v3d->render_border.xmax = 1.0f; - v3d->render_border.ymax = 1.0f; - } - } +/* render border for viewport */ +{ + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + if (v3d->render_border.xmin == 0.0f && v3d->render_border.ymin == 0.0f && + v3d->render_border.xmax == 0.0f && v3d->render_border.ymax == 0.0f) + { + v3d->render_border.xmax = 1.0f; + v3d->render_border.ymax = 1.0f; } } } } } +} +} - if (!MAIN_VERSION_ATLEAST(bmain, 264, 5)) { - /* set a unwrapping margin and ABF by default */ - Scene *scene; - - for (scene = bmain->scenes.first; scene; scene = scene->id.next) { - if (scene->toolsettings->uvcalc_margin == 0.0f) { - scene->toolsettings->uvcalc_margin = 0.001f; - scene->toolsettings->unwrapper = 0; - } +if (!MAIN_VERSION_ATLEAST(bmain, 264, 5)) { + /* set a unwrapping margin and ABF by default */ + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->toolsettings->uvcalc_margin == 0.0f) { + scene->toolsettings->uvcalc_margin = 0.001f; + scene->toolsettings->unwrapper = 0; } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 264, 7)) { - /* convert tiles size from resolution and number of tiles */ - { - Scene *scene; +if (!MAIN_VERSION_ATLEAST(bmain, 264, 7)) { + /* convert tiles size from resolution and number of tiles */ + {LISTBASE_FOREACH (Scene *, scene, &bmain->scenes){ + if (scene->r.tilex == 0 || scene->r.tiley == 1){scene->r.tilex = scene->r.tiley = 64; +} +} +} - for (scene = bmain->scenes.first; scene; scene = scene->id.next) { - if (scene->r.tilex == 0 || scene->r.tiley == 1) { - scene->r.tilex = scene->r.tiley = 64; - } - } +/* collision masks */ +{ + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + if (ob->col_group == 0) { + ob->col_group = 0x01; + ob->col_mask = 0xff; } + } +} +} - /* collision masks */ - { - Object *ob; - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - if (ob->col_group == 0) { - ob->col_group = 0x01; - ob->col_mask = 0xff; - } - } +if (!MAIN_VERSION_ATLEAST(bmain, 264, 7)) { + LISTBASE_FOREACH (MovieClip *, clip, &bmain->movieclips) { + LISTBASE_FOREACH (MovieTrackingTrack *, track, &clip->tracking.tracks_legacy) { + do_versions_affine_tracker_track(track); } - } - if (!MAIN_VERSION_ATLEAST(bmain, 264, 7)) { - LISTBASE_FOREACH (MovieClip *, clip, &bmain->movieclips) { - LISTBASE_FOREACH (MovieTrackingTrack *, track, &clip->tracking.tracks_legacy) { + LISTBASE_FOREACH (MovieTrackingObject *, tracking_object, &clip->tracking.objects) { + LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) { do_versions_affine_tracker_track(track); } - - LISTBASE_FOREACH (MovieTrackingObject *, tracking_object, &clip->tracking.objects) { - LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) { - do_versions_affine_tracker_track(track); - } - } } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 265, 3)) { - bScreen *screen; - for (screen = bmain->screens.first; screen; screen = screen->id.next) { - ScrArea *area; - for (area = screen->areabase.first; area; area = area->next) { - SpaceLink *sl; - for (sl = area->spacedata.first; sl; sl = sl->next) { - switch (sl->spacetype) { - case SPACE_VIEW3D: { - View3D *v3d = (View3D *)sl; - v3d->flag2 |= V3D_SHOW_ANNOTATION; - break; - } - case SPACE_SEQ: { - SpaceSeq *sseq = (SpaceSeq *)sl; - sseq->flag |= SEQ_PREVIEW_SHOW_GPENCIL; - break; - } - case SPACE_IMAGE: { - SpaceImage *sima = (SpaceImage *)sl; - sima->flag |= SI_SHOW_GPENCIL; - break; - } - case SPACE_NODE: { - SpaceNode *snode = (SpaceNode *)sl; - snode->flag |= SNODE_SHOW_GPENCIL; - break; - } - case SPACE_CLIP: { - SpaceClip *sclip = (SpaceClip *)sl; - sclip->flag |= SC_SHOW_ANNOTATION; - break; - } +if (!MAIN_VERSION_ATLEAST(bmain, 265, 3)) { + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + switch (sl->spacetype) { + case SPACE_VIEW3D: { + View3D *v3d = (View3D *)sl; + v3d->flag2 |= V3D_SHOW_ANNOTATION; + break; + } + case SPACE_SEQ: { + SpaceSeq *sseq = (SpaceSeq *)sl; + sseq->flag |= SEQ_PREVIEW_SHOW_GPENCIL; + break; + } + case SPACE_IMAGE: { + SpaceImage *sima = (SpaceImage *)sl; + sima->flag |= SI_SHOW_GPENCIL; + break; + } + case SPACE_NODE: { + SpaceNode *snode = (SpaceNode *)sl; + snode->flag |= SNODE_SHOW_GPENCIL; + break; + } + case SPACE_CLIP: { + SpaceClip *sclip = (SpaceClip *)sl; + sclip->flag |= SC_SHOW_ANNOTATION; + break; } } } } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 265, 5)) { - Scene *scene; - Tex *tex; - - for (scene = bmain->scenes.first; scene; scene = scene->id.next) { - if (scene->ed) { - SEQ_for_each_callback(&scene->ed->seqbase, seq_set_alpha_mode_cb, NULL); - } +if (!MAIN_VERSION_ATLEAST(bmain, 265, 5)) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->ed) { + SEQ_for_each_callback(&scene->ed->seqbase, seq_set_alpha_mode_cb, NULL); + } - if (scene->r.bake_samples == 0) { - scene->r.bake_samples = 256; - } + if (scene->r.bake_samples == 0) { + scene->r.bake_samples = 256; } + } - for (Image *image = bmain->images.first; image; image = image->id.next) { - if (image->flag & IMA_DO_PREMUL) { - image->alpha_mode = IMA_ALPHA_STRAIGHT; - } - else { - BKE_image_alpha_mode_from_extension(image); - } + LISTBASE_FOREACH (Image *, image, &bmain->images) { + if (image->flag & IMA_DO_PREMUL) { + image->alpha_mode = IMA_ALPHA_STRAIGHT; + } + else { + BKE_image_alpha_mode_from_extension(image); } + } - for (tex = bmain->textures.first; tex; tex = tex->id.next) { - if (tex->type == TEX_IMAGE && (tex->imaflag & TEX_USEALPHA) == 0) { - Image *image = blo_do_versions_newlibadr(fd, &tex->id, ID_IS_LINKED(tex), tex->ima); + LISTBASE_FOREACH (Tex *, tex, &bmain->textures) { + if (tex->type == TEX_IMAGE && (tex->imaflag & TEX_USEALPHA) == 0) { + Image *image = blo_do_versions_newlibadr(fd, &tex->id, ID_IS_LINKED(tex), tex->ima); - if (image && (image->flag & IMA_DO_PREMUL) == 0) { - enum { IMA_IGNORE_ALPHA = (1 << 12) }; - image->flag |= IMA_IGNORE_ALPHA; - } + if (image && (image->flag & IMA_DO_PREMUL) == 0) { + enum { IMA_IGNORE_ALPHA = (1 << 12) }; + image->flag |= IMA_IGNORE_ALPHA; } } + } - FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - if (ntree->type == NTREE_COMPOSIT) { - bNode *node; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == CMP_NODE_IMAGE) { - Image *image = blo_do_versions_newlibadr( - fd, &ntree->id, ID_IS_LINKED(ntree), node->id); - - if (image) { - if ((image->flag & IMA_DO_PREMUL) == 0 && image->alpha_mode == IMA_ALPHA_STRAIGHT) { - node->custom1 |= CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT; - } + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_COMPOSIT) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == CMP_NODE_IMAGE) { + Image *image = blo_do_versions_newlibadr(fd, &ntree->id, ID_IS_LINKED(ntree), node->id); + + if (image) { + if ((image->flag & IMA_DO_PREMUL) == 0 && image->alpha_mode == IMA_ALPHA_STRAIGHT) { + node->custom1 |= CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT; } } } } } - FOREACH_NODETREE_END; } - else if (!MAIN_VERSION_ATLEAST(bmain, 266, 1)) { - /* texture use alpha was removed for 2.66 but added back again for 2.66a, - * for compatibility all textures assumed it to be enabled */ - Tex *tex; - - for (tex = bmain->textures.first; tex; tex = tex->id.next) { - if (tex->type == TEX_IMAGE) { - tex->imaflag |= TEX_USEALPHA; - } + FOREACH_NODETREE_END; +} +else if (!MAIN_VERSION_ATLEAST(bmain, 266, 1)) { + /* texture use alpha was removed for 2.66 but added back again for 2.66a, + * for compatibility all textures assumed it to be enabled */ + LISTBASE_FOREACH (Tex *, tex, &bmain->textures) { + if (tex->type == TEX_IMAGE) { + tex->imaflag |= TEX_USEALPHA; } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 265, 7)) { - Curve *cu; - - for (cu = bmain->curves.first; cu; cu = cu->id.next) { - if (cu->flag & (CU_FRONT | CU_BACK)) { - if (cu->extrude != 0.0f || cu->bevel_radius != 0.0f) { - Nurb *nu; - - for (nu = cu->nurb.first; nu; nu = nu->next) { - int a; +if (!MAIN_VERSION_ATLEAST(bmain, 265, 7)) { + LISTBASE_FOREACH (Curve *, cu, &bmain->curves) { + if (cu->flag & (CU_FRONT | CU_BACK)) { + if (cu->extrude != 0.0f || cu->bevel_radius != 0.0f) { + LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) { + int a; - if (nu->bezt) { - BezTriple *bezt = nu->bezt; - a = nu->pntsu; + if (nu->bezt) { + BezTriple *bezt = nu->bezt; + a = nu->pntsu; - while (a--) { - bezt->radius = 1.0f; - bezt++; - } + while (a--) { + bezt->radius = 1.0f; + bezt++; } - else if (nu->bp) { - BPoint *bp = nu->bp; - a = nu->pntsu * nu->pntsv; + } + else if (nu->bp) { + BPoint *bp = nu->bp; + a = nu->pntsu * nu->pntsv; - while (a--) { - bp->radius = 1.0f; - bp++; - } + while (a--) { + bp->radius = 1.0f; + bp++; } } } } } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 265, 9)) { - Mesh *me; - for (me = bmain->meshes.first; me; me = me->id.next) { - BKE_mesh_do_versions_cd_flag_init(me); - } +if (!MAIN_VERSION_ATLEAST(bmain, 265, 9)) { + LISTBASE_FOREACH (Mesh *, me, &bmain->meshes) { + BKE_mesh_do_versions_cd_flag_init(me); } +} - if (!MAIN_VERSION_ATLEAST(bmain, 265, 10)) { - Brush *br; - for (br = bmain->brushes.first; br; br = br->id.next) { - if (br->ob_mode & OB_MODE_TEXTURE_PAINT) { - br->mtex.brush_map_mode = MTEX_MAP_MODE_TILED; - } +if (!MAIN_VERSION_ATLEAST(bmain, 265, 10)) { + LISTBASE_FOREACH (Brush *, br, &bmain->brushes) { + if (br->ob_mode & OB_MODE_TEXTURE_PAINT) { + br->mtex.brush_map_mode = MTEX_MAP_MODE_TILED; } } +} - /* add storage for compositor translate nodes when not existing */ - if (!MAIN_VERSION_ATLEAST(bmain, 265, 11)) { - FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - if (ntree->type == NTREE_COMPOSIT) { - bNode *node; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == CMP_NODE_TRANSLATE && node->storage == NULL) { - node->storage = MEM_callocN(sizeof(NodeTranslateData), "node translate data"); - } +/* add storage for compositor translate nodes when not existing */ +if (!MAIN_VERSION_ATLEAST(bmain, 265, 11)) { + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_COMPOSIT) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == CMP_NODE_TRANSLATE && node->storage == NULL) { + node->storage = MEM_callocN(sizeof(NodeTranslateData), "node translate data"); } } } - FOREACH_NODETREE_END; } + FOREACH_NODETREE_END; +} - if (!MAIN_VERSION_ATLEAST(bmain, 266, 2)) { - FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - do_versions_nodetree_customnodes(ntree, ((ID *)ntree == id)); - } - FOREACH_NODETREE_END; +if (!MAIN_VERSION_ATLEAST(bmain, 266, 2)) { + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + do_versions_nodetree_customnodes(ntree, ((ID *)ntree == id)); } + FOREACH_NODETREE_END; +} - if (!MAIN_VERSION_ATLEAST(bmain, 266, 2)) { - bScreen *screen; - for (screen = bmain->screens.first; screen; screen = screen->id.next) { - ScrArea *area; - for (area = screen->areabase.first; area; area = area->next) { - SpaceLink *sl; - for (sl = area->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_NODE) { - SpaceNode *snode = (SpaceNode *)sl; - - /* reset pointers to force tree path update from context */ - snode->nodetree = NULL; - snode->edittree = NULL; - snode->id = NULL; - snode->from = NULL; - - /* convert deprecated treetype setting to tree_idname */ - switch (snode->treetype) { - case NTREE_COMPOSIT: - STRNCPY(snode->tree_idname, "CompositorNodeTree"); - break; - case NTREE_SHADER: - STRNCPY(snode->tree_idname, "ShaderNodeTree"); - break; - case NTREE_TEXTURE: - STRNCPY(snode->tree_idname, "TextureNodeTree"); - break; - } +if (!MAIN_VERSION_ATLEAST(bmain, 266, 2)) { + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (sl->spacetype == SPACE_NODE) { + SpaceNode *snode = (SpaceNode *)sl; + + /* reset pointers to force tree path update from context */ + snode->nodetree = NULL; + snode->edittree = NULL; + snode->id = NULL; + snode->from = NULL; + + /* convert deprecated treetype setting to tree_idname */ + switch (snode->treetype) { + case NTREE_COMPOSIT: + STRNCPY(snode->tree_idname, "CompositorNodeTree"); + break; + case NTREE_SHADER: + STRNCPY(snode->tree_idname, "ShaderNodeTree"); + break; + case NTREE_TEXTURE: + STRNCPY(snode->tree_idname, "TextureNodeTree"); + break; } } } } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 266, 3)) { - { - /* Fix for a very old issue: - * Node names were nominally made unique in r24478 (2.50.8), but the do_versions check - * to update existing node names only applied to bmain->nodetree (i.e. group nodes). - * Uniqueness is now required for proper preview mapping, - * so do this now to ensure old files don't break. - */ - bNode *node; - FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - if (id == &ntree->id) { - continue; /* already fixed for node groups */ - } +if (!MAIN_VERSION_ATLEAST(bmain, 266, 3)) { + { + /* Fix for a very old issue: + * Node names were nominally made unique in r24478 (2.50.8), but the do_versions check + * to update existing node names only applied to bmain->nodetree (i.e. group nodes). + * Uniqueness is now required for proper preview mapping, + * so do this now to ensure old files don't break. + */ + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (id == &ntree->id) { + continue; /* already fixed for node groups */ + } - for (node = ntree->nodes.first; node; node = node->next) { - nodeUniqueName(ntree, node); - } + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + nodeUniqueName(ntree, node); } - FOREACH_NODETREE_END; } + FOREACH_NODETREE_END; } +} - if (!MAIN_VERSION_ATLEAST(bmain, 266, 4)) { - Brush *brush; - for (brush = bmain->brushes.first; brush; brush = brush->id.next) { - BKE_texture_mtex_default(&brush->mask_mtex); +if (!MAIN_VERSION_ATLEAST(bmain, 266, 4)) { + LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { + BKE_texture_mtex_default(&brush->mask_mtex); - if (brush->ob_mode & OB_MODE_TEXTURE_PAINT) { - brush->spacing /= 2; - } + if (brush->ob_mode & OB_MODE_TEXTURE_PAINT) { + brush->spacing /= 2; } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 266, 6)) { - Brush *brush; +if (!MAIN_VERSION_ATLEAST(bmain, 266, 6)) { #define BRUSH_TEXTURE_OVERLAY (1 << 21) - for (brush = bmain->brushes.first; brush; brush = brush->id.next) { - brush->overlay_flags = 0; - if (brush->flag & BRUSH_TEXTURE_OVERLAY) { - brush->overlay_flags |= (BRUSH_OVERLAY_PRIMARY | BRUSH_OVERLAY_CURSOR); - } + LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { + brush->overlay_flags = 0; + if (brush->flag & BRUSH_TEXTURE_OVERLAY) { + brush->overlay_flags |= (BRUSH_OVERLAY_PRIMARY | BRUSH_OVERLAY_CURSOR); } -#undef BRUSH_TEXTURE_OVERLAY } +#undef BRUSH_TEXTURE_OVERLAY +} - if (bmain->versionfile < 267) { - // if (!DNA_struct_elem_find(fd->filesdna, "Brush", "int", "stencil_pos")) { - Brush *brush; - - for (brush = bmain->brushes.first; brush; brush = brush->id.next) { - if (brush->stencil_dimension[0] == 0) { - brush->stencil_dimension[0] = 256; - brush->stencil_dimension[1] = 256; - brush->stencil_pos[0] = 256; - brush->stencil_pos[1] = 256; - } - if (brush->mask_stencil_dimension[0] == 0) { - brush->mask_stencil_dimension[0] = 256; - brush->mask_stencil_dimension[1] = 256; - brush->mask_stencil_pos[0] = 256; - brush->mask_stencil_pos[1] = 256; - } +if (bmain->versionfile < 267) { + // if (!DNA_struct_elem_find(fd->filesdna, "Brush", "int", "stencil_pos")) { + LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { + if (brush->stencil_dimension[0] == 0) { + brush->stencil_dimension[0] = 256; + brush->stencil_dimension[1] = 256; + brush->stencil_pos[0] = 256; + brush->stencil_pos[1] = 256; + } + if (brush->mask_stencil_dimension[0] == 0) { + brush->mask_stencil_dimension[0] = 256; + brush->mask_stencil_dimension[1] = 256; + brush->mask_stencil_pos[0] = 256; + brush->mask_stencil_pos[1] = 256; } - - /* TIP: to initialize new variables added, use the new function - * DNA_struct_elem_find(fd->filesdna, "structname", "typename", "varname") - * example: - * if (!DNA_struct_elem_find(fd->filesdna, "UserDef", "short", "image_gpubuffer_limit")) - * user->image_gpubuffer_limit = 10; - */ } - /* default values in Freestyle settings */ - if (bmain->versionfile < 267) { - Scene *sce; - SceneRenderLayer *srl; - FreestyleLineStyle *linestyle; + /* TIP: to initialize new variables added, use the new function + * DNA_struct_elem_find(fd->filesdna, "structname", "typename", "varname") + * example: + * if (!DNA_struct_elem_find(fd->filesdna, "UserDef", "short", "image_gpubuffer_limit")) + * user->image_gpubuffer_limit = 10; + */ +} - for (sce = bmain->scenes.first; sce; sce = sce->id.next) { - if (sce->r.line_thickness_mode == 0) { - sce->r.line_thickness_mode = R_LINE_THICKNESS_ABSOLUTE; - sce->r.unit_line_thickness = 1.0f; +/* default values in Freestyle settings */ +if (bmain->versionfile < 267) { + LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) { + if (sce->r.line_thickness_mode == 0) { + sce->r.line_thickness_mode = R_LINE_THICKNESS_ABSOLUTE; + sce->r.unit_line_thickness = 1.0f; + } + LISTBASE_FOREACH (SceneRenderLayer *, srl, &sce->r.layers) { + if (srl->freestyleConfig.mode == 0) { + srl->freestyleConfig.mode = FREESTYLE_CONTROL_EDITOR_MODE; } - for (srl = sce->r.layers.first; srl; srl = srl->next) { - if (srl->freestyleConfig.mode == 0) { - srl->freestyleConfig.mode = FREESTYLE_CONTROL_EDITOR_MODE; - } - if (ELEM(srl->freestyleConfig.raycasting_algorithm, - FREESTYLE_ALGO_CULLED_ADAPTIVE_CUMULATIVE, - FREESTYLE_ALGO_CULLED_ADAPTIVE_TRADITIONAL)) - { - srl->freestyleConfig.raycasting_algorithm = 0; /* deprecated */ - srl->freestyleConfig.flags |= FREESTYLE_CULLING; - } + if (ELEM(srl->freestyleConfig.raycasting_algorithm, + FREESTYLE_ALGO_CULLED_ADAPTIVE_CUMULATIVE, + FREESTYLE_ALGO_CULLED_ADAPTIVE_TRADITIONAL)) + { + srl->freestyleConfig.raycasting_algorithm = 0; /* deprecated */ + srl->freestyleConfig.flags |= FREESTYLE_CULLING; } + } - /* not freestyle */ - { - MeshStatVis *statvis = &sce->toolsettings->statvis; - if (statvis->thickness_samples == 0) { - statvis->overhang_axis = OB_NEGZ; - statvis->overhang_min = 0; - statvis->overhang_max = DEG2RADF(45.0f); + /* not freestyle */ + { + MeshStatVis *statvis = &sce->toolsettings->statvis; + if (statvis->thickness_samples == 0) { + statvis->overhang_axis = OB_NEGZ; + statvis->overhang_min = 0; + statvis->overhang_max = DEG2RADF(45.0f); - statvis->thickness_max = 0.1f; - statvis->thickness_samples = 1; + statvis->thickness_max = 0.1f; + statvis->thickness_samples = 1; - statvis->distort_min = DEG2RADF(5.0f); - statvis->distort_max = DEG2RADF(45.0f); + statvis->distort_min = DEG2RADF(5.0f); + statvis->distort_max = DEG2RADF(45.0f); - statvis->sharp_min = DEG2RADF(90.0f); - statvis->sharp_max = DEG2RADF(180.0f); - } + statvis->sharp_min = DEG2RADF(90.0f); + statvis->sharp_max = DEG2RADF(180.0f); } } - for (linestyle = bmain->linestyles.first; linestyle; linestyle = linestyle->id.next) { + } + LISTBASE_FOREACH (FreestyleLineStyle *, linestyle, &bmain->linestyles) { #if 1 - /* disable the Misc panel for now */ - if (linestyle->panel == LS_PANEL_MISC) { - linestyle->panel = LS_PANEL_STROKES; - } + /* disable the Misc panel for now */ + if (linestyle->panel == LS_PANEL_MISC) { + linestyle->panel = LS_PANEL_STROKES; + } #endif - if (linestyle->thickness_position == 0) { - linestyle->thickness_position = LS_THICKNESS_CENTER; - linestyle->thickness_ratio = 0.5f; - } - if (linestyle->chaining == 0) { - linestyle->chaining = LS_CHAINING_PLAIN; - } - if (linestyle->rounds == 0) { - linestyle->rounds = 3; - } + if (linestyle->thickness_position == 0) { + linestyle->thickness_position = LS_THICKNESS_CENTER; + linestyle->thickness_ratio = 0.5f; + } + if (linestyle->chaining == 0) { + linestyle->chaining = LS_CHAINING_PLAIN; + } + if (linestyle->rounds == 0) { + linestyle->rounds = 3; } } +} - if (bmain->versionfile < 267) { - /* Initialize the active_viewer_key for compositing */ - bScreen *screen; - Scene *scene; - bNodeInstanceKey active_viewer_key = {0}; - /* simply pick the first node space and use that for the active viewer key */ - for (screen = bmain->screens.first; screen; screen = screen->id.next) { - ScrArea *area; - for (area = screen->areabase.first; area; area = area->next) { - SpaceLink *sl; - for (sl = area->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_NODE) { - SpaceNode *snode = (SpaceNode *)sl; - bNodeTreePath *path = snode->treepath.last; - if (!path) { - continue; - } - - active_viewer_key = path->parent_key; - break; +if (bmain->versionfile < 267) { + /* Initialize the active_viewer_key for compositing */ + bNodeInstanceKey active_viewer_key = {0}; + /* simply pick the first node space and use that for the active viewer key */ + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (sl->spacetype == SPACE_NODE) { + SpaceNode *snode = (SpaceNode *)sl; + bNodeTreePath *path = snode->treepath.last; + if (!path) { + continue; } - } - if (active_viewer_key.value != 0) { + + active_viewer_key = path->parent_key; break; } } @@ -2151,429 +1919,384 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain) break; } } - - for (scene = bmain->scenes.first; scene; scene = scene->id.next) { - /* NOTE: `scene->nodetree` is a local ID block, has been direct_link'ed. */ - if (scene->nodetree) { - scene->nodetree->active_viewer_key = active_viewer_key; - } + if (active_viewer_key.value != 0) { + break; } } - if (!MAIN_VERSION_ATLEAST(bmain, 267, 1)) { - Object *ob; + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + /* NOTE: `scene->nodetree` is a local ID block, has been direct_link'ed. */ + if (scene->nodetree) { + scene->nodetree->active_viewer_key = active_viewer_key; + } + } +} - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - ModifierData *md; - for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Fluid) { - FluidModifierData *fmd = (FluidModifierData *)md; - if ((fmd->type & MOD_FLUID_TYPE_DOMAIN) && fmd->domain) { - if (fmd->domain->flags & FLUID_DOMAIN_USE_HIGH_SMOOTH) { - fmd->domain->highres_sampling = SM_HRES_LINEAR; - } - else { - fmd->domain->highres_sampling = SM_HRES_NEAREST; - } +if (!MAIN_VERSION_ATLEAST(bmain, 267, 1)) { + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_Fluid) { + FluidModifierData *fmd = (FluidModifierData *)md; + if ((fmd->type & MOD_FLUID_TYPE_DOMAIN) && fmd->domain) { + if (fmd->domain->flags & FLUID_DOMAIN_USE_HIGH_SMOOTH) { + fmd->domain->highres_sampling = SM_HRES_LINEAR; + } + else { + fmd->domain->highres_sampling = SM_HRES_NEAREST; } } } } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 268, 1)) { - Brush *brush; - for (brush = bmain->brushes.first; brush; brush = brush->id.next) { - brush->spacing = MAX2(1, brush->spacing); - } +if (!MAIN_VERSION_ATLEAST(bmain, 268, 1)) { + LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { + brush->spacing = MAX2(1, brush->spacing); } +} - if (!MAIN_VERSION_ATLEAST(bmain, 268, 2)) { - Brush *brush; +if (!MAIN_VERSION_ATLEAST(bmain, 268, 2)) { #define BRUSH_FIXED (1 << 6) - for (brush = bmain->brushes.first; brush; brush = brush->id.next) { - brush->flag &= ~BRUSH_FIXED; + LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { + brush->flag &= ~BRUSH_FIXED; - if (brush->cursor_overlay_alpha < 2) { - brush->cursor_overlay_alpha = 33; - } - if (brush->texture_overlay_alpha < 2) { - brush->texture_overlay_alpha = 33; - } - if (brush->mask_overlay_alpha < 2) { - brush->mask_overlay_alpha = 33; - } + if (brush->cursor_overlay_alpha < 2) { + brush->cursor_overlay_alpha = 33; + } + if (brush->texture_overlay_alpha < 2) { + brush->texture_overlay_alpha = 33; + } + if (brush->mask_overlay_alpha < 2) { + brush->mask_overlay_alpha = 33; } -#undef BRUSH_FIXED } +#undef BRUSH_FIXED +} - if (!MAIN_VERSION_ATLEAST(bmain, 268, 4)) { - bScreen *screen; - Object *ob; - - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - bConstraint *con; - for (con = ob->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_SHRINKWRAP) { - bShrinkwrapConstraint *data = (bShrinkwrapConstraint *)con->data; - if (data->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS) { - data->projAxis = OB_POSX; - } - else if (data->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS) { - data->projAxis = OB_POSY; - } - else { - data->projAxis = OB_POSZ; - } - data->projAxisSpace = CONSTRAINT_SPACE_LOCAL; +if (!MAIN_VERSION_ATLEAST(bmain, 268, 4)) { + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (bConstraint *, con, &ob->constraints) { + if (con->type == CONSTRAINT_TYPE_SHRINKWRAP) { + bShrinkwrapConstraint *data = con->data; + if (data->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS) { + data->projAxis = OB_POSX; + } + else if (data->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS) { + data->projAxis = OB_POSY; } + else { + data->projAxis = OB_POSZ; + } + data->projAxisSpace = CONSTRAINT_SPACE_LOCAL; } } + } - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - ModifierData *md; - for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Fluid) { - FluidModifierData *fmd = (FluidModifierData *)md; - if ((fmd->type & MOD_FLUID_TYPE_FLOW) && fmd->flow) { - if (!fmd->flow->particle_size) { - fmd->flow->particle_size = 1.0f; - } + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_Fluid) { + FluidModifierData *fmd = (FluidModifierData *)md; + if ((fmd->type & MOD_FLUID_TYPE_FLOW) && fmd->flow) { + if (!fmd->flow->particle_size) { + fmd->flow->particle_size = 1.0f; } } } } + } - /* - * FIX some files have a zoom level of 0, and was checked during the drawing of the node space - * - * We moved this check to the do versions to be sure the value makes any sense. - */ - for (screen = bmain->screens.first; screen; screen = screen->id.next) { - ScrArea *area; - for (area = screen->areabase.first; area; area = area->next) { - SpaceLink *sl; - for (sl = area->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_NODE) { - SpaceNode *snode = (SpaceNode *)sl; - if (snode->zoom < 0.02f) { - snode->zoom = 1.0; - } + /* + * FIX some files have a zoom level of 0, and was checked during the drawing of the node space + * + * We moved this check to the do versions to be sure the value makes any sense. + */ + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (sl->spacetype == SPACE_NODE) { + SpaceNode *snode = (SpaceNode *)sl; + if (snode->zoom < 0.02f) { + snode->zoom = 1.0; } } } } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 268, 5)) { - bScreen *screen; - ScrArea *area; - - /* add missing (+) expander in node editor */ - for (screen = bmain->screens.first; screen; screen = screen->id.next) { - for (area = screen->areabase.first; area; area = area->next) { - ARegion *region, *arnew; - - if (area->spacetype == SPACE_NODE) { - region = BKE_area_find_region_type(area, RGN_TYPE_TOOLS); +if (!MAIN_VERSION_ATLEAST(bmain, 268, 5)) { + /* add missing (+) expander in node editor */ + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + if (area->spacetype == SPACE_NODE) { + ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_TOOLS); - if (region) { - continue; - } + if (region) { + continue; + } - /* add subdiv level; after header */ - region = BKE_area_find_region_type(area, RGN_TYPE_HEADER); + /* add subdiv level; after header */ + region = BKE_area_find_region_type(area, RGN_TYPE_HEADER); - /* is error! */ - if (region == NULL) { - continue; - } + /* is error! */ + if (region == NULL) { + continue; + } - arnew = MEM_callocN(sizeof(ARegion), "node tools"); + ARegion *arnew = MEM_callocN(sizeof(ARegion), "node tools"); - BLI_insertlinkafter(&area->regionbase, region, arnew); - arnew->regiontype = RGN_TYPE_TOOLS; - arnew->alignment = RGN_ALIGN_LEFT; + BLI_insertlinkafter(&area->regionbase, region, arnew); + arnew->regiontype = RGN_TYPE_TOOLS; + arnew->alignment = RGN_ALIGN_LEFT; - arnew->flag = RGN_FLAG_HIDDEN; - } + arnew->flag = RGN_FLAG_HIDDEN; } } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 269, 1)) { - /* Removal of Cycles SSS Compatible falloff */ - FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - if (ntree->type == NTREE_SHADER) { - bNode *node; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == SH_NODE_SUBSURFACE_SCATTERING) { - if (node->custom1 == SHD_SUBSURFACE_COMPATIBLE) { - node->custom1 = SHD_SUBSURFACE_CUBIC; - } +if (!MAIN_VERSION_ATLEAST(bmain, 269, 1)) { + /* Removal of Cycles SSS Compatible falloff */ + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_SHADER) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == SH_NODE_SUBSURFACE_SCATTERING) { + if (node->custom1 == SHD_SUBSURFACE_COMPATIBLE) { + node->custom1 = SHD_SUBSURFACE_CUBIC; } } } } - FOREACH_NODETREE_END; } + FOREACH_NODETREE_END; +} - if (!MAIN_VERSION_ATLEAST(bmain, 269, 2)) { - /* Initialize CDL settings for Color Balance nodes */ - FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - if (ntree->type == NTREE_COMPOSIT) { - bNode *node; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == CMP_NODE_COLORBALANCE) { - NodeColorBalance *n = node->storage; - if (node->custom1 == 0) { - /* LGG mode stays the same, just init CDL settings */ - ntreeCompositColorBalanceSyncFromLGG(ntree, node); - } - else if (node->custom1 == 1) { - /* CDL previously used same variables as LGG, copy them over - * and then sync LGG for comparable results in both modes. - */ - copy_v3_v3(n->offset, n->lift); - copy_v3_v3(n->power, n->gamma); - copy_v3_v3(n->slope, n->gain); - ntreeCompositColorBalanceSyncFromCDL(ntree, node); - } +if (!MAIN_VERSION_ATLEAST(bmain, 269, 2)) { + /* Initialize CDL settings for Color Balance nodes */ + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_COMPOSIT) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == CMP_NODE_COLORBALANCE) { + NodeColorBalance *n = node->storage; + if (node->custom1 == 0) { + /* LGG mode stays the same, just init CDL settings */ + ntreeCompositColorBalanceSyncFromLGG(ntree, node); + } + else if (node->custom1 == 1) { + /* CDL previously used same variables as LGG, copy them over + * and then sync LGG for comparable results in both modes. + */ + copy_v3_v3(n->offset, n->lift); + copy_v3_v3(n->power, n->gamma); + copy_v3_v3(n->slope, n->gain); + ntreeCompositColorBalanceSyncFromCDL(ntree, node); } } } } - FOREACH_NODETREE_END; } + FOREACH_NODETREE_END; +} - if (!MAIN_VERSION_ATLEAST(bmain, 269, 3)) { - bScreen *screen; - ScrArea *area; - SpaceLink *sl; - Scene *scene; - - /* Update files using invalid (outdated) outlinevis Outliner values. */ - for (screen = bmain->screens.first; screen; screen = screen->id.next) { - for (area = screen->areabase.first; area; area = area->next) { - for (sl = area->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_OUTLINER) { - SpaceOutliner *space_outliner = (SpaceOutliner *)sl; +if (!MAIN_VERSION_ATLEAST(bmain, 269, 3)) { + /* Update files using invalid (outdated) outlinevis Outliner values. */ + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (sl->spacetype == SPACE_OUTLINER) { + SpaceOutliner *space_outliner = (SpaceOutliner *)sl; - if (!ELEM( - space_outliner->outlinevis, SO_SCENES, SO_LIBRARIES, SO_SEQUENCE, SO_DATA_API)) - { - space_outliner->outlinevis = SO_SCENES; - } + if (!ELEM(space_outliner->outlinevis, SO_SCENES, SO_LIBRARIES, SO_SEQUENCE, SO_DATA_API)) + { + space_outliner->outlinevis = SO_SCENES; } } } } + } - if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingTrack", "float", "weight")) { - LISTBASE_FOREACH (MovieClip *, clip, &bmain->movieclips) { - const MovieTracking *tracking = &clip->tracking; - LISTBASE_FOREACH (MovieTrackingObject *, tracking_object, &tracking->objects) { - const ListBase *tracksbase = (tracking_object->flag & TRACKING_OBJECT_CAMERA) ? - &tracking->tracks_legacy : - &tracking_object->tracks; - LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) { - track->weight = 1.0f; - } + if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingTrack", "float", "weight")) { + LISTBASE_FOREACH (MovieClip *, clip, &bmain->movieclips) { + const MovieTracking *tracking = &clip->tracking; + LISTBASE_FOREACH (MovieTrackingObject *, tracking_object, &tracking->objects) { + const ListBase *tracksbase = (tracking_object->flag & TRACKING_OBJECT_CAMERA) ? + &tracking->tracks_legacy : + &tracking_object->tracks; + LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) { + track->weight = 1.0f; } } } + } - if (!DNA_struct_elem_find(fd->filesdna, "TriangulateModifierData", "int", "quad_method")) { - Object *ob; - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - ModifierData *md; - for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Triangulate) { - TriangulateModifierData *tmd = (TriangulateModifierData *)md; - if (tmd->flag & MOD_TRIANGULATE_BEAUTY) { - tmd->quad_method = MOD_TRIANGULATE_QUAD_BEAUTY; - tmd->ngon_method = MOD_TRIANGULATE_NGON_BEAUTY; - } - else { - tmd->quad_method = MOD_TRIANGULATE_QUAD_FIXED; - tmd->ngon_method = MOD_TRIANGULATE_NGON_EARCLIP; - } + if (!DNA_struct_elem_find(fd->filesdna, "TriangulateModifierData", "int", "quad_method")) { + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_Triangulate) { + TriangulateModifierData *tmd = (TriangulateModifierData *)md; + if (tmd->flag & MOD_TRIANGULATE_BEAUTY) { + tmd->quad_method = MOD_TRIANGULATE_QUAD_BEAUTY; + tmd->ngon_method = MOD_TRIANGULATE_NGON_BEAUTY; + } + else { + tmd->quad_method = MOD_TRIANGULATE_QUAD_FIXED; + tmd->ngon_method = MOD_TRIANGULATE_NGON_EARCLIP; } } } } + } - for (scene = bmain->scenes.first; scene; scene = scene->id.next) { - /* this can now be turned off */ - ToolSettings *ts = scene->toolsettings; - if (ts->sculpt) { - ts->sculpt->flags |= SCULPT_DYNTOPO_SUBDIVIDE; - } + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + /* this can now be turned off */ + ToolSettings *ts = scene->toolsettings; + if (ts->sculpt) { + ts->sculpt->flags |= SCULPT_DYNTOPO_SUBDIVIDE; + } - /* 'Increment' mode disabled for nodes, use true grid snapping instead */ - if (scene->toolsettings->snap_node_mode == 0) { /* SCE_SNAP_MODE_INCREMENT */ - scene->toolsettings->snap_node_mode = 8; /* SCE_SNAP_MODE_GRID */ - } + /* 'Increment' mode disabled for nodes, use true grid snapping instead */ + if (scene->toolsettings->snap_node_mode == 0) { /* SCE_SNAP_MODE_INCREMENT */ + scene->toolsettings->snap_node_mode = 8; /* SCE_SNAP_MODE_GRID */ + } #ifdef WITH_FFMPEG - /* Update for removed "sound-only" option in FFMPEG export settings. */ - if (scene->r.ffcodecdata.type >= FFMPEG_INVALID) { - scene->r.ffcodecdata.type = FFMPEG_AVI; - } -#endif + /* Update for removed "sound-only" option in FFMPEG export settings. */ + if (scene->r.ffcodecdata.type >= FFMPEG_INVALID) { + scene->r.ffcodecdata.type = FFMPEG_AVI; } +#endif } +} - if (!MAIN_VERSION_ATLEAST(bmain, 269, 4)) { - /* Internal degrees to radians conversions... */ - { - Scene *scene; - Object *ob; - - for (Light *la = bmain->lights.first; la; la = la->id.next) { - la->spotsize = DEG2RADF(la->spotsize); - } - - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - ModifierData *md; +if (!MAIN_VERSION_ATLEAST(bmain, 269, 4)) { + /* Internal degrees to radians conversions... */ + { + LISTBASE_FOREACH (Light *, la, &bmain->lights) { + la->spotsize = DEG2RADF(la->spotsize); + } - for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_EdgeSplit) { - EdgeSplitModifierData *emd = (EdgeSplitModifierData *)md; - emd->split_angle = DEG2RADF(emd->split_angle); - } - else if (md->type == eModifierType_Bevel) { - BevelModifierData *bmd = (BevelModifierData *)md; - bmd->bevel_angle = DEG2RADF(bmd->bevel_angle); - } + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_EdgeSplit) { + EdgeSplitModifierData *emd = (EdgeSplitModifierData *)md; + emd->split_angle = DEG2RADF(emd->split_angle); + } + else if (md->type == eModifierType_Bevel) { + BevelModifierData *bmd = (BevelModifierData *)md; + bmd->bevel_angle = DEG2RADF(bmd->bevel_angle); } } + } - for (scene = bmain->scenes.first; scene; scene = scene->id.next) { - if (scene->ed) { - SEQ_for_each_callback(&scene->ed->seqbase, seq_set_wipe_angle_cb, NULL); - } + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->ed) { + SEQ_for_each_callback(&scene->ed->seqbase, seq_set_wipe_angle_cb, NULL); } + } - FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - if (ntree->type == NTREE_COMPOSIT) { - bNode *node; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == CMP_NODE_BOKEHIMAGE) { - NodeBokehImage *n = node->storage; - n->angle = DEG2RADF(n->angle); - } - if (node->type == CMP_NODE_MASK_BOX) { - NodeBoxMask *n = node->storage; - n->rotation = DEG2RADF(n->rotation); - } - if (node->type == CMP_NODE_MASK_ELLIPSE) { - NodeEllipseMask *n = node->storage; - n->rotation = DEG2RADF(n->rotation); - } + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_COMPOSIT) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == CMP_NODE_BOKEHIMAGE) { + NodeBokehImage *n = node->storage; + n->angle = DEG2RADF(n->angle); + } + if (node->type == CMP_NODE_MASK_BOX) { + NodeBoxMask *n = node->storage; + n->rotation = DEG2RADF(n->rotation); + } + if (node->type == CMP_NODE_MASK_ELLIPSE) { + NodeEllipseMask *n = node->storage; + n->rotation = DEG2RADF(n->rotation); } } } - FOREACH_NODETREE_END; } + FOREACH_NODETREE_END; + } - if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingPlaneTrack", "float", "image_opacity")) { - MovieClip *clip; - for (clip = bmain->movieclips.first; clip; clip = clip->id.next) { - MovieTrackingPlaneTrack *plane_track; - for (plane_track = clip->tracking.plane_tracks_legacy.first; plane_track; - plane_track = plane_track->next) - { - plane_track->image_opacity = 1.0f; - } + if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingPlaneTrack", "float", "image_opacity")) { + LISTBASE_FOREACH (MovieClip *, clip, &bmain->movieclips) { + LISTBASE_FOREACH ( + MovieTrackingPlaneTrack *, plane_track, &clip->tracking.plane_tracks_legacy) { + plane_track->image_opacity = 1.0f; } } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 269, 7)) { - Scene *scene; - for (scene = bmain->scenes.first; scene; scene = scene->id.next) { - Sculpt *sd = scene->toolsettings->sculpt; +if (!MAIN_VERSION_ATLEAST(bmain, 269, 7)) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + Sculpt *sd = scene->toolsettings->sculpt; - if (sd) { - enum { - SCULPT_SYMM_X = (1 << 0), - SCULPT_SYMM_Y = (1 << 1), - SCULPT_SYMM_Z = (1 << 2), - SCULPT_SYMMETRY_FEATHER = (1 << 6), - }; - int symmetry_flags = sd->flags & 7; + if (sd) { + enum { + SCULPT_SYMM_X = (1 << 0), + SCULPT_SYMM_Y = (1 << 1), + SCULPT_SYMM_Z = (1 << 2), + SCULPT_SYMMETRY_FEATHER = (1 << 6), + }; + int symmetry_flags = sd->flags & 7; - if (symmetry_flags & SCULPT_SYMM_X) { - sd->paint.symmetry_flags |= PAINT_SYMM_X; - } - if (symmetry_flags & SCULPT_SYMM_Y) { - sd->paint.symmetry_flags |= PAINT_SYMM_Y; - } - if (symmetry_flags & SCULPT_SYMM_Z) { - sd->paint.symmetry_flags |= PAINT_SYMM_Z; - } - if (symmetry_flags & SCULPT_SYMMETRY_FEATHER) { - sd->paint.symmetry_flags |= PAINT_SYMMETRY_FEATHER; - } + if (symmetry_flags & SCULPT_SYMM_X) { + sd->paint.symmetry_flags |= PAINT_SYMM_X; + } + if (symmetry_flags & SCULPT_SYMM_Y) { + sd->paint.symmetry_flags |= PAINT_SYMM_Y; + } + if (symmetry_flags & SCULPT_SYMM_Z) { + sd->paint.symmetry_flags |= PAINT_SYMM_Z; + } + if (symmetry_flags & SCULPT_SYMMETRY_FEATHER) { + sd->paint.symmetry_flags |= PAINT_SYMMETRY_FEATHER; } } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 269, 8)) { - Curve *cu; - - for (cu = bmain->curves.first; cu; cu = cu->id.next) { - if (cu->str) { - cu->len_char32 = BLI_strlen_utf8(cu->str); - } +if (!MAIN_VERSION_ATLEAST(bmain, 269, 8)) { + LISTBASE_FOREACH (Curve *, cu, &bmain->curves) { + if (cu->str) { + cu->len_char32 = BLI_strlen_utf8(cu->str); } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 269, 9)) { - Object *ob; - - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - ModifierData *md; - for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Build) { - BuildModifierData *bmd = (BuildModifierData *)md; - if (bmd->randomize) { - bmd->flag |= MOD_BUILD_FLAG_RANDOMIZE; - } +if (!MAIN_VERSION_ATLEAST(bmain, 269, 9)) { + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_Build) { + BuildModifierData *bmd = (BuildModifierData *)md; + if (bmd->randomize) { + bmd->flag |= MOD_BUILD_FLAG_RANDOMIZE; } } } } +} - if (!MAIN_VERSION_ATLEAST(bmain, 269, 11)) { - bScreen *screen; - - for (screen = bmain->screens.first; screen; screen = screen->id.next) { - ScrArea *area; - for (area = screen->areabase.first; area; area = area->next) { - SpaceLink *space_link; +if (!MAIN_VERSION_ATLEAST(bmain, 269, 11)) { + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, space_link, &area->spacedata) { + if (space_link->spacetype == SPACE_IMAGE) { + ListBase *lb; - for (space_link = area->spacedata.first; space_link; space_link = space_link->next) { - if (space_link->spacetype == SPACE_IMAGE) { - ARegion *region; - ListBase *lb; + if (space_link == area->spacedata.first) { + lb = &area->regionbase; + } + else { + lb = &space_link->regionbase; + } - if (space_link == area->spacedata.first) { - lb = &area->regionbase; - } - else { - lb = &space_link->regionbase; + LISTBASE_FOREACH (ARegion *, region, lb) { + if (region->regiontype == RGN_TYPE_PREVIEW) { + region->regiontype = RGN_TYPE_TOOLS; + region->alignment = RGN_ALIGN_LEFT; } - - for (region = lb->first; region; region = region->next) { - if (region->regiontype == RGN_TYPE_PREVIEW) { - region->regiontype = RGN_TYPE_TOOLS; - region->alignment = RGN_ALIGN_LEFT; - } - else if (region->regiontype == RGN_TYPE_UI) { - region->alignment = RGN_ALIGN_RIGHT; - } + else if (region->regiontype == RGN_TYPE_UI) { + region->alignment = RGN_ALIGN_RIGHT; } } } @@ -2581,6 +2304,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } +} void do_versions_after_linking_260(Main *bmain) { @@ -2628,7 +2352,7 @@ void do_versions_after_linking_260(Main *bmain) * If the fromnode/tonode pointers are NULL, this means a link from/to * the ntree interface sockets, which need to be redirected to new interface nodes. */ - for (link = ntree->links.first; link; link = next_link) { + for (link = ntree->links.first; link != NULL; link = next_link) { bool free_link = false; next_link = link->next; @@ -2694,7 +2418,7 @@ void do_versions_after_linking_260(Main *bmain) FOREACH_NODETREE_BEGIN (bmain, ntree, id) { bNodeLink *link, *next_link; - for (link = ntree->links.first; link; link = next_link) { + for (link = ntree->links.first; link != NULL; link = next_link) { next_link = link->next; if (link->fromnode == NULL || link->tonode == NULL) { nodeRemLink(ntree, link); diff --git a/source/blender/datatoc/datatoc_icon.c b/source/blender/datatoc/datatoc_icon.c index 9b603945a906..74c076f06045 100644 --- a/source/blender/datatoc/datatoc_icon.c +++ b/source/blender/datatoc/datatoc_icon.c @@ -36,17 +36,6 @@ /* -------------------------------------------------------------------- */ /* Utility functions */ -static int path_ensure_slash(char *path) -{ - int len = strlen(path); - if (len == 0 || path[len - 1] != SEP) { - path[len] = SEP; - path[len + 1] = '\0'; - return len + 1; - } - return len; -} - static bool path_test_extension(const char *filepath, const char *ext) { const size_t a = strlen(filepath); @@ -81,6 +70,25 @@ static const char *path_basename(const char *path) return filename ? filename + 1 : path; } +static bool path_join(char *filepath, + size_t filepath_maxncpy, + const char *dirpath, + const char *filename) +{ + int dirpath_len = strlen(dirpath); + if (dirpath_len && dirpath[dirpath_len - 1] == SEP) { + dirpath_len--; + } + const int filename_len = strlen(filename); + if (dirpath_len + 1 + filename_len + 1 > filepath_maxncpy) { + return false; + } + memcpy(filepath, dirpath, dirpath_len); + filepath[dirpath_len] = SEP; + memcpy(filepath + dirpath_len + 1, filename, filename_len + 1); + return true; +} + /* -------------------------------------------------------------------- */ /* Write a PNG from RGBA pixels */ @@ -392,8 +400,6 @@ static bool icondir_to_png(const char *path_src, const char *file_dst) DIR *dir; const struct dirent *fname; char filepath[1024]; - char *filename; - int path_str_len; int found = 0, fail = 0; struct IconMergeContext context; @@ -411,15 +417,12 @@ static bool icondir_to_png(const char *path_src, const char *file_dst) return false; } - strcpy(filepath, path_src); - path_str_len = path_ensure_slash(filepath); - filename = &filepath[path_str_len]; - while ((fname = readdir(dir)) != NULL) { if (path_test_extension(fname->d_name, ".dat")) { - - strcpy(filename, fname->d_name); - + if (!path_join(filepath, sizeof(filepath), path_src, fname->d_name)) { + printf("%s: path is too long (%s, %s)\n", __func__, path_src, fname->d_name); + return false; + } if (icon_merge(&context, filepath, &pixels_canvas, &canvas_w, &canvas_h)) { found++; } diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index 5a6d17ea7262..89324a22829c 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -86,8 +86,7 @@ static float light_shape_radiance_get(const Light *la, const EEVEE_Light *evli) case LA_LOCAL: { /* Sphere area. */ float area = 4.0f * (float)M_PI * square_f(evli->radius); - /* NOTE: Presence of a factor of PI here to match Cycles. But it should be missing to be - * consistent with the other cases. */ + /* Convert radiant flux to radiance. */ return 1.0f / (area * (float)M_PI); } default: @@ -128,10 +127,9 @@ static float light_volume_radiance_factor_get(const Light *la, } case LA_SPOT: case LA_LOCAL: { - /* Sphere solid angle. */ - float area = 4.0f * (float)M_PI; - /* NOTE: Missing a factor of PI here to match Cycles. */ - power *= 1.0f / area; + /* Convert radiant flux to intensity. */ + /* Inverse of sphere solid angle. */ + power *= 0.25f * (float)M_1_PI; break; } default: diff --git a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl index 341505bfc1df..218f9eb4e8a4 100644 --- a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl @@ -326,6 +326,20 @@ float light_diffuse(LightData ld, vec3 N, vec3 V, vec4 l_vector) return ltc_evaluate_disk(N, V, mat3(1.0), points); } + else if (ld.l_type == POINT) { + if (l_vector.w < ld.l_radius) { + /* Inside, treat as hemispherical light. */ + return 1.0; + } + else { + /* Outside, treat as disk light spanning the same solid angle. */ + /* The result is the same as passing the scaled radius to #ltc_evaluate_disk_simple (see + * #light_specular), using simplified math here. */ + float r_sq = sqr(ld.l_radius / l_vector.w); + vec3 L = l_vector.xyz / l_vector.w; + return r_sq * diffuse_sphere_integral(dot(N, L), r_sq); + } + } else { float radius = ld.l_radius; radius /= (ld.l_type == SUN) ? 1.0 : l_vector.w; @@ -348,11 +362,22 @@ float light_specular(LightData ld, vec4 ltc_mat, vec3 N, vec3 V, vec4 l_vector) return ltc_evaluate_quad(corners, vec3(0.0, 0.0, 1.0)); } + else if (ld.l_type == POINT && l_vector.w < ld.l_radius) { + /* Inside the sphere light, integrate over the hemisphere. */ + return 1.0; + } else { bool is_ellipse = (ld.l_type == AREA_ELLIPSE); float radius_x = is_ellipse ? ld.l_sizex : ld.l_radius; float radius_y = is_ellipse ? ld.l_sizey : ld.l_radius; + if (ld.l_type == POINT) { + /* The sine of the half-angle spanned by a sphere light is equal to the tangent of the + * half-angle spanned by a disk light with the same radius. */ + radius_x *= inversesqrt(1.0 - sqr(radius_x / l_vector.w)); + radius_y *= inversesqrt(1.0 - sqr(radius_y / l_vector.w)); + } + vec3 L = (ld.l_type == SUN) ? -ld.l_forward : l_vector.xyz; vec3 Px = ld.l_right; vec3 Py = ld.l_up; diff --git a/source/blender/draw/engines/eevee_next/eevee_light.cc b/source/blender/draw/engines/eevee_next/eevee_light.cc index 239e0e0d3879..b85e35a2171c 100644 --- a/source/blender/draw/engines/eevee_next/eevee_light.cc +++ b/source/blender/draw/engines/eevee_next/eevee_light.cc @@ -186,8 +186,7 @@ float Light::shape_radiance_get(const ::Light *la) case LA_LOCAL: { /* Sphere area. */ float area = 4.0f * float(M_PI) * square_f(_radius); - /* NOTE: Presence of a factor of PI here to match Cycles. But it should be missing to be - * consistent with the other cases. */ + /* Convert radiant flux to radiance. */ return 1.0f / (area * float(M_PI)); } default: @@ -221,10 +220,9 @@ float Light::point_radiance_get(const ::Light *la) } case LA_SPOT: case LA_LOCAL: { - /* Sphere solid angle. */ - float area = 4.0f * float(M_PI); - /* NOTE: Missing a factor of PI here to match Cycles. */ - return 1.0f / area; + /* Convert radiant flux to intensity. */ + /* Inverse of sphere solid angle. */ + return 0.25f * float(M_1_PI); } default: case LA_SUN: { diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_light_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_light_lib.glsl index 761e403b1389..8894f6327519 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_light_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_light_lib.glsl @@ -106,7 +106,20 @@ float light_diffuse(sampler2DArray utility_tx, vec3 L, float dist) { - if (is_directional || !is_area_light(ld.type)) { + if (ld.type == LIGHT_POINT) { + if (dist < ld._radius) { + /* Inside, treat as hemispherical light. */ + return 1.0; + } + else { + /* Outside, treat as disk light spanning the same solid angle. */ + /* The result is the same as passing the scaled radius to #ltc_evaluate_disk_simple (see + * #light_ltc), using simplified math here. */ + float r_sq = sqr(ld._radius / dist); + return r_sq * ltc_diffuse_sphere_integral(utility_tx, dot(N, L), r_sq); + } + } + else if (is_directional || ld.type == LIGHT_SPOT) { float radius = ld._radius / dist; return ltc_evaluate_disk_simple(utility_tx, radius, dot(N, L)); } @@ -147,7 +160,11 @@ float light_ltc(sampler2DArray utility_tx, float dist, vec4 ltc_mat) { - if (is_directional || ld.type != LIGHT_RECT) { + if (ld.type == LIGHT_POINT && dist < ld._radius) { + /* Inside the sphere light, integrate over the hemisphere. */ + return 1.0; + } + else if (is_directional || ld.type != LIGHT_RECT) { vec3 Px = ld._right; vec3 Py = ld._up; @@ -156,8 +173,18 @@ float light_ltc(sampler2DArray utility_tx, } vec3 points[3]; - points[0] = Px * -ld._area_size_x + Py * -ld._area_size_y; - points[1] = Px * ld._area_size_x + Py * -ld._area_size_y; + if (ld.type == LIGHT_POINT) { + /* The sine of the half-angle spanned by a sphere light is equal to the tangent of the + * half-angle spanned by a disk light with the same radius. */ + float radius = ld._radius * inversesqrt(1.0 - sqr(ld._radius / dist)); + + points[0] = Px * -radius + Py * -radius; + points[1] = Px * radius + Py * -radius; + } + else { + points[0] = Px * -ld._area_size_x + Py * -ld._area_size_y; + points[1] = Px * ld._area_size_x + Py * -ld._area_size_y; + } points[2] = -points[0]; points[0] += L * dist; diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index a038e02e416b..54c4cb2931a1 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -266,7 +266,7 @@ static bool need_extra_redraw_after_scrubbing_ends(bContext *C) return true; } Scene *scene = CTX_data_scene(C); - if (scene->eevee.flag & SCE_EEVEE_TAA_REPROJECTION) { + if (scene->eevee.taa_samples != 1) { return true; } wmWindowManager *wm = CTX_wm_manager(C); diff --git a/source/blender/editors/include/ED_viewer_path.hh b/source/blender/editors/include/ED_viewer_path.hh index 87c228e108d6..4d9f02b58873 100644 --- a/source/blender/editors/include/ED_viewer_path.hh +++ b/source/blender/editors/include/ED_viewer_path.hh @@ -37,7 +37,8 @@ Object *parse_object_only(const ViewerPath &viewer_path); struct ViewerPathForGeometryNodesViewer { Object *object; blender::StringRefNull modifier_name; - blender::Vector group_node_ids; + /* Contains only group node and simulation zone elements. */ + blender::Vector node_path; int32_t viewer_node_id; }; @@ -65,7 +66,6 @@ bool exists_geometry_nodes_viewer(const ViewerPathForGeometryNodesViewer &parsed * Checks if the node referenced by the viewer and its entire context is still active, i.e. some * editor is showing it. */ -bool is_active_geometry_nodes_viewer(const bContext &C, - const ViewerPathForGeometryNodesViewer &parsed_viewer_path); +bool is_active_geometry_nodes_viewer(const bContext &C, const ViewerPath &viewer_path); } // namespace blender::ed::viewer_path diff --git a/source/blender/editors/interface/interface_region_popover.cc b/source/blender/editors/interface/interface_region_popover.cc index 9a2967a5cc20..46d0154fd706 100644 --- a/source/blender/editors/interface/interface_region_popover.cc +++ b/source/blender/editors/interface/interface_region_popover.cc @@ -75,13 +75,21 @@ struct uiPopover { #endif }; -static void ui_popover_create_block(bContext *C, uiPopover *pup, wmOperatorCallContext opcontext) +/** + * \param region: Optional, the region the block will be placed in. Must be set if the popover is + * supposed to support refreshing. + */ +static void ui_popover_create_block(bContext *C, + ARegion *region, + uiPopover *pup, + wmOperatorCallContext opcontext) { BLI_assert(pup->ui_size_x != 0); const uiStyle *style = UI_style_get_dpi(); - pup->block = UI_block_begin(C, nullptr, __func__, UI_EMBOSS); + pup->block = UI_block_begin(C, region, __func__, UI_EMBOSS); + UI_block_flag_enable(pup->block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_POPOVER); #ifdef USE_UI_POPOVER_ONCE if (pup->is_once) { @@ -109,7 +117,7 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v /* Create UI block and layout now if it wasn't done between begin/end. */ if (!pup->layout) { - ui_popover_create_block(C, pup, WM_OP_INVOKE_REGION_WIN); + ui_popover_create_block(C, nullptr, pup, WM_OP_INVOKE_REGION_WIN); if (pup->menu_func) { pup->block->handle = handle; @@ -124,7 +132,12 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v uiBlock *block = pup->block; int width, height; - UI_block_region_set(block, handle->region); + /* in some cases we create the block before the region, + * so we set it delayed here if necessary */ + if (BLI_findindex(&handle->region->uiblocks, block) == -1) { + UI_block_region_set(block, handle->region); + } + UI_block_layout_resolve(block, &width, &height); UI_block_direction_set(block, UI_DIR_DOWN | UI_DIR_CENTER_X); @@ -348,7 +361,7 @@ uiPopover *UI_popover_begin(bContext *C, int ui_menu_width, bool from_active_but pup->butregion = butregion; /* Operator context default same as menus, change if needed. */ - ui_popover_create_block(C, pup, WM_OP_EXEC_REGION_WIN); + ui_popover_create_block(C, nullptr, pup, WM_OP_EXEC_REGION_WIN); /* create in advance so we can let buttons point to retval already */ pup->block->handle = MEM_cnew(__func__); diff --git a/source/blender/editors/screen/workspace_listen.cc b/source/blender/editors/screen/workspace_listen.cc index 7acf51336c46..9dd8303c6a5a 100644 --- a/source/blender/editors/screen/workspace_listen.cc +++ b/source/blender/editors/screen/workspace_listen.cc @@ -20,11 +20,7 @@ static void validate_viewer_paths(bContext &C, WorkSpace &workspace) return; } - const std::optional parsed_path = - blender::ed::viewer_path::parse_geometry_nodes_viewer(workspace.viewer_path); - if (parsed_path.has_value() && - blender::ed::viewer_path::is_active_geometry_nodes_viewer(C, *parsed_path)) - { + if (blender::ed::viewer_path::is_active_geometry_nodes_viewer(C, workspace.viewer_path)) { /* The current viewer path is still valid and active. */ return; } diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index b31b97d81f20..6eea19a8f049 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -94,8 +94,8 @@ #include namespace geo_log = blender::nodes::geo_eval_log; -using blender::bke::node_tree_zones::TreeZone; -using blender::bke::node_tree_zones::TreeZones; +using blender::bke::bNodeTreeZone; +using blender::bke::bNodeTreeZones; /** * This is passed to many functions which draw the node editor. @@ -113,7 +113,7 @@ struct TreeDrawContext { * Geometry nodes logs various data during execution. The logged data that corresponds to the * currently drawn node tree can be retrieved from the log below. */ - geo_log::GeoTreeLog *geo_tree_log = nullptr; + blender::Map geo_log_by_zone; /** * True if there is an active realtime compositor using the node tree, false otherwise. */ @@ -1068,8 +1068,8 @@ static void create_inspection_string_for_geometry_socket(std::stringstream &ss, } } -static std::optional create_socket_inspection_string(TreeDrawContext &tree_draw_ctx, - const bNodeSocket &socket) +static std::optional create_socket_inspection_string( + geo_log::GeoTreeLog &geo_tree_log, const bNodeSocket &socket) { using namespace blender::nodes::geo_eval_log; @@ -1077,8 +1077,8 @@ static std::optional create_socket_inspection_string(TreeDrawContex return std::nullopt; } - tree_draw_ctx.geo_tree_log->ensure_socket_values(); - ValueLog *value_log = tree_draw_ctx.geo_tree_log->find_socket_value_log(socket); + geo_tree_log.ensure_socket_values(); + ValueLog *value_log = geo_tree_log.find_socket_value_log(socket); std::stringstream ss; if (const geo_log::GenericValueLog *generic_value_log = dynamic_cast(value_log)) @@ -1131,7 +1131,8 @@ static char *node_socket_get_tooltip(const SpaceNode *snode, TreeDrawContext tree_draw_ctx; if (snode != nullptr) { if (ntree.type == NTREE_GEOMETRY) { - tree_draw_ctx.geo_tree_log = geo_log::GeoModifierLog::get_tree_log_for_node_editor(*snode); + tree_draw_ctx.geo_log_by_zone = + geo_log::GeoModifierLog::get_tree_log_by_zone_for_node_editor(*snode); } } @@ -1144,13 +1145,22 @@ static char *node_socket_get_tooltip(const SpaceNode *snode, } } - if (ntree.type == NTREE_GEOMETRY && tree_draw_ctx.geo_tree_log != nullptr) { + geo_log::GeoTreeLog *geo_tree_log = [&]() -> geo_log::GeoTreeLog * { + const bNodeTreeZones *zones = ntree.zones(); + if (!zones) { + return nullptr; + } + const bNodeTreeZone *zone = zones->get_zone_by_socket(socket); + return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr); + }(); + + if (ntree.type == NTREE_GEOMETRY && geo_tree_log != nullptr) { if (!output.str().empty()) { output << ".\n\n"; } std::optional socket_inspection_str = create_socket_inspection_string( - tree_draw_ctx, socket); + *geo_tree_log, socket); if (socket_inspection_str.has_value()) { output << *socket_inspection_str; } @@ -1738,9 +1748,18 @@ static void node_add_error_message_button(const TreeDrawContext &tree_draw_ctx, return; } + geo_log::GeoTreeLog *geo_tree_log = [&]() -> geo_log::GeoTreeLog * { + const bNodeTreeZones *zones = node.owner_tree().zones(); + if (!zones) { + return nullptr; + } + const bNodeTreeZone *zone = zones->get_zone_by_node(node.identifier); + return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr); + }(); + Span warnings; - if (tree_draw_ctx.geo_tree_log) { - geo_log::GeoNodeLog *node_log = tree_draw_ctx.geo_tree_log->nodes.lookup_ptr(node.identifier); + if (geo_tree_log) { + geo_log::GeoNodeLog *node_log = geo_tree_log->nodes.lookup_ptr(node.identifier); if (node_log != nullptr) { warnings = node_log->warnings; } @@ -1778,7 +1797,15 @@ static void node_add_error_message_button(const TreeDrawContext &tree_draw_ctx, static std::optional node_get_execution_time( const TreeDrawContext &tree_draw_ctx, const bNodeTree &ntree, const bNode &node) { - const geo_log::GeoTreeLog *tree_log = tree_draw_ctx.geo_tree_log; + geo_log::GeoTreeLog *tree_log = [&]() -> geo_log::GeoTreeLog * { + const bNodeTreeZones *zones = ntree.zones(); + if (!zones) { + return nullptr; + } + const bNodeTreeZone *zone = zones->get_zone_by_node(node.identifier); + return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr); + }(); + if (tree_log == nullptr) { return std::nullopt; } @@ -1936,7 +1963,15 @@ static NodeExtraInfoRow row_from_used_named_attribute( static std::optional node_get_accessed_attributes_row( TreeDrawContext &tree_draw_ctx, const bNode &node) { - if (tree_draw_ctx.geo_tree_log == nullptr) { + geo_log::GeoTreeLog *geo_tree_log = [&]() -> geo_log::GeoTreeLog * { + const bNodeTreeZones *zones = node.owner_tree().zones(); + if (!zones) { + return nullptr; + } + const bNodeTreeZone *zone = zones->get_zone_by_node(node.identifier); + return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr); + }(); + if (geo_tree_log == nullptr) { return std::nullopt; } if (ELEM(node.type, @@ -1953,8 +1988,8 @@ static std::optional node_get_accessed_attributes_row( } } } - tree_draw_ctx.geo_tree_log->ensure_used_named_attributes(); - geo_log::GeoNodeLog *node_log = tree_draw_ctx.geo_tree_log->nodes.lookup_ptr(node.identifier); + geo_tree_log->ensure_used_named_attributes(); + geo_log::GeoNodeLog *node_log = geo_tree_log->nodes.lookup_ptr(node.identifier); if (node_log == nullptr) { return std::nullopt; } @@ -1998,7 +2033,16 @@ static Vector node_get_extra_info(TreeDrawContext &tree_draw_c } if (snode.edittree->type == NTREE_GEOMETRY) { - if (geo_log::GeoTreeLog *tree_log = tree_draw_ctx.geo_tree_log) { + geo_log::GeoTreeLog *tree_log = [&]() -> geo_log::GeoTreeLog * { + const bNodeTreeZones *tree_zones = node.owner_tree().zones(); + if (!tree_zones) { + return nullptr; + } + const bNodeTreeZone *zone = tree_zones->get_zone_by_node(node.identifier); + return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr); + }(); + + if (tree_log) { tree_log->ensure_debug_messages(); const geo_log::GeoNodeLog *node_log = tree_log->nodes.lookup_ptr(node.identifier); if (node_log != nullptr) { @@ -3053,8 +3097,8 @@ static void add_rect_corner_positions(Vector &positions, const rctf &rec } static void find_bounds_by_zone_recursive(const SpaceNode &snode, - const TreeZone &zone, - const Span> all_zones, + const bNodeTreeZone &zone, + const Span> all_zones, MutableSpan> r_bounds_by_zone) { const float node_padding = UI_UNIT_X; @@ -3066,7 +3110,7 @@ static void find_bounds_by_zone_recursive(const SpaceNode &snode, } Vector possible_bounds; - for (const TreeZone *child_zone : zone.child_zones) { + for (const bNodeTreeZone *child_zone : zone.child_zones) { find_bounds_by_zone_recursive(snode, *child_zone, all_zones, r_bounds_by_zone); const Span child_bounds = r_bounds_by_zone[child_zone->index]; for (const float2 &pos : child_bounds) { @@ -3126,7 +3170,7 @@ static void node_draw_zones(TreeDrawContext & /*tree_draw_ctx*/, const SpaceNode &snode, const bNodeTree &ntree) { - const TreeZones *zones = bke::node_tree_zones::get_tree_zones(ntree); + const bNodeTreeZones *zones = ntree.zones(); if (zones == nullptr) { return; } @@ -3135,7 +3179,7 @@ static void node_draw_zones(TreeDrawContext & /*tree_draw_ctx*/, Array fillet_curve_by_zone(zones->zones.size()); for (const int zone_i : zones->zones.index_range()) { - const TreeZone &zone = *zones->zones[zone_i]; + const bNodeTreeZone &zone = *zones->zones[zone_i]; find_bounds_by_zone_recursive(snode, zone, zones->zones, bounds_by_zone); const Span boundary_positions = bounds_by_zone[zone_i]; @@ -3368,10 +3412,11 @@ static void draw_nodetree(const bContext &C, TreeDrawContext tree_draw_ctx; if (ntree.type == NTREE_GEOMETRY) { - tree_draw_ctx.geo_tree_log = geo_log::GeoModifierLog::get_tree_log_for_node_editor(*snode); - if (tree_draw_ctx.geo_tree_log != nullptr) { - tree_draw_ctx.geo_tree_log->ensure_node_warnings(); - tree_draw_ctx.geo_tree_log->ensure_node_run_time(); + tree_draw_ctx.geo_log_by_zone = geo_log::GeoModifierLog::get_tree_log_by_zone_for_node_editor( + *snode); + for (geo_log::GeoTreeLog *log : tree_draw_ctx.geo_log_by_zone.values()) { + log->ensure_node_warnings(); + log->ensure_node_run_time(); } const WorkSpace *workspace = CTX_wm_workspace(&C); tree_draw_ctx.active_geometry_nodes_viewer = viewer_path::find_geometry_nodes_viewer( diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc index 62a1fbb092ad..eaf9d07ca95a 100644 --- a/source/blender/editors/space_node/node_geometry_attribute_search.cc +++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc @@ -18,6 +18,7 @@ #include "BKE_context.h" #include "BKE_node_runtime.hh" #include "BKE_node_tree_update.h" +#include "BKE_node_tree_zones.hh" #include "BKE_object.h" #include "RNA_access.h" @@ -69,23 +70,33 @@ static Vector get_attribute_info_from_context( BLI_assert_unreachable(); return {}; } - GeoTreeLog *tree_log = GeoModifierLog::get_tree_log_for_node_editor(*snode); - if (tree_log == nullptr) { + const bke::bNodeTreeZones *tree_zones = node_tree->zones(); + if (!tree_zones) { return {}; } - tree_log->ensure_socket_values(); + const Map log_by_zone = + GeoModifierLog::get_tree_log_by_zone_for_node_editor(*snode); /* For the attribute input node, collect attribute information from all nodes in the group. */ if (node->type == GEO_NODE_INPUT_NAMED_ATTRIBUTE) { - tree_log->ensure_existing_attributes(); Vector attributes; - for (const GeometryAttributeInfo *attribute : tree_log->existing_attributes) { - if (bke::allow_procedural_attribute_access(attribute->name)) { - attributes.append(attribute); + for (GeoTreeLog *tree_log : log_by_zone.values()) { + tree_log->ensure_socket_values(); + tree_log->ensure_existing_attributes(); + for (const GeometryAttributeInfo *attribute : tree_log->existing_attributes) { + if (bke::allow_procedural_attribute_access(attribute->name)) { + attributes.append(attribute); + } } } return attributes; } + const bke::bNodeTreeZone *zone = tree_zones->get_zone_by_node(node->identifier); + GeoTreeLog *tree_log = log_by_zone.lookup_default(zone, nullptr); + if (!tree_log) { + return {}; + } + tree_log->ensure_socket_values(); GeoNodeLog *node_log = tree_log->nodes.lookup_ptr(node->identifier); if (node_log == nullptr) { return {}; diff --git a/source/blender/editors/space_outliner/outliner_tree.cc b/source/blender/editors/space_outliner/outliner_tree.cc index 3b793eba34e8..2970fa0929d7 100644 --- a/source/blender/editors/space_outliner/outliner_tree.cc +++ b/source/blender/editors/space_outliner/outliner_tree.cc @@ -18,20 +18,15 @@ #include "DNA_collection_types.h" #include "DNA_constraint_types.h" #include "DNA_curves_types.h" -#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" #include "DNA_key_types.h" #include "DNA_light_types.h" #include "DNA_lightprobe_types.h" -#include "DNA_linestyle_types.h" #include "DNA_material_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meta_types.h" #include "DNA_object_types.h" #include "DNA_particle_types.h" #include "DNA_pointcloud_types.h" #include "DNA_scene_types.h" -#include "DNA_sequence_types.h" #include "DNA_shader_fx_types.h" #include "DNA_simulation_types.h" #include "DNA_speaker_types.h" @@ -42,25 +37,19 @@ #include "BLI_fnmatch.h" #include "BLI_listbase.h" #include "BLI_mempool.h" -#include "BLI_timeit.hh" #include "BLI_utildefines.h" #include "BLT_translation.h" -#include "BKE_armature.h" #include "BKE_deform.h" #include "BKE_layer.h" -#include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_outliner_treehash.hh" #include "ED_screen.h" -#include "RNA_access.h" - #include "UI_interface.h" -#include "UI_resources.h" #include "outliner_intern.hh" #include "tree/common.hh" diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c index c02d1484cf19..250ed29d03f2 100644 --- a/source/blender/editors/transform/transform_convert_nla.c +++ b/source/blender/editors/transform/transform_convert_nla.c @@ -55,6 +55,11 @@ typedef struct TransDataNla { /** index of track that strip is currently in. */ int trackIndex; + + /** NOTE: This index is relative to the initial first track at the start of transforming and + * thus can be negative when the tracks list grows downward. */ + int signed_track_index; + /** handle-index: 0 for dummy entry, -1 for start, 1 for end, 2 for both ends. */ int handle; } TransDataNla; @@ -143,6 +148,146 @@ static float transdata_get_time_shuffle_offset(ListBase *trans_datas) return -offset_left < offset_right ? offset_left : offset_right; } +/** Assumes all of given trans_datas are part of the same ID. + * + * + * \param shuffle_direction: the direction the strip is traveling. 1 is towards the bottom + * of the stack, -1 is away from it. + * + * \param r_total_offset: The minimal total signed offset that results in valid strip track-moves + * for all strips from \a trans_datas. + * + * \returns true if \a r_total_offset results in a valid offset, false if no solution exists in the + * desired direction. + */ +static bool transdata_get_track_shuffle_offset_side(ListBase *trans_datas, + const int shuffle_direction, + int *r_total_offset) +{ + *r_total_offset = 0; + if (BLI_listbase_is_empty(trans_datas)) { + return false; + } + + LinkData *first_link = trans_datas->first; + TransDataNla *first_transdata = first_link->data; + AnimData *adt = BKE_animdata_from_id(first_transdata->id); + ListBase *tracks = &adt->nla_tracks; + + int offset; + do { + offset = 0; + + LISTBASE_FOREACH (LinkData *, link, trans_datas) { + TransDataNla *trans_data = (TransDataNla *)link->data; + + NlaTrack *dst_track = BLI_findlink(tracks, trans_data->trackIndex + *r_total_offset); + + /* Cannot keep moving strip in given track direction. No solution. */ + if (dst_track == NULL) { + return false; + } + + /* Shuffle only if track is locked or library override. */ + if (((dst_track->flag & NLATRACK_PROTECTED) == 0) && + !BKE_nlatrack_is_nonlocal_in_liboverride(trans_data->id, dst_track)) + { + continue; + } + + offset = shuffle_direction; + break; + } + + *r_total_offset += offset; + } while (offset != 0); + + return true; +} + +/** Assumes all of given trans_datas are part of the same ID. + * + * \param r_track_offset: The minimal total signed offset that results in valid strip track-moves + * for all strips from \a trans_datas. + * + * \returns true if \a r_track_offset results in a valid offset, false if no solution exists in + * either direction. + */ +static bool transdata_get_track_shuffle_offset(ListBase *trans_datas, int *r_track_offset) +{ + int offset_down = 0; + const bool down_valid = transdata_get_track_shuffle_offset_side(trans_datas, 1, &offset_down); + + int offset_up = 0; + const bool up_valid = transdata_get_track_shuffle_offset_side(trans_datas, -1, &offset_up); + + if (down_valid && up_valid) { + if (offset_down < abs(offset_up)) { + *r_track_offset = offset_down; + } + else { + *r_track_offset = offset_up; + } + } + else if (down_valid) { + *r_track_offset = offset_down; + } + else if (up_valid) { + *r_track_offset = offset_up; + } + + return down_valid || up_valid; +} + +/* -------------------------------------------------------------------- */ +/** \name Transform application to NLA strips + * \{ */ + +/** \} */ +static void nlatrack_truncate_temporary_tracks(bAnimContext *ac) +{ + short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA); + ListBase anim_data = {NULL, NULL}; + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { + ListBase *nla_tracks = &ale->adt->nla_tracks; + + /** Remove top tracks that weren't necessary. */ + LISTBASE_FOREACH_BACKWARD_MUTABLE (NlaTrack *, track, nla_tracks) { + if (!(track->flag & NLATRACK_TEMPORARILY_ADDED)) { + break; + } + if (track->strips.first != NULL) { + break; + } + BKE_nlatrack_remove_and_free(nla_tracks, track, true); + } + + /** Remove bottom tracks that weren't necessary. */ + LISTBASE_FOREACH_MUTABLE (NlaTrack *, track, nla_tracks) { + /** Library override tracks are the first N tracks. They're never temporary and determine + * where we start removing temporaries.*/ + if ((track->flag & NLATRACK_OVERRIDELIBRARY_LOCAL) == 0) { + continue; + } + if (!(track->flag & NLATRACK_TEMPORARILY_ADDED)) { + break; + } + if (track->strips.first != NULL) { + break; + } + BKE_nlatrack_remove_and_free(nla_tracks, track, true); + } + + /** Clear temporary flag. */ + LISTBASE_FOREACH_MUTABLE (NlaTrack *, track, nla_tracks) { + track->flag &= ~NLATRACK_TEMPORARILY_ADDED; + } + } + + ANIM_animdata_freelist(&anim_data); +} /* -------------------------------------------------------------------- */ /** \name Transform application to NLA strips * \{ */ @@ -400,6 +545,7 @@ static void createTransNlaData(bContext *C, TransInfo *t) tdn->oldTrack = tdn->nlt = nlt; tdn->strip = strip; tdn->trackIndex = BLI_findindex(&adt->nla_tracks, nlt); + tdn->signed_track_index = tdn->trackIndex; yval = (float)(tdn->trackIndex * NLACHANNEL_STEP(snla)); @@ -581,56 +727,83 @@ static void recalcData_nla(TransInfo *t) continue; } - delta_y1 = ((int)tdn->h1[1] / NLACHANNEL_STEP(snla) - tdn->trackIndex); - delta_y2 = ((int)tdn->h2[1] / NLACHANNEL_STEP(snla) - tdn->trackIndex); + delta_y1 = ((int)tdn->h1[1] / NLACHANNEL_STEP(snla) - tdn->signed_track_index); + delta_y2 = ((int)tdn->h2[1] / NLACHANNEL_STEP(snla) - tdn->signed_track_index); + /* Move strip into track in the requested direction. */ if (delta_y1 || delta_y2) { - NlaTrack *track; int delta = (delta_y2) ? delta_y2 : delta_y1; - int n; - /* Move in the requested direction, - * checking at each layer if there's space for strip to pass through, - * stopping on the last track available or that we're able to fit in. + AnimData *anim_data = BKE_animdata_from_id(tdn->id); + ListBase *nla_tracks = &anim_data->nla_tracks; + + NlaTrack *old_track = tdn->nlt; + NlaTrack *dst_track = NULL; + + /* Calculate the total new tracks needed + * + * Determine dst_track, which will end up being NULL, the last library override + * track, or a normal local track. The first two cases lead to delta_new_tracks!=0. + * The last case leads to delta_new_tracks==0. */ - if (delta > 0) { - for (track = tdn->nlt->next, n = 0; (track) && (n < delta); track = track->next, n++) { - /* check if space in this track for the strip */ - if (BKE_nlatrack_has_space(track, strip->start, strip->end) && - !BKE_nlatrack_is_nonlocal_in_liboverride(tdn->id, track)) - { - /* move strip to this track */ - BKE_nlatrack_remove_strip(tdn->nlt, strip); - BKE_nlatrack_add_strip(track, strip, is_liboverride); - - tdn->nlt = track; - tdn->trackIndex++; - } - else { /* can't move any further */ - break; - } - } + int delta_new_tracks = delta; + + /* it's possible to drag a strip fast enough to make delta > |1|. We only want to process + * 1 track shift at a time. + */ + CLAMP(delta_new_tracks, -1, 1); + dst_track = old_track; + + while (delta_new_tracks < 0) { + dst_track = dst_track->prev; + delta_new_tracks++; } - else { - /* make delta 'positive' before using it, since we now know to go backwards */ - delta = -delta; - - for (track = tdn->nlt->prev, n = 0; (track) && (n < delta); track = track->prev, n++) { - /* check if space in this track for the strip */ - if (BKE_nlatrack_has_space(track, strip->start, strip->end) && - !BKE_nlatrack_is_nonlocal_in_liboverride(tdn->id, track)) - { - /* move strip to this track */ - BKE_nlatrack_remove_strip(tdn->nlt, strip); - BKE_nlatrack_add_strip(track, strip, is_liboverride); - - tdn->nlt = track; - tdn->trackIndex--; - } - else { /* can't move any further */ - break; - } - } + + /* We assume all library tracks are grouped at the bottom of the nla stack. + * Thus, no need to check for them when moving tracks upward. + */ + while (delta_new_tracks > 0) { + dst_track = dst_track->next; + delta_new_tracks--; + } + + for (int i = 0; i < -delta_new_tracks; i++) { + NlaTrack *new_track = BKE_nlatrack_new(); + new_track->flag |= NLATRACK_TEMPORARILY_ADDED; + BKE_nlatrack_insert_before( + nla_tracks, (NlaTrack *)nla_tracks->first, new_track, is_liboverride); + dst_track = new_track; + } + + for (int i = 0; i < delta_new_tracks; i++) { + NlaTrack *new_track = BKE_nlatrack_new(); + new_track->flag |= NLATRACK_TEMPORARILY_ADDED; + + BKE_nlatrack_insert_after( + nla_tracks, (NlaTrack *)nla_tracks->last, new_track, is_liboverride); + dst_track = new_track; + } + + /* If the destination track is null, then we need to go to the last track. */ + if (dst_track == NULL) { + dst_track = old_track; + } + + /* Move strip from old_track to dst_track. */ + if (dst_track != old_track) { + BKE_nlatrack_remove_strip(old_track, strip); + BKE_nlastrips_add_strip_unsafe(&dst_track->strips, strip); + + tdn->nlt = dst_track; + tdn->signed_track_index += delta; + tdn->trackIndex = BLI_findindex(nla_tracks, dst_track); + } + + /* Ensure we set the target track as active. */ + BKE_nlatrack_set_active(nla_tracks, dst_track); + + if (tdn->nlt->flag & NLATRACK_PROTECTED) { + strip->flag |= NLASTRIP_FLAG_INVALID_LOCATION; } } @@ -699,6 +872,38 @@ static void nlastrip_shuffle_transformed(TransDataContainer *tc, TransDataNla *f LISTBASE_FOREACH (IDGroupedTransData *, group, &grouped_trans_datas) { ListBase *trans_datas = &group->trans_datas; + /* Apply vertical shuffle. */ + int minimum_track_offset = 0; + transdata_get_track_shuffle_offset(trans_datas, &minimum_track_offset); + if (minimum_track_offset != 0) { + ListBase *tracks = &BKE_animdata_from_id(group->id)->nla_tracks; + + LISTBASE_FOREACH (LinkData *, link, trans_datas) { + TransDataNla *trans_data = (TransDataNla *)link->data; + NlaTrack *dst_track = BLI_findlink(tracks, trans_data->trackIndex + minimum_track_offset); + + NlaStrip *strip = trans_data->strip; + if ((dst_track->flag & NLATRACK_PROTECTED) != 0) { + + BKE_nlatrack_remove_strip(trans_data->nlt, strip); + BKE_nlatrack_add_strip(dst_track, strip, false); + + trans_data->nlt = dst_track; + } + else { + /* if destination track is locked, we need revert strip to source track. */ + printf("Cannot moved. Target track '%s' is locked. \n", trans_data->nlt->name); + int old_track_index = BLI_findindex(tracks, trans_data->oldTrack); + NlaTrack *old_track = BLI_findlink(tracks, old_track_index); + + BKE_nlatrack_remove_strip(trans_data->nlt, strip); + BKE_nlastrips_add_strip_unsafe(&old_track->strips, strip); + + trans_data->nlt = old_track; + } + } + } + /* Apply horizontal shuffle. */ const float minimum_time_offset = transdata_get_time_shuffle_offset(trans_datas); LISTBASE_FOREACH (LinkData *, link, trans_datas) { @@ -735,7 +940,7 @@ static void special_aftertrans_update__nla(bContext *C, TransInfo *t) TransDataNla *first_trans_data = tc->custom.type.data; /* Shuffle transformed strips. */ - if (ELEM(t->mode, TFM_TRANSLATION)) { + if (ELEM(t->mode, TFM_TRANSLATION) && t->state != TRANS_CANCEL) { nlastrip_shuffle_transformed(tc, first_trans_data); } @@ -774,6 +979,9 @@ static void special_aftertrans_update__nla(bContext *C, TransInfo *t) /* free temp memory */ ANIM_animdata_freelist(&anim_data); + /* Truncate temporarily added tracks. */ + nlatrack_truncate_temporary_tracks(&ac); + /* Perform after-transform validation. */ ED_nla_postop_refresh(&ac); } diff --git a/source/blender/editors/util/ed_viewer_path.cc b/source/blender/editors/util/ed_viewer_path.cc index b3351902312d..c2207dd93be3 100644 --- a/source/blender/editors/util/ed_viewer_path.cc +++ b/source/blender/editors/util/ed_viewer_path.cc @@ -8,6 +8,7 @@ #include "BKE_context.h" #include "BKE_main.h" #include "BKE_node_runtime.hh" +#include "BKE_node_tree_zones.hh" #include "BKE_workspace.h" #include "BLI_listbase.h" @@ -22,6 +23,9 @@ namespace blender::ed::viewer_path { +using bke::bNodeTreeZone; +using bke::bNodeTreeZones; + static void viewer_path_for_geometry_node(const SpaceNode &snode, const bNode &node, ViewerPath &r_dst) @@ -55,27 +59,57 @@ static void viewer_path_for_geometry_node(const SpaceNode &snode, modifier = nmd; } } - if (modifier != nullptr) { - ModifierViewerPathElem *modifier_elem = BKE_viewer_path_elem_new_modifier(); - modifier_elem->modifier_name = BLI_strdup(modifier->modifier.name); - BLI_addtail(&r_dst.path, modifier_elem); + if (modifier == nullptr) { + return; } + ModifierViewerPathElem *modifier_elem = BKE_viewer_path_elem_new_modifier(); + modifier_elem->modifier_name = BLI_strdup(modifier->modifier.name); + BLI_addtail(&r_dst.path, modifier_elem); Vector tree_path = snode.treepath; for (const int i : tree_path.index_range().drop_back(1)) { + bNodeTree *tree = tree_path[i]->nodetree; /* The tree path contains the name of the node but not its ID. */ - const bNode *node = nodeFindNodebyName(tree_path[i]->nodetree, tree_path[i + 1]->node_name); + const char *node_name = tree_path[i + 1]->node_name; + const bNode *node = nodeFindNodebyName(tree, node_name); /* The name in the tree path should match a group node in the tree. */ BLI_assert(node != nullptr); - NodeViewerPathElem *node_elem = BKE_viewer_path_elem_new_node(); + + tree->ensure_topology_cache(); + const bNodeTreeZones *tree_zones = tree->zones(); + if (!tree_zones) { + return; + } + const Vector zone_stack = tree_zones->get_zone_stack_for_node( + node->identifier); + for (const bNodeTreeZone *zone : zone_stack) { + SimulationZoneViewerPathElem *node_elem = BKE_viewer_path_elem_new_simulation_zone(); + node_elem->sim_output_node_id = zone->output_node->identifier; + BLI_addtail(&r_dst.path, node_elem); + } + + GroupNodeViewerPathElem *node_elem = BKE_viewer_path_elem_new_group_node(); node_elem->node_id = node->identifier; - node_elem->node_name = BLI_strdup(node->name); + node_elem->base.ui_name = BLI_strdup(node->name); BLI_addtail(&r_dst.path, node_elem); } - NodeViewerPathElem *viewer_node_elem = BKE_viewer_path_elem_new_node(); + snode.edittree->ensure_topology_cache(); + const bNodeTreeZones *tree_zones = snode.edittree->zones(); + if (!tree_zones) { + return; + } + const Vector zone_stack = tree_zones->get_zone_stack_for_node( + node.identifier); + for (const bNodeTreeZone *zone : zone_stack) { + SimulationZoneViewerPathElem *node_elem = BKE_viewer_path_elem_new_simulation_zone(); + node_elem->sim_output_node_id = zone->output_node->identifier; + BLI_addtail(&r_dst.path, node_elem); + } + + ViewerNodeViewerPathElem *viewer_node_elem = BKE_viewer_path_elem_new_viewer_node(); viewer_node_elem->node_id = node.identifier; - viewer_node_elem->node_name = BLI_strdup(node.name); + viewer_node_elem->base.ui_name = BLI_strdup(node.name); BLI_addtail(&r_dst.path, viewer_node_elem); } @@ -185,16 +219,21 @@ std::optional parse_geometry_nodes_viewer( return std::nullopt; } remaining_elems = remaining_elems.drop_front(1); - Vector node_ids; - for (const ViewerPathElem *elem : remaining_elems) { - if (elem->type != VIEWER_PATH_ELEM_TYPE_NODE) { + Vector node_path; + for (const ViewerPathElem *elem : remaining_elems.drop_back(1)) { + if (!ELEM(elem->type, VIEWER_PATH_ELEM_TYPE_GROUP_NODE, VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE)) + { return std::nullopt; } - const int32_t node_id = reinterpret_cast(elem)->node_id; - node_ids.append(node_id); + node_path.append(elem); + } + const ViewerPathElem *last_elem = remaining_elems.last(); + if (last_elem->type != VIEWER_PATH_ELEM_TYPE_VIEWER_NODE) { + return std::nullopt; } - const int32_t viewer_node_id = node_ids.pop_last(); - return ViewerPathForGeometryNodesViewer{root_ob, modifier_name, node_ids, viewer_node_id}; + const int32_t viewer_node_id = + reinterpret_cast(last_elem)->node_id; + return ViewerPathForGeometryNodesViewer{root_ob, modifier_name, node_path, viewer_node_id}; } bool exists_geometry_nodes_viewer(const ViewerPathForGeometryNodesViewer &parsed_viewer_path) @@ -217,81 +256,73 @@ bool exists_geometry_nodes_viewer(const ViewerPathForGeometryNodesViewer &parsed return false; } const bNodeTree *ngroup = modifier->node_group; - ngroup->ensure_topology_cache(); - for (const int32_t group_node_id : parsed_viewer_path.group_node_ids) { - const bNode *group_node = nullptr; - for (const bNode *node : ngroup->group_nodes()) { - if (node->identifier != group_node_id) { - continue; + const bNodeTreeZone *zone = nullptr; + for (const ViewerPathElem *path_elem : parsed_viewer_path.node_path) { + ngroup->ensure_topology_cache(); + const bNodeTreeZones *tree_zones = ngroup->zones(); + switch (path_elem->type) { + case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: { + const auto &typed_elem = *reinterpret_cast( + path_elem); + const bNodeTreeZone *next_zone = tree_zones->get_zone_by_node( + typed_elem.sim_output_node_id); + if (next_zone == nullptr) { + return false; + } + if (next_zone->parent_zone != zone) { + return false; + } + zone = next_zone; + break; + } + case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: { + const auto &typed_elem = *reinterpret_cast(path_elem); + const bNode *group_node = ngroup->node_by_id(typed_elem.node_id); + if (group_node == nullptr) { + return false; + } + const bNodeTreeZone *parent_zone = tree_zones->get_zone_by_node(typed_elem.node_id); + if (parent_zone != zone) { + return false; + } + if (group_node->id == nullptr) { + return false; + } + ngroup = reinterpret_cast(group_node->id); + zone = nullptr; + break; + } + default: { + BLI_assert_unreachable(); } - group_node = node; - break; - } - if (group_node == nullptr) { - return false; - } - if (group_node->id == nullptr) { - return false; - } - ngroup = reinterpret_cast(group_node->id); - } - const bNode *viewer_node = nullptr; - for (const bNode *node : ngroup->nodes_by_type("GeometryNodeViewer")) { - if (node->identifier != parsed_viewer_path.viewer_node_id) { - continue; } - viewer_node = node; - break; } + + const bNode *viewer_node = ngroup->node_by_id(parsed_viewer_path.viewer_node_id); if (viewer_node == nullptr) { return false; } - return true; -} - -static bool viewer_path_matches_node_editor_path( - const SpaceNode &snode, const ViewerPathForGeometryNodesViewer &parsed_viewer_path) -{ - Vector tree_path = snode.treepath; - if (tree_path.size() != parsed_viewer_path.group_node_ids.size() + 1) { + const bNodeTreeZones *tree_zones = ngroup->zones(); + if (tree_zones == nullptr) { return false; } - for (const int i : parsed_viewer_path.group_node_ids.index_range()) { - const bNode *node = tree_path[i]->nodetree->node_by_id(parsed_viewer_path.group_node_ids[i]); - if (!node) { - return false; - } - if (!STREQ(node->name, tree_path[i + 1]->node_name)) { - return false; - } + if (tree_zones->get_zone_by_node(viewer_node->identifier) != zone) { + return false; } return true; } -bool is_active_geometry_nodes_viewer(const bContext &C, - const ViewerPathForGeometryNodesViewer &parsed_viewer_path) +bool is_active_geometry_nodes_viewer(const bContext &C, const ViewerPath &viewer_path) { - const NodesModifierData *modifier = nullptr; - LISTBASE_FOREACH (const ModifierData *, md, &parsed_viewer_path.object->modifiers) { - if (md->name != parsed_viewer_path.modifier_name) { - continue; - } - if (md->type != eModifierType_Nodes) { - return false; - } - if ((md->mode & eModifierMode_Realtime) == 0) { - return false; - } - modifier = reinterpret_cast(md); - break; - } - if (modifier == nullptr) { + if (BLI_listbase_is_empty(&viewer_path.path)) { return false; } - if (modifier->node_group == nullptr) { + const ViewerPathElem *last_elem = static_cast(viewer_path.path.last); + if (last_elem->type != VIEWER_PATH_ELEM_TYPE_VIEWER_NODE) { return false; } - const bool modifier_is_active = modifier->modifier.flag & eModifierFlag_Active; + const int32_t viewer_node_id = + reinterpret_cast(last_elem)->node_id; const Main *bmain = CTX_data_main(&C); const wmWindowManager *wm = static_cast(bmain->wm.first); @@ -315,30 +346,26 @@ bool is_active_geometry_nodes_viewer(const bContext &C, continue; } const SpaceNode &snode = *reinterpret_cast(sl); - if (!modifier_is_active) { - if (!(snode.flag & SNODE_PIN)) { - /* Node tree has to be pinned when the modifier is not active. */ - continue; - } - } - if (snode.id != &parsed_viewer_path.object->id) { + if (snode.edittree == nullptr) { continue; } - if (snode.nodetree != modifier->node_group) { + if (snode.edittree->type != NTREE_GEOMETRY) { continue; } - if (!viewer_path_matches_node_editor_path(snode, parsed_viewer_path)) { - continue; - } - const bNodeTree *ngroup = snode.edittree; - ngroup->ensure_topology_cache(); - const bNode *viewer_node = ngroup->node_by_id(parsed_viewer_path.viewer_node_id); + snode.edittree->ensure_topology_cache(); + const bNode *viewer_node = snode.edittree->node_by_id(viewer_node_id); if (viewer_node == nullptr) { continue; } if (!(viewer_node->flag & NODE_DO_OUTPUT)) { continue; } + ViewerPath tmp_viewer_path{}; + BLI_SCOPED_DEFER([&]() { BKE_viewer_path_clear(&tmp_viewer_path); }); + viewer_path_for_geometry_node(snode, *viewer_node, tmp_viewer_path); + if (!BKE_viewer_path_equal(&viewer_path, &tmp_viewer_path)) { + continue; + } return true; } } diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.cc b/source/blender/editors/uvedit/uvedit_unwrap_ops.cc index 2242cea8e439..40db9351f5b8 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.cc +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.cc @@ -1512,7 +1512,13 @@ static int pack_islands_exec(bContext *C, wmOperator *op) } pack_island_params.scale_to_fit = RNA_boolean_get(op->ptr, "scale"); pack_island_params.merge_overlap = RNA_boolean_get(op->ptr, "merge_overlap"); - pack_island_params.pin_method = eUVPackIsland_PinMethod(RNA_enum_get(op->ptr, "pin")); + + if (RNA_boolean_get(op->ptr, "pin")) { + pack_island_params.pin_method = eUVPackIsland_PinMethod(RNA_enum_get(op->ptr, "pin_method")); + } + else { + pack_island_params.pin_method = ED_UVPACK_PIN_NONE; + } pack_island_params.margin_method = eUVPackIsland_MarginMethod( RNA_enum_get(op->ptr, "margin_method")); @@ -1592,17 +1598,21 @@ static const EnumPropertyItem pack_shape_method_items[] = { {0, nullptr, 0, nullptr, nullptr}, }; +/** + * \note #ED_UVPACK_PIN_NONE is exposed as a boolean "pin". + * \note #ED_UVPACK_PIN_IGNORE is intentionally not exposed as it is confusing from the UI level + * (users can simply not select these islands). + * The option is kept kept internally because it's used for live unwrap. + */ static const EnumPropertyItem pinned_islands_method_items[] = { - {ED_UVPACK_PIN_PACK, "PACK", 0, "Pack", "Pinned islands are packed normally"}, - {ED_UVPACK_PIN_LOCK_SCALE, "SCALE", 0, "Lock Scale", "Pinned islands won't rescale"}, - {ED_UVPACK_PIN_LOCK_ROTATION, "ROTATION", 0, "Lock Rotation", "Pinned islands won't rotate"}, + {ED_UVPACK_PIN_LOCK_SCALE, "SCALE", 0, "Scale", "Pinned islands won't rescale"}, + {ED_UVPACK_PIN_LOCK_ROTATION, "ROTATION", 0, "Rotation", "Pinned islands won't rotate"}, {ED_UVPACK_PIN_LOCK_ROTATION_SCALE, "ROTATION_SCALE", 0, - "Lock Rotation and Scale", + "Rotation and Scale", "Pinned islands will translate only"}, - {ED_UVPACK_PIN_LOCK_ALL, "LOCKED", 0, "Lock in Place", "Pinned islands are locked in place"}, - {ED_UVPACK_PIN_IGNORE, "IGNORE", 0, "Ignore", "Pinned islands are not packed"}, + {ED_UVPACK_PIN_LOCK_ALL, "LOCKED", 0, "All", "Pinned islands are locked in place"}, {0, nullptr, 0, nullptr, nullptr}, }; @@ -1613,15 +1623,23 @@ static void uv_pack_islands_ui(bContext * /*C*/, wmOperator *op) uiLayoutSetPropDecorate(layout, false); uiItemR(layout, op->ptr, "shape_method", 0, nullptr, ICON_NONE); uiItemR(layout, op->ptr, "scale", 0, nullptr, ICON_NONE); - uiItemR(layout, op->ptr, "rotate", 0, nullptr, ICON_NONE); - uiLayout *sub = uiLayoutRow(layout, true); - uiLayoutSetActive(sub, RNA_boolean_get(op->ptr, "rotate")); - uiItemR(sub, op->ptr, "rotate_method", 0, nullptr, ICON_NONE); - uiItemS(layout); + { + uiItemR(layout, op->ptr, "rotate", 0, nullptr, ICON_NONE); + uiLayout *sub = uiLayoutRow(layout, true); + uiLayoutSetActive(sub, RNA_boolean_get(op->ptr, "rotate")); + uiItemR(sub, op->ptr, "rotate_method", 0, nullptr, ICON_NONE); + uiItemS(layout); + } uiItemR(layout, op->ptr, "margin_method", 0, nullptr, ICON_NONE); uiItemR(layout, op->ptr, "margin", 0, nullptr, ICON_NONE); uiItemS(layout); - uiItemR(layout, op->ptr, "pin", 0, nullptr, ICON_NONE); + { + uiItemR(layout, op->ptr, "pin", 0, nullptr, ICON_NONE); + uiLayout *sub = uiLayoutRow(layout, true); + uiLayoutSetActive(sub, RNA_boolean_get(op->ptr, "pin")); + uiItemR(sub, op->ptr, "pin_method", 0, IFACE_("Lock Method"), ICON_NONE); + uiItemS(layout); + } uiItemR(layout, op->ptr, "merge_overlap", 0, nullptr, ICON_NONE); uiItemR(layout, op->ptr, "udim_source", 0, nullptr, ICON_NONE); uiItemS(layout); @@ -1687,8 +1705,17 @@ void UV_OT_pack_islands(wmOperatorType *ot) ""); RNA_def_float_factor( ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f); - RNA_def_enum( - ot->srna, "pin", pinned_islands_method_items, ED_UVPACK_PIN_PACK, "Pinned Islands", ""); + RNA_def_boolean(ot->srna, + "pin", + false, + "Lock Pinned Islands", + "Constrain islands containing any pinned UV's"); + RNA_def_enum(ot->srna, + "pin_method", + pinned_islands_method_items, + ED_UVPACK_PIN_LOCK_ALL, + "Pin Method", + ""); RNA_def_enum(ot->srna, "shape_method", pack_shape_method_items, diff --git a/source/blender/geometry/GEO_uv_pack.hh b/source/blender/geometry/GEO_uv_pack.hh index da78577e8445..f5157ba44666 100644 --- a/source/blender/geometry/GEO_uv_pack.hh +++ b/source/blender/geometry/GEO_uv_pack.hh @@ -49,12 +49,18 @@ enum eUVPackIsland_ShapeMethod { }; enum eUVPackIsland_PinMethod { - ED_UVPACK_PIN_IGNORE = 0, - ED_UVPACK_PIN_PACK, + /** Pin has no impact on packing. */ + ED_UVPACK_PIN_NONE = 0, + /** + * Ignore islands containing any pinned UV's. + * \note Not exposed in the UI, used only for live-unwrap. + */ + ED_UVPACK_PIN_IGNORE, ED_UVPACK_PIN_LOCK_ROTATION, ED_UVPACK_PIN_LOCK_ROTATION_SCALE, ED_UVPACK_PIN_LOCK_SCALE, - ED_UVPACK_PIN_LOCK_ALL, /* Lock translation, rotation and scale. */ + /** Lock the island in-place (translation, rotation and scale). */ + ED_UVPACK_PIN_LOCK_ALL, }; namespace blender::geometry { diff --git a/source/blender/geometry/intern/uv_pack.cc b/source/blender/geometry/intern/uv_pack.cc index 828f2d03b0c4..4c93437758fc 100644 --- a/source/blender/geometry/intern/uv_pack.cc +++ b/source/blender/geometry/intern/uv_pack.cc @@ -339,7 +339,7 @@ UVPackIsland_Params::UVPackIsland_Params() only_selected_faces = false; use_seams = false; correct_aspect = false; - pin_method = ED_UVPACK_PIN_PACK; + pin_method = ED_UVPACK_PIN_NONE; pin_unselected = false; merge_overlap = false; margin = 0.001f; @@ -1855,7 +1855,7 @@ static float pack_islands_scale_margin(const Span islands, rotate_inside_square(slow_aabbs, islands, params, scale, margin, r_phis, &extent); } - if (!memcmp(&extent, &fast_extent, sizeof(rctf))) { + if (BLI_rctf_compare(&extent, &fast_extent, 0.0f)) { /* The fast packer was the best so far. Lets just use the fast packer for everything. */ slow_aabbs = slow_aabbs.take_front(locked_island_count); extent = locked_bounds; diff --git a/source/blender/gpu/metal/mtl_memory.hh b/source/blender/gpu/metal/mtl_memory.hh index 0ca60df2b84a..12da6d109dc5 100644 --- a/source/blender/gpu/metal/mtl_memory.hh +++ b/source/blender/gpu/metal/mtl_memory.hh @@ -109,6 +109,11 @@ class MTLUniformBuf; /* MTLBuffer allocation wrapper. */ class MTLBuffer { + public: + /* NOTE: ListBase API is not used due to cutsom destructor operation required to release + * Metal objective C buffer resource. */ + gpu::MTLBuffer *next, *prev; + private: /* Metal resource. */ id metal_buffer_; @@ -179,6 +184,8 @@ class MTLBuffer { /* Safety check to ensure buffers are not used after free. */ void debug_ensure_used(); + + MEM_CXX_CLASS_ALLOC_FUNCS("MTLBuffer"); }; /* View into part of an MTLBuffer. */ @@ -335,6 +342,8 @@ class MTLSafeFreeList { } } } + + MEM_CXX_CLASS_ALLOC_FUNCS("MTLSafeFreeList"); }; /* MTLBuffer pools. */ @@ -364,7 +373,7 @@ class MTLBufferPool { #endif /* Metal resources. */ - bool ensure_initialised_ = false; + bool initialized_ = false; id device_ = nil; /* The buffer selection aims to pick a buffer which meets the minimum size requirements. @@ -391,7 +400,10 @@ class MTLBufferPool { std::mutex buffer_pool_lock_; blender::Map buffer_pools_; - blender::Vector allocations_; + + /* Linked list to track all existing allocations. Prioritizing fast insert/deletion. */ + gpu::MTLBuffer *allocations_list_base_; + uint allocations_list_size_; /* Maintain a queue of all MTLSafeFreeList's that have been released * by the GPU and are ready to have their buffers re-inserted into the @@ -434,6 +446,11 @@ class MTLBufferPool { void ensure_buffer_pool(MTLResourceOptions options); void insert_buffer_into_pool(MTLResourceOptions options, gpu::MTLBuffer *buffer); void free(); + + /* Allocations list. */ + void allocations_list_insert(gpu::MTLBuffer *buffer); + void allocations_list_delete(gpu::MTLBuffer *buffer); + void allocations_list_delete_all(); }; /* Scratch buffers are circular-buffers used for temporary data within the current frame. @@ -494,6 +511,8 @@ class MTLScratchBufferManager { * This call will perform a partial flush of the buffer starting from * the last offset the data was flushed from, to the current offset. */ void flush_active_scratch_buffer(); + + MEM_CXX_CLASS_ALLOC_FUNCS("MTLBufferPool"); }; /** \} */ diff --git a/source/blender/gpu/metal/mtl_memory.mm b/source/blender/gpu/metal/mtl_memory.mm index a8d8ea164cdb..99cffc2f8551 100644 --- a/source/blender/gpu/metal/mtl_memory.mm +++ b/source/blender/gpu/metal/mtl_memory.mm @@ -27,9 +27,9 @@ void MTLBufferPool::init(id mtl_device) { - if (!ensure_initialised_) { + if (!initialized_) { BLI_assert(mtl_device); - ensure_initialised_ = true; + initialized_ = true; device_ = mtl_device; #if MTL_DEBUG_MEMORY_STATISTICS == 1 @@ -41,6 +41,10 @@ /* Track pool allocation size. */ allocations_in_pool_ = 0; + /* Live allocations list. */ + allocations_list_base_ = nullptr; + allocations_list_size_ = 0; + /* Free pools -- Create initial safe free pool */ BLI_assert(current_free_list_ == nullptr); this->begin_new_safe_list(); @@ -55,17 +59,29 @@ void MTLBufferPool::free() { buffer_pool_lock_.lock(); - for (auto buffer : allocations_) { - BLI_assert(buffer); - delete buffer; + + /* Delete all existing allocations. */ + allocations_list_delete_all(); + + /* Release safe free lists. */ + for (int safe_pool_free_index = 0; safe_pool_free_index < completed_safelist_queue_.size(); + safe_pool_free_index++) + { + delete completed_safelist_queue_[safe_pool_free_index]; + } + completed_safelist_queue_.clear(); + if (current_free_list_ != nullptr) { + delete current_free_list_; + current_free_list_ = nullptr; } - allocations_.clear(); + /* Clear and release memory pools. */ for (std::multiset *buffer_pool : buffer_pools_.values()) { delete buffer_pool; } + buffer_pools_.clear(); buffer_pool_lock_.unlock(); } @@ -156,10 +172,7 @@ new_buffer = new gpu::MTLBuffer(device_, size, options, alignment); /* Track allocation in context. */ - allocations_.append(new_buffer); -#if MTL_DEBUG_MEMORY_STATISTICS == 1 - total_allocation_bytes_ += aligned_alloc_size; -#endif + allocations_list_insert(new_buffer); } else { /* Re-use suitable buffer. */ @@ -290,6 +303,7 @@ * animation. * If memory is continually used, then we do not want to free this memory as it will be * re-allocated during a short time period. */ + const time_t time_now = std::time(nullptr); for (auto buffer_pool_list : buffer_pools_.items()) { MTLBufferPoolOrderedList *pool_allocations = buffer_pool_list.value; @@ -324,12 +338,13 @@ if (time_passed > deletion_time_threshold_s) { - /* Delete allocation. */ - delete handle.buffer; + /* Remove buffer from global allocations list and release resource. */ + allocations_list_delete(handle.buffer); + + /* Remove buffer from pool and update pool statistics. */ pool_iterator = pool_allocations->erase(pool_iterator); allocations_in_pool_ -= handle.buffer_size; #if MTL_DEBUG_MEMORY_STATISTICS == 1 - total_allocation_bytes_ -= handle.buffer_size; buffers_in_pool_--; #endif continue; @@ -344,7 +359,7 @@ uint framealloc = (uint)per_frame_allocation_count_; printf(" Allocations in frame: %u\n", framealloc); - printf(" Total Buffers allocated: %u\n", (uint)allocations_.size()); + printf(" Total Buffers allocated: %u\n", allocations_list_size_); printf(" Total Memory allocated: %u MB\n", (uint)total_allocation_bytes_ / (1024 * 1024)); uint allocs = (uint)(allocations_in_pool_) / 1024 / 2024; @@ -454,6 +469,80 @@ #endif } +void MTLBufferPool::allocations_list_insert(gpu::MTLBuffer *buffer) +{ + /* NOTE: Function should only be called while buffer_pool_lock_ is acquired. */ + BLI_assert(initialized_); + BLI_assert(buffer != nullptr); + + /* Insert buffer at base of allocations list. */ + gpu::MTLBuffer *current_head = allocations_list_base_; + buffer->next = current_head; + buffer->prev = nullptr; + + if (current_head != nullptr) { + current_head->prev = buffer; + } + + allocations_list_base_ = buffer; + allocations_list_size_++; + +#if MTL_DEBUG_MEMORY_STATISTICS == 1 + total_allocation_bytes_ += buffer->get_size(); +#endif +} + +void MTLBufferPool::allocations_list_delete(gpu::MTLBuffer *buffer) +{ + /* NOTE: Function should only be called while buffer_pool_lock_ is acquired. */ + /* Remove a buffer link in the allocations chain. */ + BLI_assert(initialized_); + BLI_assert(buffer != nullptr); + BLI_assert(allocations_list_size_ >= 1); + + gpu::MTLBuffer *next = buffer->next; + gpu::MTLBuffer *prev = buffer->prev; + + if (prev != nullptr) { + BLI_assert(prev->next == buffer); + prev->next = next; + } + + if (next != nullptr) { + BLI_assert(next->prev == buffer); + next->prev = prev; + } + + if (allocations_list_base_ == buffer) { + allocations_list_base_ = next; + BLI_assert(prev == nullptr); + } + allocations_list_size_--; + +#if MTL_DEBUG_MEMORY_STATISTICS == 1 + total_allocation_bytes_ -= buffer->get_size(); +#endif + + /* Delete buffer. */ + delete buffer; +} + +void MTLBufferPool::allocations_list_delete_all() +{ + gpu::MTLBuffer *current = allocations_list_base_; + while (current != nullptr) { + gpu::MTLBuffer *next = current->next; + delete current; + current = next; + } + allocations_list_size_ = 0; + allocations_list_base_ = nullptr; + +#if MTL_DEBUG_MEMORY_STATISTICS == 1 + total_allocation_bytes_ = 0; +#endif +} + MTLSafeFreeList::MTLSafeFreeList() { reference_count_ = 1; @@ -566,6 +655,9 @@ else { data_ = nullptr; } + + /* Linked resources. */ + next = prev = nullptr; } MTLBuffer::MTLBuffer(id external_buffer) @@ -585,6 +677,9 @@ this->set_usage_size(size_); data_ = [metal_buffer_ contents]; in_use_ = true; + + /* Linked resources. */ + next = prev = nullptr; } gpu::MTLBuffer::~MTLBuffer() diff --git a/source/blender/imbuf/intern/oiio/openimageio_support.cc b/source/blender/imbuf/intern/oiio/openimageio_support.cc index d1a5b615377e..7207292217b6 100644 --- a/source/blender/imbuf/intern/oiio/openimageio_support.cc +++ b/source/blender/imbuf/intern/oiio/openimageio_support.cc @@ -180,11 +180,12 @@ static ImBuf *get_oiio_ibuf(ImageInput *in, const ReadContext &ctx, char colorsp const ImageSpec &spec = in->spec(); const int width = spec.width; const int height = spec.height; - const int channels = spec.nchannels; const bool has_alpha = spec.alpha_channel != -1; const bool is_float = spec.format.basesize() > 1; - if (channels < 1 || channels > 4) { + /* Only a maximum of 4 channels are supported by ImBuf. */ + const int channels = spec.nchannels <= 4 ? spec.nchannels : 4; + if (channels < 1) { return nullptr; } diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc index 8067be5a62ff..90af7db308da 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.cc +++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc @@ -467,8 +467,8 @@ static void read_velocity(const V3fArraySamplePtr &velocities, } } -static bool samples_have_same_topology(const IPolyMeshSchema::Sample &sample, - const IPolyMeshSchema::Sample &ceil_sample) +template +static bool samples_have_same_topology(const SampleType &sample, const SampleType &ceil_sample) { const P3fArraySamplePtr &positions = sample.getPositions(); const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); @@ -926,7 +926,10 @@ static void read_subd_sample(const std::string &iobject_full_name, if (config.weight != 0.0f) { Alembic::AbcGeom::ISubDSchema::Sample ceil_sample; schema.get(ceil_sample, Alembic::Abc::ISampleSelector(config.ceil_index)); - abc_mesh_data.ceil_positions = ceil_sample.getPositions(); + if (samples_have_same_topology(sample, ceil_sample)) { + /* Only set interpolation data if the samples are compatible. */ + abc_mesh_data.ceil_positions = ceil_sample.getPositions(); + } } if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) { @@ -1161,6 +1164,7 @@ Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh, const bool use_vertex_interpolation = read_flag & MOD_MESHSEQ_INTERPOLATE_VERTICES; CDStreamConfig config = get_config(mesh_to_export, use_vertex_interpolation); config.time = sample_sel.getRequestedTime(); + config.modifier_error_message = err_str; read_subd_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config); return mesh_to_export; diff --git a/source/blender/io/collada/GeometryExporter.cpp b/source/blender/io/collada/GeometryExporter.cpp index 026835d93fdc..f307024095b2 100644 --- a/source/blender/io/collada/GeometryExporter.cpp +++ b/source/blender/io/collada/GeometryExporter.cpp @@ -370,17 +370,16 @@ void GeometryExporter::create_mesh_primitive_list(short material_index, /* if mesh has uv coords writes for TEXCOORD */ int num_layers = CustomData_number_of_layers(&me->ldata, CD_PROP_FLOAT2); - int active_uv_index = CustomData_get_active_layer_index(&me->ldata, CD_PROP_FLOAT2); + int active_uv = CustomData_get_active_layer(&me->ldata, CD_PROP_FLOAT2); for (int i = 0; i < num_layers; i++) { - int layer_index = CustomData_get_layer_index_n(&me->ldata, CD_PROP_FLOAT2, i); - if (!this->export_settings.get_active_uv_only() || layer_index == active_uv_index) { + if (!this->export_settings.get_active_uv_only() || i == active_uv) { // char *name = CustomData_get_layer_name(&me->ldata, CD_PROP_FLOAT2, i); COLLADASW::Input texcoord_input( COLLADASW::InputSemantic::TEXCOORD, makeUrl(makeTexcoordSourceId(geom_id, i, this->export_settings.get_active_uv_only())), 2, /* this is only until we have optimized UV sets */ - (this->export_settings.get_active_uv_only()) ? 0 : layer_index - 1 /* set (0,1,2,...) */ + (this->export_settings.get_active_uv_only()) ? 0 : i /* set (0,1,2,...) */ ); til.push_back(texcoord_input); } diff --git a/source/blender/io/usd/intern/usd_writer_material.cc b/source/blender/io/usd/intern/usd_writer_material.cc index 8db851790fae..4dfb1c8e094b 100644 --- a/source/blender/io/usd/intern/usd_writer_material.cc +++ b/source/blender/io/usd/intern/usd_writer_material.cc @@ -280,8 +280,6 @@ void create_usd_viewport_material(const USDExporterContext &usd_export_context, shader.CreateIdAttr(pxr::VtValue(usdtokens::preview_surface)); shader.CreateInput(usdtokens::diffuse_color, pxr::SdfValueTypeNames->Color3f) .Set(pxr::GfVec3f(material->r, material->g, material->b)); - shader.CreateInput(usdtokens::emissive_color, pxr::SdfValueTypeNames->Color3f) - .Set(pxr::GfVec3f(material->r, material->g, material->b)); shader.CreateInput(usdtokens::roughness, pxr::SdfValueTypeNames->Float).Set(material->roughness); shader.CreateInput(usdtokens::metallic, pxr::SdfValueTypeNames->Float).Set(material->metallic); diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index e83cfcf47e07..ff6346c70092 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -906,6 +906,10 @@ typedef enum eNlaTrack_Flag { * usually as result of tweaking being enabled (internal flag) */ NLATRACK_DISABLED = (1 << 10), + /** Marks tracks automatically added for space while dragging strips vertically. + * Internal flag that's only set during transform operator. */ + NLATRACK_TEMPORARILY_ADDED = (1 << 11), + /** This NLA track is added to an override ID, which means it is fully editable. * Irrelevant in case the owner ID is not an override. */ NLATRACK_OVERRIDELIBRARY_LOCAL = 1 << 16, diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index b5166042f73a..076fe448e788 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -31,6 +31,10 @@ class bNodeTreeRuntime; class bNodeRuntime; class bNodeSocketRuntime; } // namespace blender::bke +namespace blender::bke { +class bNodeTreeZones; +class bNodeTreeZone; +} // namespace blender::bke using NodeDeclarationHandle = blender::nodes::NodeDeclaration; using SocketDeclarationHandle = blender::nodes::SocketDeclaration; using bNodeTreeRuntimeHandle = blender::bke::bNodeTreeRuntime; @@ -677,6 +681,8 @@ typedef struct bNodeTree { blender::Span panels() const; blender::MutableSpan panels_for_write(); + /** Zones in the node tree. Currently there are only simulation zones in geometry nodes. */ + const blender::bke::bNodeTreeZones *zones() const; #endif } bNodeTree; diff --git a/source/blender/makesdna/DNA_viewer_path_types.h b/source/blender/makesdna/DNA_viewer_path_types.h index c6d6a75be08d..e9593e896fac 100644 --- a/source/blender/makesdna/DNA_viewer_path_types.h +++ b/source/blender/makesdna/DNA_viewer_path_types.h @@ -12,13 +12,16 @@ struct ID; typedef enum ViewerPathElemType { VIEWER_PATH_ELEM_TYPE_ID = 0, VIEWER_PATH_ELEM_TYPE_MODIFIER = 1, - VIEWER_PATH_ELEM_TYPE_NODE = 2, + VIEWER_PATH_ELEM_TYPE_GROUP_NODE = 2, + VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE = 3, + VIEWER_PATH_ELEM_TYPE_VIEWER_NODE = 4, } ViewerPathElemType; typedef struct ViewerPathElem { struct ViewerPathElem *next, *prev; int type; char _pad[4]; + char *ui_name; } ViewerPathElem; typedef struct IDViewerPathElem { @@ -31,18 +34,26 @@ typedef struct ModifierViewerPathElem { char *modifier_name; } ModifierViewerPathElem; -typedef struct NodeViewerPathElem { +typedef struct GroupNodeViewerPathElem { ViewerPathElem base; int32_t node_id; char _pad1[4]; +} GroupNodeViewerPathElem; - /** - * The name of the node with the identifier. Not used to lookup nodes, only for display - * in the UI. Still stored here to avoid looking up the name for every redraw. - */ - char *node_name; -} NodeViewerPathElem; +typedef struct SimulationZoneViewerPathElem { + ViewerPathElem base; + + int32_t sim_output_node_id; + char _pad1[4]; +} SimulationZoneViewerPathElem; + +typedef struct ViewerNodeViewerPathElem { + ViewerPathElem base; + + int32_t node_id; + char _pad1[4]; +} ViewerNodeViewerPathElem; typedef struct ViewerPath { /** List of #ViewerPathElem. */ diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 053da6e9fd2d..403b4f9f6cf1 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -19,7 +19,7 @@ set(DEFSRC rna_actuator.c rna_animation.c rna_animviz.c - rna_armature.c + rna_armature.cc rna_asset.c rna_attribute.c rna_boid.c @@ -107,7 +107,7 @@ set(APISRC rna_action_api.c rna_actuator_api.c rna_animation_api.c - rna_armature_api.c + rna_armature_api.cc rna_camera_api.c rna_controller_api.c rna_curve_api.cc diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 688f049b0938..11babbbcc84a 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -1422,8 +1422,20 @@ static char *rna_def_property_set_func( } else { rna_clamp_value_range(f, prop); + /* C++ may require casting to an enum type. */ + fprintf(f, "#ifdef __cplusplus\n"); + fprintf(f, + /* If #rna_clamp_value() adds an expression like `CLAMPIS(...)` (instead of an + lvalue), #decltype() yields a reference, so that has to be removed.*/ + " data->%s = %s(std::remove_reference_t%s)>)", + dp->dnaname, + (dp->booleannegative) ? "!" : "", + dp->dnaname); + rna_clamp_value(f, prop, 0); + fprintf(f, "#else\n"); fprintf(f, " data->%s = %s", dp->dnaname, (dp->booleannegative) ? "!" : ""); rna_clamp_value(f, prop, 0); + fprintf(f, "#endif\n"); } } @@ -4540,7 +4552,7 @@ static RNAProcessItem PROCESS_ITEMS[] = { {"rna_actuator.c", "rna_actuator_api.c", RNA_def_actuator}, {"rna_animation.c", "rna_animation_api.c", RNA_def_animation}, {"rna_animviz.c", NULL, RNA_def_animviz}, - {"rna_armature.c", "rna_armature_api.c", RNA_def_armature}, + {"rna_armature.cc", "rna_armature_api.cc", RNA_def_armature}, {"rna_attribute.c", NULL, RNA_def_attribute}, {"rna_asset.c", NULL, RNA_def_asset}, {"rna_boid.c", NULL, RNA_def_boid}, diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.cc similarity index 84% rename from source/blender/makesrna/intern/rna_armature.c rename to source/blender/makesrna/intern/rna_armature.cc index f256f60ac9d5..08b975600655 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.cc @@ -40,23 +40,23 @@ # include "DEG_depsgraph.h" # include "DEG_depsgraph_build.h" -static void rna_Armature_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_Armature_update(Main * /*bmain*/, Scene * /*scene*/, PointerRNA *ptr) { ID *id = ptr->owner_id; DEG_id_tag_update(id, ID_RECALC_COPY_ON_WRITE); } -static void rna_Armature_update_data(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_Armature_update_data(Main * /*bmain*/, Scene * /*scene*/, PointerRNA *ptr) { ID *id = ptr->owner_id; DEG_id_tag_update(id, 0); WM_main_add_notifier(NC_GEOM | ND_DATA, id); - // WM_main_add_notifier(NC_OBJECT|ND_POSE, NULL); + // WM_main_add_notifier(NC_OBJECT|ND_POSE, nullptr); } -static void rna_Armature_dependency_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_Armature_dependency_update(Main *bmain, Scene * /*scene*/, PointerRNA *ptr) { ID *id = ptr->owner_id; @@ -68,12 +68,12 @@ static void rna_Armature_dependency_update(Main *bmain, Scene *UNUSED(scene), Po static void rna_Armature_act_bone_set(PointerRNA *ptr, PointerRNA value, - struct ReportList *UNUSED(reports)) + struct ReportList * /*reports*/) { bArmature *arm = (bArmature *)ptr->data; - if (value.owner_id == NULL && value.data == NULL) { - arm->act_bone = NULL; + if (value.owner_id == nullptr && value.data == nullptr) { + arm->act_bone = nullptr; } else { if (value.owner_id != &arm->id) { @@ -85,26 +85,26 @@ static void rna_Armature_act_bone_set(PointerRNA *ptr, } } - arm->act_bone = value.data; + arm->act_bone = static_cast(value.data); arm->act_bone->flag |= BONE_SELECTED; } } static void rna_Armature_act_edit_bone_set(PointerRNA *ptr, PointerRNA value, - struct ReportList *UNUSED(reports)) + struct ReportList * /*reports*/) { bArmature *arm = (bArmature *)ptr->data; - if (value.owner_id == NULL && value.data == NULL) { - arm->act_edbone = NULL; + if (value.owner_id == nullptr && value.data == nullptr) { + arm->act_edbone = nullptr; } else { if (value.owner_id != &arm->id) { /* raise an error! */ } else { - arm->act_edbone = value.data; + arm->act_edbone = static_cast(value.data); ((EditBone *)arm->act_edbone)->flag |= BONE_SELECTED; } } @@ -112,12 +112,12 @@ static void rna_Armature_act_edit_bone_set(PointerRNA *ptr, static EditBone *rna_Armature_edit_bone_new(bArmature *arm, ReportList *reports, const char *name) { - if (arm->edbo == NULL) { + if (arm->edbo == nullptr) { BKE_reportf(reports, RPT_ERROR, "Armature '%s' not in edit mode, cannot add an editbone", arm->id.name + 2); - return NULL; + return nullptr; } return ED_armature_ebone_add(arm, name); } @@ -126,8 +126,8 @@ static void rna_Armature_edit_bone_remove(bArmature *arm, ReportList *reports, PointerRNA *ebone_ptr) { - EditBone *ebone = ebone_ptr->data; - if (arm->edbo == NULL) { + EditBone *ebone = static_cast(ebone_ptr->data); + if (arm->edbo == nullptr) { BKE_reportf(reports, RPT_ERROR, "Armature '%s' not in edit mode, cannot remove an editbone", @@ -148,7 +148,7 @@ static void rna_Armature_edit_bone_remove(bArmature *arm, RNA_POINTER_INVALIDATE(ebone_ptr); } -static void rna_Armature_update_layers(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_Armature_update_layers(Main * /*bmain*/, Scene * /*scene*/, PointerRNA *ptr) { bArmature *arm = (bArmature *)ptr->owner_id; @@ -156,7 +156,7 @@ static void rna_Armature_update_layers(Main *UNUSED(bmain), Scene *UNUSED(scene) WM_main_add_notifier(NC_GEOM | ND_DATA, arm); } -static void rna_Armature_redraw_data(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_Armature_redraw_data(Main * /*bmain*/, Scene * /*scene*/, PointerRNA *ptr) { ID *id = ptr->owner_id; @@ -165,7 +165,7 @@ static void rna_Armature_redraw_data(Main *UNUSED(bmain), Scene *UNUSED(scene), } /* Unselect bones when hidden */ -static void rna_Bone_hide_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_Bone_hide_update(Main * /*bmain*/, Scene * /*scene*/, PointerRNA *ptr) { bArmature *arm = (bArmature *)ptr->owner_id; Bone *bone = (Bone *)ptr->data; @@ -179,7 +179,7 @@ static void rna_Bone_hide_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poin } /* called whenever a bone is renamed */ -static void rna_Bone_update_renamed(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_Bone_update_renamed(Main * /*bmain*/, Scene * /*scene*/, PointerRNA *ptr) { ID *id = ptr->owner_id; @@ -190,7 +190,7 @@ static void rna_Bone_update_renamed(Main *UNUSED(bmain), Scene *UNUSED(scene), P WM_main_add_notifier(NC_ANIMATION | ND_ANIMCHAN, id); } -static void rna_Bone_select_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_Bone_select_update(Main * /*bmain*/, Scene * /*scene*/, PointerRNA *ptr) { ID *id = ptr->owner_id; @@ -250,13 +250,13 @@ static char *rna_Bone_path(const PointerRNA *ptr) static IDProperty **rna_Bone_idprops(PointerRNA *ptr) { - Bone *bone = ptr->data; + Bone *bone = static_cast(ptr->data); return &bone->prop; } static IDProperty **rna_EditBone_idprops(PointerRNA *ptr) { - EditBone *ebone = ptr->data; + EditBone *ebone = static_cast(ptr->data); return &ebone->prop; } @@ -291,7 +291,7 @@ static void rna_Bone_layer_set(PointerRNA *ptr, const bool *values) Bone *bone = (Bone *)ptr->data; rna_bone_layer_set(&bone->layer, values); - BKE_armature_refresh_layer_used(NULL, arm); + BKE_armature_refresh_layer_used(nullptr, arm); } /* TODO: remove the deprecation stubs. */ @@ -427,17 +427,17 @@ static PointerRNA rna_EditBone_parent_get(PointerRNA *ptr) static void rna_EditBone_parent_set(PointerRNA *ptr, PointerRNA value, - struct ReportList *UNUSED(reports)) + struct ReportList * /*reports*/) { EditBone *ebone = (EditBone *)(ptr->data); EditBone *pbone, *parbone = (EditBone *)value.data; - if (parbone == NULL) { + if (parbone == nullptr) { if (ebone->parent && !(ebone->parent->flag & BONE_ROOTSEL)) { ebone->parent->flag &= ~BONE_TIPSEL; } - ebone->parent = NULL; + ebone->parent = nullptr; ebone->flag &= ~BONE_CONNECTED; } else { @@ -501,7 +501,9 @@ static void rna_Bone_bbone_handle_update(Main *bmain, Scene *scene, PointerRNA * Bone *bone = (Bone *)ptr->data; /* Update all users of this armature after changing B-Bone handles. */ - for (Object *obt = bmain->objects.first; obt; obt = obt->id.next) { + for (Object *obt = static_cast(bmain->objects.first); obt; + obt = static_cast(obt->id.next)) + { if (obt->data == arm && obt->pose) { bPoseChannel *pchan = BKE_pose_channel_find_name(obt->pose, bone->name); @@ -523,26 +525,26 @@ static PointerRNA rna_EditBone_bbone_prev_get(PointerRNA *ptr) static void rna_EditBone_bbone_prev_set(PointerRNA *ptr, PointerRNA value, - struct ReportList *UNUSED(reports)) + struct ReportList * /*reports*/) { EditBone *ebone = (EditBone *)(ptr->data); EditBone *hbone = (EditBone *)value.data; /* Within the same armature? */ - if (hbone == NULL || value.owner_id == ptr->owner_id) { + if (hbone == nullptr || value.owner_id == ptr->owner_id) { ebone->bbone_prev = hbone; } } static void rna_Bone_bbone_prev_set(PointerRNA *ptr, PointerRNA value, - struct ReportList *UNUSED(reports)) + struct ReportList * /*reports*/) { Bone *bone = (Bone *)ptr->data; Bone *hbone = (Bone *)value.data; /* Within the same armature? */ - if (hbone == NULL || value.owner_id == ptr->owner_id) { + if (hbone == nullptr || value.owner_id == ptr->owner_id) { bone->bbone_prev = hbone; } } @@ -555,26 +557,26 @@ static PointerRNA rna_EditBone_bbone_next_get(PointerRNA *ptr) static void rna_EditBone_bbone_next_set(PointerRNA *ptr, PointerRNA value, - struct ReportList *UNUSED(reports)) + struct ReportList * /*reports*/) { EditBone *ebone = (EditBone *)(ptr->data); EditBone *hbone = (EditBone *)value.data; /* Within the same armature? */ - if (hbone == NULL || value.owner_id == ptr->owner_id) { + if (hbone == nullptr || value.owner_id == ptr->owner_id) { ebone->bbone_next = hbone; } } static void rna_Bone_bbone_next_set(PointerRNA *ptr, PointerRNA value, - struct ReportList *UNUSED(reports)) + struct ReportList * /*reports*/) { Bone *bone = (Bone *)ptr->data; Bone *hbone = (Bone *)value.data; /* Within the same armature? */ - if (hbone == NULL || value.owner_id == ptr->owner_id) { + if (hbone == nullptr || value.owner_id == ptr->owner_id) { bone->bbone_next = hbone; } } @@ -591,7 +593,7 @@ static void rna_Armature_editbone_transform_update(Main *bmain, Scene *scene, Po } /* update our children if necessary */ - for (child = arm->edbo->first; child; child = child->next) { + for (child = static_cast(arm->edbo->first); child; child = child->next) { if (child->parent == ebone && (child->flag & BONE_CONNECTED)) { copy_v3_v3(child->head, ebone->tail); } @@ -616,7 +618,7 @@ static void rna_Armature_bones_next(CollectionPropertyIterator *iter) internal->link = (Link *)bone->next; } else { - internal->link = NULL; + internal->link = nullptr; do { bone = bone->parent; @@ -627,7 +629,7 @@ static void rna_Armature_bones_next(CollectionPropertyIterator *iter) } while (bone); } - iter->valid = (internal->link != NULL); + iter->valid = (internal->link != nullptr); } /* not essential, but much faster than the default lookup function */ @@ -647,7 +649,7 @@ static int rna_Armature_bones_lookup_string(PointerRNA *ptr, const char *key, Po static bool rna_Armature_is_editmode_get(PointerRNA *ptr) { bArmature *arm = (bArmature *)ptr->owner_id; - return (arm->edbo != NULL); + return (arm->edbo != nullptr); } static void rna_Armature_transform(bArmature *arm, float mat[16]) @@ -703,14 +705,14 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone, bool is_editb /* Roll In/Out */ prop = RNA_def_property(srna, "bbone_rollin", PROP_FLOAT, PROP_ANGLE); - RNA_def_property_float_sdna(prop, NULL, "roll1"); + RNA_def_property_float_sdna(prop, nullptr, "roll1"); RNA_def_property_ui_range(prop, -M_PI * 2, M_PI * 2, 10, 2); RNA_def_property_ui_text( prop, "Roll In", "Roll offset for the start of the B-Bone, adjusts twist"); RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone); prop = RNA_def_property(srna, "bbone_rollout", PROP_FLOAT, PROP_ANGLE); - RNA_def_property_float_sdna(prop, NULL, "roll2"); + RNA_def_property_float_sdna(prop, nullptr, "roll2"); RNA_def_property_ui_range(prop, -M_PI * 2, M_PI * 2, 10, 2); RNA_def_property_ui_text( prop, "Roll Out", "Roll offset for the end of the B-Bone, adjusts twist"); @@ -720,35 +722,35 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone, bool is_editb prop = RNA_def_property(srna, "use_endroll_as_inroll", PROP_BOOLEAN, PROP_NONE); RNA_def_property_ui_text( prop, "Inherit End Roll", "Add Roll Out of the Start Handle bone to the Roll In value"); - RNA_def_property_boolean_sdna(prop, NULL, "bbone_flag", BBONE_ADD_PARENT_END_ROLL); + RNA_def_property_boolean_sdna(prop, nullptr, "bbone_flag", BBONE_ADD_PARENT_END_ROLL); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, 0, "rna_Armature_dependency_update"); } /* Curve X/Y Offsets */ prop = RNA_def_property(srna, "bbone_curveinx", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "curve_in_x"); + RNA_def_property_float_sdna(prop, nullptr, "curve_in_x"); RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); RNA_def_property_ui_text( prop, "In X", "X-axis handle offset for start of the B-Bone's curve, adjusts curvature"); RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone); prop = RNA_def_property(srna, "bbone_curveinz", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "curve_in_z"); + RNA_def_property_float_sdna(prop, nullptr, "curve_in_z"); RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); RNA_def_property_ui_text( prop, "In Z", "Z-axis handle offset for start of the B-Bone's curve, adjusts curvature"); RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone); prop = RNA_def_property(srna, "bbone_curveoutx", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "curve_out_x"); + RNA_def_property_float_sdna(prop, nullptr, "curve_out_x"); RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); RNA_def_property_ui_text( prop, "Out X", "X-axis handle offset for end of the B-Bone's curve, adjusts curvature"); RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone); prop = RNA_def_property(srna, "bbone_curveoutz", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "curve_out_z"); + RNA_def_property_float_sdna(prop, nullptr, "curve_out_z"); RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); RNA_def_property_ui_text( prop, "Out Z", "Z-axis handle offset for end of the B-Bone's curve, adjusts curvature"); @@ -756,7 +758,7 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone, bool is_editb /* Ease In/Out */ prop = RNA_def_property(srna, "bbone_easein", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "ease1"); + RNA_def_property_float_sdna(prop, nullptr, "ease1"); RNA_def_property_ui_range(prop, -5.0f, 5.0f, 1, 3); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_ui_text(prop, "Ease In", "Length of first Bezier Handle (for B-Bones only)"); @@ -764,7 +766,7 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone, bool is_editb RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone); prop = RNA_def_property(srna, "bbone_easeout", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "ease2"); + RNA_def_property_float_sdna(prop, nullptr, "ease2"); RNA_def_property_ui_range(prop, -5.0f, 5.0f, 1, 3); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_ui_text(prop, "Ease Out", "Length of second Bezier Handle (for B-Bones only)"); @@ -775,13 +777,13 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone, bool is_editb prop = RNA_def_property(srna, "use_scale_easing", PROP_BOOLEAN, PROP_NONE); RNA_def_property_ui_text( prop, "Scale Easing", "Multiply the final easing values by the Scale In/Out Y factors"); - RNA_def_property_boolean_sdna(prop, NULL, "bbone_flag", BBONE_SCALE_EASING); + RNA_def_property_boolean_sdna(prop, nullptr, "bbone_flag", BBONE_SCALE_EASING); RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone); } /* Scale In/Out */ prop = RNA_def_property(srna, "bbone_scalein", PROP_FLOAT, PROP_XYZ); - RNA_def_property_float_sdna(prop, NULL, "scale_in"); + RNA_def_property_float_sdna(prop, nullptr, "scale_in"); RNA_def_property_array(prop, 3); RNA_def_property_flag(prop, PROP_PROPORTIONAL); RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, 3); @@ -793,7 +795,7 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone, bool is_editb RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone); prop = RNA_def_property(srna, "bbone_scaleout", PROP_FLOAT, PROP_XYZ); - RNA_def_property_float_sdna(prop, NULL, "scale_out"); + RNA_def_property_float_sdna(prop, nullptr, "scale_out"); RNA_def_property_array(prop, 3); RNA_def_property_flag(prop, PROP_PROPORTIONAL); RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, 3); @@ -830,7 +832,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) 0, "Tangent", "Use the orientation of the specified bone to compute the handle, ignoring the location"}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; static const EnumPropertyItem prop_inherit_scale_mode[] = { @@ -858,21 +860,21 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) "None (Legacy)", "Ignore parent scaling without compensating for parent shear. " "Replicates the effect of disabling the original Inherit Scale checkbox"}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; PropertyRNA *prop; /* strings */ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); - RNA_def_property_string_sdna(prop, NULL, "name"); + RNA_def_property_string_sdna(prop, nullptr, "name"); RNA_def_property_ui_text(prop, "Name", ""); RNA_def_struct_name_property(srna, prop); if (editbone) { - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_EditBone_name_set"); + RNA_def_property_string_funcs(prop, nullptr, nullptr, "rna_EditBone_name_set"); } else { - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Bone_name_set"); + RNA_def_property_string_funcs(prop, nullptr, nullptr, "rna_Bone_name_set"); } RNA_def_property_update(prop, 0, "rna_Bone_update_renamed"); @@ -880,21 +882,21 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) /* flags */ prop = RNA_def_property(srna, "layers", PROP_BOOLEAN, PROP_LAYER_MEMBER); - RNA_def_property_boolean_sdna(prop, NULL, "layer", 1); + RNA_def_property_boolean_sdna(prop, nullptr, "layer", 1); RNA_def_property_array(prop, 32); if (editbone) { - RNA_def_property_boolean_funcs(prop, NULL, "rna_EditBone_layer_set"); + RNA_def_property_boolean_funcs(prop, nullptr, "rna_EditBone_layer_set"); } else { - RNA_def_property_boolean_funcs(prop, NULL, "rna_Bone_layer_set"); + RNA_def_property_boolean_funcs(prop, nullptr, "rna_Bone_layer_set"); } RNA_def_property_ui_text(prop, "Layers", "Layers bone exists in"); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); prop = RNA_def_property(srna, "use_connect", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_CONNECTED); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", BONE_CONNECTED); if (editbone) { - RNA_def_property_boolean_funcs(prop, NULL, "rna_EditBone_connected_set"); + RNA_def_property_boolean_funcs(prop, nullptr, "rna_EditBone_connected_set"); } else { RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -904,13 +906,13 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) RNA_def_property_update(prop, 0, "rna_Armature_update_data"); prop = RNA_def_property(srna, "use_inherit_rotation", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", BONE_HINGE); + RNA_def_property_boolean_negative_sdna(prop, nullptr, "flag", BONE_HINGE); RNA_def_property_ui_text( prop, "Inherit Rotation", "Bone inherits rotation or scale from parent bone"); RNA_def_property_update(prop, 0, "rna_Armature_update_data"); prop = RNA_def_property(srna, "use_envelope_multiply", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_MULT_VG_ENV); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", BONE_MULT_VG_ENV); RNA_def_property_ui_text( prop, "Multiply Vertex Group with Envelope", @@ -918,14 +920,14 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) RNA_def_property_update(prop, 0, "rna_Armature_update_data"); prop = RNA_def_property(srna, "use_deform", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", BONE_NO_DEFORM); + RNA_def_property_boolean_negative_sdna(prop, nullptr, "flag", BONE_NO_DEFORM); RNA_def_property_ui_text(prop, "Deform", "Enable Bone to deform geometry"); RNA_def_property_update(prop, 0, "rna_Armature_update_data"); prop = RNA_def_property(srna, "inherit_scale", PROP_ENUM, PROP_NONE); RNA_def_property_ui_text( prop, "Inherit Scale", "Specifies how the bone inherits scaling from the parent bone"); - RNA_def_property_enum_sdna(prop, NULL, "inherit_scale_mode"); + RNA_def_property_enum_sdna(prop, nullptr, "inherit_scale_mode"); RNA_def_property_enum_items(prop, prop_inherit_scale_mode); RNA_def_property_update(prop, 0, "rna_Armature_update_data"); @@ -945,17 +947,17 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) prop = RNA_def_property(srna, "use_local_location", PROP_BOOLEAN, PROP_NONE); RNA_def_property_ui_text(prop, "Local Location", "Bone location is set in local space"); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", BONE_NO_LOCAL_LOCATION); + RNA_def_property_boolean_negative_sdna(prop, nullptr, "flag", BONE_NO_LOCAL_LOCATION); RNA_def_property_update(prop, 0, "rna_Armature_update_data"); prop = RNA_def_property(srna, "use_relative_parent", PROP_BOOLEAN, PROP_NONE); RNA_def_property_ui_text( prop, "Relative Parenting", "Object children will use relative transform, like deform"); - RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_RELATIVE_PARENTING); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", BONE_RELATIVE_PARENTING); RNA_def_property_update(prop, 0, "rna_Armature_update_data"); prop = RNA_def_property(srna, "show_wire", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_DRAWWIRE); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", BONE_DRAWWIRE); RNA_def_property_ui_text( prop, "Display Wire", @@ -965,7 +967,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) /* XXX: use_cyclic_offset is deprecated in 2.5. May/may not return */ prop = RNA_def_property(srna, "use_cyclic_offset", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", BONE_NO_CYCLICOFFSET); + RNA_def_property_boolean_negative_sdna(prop, nullptr, "flag", BONE_NO_CYCLICOFFSET); RNA_def_property_ui_text( prop, "Cyclic Offset", @@ -974,7 +976,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) RNA_def_property_update(prop, 0, "rna_Armature_update_data"); prop = RNA_def_property(srna, "hide_select", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_UNSELECTABLE); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", BONE_UNSELECTABLE); RNA_def_property_ui_text(prop, "Selectable", "Bone is able to be selected"); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); @@ -987,13 +989,13 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) else { RNA_def_property_update(prop, 0, "rna_Armature_update_data"); } - RNA_def_property_float_sdna(prop, NULL, "dist"); + RNA_def_property_float_sdna(prop, nullptr, "dist"); RNA_def_property_range(prop, 0.0f, 1000.0f); RNA_def_property_ui_text( prop, "Envelope Deform Distance", "Bone deformation distance (for Envelope deform only)"); prop = RNA_def_property(srna, "envelope_weight", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "weight"); + RNA_def_property_float_sdna(prop, nullptr, "weight"); RNA_def_property_range(prop, 0.0f, 1000.0f); RNA_def_property_ui_text( prop, "Envelope Deform Weight", "Bone deformation weight (for Envelope deform only)"); @@ -1006,7 +1008,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) else { RNA_def_property_update(prop, 0, "rna_Armature_update_data"); } - RNA_def_property_float_sdna(prop, NULL, "rad_head"); + RNA_def_property_float_sdna(prop, nullptr, "rad_head"); /* XXX range is 0 to limit, where limit = 10000.0f * MAX2(1.0, view3d->grid); */ // RNA_def_property_range(prop, 0, 1000); RNA_def_property_ui_range(prop, 0.01, 100, 0.1, 3); @@ -1020,7 +1022,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) else { RNA_def_property_update(prop, 0, "rna_Armature_update_data"); } - RNA_def_property_float_sdna(prop, NULL, "rad_tail"); + RNA_def_property_float_sdna(prop, nullptr, "rad_tail"); /* XXX range is 0 to limit, where limit = 10000.0f * MAX2(1.0, view3d->grid); */ // RNA_def_property_range(prop, 0, 1000); RNA_def_property_ui_range(prop, 0.01, 100, 0.1, 3); @@ -1035,7 +1037,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) else { RNA_def_property_update(prop, 0, "rna_Armature_dependency_update"); } - RNA_def_property_int_sdna(prop, NULL, "segments"); + RNA_def_property_int_sdna(prop, nullptr, "segments"); RNA_def_property_range(prop, 1, 32); RNA_def_property_ui_text( prop, "B-Bone Segments", "Number of subdivisions of bone (for B-Bones only)"); @@ -1047,7 +1049,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) else { RNA_def_property_update(prop, 0, "rna_Armature_update_data"); } - RNA_def_property_float_sdna(prop, NULL, "xwidth"); + RNA_def_property_float_sdna(prop, nullptr, "xwidth"); RNA_def_property_ui_range(prop, 0.0f, 1000.0f, 1, RNA_TRANSLATION_PREC_DEFAULT); RNA_def_property_ui_text(prop, "B-Bone Display X Width", "B-Bone X size"); @@ -1058,13 +1060,13 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) else { RNA_def_property_update(prop, 0, "rna_Armature_update_data"); } - RNA_def_property_float_sdna(prop, NULL, "zwidth"); + RNA_def_property_float_sdna(prop, nullptr, "zwidth"); RNA_def_property_ui_range(prop, 0.0f, 1000.0f, 1, RNA_TRANSLATION_PREC_DEFAULT); RNA_def_property_ui_text(prop, "B-Bone Display Z Width", "B-Bone Z size"); /* B-Bone Start Handle settings. */ prop = RNA_def_property(srna, "bbone_handle_type_start", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "bbone_prev_type"); + RNA_def_property_enum_sdna(prop, nullptr, "bbone_prev_type"); RNA_def_property_enum_items(prop, prop_bbone_handle_type); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text( @@ -1072,15 +1074,15 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) RNA_def_property_update(prop, 0, "rna_Armature_dependency_update"); prop = RNA_def_property(srna, "bbone_custom_handle_start", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "bbone_prev"); + RNA_def_property_pointer_sdna(prop, nullptr, "bbone_prev"); RNA_def_property_struct_type(prop, editbone ? "EditBone" : "Bone"); if (editbone) { RNA_def_property_pointer_funcs( - prop, "rna_EditBone_bbone_prev_get", "rna_EditBone_bbone_prev_set", NULL, NULL); + prop, "rna_EditBone_bbone_prev_get", "rna_EditBone_bbone_prev_set", nullptr, nullptr); RNA_def_property_update(prop, 0, "rna_Armature_dependency_update"); } else { - RNA_def_property_pointer_funcs(prop, NULL, "rna_Bone_bbone_prev_set", NULL, NULL); + RNA_def_property_pointer_funcs(prop, nullptr, "rna_Bone_bbone_prev_set", nullptr, nullptr); RNA_def_property_update(prop, 0, "rna_Bone_bbone_handle_update"); } RNA_def_property_flag(prop, PROP_EDITABLE | PROP_PTR_NO_OWNERSHIP); @@ -1094,7 +1096,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) "Start Handle Scale", "Multiply B-Bone Scale In channels by the local scale values of the start handle. " "This is done after the Scale Easing option and isn't affected by it"); - RNA_def_property_boolean_sdna(prop, NULL, "bbone_prev_flag", BBONE_HANDLE_SCALE_X); + RNA_def_property_boolean_sdna(prop, nullptr, "bbone_prev_flag", BBONE_HANDLE_SCALE_X); RNA_def_property_array(prop, 3); RNA_def_property_update(prop, 0, "rna_Armature_update_data"); @@ -1104,12 +1106,12 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) "Start Handle Ease", "Multiply the B-Bone Ease In channel by the local Y scale value of the start handle. " "This is done after the Scale Easing option and isn't affected by it"); - RNA_def_property_boolean_sdna(prop, NULL, "bbone_prev_flag", BBONE_HANDLE_SCALE_EASE); + RNA_def_property_boolean_sdna(prop, nullptr, "bbone_prev_flag", BBONE_HANDLE_SCALE_EASE); RNA_def_property_update(prop, 0, "rna_Armature_update_data"); /* B-Bone End Handle settings. */ prop = RNA_def_property(srna, "bbone_handle_type_end", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "bbone_next_type"); + RNA_def_property_enum_sdna(prop, nullptr, "bbone_next_type"); RNA_def_property_enum_items(prop, prop_bbone_handle_type); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text( @@ -1117,15 +1119,15 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) RNA_def_property_update(prop, 0, "rna_Armature_dependency_update"); prop = RNA_def_property(srna, "bbone_custom_handle_end", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "bbone_next"); + RNA_def_property_pointer_sdna(prop, nullptr, "bbone_next"); RNA_def_property_struct_type(prop, editbone ? "EditBone" : "Bone"); if (editbone) { RNA_def_property_pointer_funcs( - prop, "rna_EditBone_bbone_next_get", "rna_EditBone_bbone_next_set", NULL, NULL); + prop, "rna_EditBone_bbone_next_get", "rna_EditBone_bbone_next_set", nullptr, nullptr); RNA_def_property_update(prop, 0, "rna_Armature_dependency_update"); } else { - RNA_def_property_pointer_funcs(prop, NULL, "rna_Bone_bbone_next_set", NULL, NULL); + RNA_def_property_pointer_funcs(prop, nullptr, "rna_Bone_bbone_next_set", nullptr, nullptr); RNA_def_property_update(prop, 0, "rna_Bone_bbone_handle_update"); } RNA_def_property_flag(prop, PROP_EDITABLE | PROP_PTR_NO_OWNERSHIP); @@ -1139,7 +1141,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) "End Handle Scale", "Multiply B-Bone Scale Out channels by the local scale values of the end handle. " "This is done after the Scale Easing option and isn't affected by it"); - RNA_def_property_boolean_sdna(prop, NULL, "bbone_next_flag", BBONE_HANDLE_SCALE_X); + RNA_def_property_boolean_sdna(prop, nullptr, "bbone_next_flag", BBONE_HANDLE_SCALE_X); RNA_def_property_array(prop, 3); RNA_def_property_update(prop, 0, "rna_Armature_update_data"); @@ -1149,7 +1151,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) "End Handle Ease", "Multiply the B-Bone Ease Out channel by the local Y scale value of the end handle. " "This is done after the Scale Easing option and isn't affected by it"); - RNA_def_property_boolean_sdna(prop, NULL, "bbone_next_flag", BBONE_HANDLE_SCALE_EASE); + RNA_def_property_boolean_sdna(prop, nullptr, "bbone_next_flag", BBONE_HANDLE_SCALE_EASE); RNA_def_property_update(prop, 0, "rna_Armature_update_data"); RNA_define_lib_overridable(false); @@ -1161,7 +1163,7 @@ static void rna_def_bone(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; - srna = RNA_def_struct(brna, "Bone", NULL); + srna = RNA_def_struct(brna, "Bone", nullptr); RNA_def_struct_ui_text(srna, "Bone", "Bone in an Armature data-block"); RNA_def_struct_ui_icon(srna, ICON_BONE_DATA); RNA_def_struct_path_func(srna, "rna_Bone_path"); @@ -1171,14 +1173,14 @@ static void rna_def_bone(BlenderRNA *brna) /* parent (pointer) */ prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "Bone"); - RNA_def_property_pointer_sdna(prop, NULL, "parent"); + RNA_def_property_pointer_sdna(prop, nullptr, "parent"); RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_ui_text(prop, "Parent", "Parent bone (in same Armature)"); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); /* children (collection) */ prop = RNA_def_property(srna, "children", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "childbase", NULL); + RNA_def_property_collection_sdna(prop, nullptr, "childbase", nullptr); RNA_def_property_struct_type(prop, "Bone"); RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_ui_text(prop, "Children", "Bones which are children of this bone"); @@ -1191,7 +1193,7 @@ static void rna_def_bone(BlenderRNA *brna) /* XXX should we define this in PoseChannel wrapping code instead? * But PoseChannels directly get some of their flags from here... */ prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_HIDDEN_P); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", BONE_HIDDEN_P); RNA_def_property_ui_text( prop, "Hide", @@ -1200,7 +1202,7 @@ static void rna_def_bone(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Bone_hide_update"); prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_SELECTED); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", BONE_SELECTED); RNA_def_property_ui_text(prop, "Select", ""); RNA_def_property_clear_flag( prop, @@ -1208,33 +1210,33 @@ static void rna_def_bone(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Bone_select_update"); prop = RNA_def_property(srna, "select_head", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_ROOTSEL); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", BONE_ROOTSEL); RNA_def_property_ui_text(prop, "Select Head", ""); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); prop = RNA_def_property(srna, "select_tail", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_TIPSEL); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", BONE_TIPSEL); RNA_def_property_ui_text(prop, "Select Tail", ""); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); /* XXX better matrix descriptions possible (Arystan) */ prop = RNA_def_property(srna, "matrix", PROP_FLOAT, PROP_MATRIX); - RNA_def_property_float_sdna(prop, NULL, "bone_mat"); + RNA_def_property_float_sdna(prop, nullptr, "bone_mat"); RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_3x3); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Bone Matrix", "3x3 bone matrix"); prop = RNA_def_property(srna, "matrix_local", PROP_FLOAT, PROP_MATRIX); - RNA_def_property_float_sdna(prop, NULL, "arm_mat"); + RNA_def_property_float_sdna(prop, nullptr, "arm_mat"); RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text( prop, "Bone Armature-Relative Matrix", "4x4 bone matrix relative to armature"); prop = RNA_def_property(srna, "tail", PROP_FLOAT, PROP_TRANSLATION); - RNA_def_property_float_sdna(prop, NULL, "tail"); + RNA_def_property_float_sdna(prop, nullptr, "tail"); RNA_def_property_array(prop, 3); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text( @@ -1242,7 +1244,7 @@ static void rna_def_bone(BlenderRNA *brna) RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); prop = RNA_def_property(srna, "tail_local", PROP_FLOAT, PROP_TRANSLATION); - RNA_def_property_float_sdna(prop, NULL, "arm_tail"); + RNA_def_property_float_sdna(prop, nullptr, "arm_tail"); RNA_def_property_array(prop, 3); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text( @@ -1250,7 +1252,7 @@ static void rna_def_bone(BlenderRNA *brna) RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); prop = RNA_def_property(srna, "head", PROP_FLOAT, PROP_TRANSLATION); - RNA_def_property_float_sdna(prop, NULL, "head"); + RNA_def_property_float_sdna(prop, nullptr, "head"); RNA_def_property_array(prop, 3); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text( @@ -1258,7 +1260,7 @@ static void rna_def_bone(BlenderRNA *brna) RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); prop = RNA_def_property(srna, "head_local", PROP_FLOAT, PROP_TRANSLATION); - RNA_def_property_float_sdna(prop, NULL, "arm_head"); + RNA_def_property_float_sdna(prop, nullptr, "arm_head"); RNA_def_property_array(prop, 3); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text( @@ -1266,7 +1268,7 @@ static void rna_def_bone(BlenderRNA *brna) RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); prop = RNA_def_property(srna, "length", PROP_FLOAT, PROP_DISTANCE); - RNA_def_property_float_sdna(prop, NULL, "length"); + RNA_def_property_float_sdna(prop, nullptr, "length"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Length", "Length of the bone"); @@ -1280,7 +1282,7 @@ static void rna_def_edit_bone(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; - srna = RNA_def_struct(brna, "EditBone", NULL); + srna = RNA_def_struct(brna, "EditBone", nullptr); RNA_def_struct_sdna(srna, "EditBone"); RNA_def_struct_idprops_func(srna, "rna_EditBone_idprops"); RNA_def_struct_ui_text(srna, "Edit Bone", "Edit mode bone in an armature data-block"); @@ -1291,20 +1293,20 @@ static void rna_def_edit_bone(BlenderRNA *brna) prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "EditBone"); RNA_def_property_pointer_funcs( - prop, "rna_EditBone_parent_get", "rna_EditBone_parent_set", NULL, NULL); + prop, "rna_EditBone_parent_get", "rna_EditBone_parent_set", nullptr, nullptr); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Parent", "Parent edit bone (in same Armature)"); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); prop = RNA_def_property(srna, "roll", PROP_FLOAT, PROP_ANGLE); - RNA_def_property_float_sdna(prop, NULL, "roll"); + RNA_def_property_float_sdna(prop, nullptr, "roll"); RNA_def_property_ui_range(prop, -M_PI * 2, M_PI * 2, 10, 2); RNA_def_property_ui_text(prop, "Roll", "Bone rotation around head-tail axis"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, 0, "rna_Armature_editbone_transform_update"); prop = RNA_def_property(srna, "head", PROP_FLOAT, PROP_TRANSLATION); - RNA_def_property_float_sdna(prop, NULL, "head"); + RNA_def_property_float_sdna(prop, nullptr, "head"); RNA_def_property_ui_range(prop, 0, FLT_MAX, 10, RNA_TRANSLATION_PREC_DEFAULT); RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Head", "Location of head end of the bone"); @@ -1312,7 +1314,7 @@ static void rna_def_edit_bone(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Armature_editbone_transform_update"); prop = RNA_def_property(srna, "tail", PROP_FLOAT, PROP_TRANSLATION); - RNA_def_property_float_sdna(prop, NULL, "tail"); + RNA_def_property_float_sdna(prop, nullptr, "tail"); RNA_def_property_ui_range(prop, 0, FLT_MAX, 10, RNA_TRANSLATION_PREC_DEFAULT); RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Tail", "Location of tail end of the bone"); @@ -1320,7 +1322,8 @@ static void rna_def_edit_bone(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Armature_editbone_transform_update"); prop = RNA_def_property(srna, "length", PROP_FLOAT, PROP_DISTANCE); - RNA_def_property_float_funcs(prop, "rna_EditBone_length_get", "rna_EditBone_length_set", NULL); + RNA_def_property_float_funcs( + prop, "rna_EditBone_length_get", "rna_EditBone_length_set", nullptr); RNA_def_property_range(prop, 0, FLT_MAX); RNA_def_property_ui_range(prop, 0, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); RNA_def_property_ui_text(prop, "Length", "Length of the bone. Changing moves the tail end"); @@ -1331,38 +1334,38 @@ static void rna_def_edit_bone(BlenderRNA *brna) rna_def_bone_curved_common(srna, false, true); prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_HIDDEN_A); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", BONE_HIDDEN_A); RNA_def_property_ui_text(prop, "Hide", "Bone is not visible when in Edit Mode"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_EDITMODE_LOCKED); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", BONE_EDITMODE_LOCKED); RNA_def_property_ui_text(prop, "Lock", "Bone is not able to be transformed when in Edit Mode"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_SELECTED); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", BONE_SELECTED); RNA_def_property_ui_text(prop, "Select", ""); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); prop = RNA_def_property(srna, "select_head", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_ROOTSEL); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", BONE_ROOTSEL); RNA_def_property_ui_text(prop, "Head Select", ""); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); prop = RNA_def_property(srna, "select_tail", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_TIPSEL); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", BONE_TIPSEL); RNA_def_property_ui_text(prop, "Tail Select", ""); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); /* calculated and read only, not actual data access */ prop = RNA_def_property(srna, "matrix", PROP_FLOAT, PROP_MATRIX); - // RNA_def_property_float_sdna(prop, NULL, ""); /* Doesn't access any real data. */ + // RNA_def_property_float_sdna(prop, nullptr, ""); /* Doesn't access any real data. */ RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); // RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_THICK_WRAP); /* no reference to original data */ @@ -1371,7 +1374,8 @@ static void rna_def_edit_bone(BlenderRNA *brna) "Edit Bone Matrix", "Matrix combining location and rotation of the bone (head position, direction and roll), " "in armature space (does not include/support bone's length/size)"); - RNA_def_property_float_funcs(prop, "rna_EditBone_matrix_get", "rna_EditBone_matrix_set", NULL); + RNA_def_property_float_funcs( + prop, "rna_EditBone_matrix_get", "rna_EditBone_matrix_set", nullptr); RNA_api_armature_edit_bone(srna); @@ -1388,16 +1392,16 @@ static void rna_def_armature_bones(BlenderRNA *brna, PropertyRNA *cprop) /* PropertyRNA *parm; */ RNA_def_property_srna(cprop, "ArmatureBones"); - srna = RNA_def_struct(brna, "ArmatureBones", NULL); + srna = RNA_def_struct(brna, "ArmatureBones", nullptr); RNA_def_struct_sdna(srna, "bArmature"); RNA_def_struct_ui_text(srna, "Armature Bones", "Collection of armature bones"); prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "Bone"); - RNA_def_property_pointer_sdna(prop, NULL, "act_bone"); + RNA_def_property_pointer_sdna(prop, nullptr, "act_bone"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Active Bone", "Armature's active bone"); - RNA_def_property_pointer_funcs(prop, NULL, "rna_Armature_act_bone_set", NULL, NULL); + RNA_def_property_pointer_funcs(prop, nullptr, "rna_Armature_act_bone_set", nullptr, nullptr); RNA_def_property_update(prop, 0, "rna_Armature_update"); /* TODO: redraw. */ @@ -1414,17 +1418,18 @@ static void rna_def_armature_edit_bones(BlenderRNA *brna, PropertyRNA *cprop) PropertyRNA *parm; RNA_def_property_srna(cprop, "ArmatureEditBones"); - srna = RNA_def_struct(brna, "ArmatureEditBones", NULL); + srna = RNA_def_struct(brna, "ArmatureEditBones", nullptr); RNA_def_struct_sdna(srna, "bArmature"); RNA_def_struct_ui_text(srna, "Armature EditBones", "Collection of armature edit bones"); prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "EditBone"); - RNA_def_property_pointer_sdna(prop, NULL, "act_edbone"); + RNA_def_property_pointer_sdna(prop, nullptr, "act_edbone"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Active EditBone", "Armatures active edit bone"); RNA_def_property_update(prop, 0, "rna_Armature_update"); - RNA_def_property_pointer_funcs(prop, NULL, "rna_Armature_act_edit_bone_set", NULL, NULL); + RNA_def_property_pointer_funcs( + prop, nullptr, "rna_Armature_act_edit_bone_set", nullptr, nullptr); /* TODO: redraw. */ /* RNA_def_property_collection_active(prop, prop_act); */ @@ -1434,7 +1439,7 @@ static void rna_def_armature_edit_bones(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Add a new bone"); parm = RNA_def_string(func, "name", "Object", 0, "", "New name for the bone"); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "bone", "EditBone", "", "Newly created edit bone"); RNA_def_function_return(func, parm); @@ -1446,7 +1451,7 @@ static void rna_def_armature_edit_bones(BlenderRNA *brna, PropertyRNA *cprop) /* Target to remove. */ parm = RNA_def_pointer(func, "bone", "EditBone", "", "EditBone to remove"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); - RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, ParameterFlag(0)); } static void rna_def_armature(BlenderRNA *brna) @@ -1475,7 +1480,7 @@ static void rna_def_armature(BlenderRNA *brna) 0, "Wire", "Display bones as thin wires, showing subdivision and B-Splines"}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; static const EnumPropertyItem prop_pose_position_items[] = { {0, "POSE", 0, "Pose Position", "Show armature in posed state"}, @@ -1484,12 +1489,12 @@ static void rna_def_armature(BlenderRNA *brna) 0, "Rest Position", "Show Armature in binding pose state (no posing possible)"}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; static const EnumPropertyItem prop_relation_lines_items[] = { {0, "TAIL", 0, "Tail", "Draw the relationship line from the parent tail to the child head"}, {1, "HEAD", 0, "Head", "Draw the relationship line from the parent head to the child head"}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; srna = RNA_def_struct(brna, "Armature", "ID"); @@ -1502,8 +1507,8 @@ static void rna_def_armature(BlenderRNA *brna) func = RNA_def_function(srna, "transform", "rna_Armature_transform"); RNA_def_function_ui_description(func, "Transform armature bones by a matrix"); - parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_float_matrix(func, "matrix", 4, 4, nullptr, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f); + RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED); /* Animation Data */ rna_def_animdata_common(srna); @@ -1512,29 +1517,29 @@ static void rna_def_armature(BlenderRNA *brna) /* Collections */ prop = RNA_def_property(srna, "bones", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "bonebase", NULL); + RNA_def_property_collection_sdna(prop, nullptr, "bonebase", nullptr); RNA_def_property_collection_funcs(prop, - NULL, + nullptr, "rna_Armature_bones_next", - NULL, - NULL, - NULL, - NULL, + nullptr, + nullptr, + nullptr, + nullptr, "rna_Armature_bones_lookup_string", - NULL); + nullptr); RNA_def_property_struct_type(prop, "Bone"); RNA_def_property_ui_text(prop, "Bones", ""); rna_def_armature_bones(brna, prop); prop = RNA_def_property(srna, "edit_bones", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "edbo", NULL); + RNA_def_property_collection_sdna(prop, nullptr, "edbo", nullptr); RNA_def_property_struct_type(prop, "EditBone"); RNA_def_property_ui_text(prop, "Edit Bones", ""); rna_def_armature_edit_bones(brna, prop); /* Enum values */ prop = RNA_def_property(srna, "pose_position", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); + RNA_def_property_enum_bitflag_sdna(prop, nullptr, "flag"); RNA_def_property_enum_items(prop, prop_pose_position_items); RNA_def_property_ui_text( prop, "Pose Position", "Show armature in binding pose or final posed state"); @@ -1542,7 +1547,7 @@ static void rna_def_armature(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); prop = RNA_def_property(srna, "display_type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "drawtype"); + RNA_def_property_enum_sdna(prop, nullptr, "drawtype"); RNA_def_property_enum_items(prop, prop_drawtype_items); RNA_def_property_ui_text(prop, "Display Type", ""); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); @@ -1551,16 +1556,16 @@ static void rna_def_armature(BlenderRNA *brna) /* Boolean values */ /* layer */ prop = RNA_def_property(srna, "layers", PROP_BOOLEAN, PROP_LAYER_MEMBER); - RNA_def_property_boolean_sdna(prop, NULL, "layer", 1); + RNA_def_property_boolean_sdna(prop, nullptr, "layer", 1); RNA_def_property_array(prop, 32); RNA_def_property_ui_text(prop, "Visible Layers", "Armature layer visibility"); - RNA_def_property_boolean_funcs(prop, NULL, "rna_Armature_layer_set"); + RNA_def_property_boolean_funcs(prop, nullptr, "rna_Armature_layer_set"); RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Armature_update_layers"); RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); /* layer protection */ prop = RNA_def_property(srna, "layers_protected", PROP_BOOLEAN, PROP_LAYER); - RNA_def_property_boolean_sdna(prop, NULL, "layer_protected", 1); + RNA_def_property_boolean_sdna(prop, nullptr, "layer_protected", 1); RNA_def_property_array(prop, 32); RNA_def_property_ui_text(prop, "Layer Override Protection", @@ -1570,13 +1575,13 @@ static void rna_def_armature(BlenderRNA *brna) /* flag */ prop = RNA_def_property(srna, "show_axes", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", ARM_DRAWAXES); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", ARM_DRAWAXES); RNA_def_property_ui_text(prop, "Display Axes", "Display bone axes"); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); prop = RNA_def_property(srna, "axes_position", PROP_FLOAT, PROP_FACTOR); - RNA_def_property_float_sdna(prop, NULL, "axes_position"); + RNA_def_property_float_sdna(prop, nullptr, "axes_position"); RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_ui_range(prop, 0.0, 1.0, 10, 1); RNA_def_property_ui_text(prop, @@ -1596,35 +1601,35 @@ static void rna_def_armature(BlenderRNA *brna) RNA_def_property_enum_funcs(prop, "rna_Armature_relation_line_position_get", "rna_Armature_relation_line_position_set", - /*item function*/ NULL); + /*item function*/ nullptr); RNA_define_verify_sdna(true); /* Restore default. */ prop = RNA_def_property(srna, "show_names", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", ARM_DRAWNAMES); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", ARM_DRAWNAMES); RNA_def_property_ui_text(prop, "Display Names", "Display bone names"); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); prop = RNA_def_property(srna, "use_mirror_x", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", ARM_MIRROR_EDIT); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", ARM_MIRROR_EDIT); RNA_def_property_ui_text( prop, "X-Axis Mirror", "Apply changes to matching bone on opposite side of X-Axis"); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); prop = RNA_def_property(srna, "show_bone_custom_shapes", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", ARM_NO_CUSTOM); + RNA_def_property_boolean_negative_sdna(prop, nullptr, "flag", ARM_NO_CUSTOM); RNA_def_property_ui_text( prop, "Display Custom Bone Shapes", "Display bones with their custom shapes"); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); prop = RNA_def_property(srna, "show_group_colors", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", ARM_COL_CUSTOM); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", ARM_COL_CUSTOM); RNA_def_property_ui_text(prop, "Display Bone Group Colors", "Display bone group colors"); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); prop = RNA_def_property(srna, "is_editmode", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_funcs(prop, "rna_Armature_is_editmode_get", NULL); + RNA_def_property_boolean_funcs(prop, "rna_Armature_is_editmode_get", nullptr); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Is Editmode", "True when used in editmode"); diff --git a/source/blender/makesrna/intern/rna_armature_api.c b/source/blender/makesrna/intern/rna_armature_api.cc similarity index 93% rename from source/blender/makesrna/intern/rna_armature_api.c rename to source/blender/makesrna/intern/rna_armature_api.cc index 21448491fea4..9bf07221d7c7 100644 --- a/source/blender/makesrna/intern/rna_armature_api.c +++ b/source/blender/makesrna/intern/rna_armature_api.cc @@ -57,7 +57,7 @@ static void rna_Bone_convert_local_to_pose(Bone *bone, if (is_zero_m4(parent_pose_mat) || is_zero_m4(parent_arm_mat)) { /* No parent case. */ BKE_bone_parent_transform_calc_from_matrices( - bone->flag, bone->inherit_scale_mode, bone_arm_mat, NULL, NULL, &bpt); + bone->flag, bone->inherit_scale_mode, bone_arm_mat, nullptr, nullptr, &bpt); } else { invert_m4_m4(offs_bone, parent_arm_mat); @@ -107,8 +107,8 @@ void RNA_api_armature_edit_bone(StructRNA *srna) "Align the bone to a local-space roll so the Z axis " "points in the direction of the vector given"); parm = RNA_def_float_vector( - func, "vector", 3, NULL, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + func, "vector", 3, nullptr, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX); + RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED); } void RNA_api_bone(StructRNA *srna) @@ -121,14 +121,14 @@ void RNA_api_bone(StructRNA *srna) parm = RNA_def_float_vector_xyz(func, "point", 3, - NULL, + nullptr, -FLT_MAX, FLT_MAX, "Point", "Position in 3d space to evaluate", -FLT_MAX, FLT_MAX); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED); /* return value */ parm = RNA_def_float( func, "factor", 0, -FLT_MAX, FLT_MAX, "Factor", "Envelope factor", -FLT_MAX, FLT_MAX); @@ -148,11 +148,11 @@ void RNA_api_bone(StructRNA *srna) parm = RNA_def_property(func, "matrix", PROP_FLOAT, PROP_MATRIX); RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4); RNA_def_property_ui_text(parm, "", "The matrix to transform"); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED); parm = RNA_def_property(func, "matrix_local", PROP_FLOAT, PROP_MATRIX); RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4); RNA_def_property_ui_text(parm, "", "The custom rest matrix of this bone (Bone.matrix_local)"); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED); parm = RNA_def_property(func, "parent_matrix", PROP_FLOAT, PROP_MATRIX); RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4); RNA_def_property_ui_text( @@ -173,7 +173,7 @@ void RNA_api_bone(StructRNA *srna) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "roll", PROP_FLOAT, PROP_NONE); RNA_def_property_ui_text(parm, "", "The roll of the bone"); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED); parm = RNA_def_property(func, "result_matrix", PROP_FLOAT, PROP_MATRIX); RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_3x3); RNA_def_property_ui_text(parm, "", "The resulting orientation matrix"); diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index b14d5b3bd4d4..48586d83b856 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -526,7 +526,7 @@ static int rna_find_sdna_member(SDNA *sdna, return 0; } -static int rna_validate_identifier(const char *identifier, char *error, bool property) +static bool rna_validate_identifier(const char *identifier, bool property, const char **r_error) { int a = 0; @@ -548,15 +548,15 @@ static int rna_validate_identifier(const char *identifier, char *error, bool pro }; if (!isalpha(identifier[0])) { - strcpy(error, "first character failed isalpha() check"); - return 0; + *r_error = "first character failed isalpha() check"; + return false; } for (a = 0; identifier[a]; a++) { if (DefRNA.preprocess && property) { if (isalpha(identifier[a]) && isupper(identifier[a])) { - strcpy(error, "property names must contain lower case characters only"); - return 0; + *r_error = "property names must contain lower case characters only"; + return false; } } @@ -565,20 +565,20 @@ static int rna_validate_identifier(const char *identifier, char *error, bool pro } if (identifier[a] == ' ') { - strcpy(error, "spaces are not okay in identifier names"); - return 0; + *r_error = "spaces are not okay in identifier names"; + return false; } if (isalnum(identifier[a]) == 0) { - strcpy(error, "one of the characters failed an isalnum() check and is not an underscore"); - return 0; + *r_error = "one of the characters failed an isalnum() check and is not an underscore"; + return false; } } for (a = 0; kwlist[a]; a++) { if (STREQ(identifier, kwlist[a])) { - strcpy(error, "this keyword is reserved by Python"); - return 0; + *r_error = "this keyword is reserved by Python"; + return false; } } @@ -594,13 +594,13 @@ static int rna_validate_identifier(const char *identifier, char *error, bool pro for (a = 0; kwlist_prop[a]; a++) { if (STREQ(identifier, kwlist_prop[a])) { - strcpy(error, "this keyword is reserved by Python"); - return 0; + *r_error = "this keyword is reserved by Python"; + return false; } } } - return 1; + return true; } void RNA_identifier_sanitize(char *identifier, int property) @@ -907,9 +907,9 @@ StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRN PropertyRNA *prop; if (DefRNA.preprocess) { - char error[512]; + const char *error = NULL; - if (rna_validate_identifier(identifier, error, false) == 0) { + if (!rna_validate_identifier(identifier, false, &error)) { CLOG_ERROR(&LOG, "struct identifier \"%s\" error - %s", identifier, error); DefRNA.error = true; } @@ -1269,9 +1269,9 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, PropertyRNA *prop; if (DefRNA.preprocess) { - char error[512]; + const char *error = NULL; - if (rna_validate_identifier(identifier, error, true) == 0) { + if (!rna_validate_identifier(identifier, true, &error)) { CLOG_ERROR( &LOG, "property identifier \"%s.%s\" - %s", CONTAINER_RNA_ID(cont), identifier, error); DefRNA.error = true; @@ -1290,8 +1290,8 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, } else { #ifndef NDEBUG - char error[512]; - if (rna_validate_identifier(identifier, error, true) == 0) { + const char *error = NULL; + if (!rna_validate_identifier(identifier, true, &error)) { CLOG_ERROR(&LOG, "runtime property identifier \"%s.%s\" - %s", CONTAINER_RNA_ID(cont), @@ -3477,8 +3477,8 @@ void RNA_def_property_collection_funcs(PropertyRNA *prop, void RNA_def_property_srna(PropertyRNA *prop, const char *type) { - char error[512]; - if (rna_validate_identifier(type, error, false) == 0) { + const char *error = NULL; + if (!rna_validate_identifier(type, false, &error)) { CLOG_ERROR(&LOG, "struct identifier \"%s\" error - %s", type, error); DefRNA.error = true; return; @@ -4247,9 +4247,8 @@ static FunctionRNA *rna_def_function(StructRNA *srna, const char *identifier) FunctionDefRNA *dfunc; if (DefRNA.preprocess) { - char error[512]; - - if (rna_validate_identifier(identifier, error, false) == 0) { + const char *error = NULL; + if (!rna_validate_identifier(identifier, false, &error)) { CLOG_ERROR(&LOG, "function identifier \"%s\" - %s", identifier, error); DefRNA.error = true; } diff --git a/source/blender/makesrna/intern/rna_object.cc b/source/blender/makesrna/intern/rna_object.cc index f9775651aa49..f5ff2e84d5f1 100644 --- a/source/blender/makesrna/intern/rna_object.cc +++ b/source/blender/makesrna/intern/rna_object.cc @@ -1403,7 +1403,7 @@ static int rna_MaterialSlot_name_length(PointerRNA *ptr) return 0; } -static void rna_MaterialSlot_name_get(PointerRNA *ptr, char *str) +static void rna_MaterialSlot_name_get(PointerRNA *ptr, char *value) { Object *ob = reinterpret_cast(ptr->owner_id); Material *ma; @@ -1412,10 +1412,10 @@ static void rna_MaterialSlot_name_get(PointerRNA *ptr, char *str) ma = BKE_object_material_get(ob, index + 1); if (ma) { - strcpy(str, ma->id.name + 2); + strcpy(value, ma->id.name + 2); } else { - str[0] = '\0'; + value[0] = '\0'; } } diff --git a/source/blender/makesrna/intern/rna_object_api.cc b/source/blender/makesrna/intern/rna_object_api.cc index 33c59ccada90..a880b84b9d7a 100644 --- a/source/blender/makesrna/intern/rna_object_api.cc +++ b/source/blender/makesrna/intern/rna_object_api.cc @@ -30,6 +30,8 @@ #include "rna_internal.h" /* own include */ +#define MESH_DM_INFO_STR_MAX 16384 + static const EnumPropertyItem space_items[] = { {CONSTRAINT_SPACE_WORLD, "WORLD", 0, "World Space", "The most global space in Blender"}, {CONSTRAINT_SPACE_POSE, @@ -763,7 +765,7 @@ void rna_Object_me_eval_info( if (me_eval) { ret = BKE_mesh_debug_info(me_eval); if (ret) { - strcpy(result, ret); + BLI_strncpy(result, ret, MESH_DM_INFO_STR_MAX); MEM_freeN(ret); } } @@ -1329,7 +1331,8 @@ void RNA_api_object(StructRNA *srna) "(only needed if current Context's depsgraph is not suitable)"); RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_RNAPTR); /* weak!, no way to return dynamic string type */ - parm = RNA_def_string(func, "result", nullptr, 16384, "", "Requested information"); + parm = RNA_def_string( + func, "result", nullptr, MESH_DM_INFO_STR_MAX, "", "Requested information"); RNA_def_parameter_flags( parm, PROP_THICK_WRAP, ParameterFlag(0)); /* needed for string return value */ RNA_def_function_output(func, parm); diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index b88cbc16826f..176070ef52d5 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -1168,7 +1168,7 @@ static void rna_ParticleSystem_active_particle_target_index_set(struct PointerRN } } -static void rna_ParticleTarget_name_get(PointerRNA *ptr, char *str) +static void rna_ParticleTarget_name_get(PointerRNA *ptr, char *value) { ParticleTarget *pt = ptr->data; @@ -1185,28 +1185,28 @@ static void rna_ParticleTarget_name_get(PointerRNA *ptr, char *str) if (psys) { if (pt->ob) { - BLI_sprintf(str, "%s: %s", pt->ob->id.name + 2, psys->name); + BLI_sprintf(value, "%s: %s", pt->ob->id.name + 2, psys->name); } else { - strcpy(str, psys->name); + strcpy(value, psys->name); } } else { - strcpy(str, TIP_("Invalid target!")); + strcpy(value, TIP_("Invalid target!")); } } else { - strcpy(str, TIP_("Invalid target!")); + strcpy(value, TIP_("Invalid target!")); } } static int rna_ParticleTarget_name_length(PointerRNA *ptr) { - char tstr[MAX_ID_NAME + MAX_ID_NAME + 64]; + char tvalue[MAX_ID_NAME + MAX_ID_NAME + 64]; - rna_ParticleTarget_name_get(ptr, tstr); + rna_ParticleTarget_name_get(ptr, tvalue); - return strlen(tstr); + return strlen(tvalue); } static int particle_id_check(const PointerRNA *ptr) @@ -1304,7 +1304,7 @@ static void rna_ParticleDupliWeight_active_index_set(struct PointerRNA *ptr, int } } -static void rna_ParticleDupliWeight_name_get(PointerRNA *ptr, char *str) +static void rna_ParticleDupliWeight_name_get(PointerRNA *ptr, char *value) { ParticleSettings *part = (ParticleSettings *)ptr->owner_id; psys_find_group_weights(part); @@ -1312,20 +1312,20 @@ static void rna_ParticleDupliWeight_name_get(PointerRNA *ptr, char *str) ParticleDupliWeight *dw = ptr->data; if (dw->ob) { - BLI_sprintf(str, "%s: %i", dw->ob->id.name + 2, dw->count); + BLI_sprintf(value, "%s: %i", dw->ob->id.name + 2, dw->count); } else { - strcpy(str, "No object"); + strcpy(value, "No object"); } } static int rna_ParticleDupliWeight_name_length(PointerRNA *ptr) { - char tstr[MAX_ID_NAME + 64]; + char tvalue[MAX_ID_NAME + 64]; - rna_ParticleDupliWeight_name_get(ptr, tstr); + rna_ParticleDupliWeight_name_get(ptr, tvalue); - return strlen(tstr); + return strlen(tvalue); } static const EnumPropertyItem *rna_Particle_type_itemf(bContext *UNUSED(C), diff --git a/source/blender/makesrna/intern/rna_space.cc b/source/blender/makesrna/intern/rna_space.cc index f5c89fbc2385..e16415bfc623 100644 --- a/source/blender/makesrna/intern/rna_space.cc +++ b/source/blender/makesrna/intern/rna_space.cc @@ -3335,8 +3335,12 @@ static StructRNA *rna_viewer_path_elem_refine(PointerRNA *ptr) return &RNA_IDViewerPathElem; case VIEWER_PATH_ELEM_TYPE_MODIFIER: return &RNA_ModifierViewerPathElem; - case VIEWER_PATH_ELEM_TYPE_NODE: - return &RNA_NodeViewerPathElem; + case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: + return &RNA_GroupNodeViewerPathElem; + case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: + return &RNA_SimulationZoneViewerPathElem; + case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: + return &RNA_ViewerNodeViewerPathElem; } BLI_assert_unreachable(); return nullptr; @@ -8133,7 +8137,9 @@ static void rna_def_spreadsheet_row_filter(BlenderRNA *brna) static const EnumPropertyItem viewer_path_elem_type_items[] = { {VIEWER_PATH_ELEM_TYPE_ID, "ID", ICON_NONE, "ID", ""}, {VIEWER_PATH_ELEM_TYPE_MODIFIER, "MODIFIER", ICON_NONE, "Modifier", ""}, - {VIEWER_PATH_ELEM_TYPE_NODE, "NODE", ICON_NONE, "Node", ""}, + {VIEWER_PATH_ELEM_TYPE_GROUP_NODE, "GROUP_NODE", ICON_NONE, "Group Node", ""}, + {VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE, "SIMULATION_ZONE", ICON_NONE, "Simulation Zone", ""}, + {VIEWER_PATH_ELEM_TYPE_VIEWER_NODE, "VIEWER_NODE", ICON_NONE, "Viewer Node", ""}, {0, nullptr, 0, nullptr, nullptr}, }; @@ -8150,6 +8156,11 @@ static void rna_def_viewer_path_elem(BlenderRNA *brna) RNA_def_property_enum_items(prop, viewer_path_elem_type_items); RNA_def_property_ui_text(prop, "Type", "Type of the path element"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + prop = RNA_def_property(srna, "ui_name", PROP_STRING, PROP_NONE); + RNA_def_property_ui_text( + prop, "UI Name", "Name that can be displayed in the UI for this element"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); } static void rna_def_id_viewer_path_elem(BlenderRNA *brna) @@ -8174,15 +8185,37 @@ static void rna_def_modifier_viewer_path_elem(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Modifier Name", ""); } -static void rna_def_node_viewer_path_elem(BlenderRNA *brna) +static void rna_def_group_node_viewer_path_elem(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "GroupNodeViewerPathElem", "ViewerPathElem"); + + prop = RNA_def_property(srna, "node_id", PROP_INT, PROP_NONE); + RNA_def_property_ui_text(prop, "Node ID", ""); +} + +static void rna_def_simulation_zone_viewer_path_elem(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "SimulationZoneViewerPathElem", "ViewerPathElem"); + + prop = RNA_def_property(srna, "sim_output_node_id", PROP_INT, PROP_NONE); + RNA_def_property_ui_text(prop, "Simulation Output Node ID", ""); +} + +static void rna_def_viewer_node_viewer_path_elem(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; - srna = RNA_def_struct(brna, "NodeViewerPathElem", "ViewerPathElem"); + srna = RNA_def_struct(brna, "ViewerNodeViewerPathElem", "ViewerPathElem"); - prop = RNA_def_property(srna, "node_name", PROP_STRING, PROP_NONE); - RNA_def_property_ui_text(prop, "Node Name", ""); + prop = RNA_def_property(srna, "node_id", PROP_INT, PROP_NONE); + RNA_def_property_ui_text(prop, "Node ID", ""); } static void rna_def_viewer_path(BlenderRNA *brna) @@ -8193,7 +8226,9 @@ static void rna_def_viewer_path(BlenderRNA *brna) rna_def_viewer_path_elem(brna); rna_def_id_viewer_path_elem(brna); rna_def_modifier_viewer_path_elem(brna); - rna_def_node_viewer_path_elem(brna); + rna_def_group_node_viewer_path_elem(brna); + rna_def_simulation_zone_viewer_path_elem(brna); + rna_def_viewer_node_viewer_path_elem(brna); srna = RNA_def_struct(brna, "ViewerPath", nullptr); RNA_def_struct_ui_text(srna, "Viewer Path", "Path to data that is viewed"); diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index a5764af75bfa..923651bdaac8 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -349,15 +349,15 @@ static int rna_TextureSlot_name_length(PointerRNA *ptr) return 0; } -static void rna_TextureSlot_name_get(PointerRNA *ptr, char *str) +static void rna_TextureSlot_name_get(PointerRNA *ptr, char *value) { MTex *mtex = ptr->data; if (mtex->tex) { - strcpy(str, mtex->tex->id.name + 2); + strcpy(value, mtex->tex->id.name + 2); } else { - str[0] = '\0'; + value[0] = '\0'; } } diff --git a/source/blender/makesrna/intern/rna_ui.cc b/source/blender/makesrna/intern/rna_ui.cc index 15fe02e1ac7a..06e3655ccafc 100644 --- a/source/blender/makesrna/intern/rna_ui.cc +++ b/source/blender/makesrna/intern/rna_ui.cc @@ -266,7 +266,7 @@ static StructRNA *rna_Panel_register(Main *bmain, RNA_pointer_create(nullptr, &RNA_Panel, &dummy_panel, &dummy_panel_ptr); /* We have to set default context! Else we get a void string... */ - strcpy(dummy_pt.translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + STRNCPY(dummy_pt.translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); /* validate the python class */ if (validate(&dummy_panel_ptr, data, have_function) != 0) { @@ -286,7 +286,7 @@ static StructRNA *rna_Panel_register(Main *bmain, if ((1 << dummy_pt.region_type) & RGN_TYPE_HAS_CATEGORY_MASK) { if (dummy_pt.category[0] == '\0') { /* Use a fallback, otherwise an empty value will draw the panel in every category. */ - strcpy(dummy_pt.category, PNL_CATEGORY_FALLBACK); + STRNCPY(dummy_pt.category, PNL_CATEGORY_FALLBACK); # ifndef NDEBUG printf("%s '%s' misses category, please update the script\n", error_prefix, dummy_pt.idname); # endif @@ -989,7 +989,7 @@ static StructRNA *rna_Menu_register(Main *bmain, RNA_pointer_create(nullptr, &RNA_Menu, &dummy_menu, &dummy_menu_ptr); /* We have to set default context! Else we get a void string... */ - strcpy(dummy_mt.translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + STRNCPY(dummy_mt.translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); /* validate the python class */ if (validate(&dummy_menu_ptr, data, have_function) != 0) { diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc index 92a8ded1c9e4..5d85becec304 100644 --- a/source/blender/modifiers/intern/MOD_mask.cc +++ b/source/blender/modifiers/intern/MOD_mask.cc @@ -6,8 +6,6 @@ * \ingroup modifiers */ -#define DNA_DEPRECATED_ALLOW - #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" @@ -297,7 +295,7 @@ static void compute_interpolated_polys(const Mesh *mesh, } if (0 < in_count && in_count < poly_src.size()) { /* Ring search starting at a vertex which is not included in the mask. */ - int last_corner_vert = corner_verts[start]; + int last_corner_vert = poly_verts_src[start]; bool v_loop_in_mask_last = vertex_mask[last_corner_vert]; for (const int j : poly_verts_src.index_range()) { const int corner_vert = poly_verts_src[(start + 1 + j) % poly_src.size()]; diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 76ad845166a3..dbee969bf8bd 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -424,25 +424,6 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd) namespace blender { -static const lf::FunctionNode *find_viewer_lf_node(const bNode &viewer_bnode) -{ - if (const nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info = - nodes::ensure_geometry_nodes_lazy_function_graph(viewer_bnode.owner_tree())) - { - return lf_graph_info->mapping.viewer_node_map.lookup_default(&viewer_bnode, nullptr); - } - return nullptr; -} -static const lf::FunctionNode *find_group_lf_node(const bNode &group_bnode) -{ - if (const nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info = - nodes::ensure_geometry_nodes_lazy_function_graph(group_bnode.owner_tree())) - { - return lf_graph_info->mapping.group_node_map.lookup_default(&group_bnode, nullptr); - } - return nullptr; -} - static void find_side_effect_nodes_for_viewer_path( const ViewerPath &viewer_path, const NodesModifierData &nmd, @@ -464,45 +445,101 @@ static void find_side_effect_nodes_for_viewer_path( ComputeContextBuilder compute_context_builder; compute_context_builder.push(parsed_path->modifier_name); + /* Write side effect nodes to a new map and only if everything succeeds, move the nodes to the + * caller. This is easier than changing r_side_effect_nodes directly and then undoing changes in + * case of errors. */ + MultiValueMap local_side_effect_nodes; + const bNodeTree *group = nmd.node_group; - Stack group_node_stack; - for (const int32_t group_node_id : parsed_path->group_node_ids) { - const bNode *found_node = group->node_by_id(group_node_id); - if (found_node == nullptr) { + const bke::bNodeTreeZone *zone = nullptr; + for (const ViewerPathElem *elem : parsed_path->node_path) { + const bke::bNodeTreeZones *tree_zones = group->zones(); + if (tree_zones == nullptr) { return; } - if (found_node->id == nullptr) { + const auto *lf_graph_info = nodes::ensure_geometry_nodes_lazy_function_graph(*group); + if (lf_graph_info == nullptr) { return; } - if (found_node->is_muted()) { - return; + switch (elem->type) { + case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: { + const auto &typed_elem = *reinterpret_cast(elem); + const bke::bNodeTreeZone *next_zone = tree_zones->get_zone_by_node( + typed_elem.sim_output_node_id); + if (next_zone == nullptr) { + return; + } + if (next_zone->parent_zone != zone) { + return; + } + const lf::FunctionNode *lf_zone_node = lf_graph_info->mapping.zone_node_map.lookup_default( + next_zone, nullptr); + if (lf_zone_node == nullptr) { + return; + } + local_side_effect_nodes.add(compute_context_builder.hash(), lf_zone_node); + compute_context_builder.push(*next_zone->output_node); + zone = next_zone; + break; + } + case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: { + const auto &typed_elem = *reinterpret_cast(elem); + const bNode *node = group->node_by_id(typed_elem.node_id); + if (node == nullptr) { + return; + } + if (node->id == nullptr) { + return; + } + if (node->is_muted()) { + return; + } + if (zone != tree_zones->get_zone_by_node(node->identifier)) { + return; + } + const lf::FunctionNode *lf_group_node = + lf_graph_info->mapping.group_node_map.lookup_default(node, nullptr); + if (lf_group_node == nullptr) { + return; + } + local_side_effect_nodes.add(compute_context_builder.hash(), lf_group_node); + compute_context_builder.push(*node); + group = reinterpret_cast(node->id); + zone = nullptr; + break; + } + default: { + BLI_assert_unreachable(); + return; + } } - group_node_stack.push(found_node); - group = reinterpret_cast(found_node->id); - compute_context_builder.push(*found_node); } const bNode *found_viewer_node = group->node_by_id(parsed_path->viewer_node_id); if (found_viewer_node == nullptr) { return; } - const lf::FunctionNode *lf_viewer_node = find_viewer_lf_node(*found_viewer_node); + const auto *lf_graph_info = nodes::ensure_geometry_nodes_lazy_function_graph(*group); + if (lf_graph_info == nullptr) { + return; + } + const bke::bNodeTreeZones *tree_zones = group->zones(); + if (tree_zones == nullptr) { + return; + } + if (tree_zones->get_zone_by_node(found_viewer_node->identifier) != zone) { + return; + } + const lf::FunctionNode *lf_viewer_node = lf_graph_info->mapping.viewer_node_map.lookup_default( + found_viewer_node, nullptr); if (lf_viewer_node == nullptr) { return; } + local_side_effect_nodes.add(compute_context_builder.hash(), lf_viewer_node); - /* Not only mark the viewer node as having side effects, but also all group nodes it is contained - * in. */ - r_side_effect_nodes.add_non_duplicates(compute_context_builder.hash(), lf_viewer_node); - compute_context_builder.pop(); - while (!compute_context_builder.is_empty()) { - const lf::FunctionNode *lf_group_node = find_group_lf_node(*group_node_stack.pop()); - if (lf_group_node == nullptr) { - return; - } - - r_side_effect_nodes.add_non_duplicates(compute_context_builder.hash(), lf_group_node); - compute_context_builder.pop(); + /* Successfully found all compute contexts for the viewer. */ + for (const auto item : local_side_effect_nodes.items()) { + r_side_effect_nodes.add_multiple(item.key, item.value); } } @@ -550,11 +587,11 @@ static void find_socket_log_contexts(const NodesModifierData &nmd, const SpaceLink *sl = static_cast(area->spacedata.first); if (sl->spacetype == SPACE_NODE) { const SpaceNode &snode = *reinterpret_cast(sl); - if (const std::optional hash = - geo_log::GeoModifierLog::get_compute_context_hash_for_node_editor( - snode, nmd.modifier.name)) - { - r_socket_log_contexts.add(*hash); + const Map hash_by_zone = + geo_log::GeoModifierLog::get_context_hash_by_zone_for_node_editor(snode, + nmd.modifier.name); + for (const ComputeContextHash &hash : hash_by_zone.values()) { + r_socket_log_contexts.add(hash); } } } diff --git a/source/blender/nodes/NOD_geometry_nodes_lazy_function.hh b/source/blender/nodes/NOD_geometry_nodes_lazy_function.hh index 3f05774d1cdd..61f1e1394f38 100644 --- a/source/blender/nodes/NOD_geometry_nodes_lazy_function.hh +++ b/source/blender/nodes/NOD_geometry_nodes_lazy_function.hh @@ -28,6 +28,7 @@ #include "BLI_compute_context.hh" +#include "BKE_node_tree_zones.hh" #include "BKE_simulation_state.hh" struct Object; @@ -175,7 +176,7 @@ struct GeometryNodeLazyFunctionGraphMapping { */ Map group_node_map; Map viewer_node_map; - Map sim_output_node_map; + Map zone_node_map; /* Indexed by #bNodeSocket::index_in_all_outputs. */ Array lf_input_index_for_output_bsocket_usage; @@ -190,29 +191,9 @@ struct GeometryNodeLazyFunctionGraphMapping { */ struct GeometryNodesLazyFunctionGraphInfo { /** - * Allocator used for many things contained in this struct. + * Contains resources that need to be freed when the graph is not needed anymore. */ - LinearAllocator<> allocator; - /** - * Many nodes are implemented as multi-functions. So this contains a mapping from nodes to their - * corresponding multi-functions. - */ - std::unique_ptr node_multi_functions; - /** - * Many lazy-functions are build for the lazy-function graph. Since the graph does not own them, - * we have to keep track of them separately. - */ - Vector> functions; - /** - * Debug info that has to be destructed when the graph is not used anymore. - */ - Vector> dummy_debug_infos_; - /** - * Many sockets have default values. Since those are not owned by the lazy-function graph, we - * have to keep track of them separately. This only owns the values, the memory is owned by the - * allocator above. - */ - Vector values_to_destruct; + ResourceScope scope; /** * The actual lazy-function graph. */ @@ -226,9 +207,6 @@ struct GeometryNodesLazyFunctionGraphInfo { * This can be used as a simple heuristic for the complexity of the node group. */ int num_inline_nodes_approximate = 0; - - GeometryNodesLazyFunctionGraphInfo(); - ~GeometryNodesLazyFunctionGraphInfo(); }; /** diff --git a/source/blender/nodes/NOD_geometry_nodes_log.hh b/source/blender/nodes/NOD_geometry_nodes_log.hh index 7502faee6e25..75d9825f96f8 100644 --- a/source/blender/nodes/NOD_geometry_nodes_log.hh +++ b/source/blender/nodes/NOD_geometry_nodes_log.hh @@ -37,6 +37,7 @@ #include "BKE_attribute.h" #include "BKE_geometry_set.hh" +#include "BKE_node_tree_zones.hh" #include "BKE_viewer_path.h" #include "FN_field.hh" @@ -333,9 +334,11 @@ class GeoModifierLog { /** * Utility accessor to logged data. */ - static std::optional get_compute_context_hash_for_node_editor( - const SpaceNode &snode, StringRefNull modifier_name); - static GeoTreeLog *get_tree_log_for_node_editor(const SpaceNode &snode); + static Map + get_context_hash_by_zone_for_node_editor(const SpaceNode &snode, StringRefNull modifier_name); + + static Map get_tree_log_by_zone_for_node_editor( + const SpaceNode &snode); static const ViewerNodeLog *find_viewer_node_log_for_path(const ViewerPath &viewer_path); }; diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index 9574777321b4..c54145733590 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -5,10 +5,15 @@ /** \file * \ingroup nodes * - * This file mainly converts a #bNodeTree into a lazy-function graph. This generally works by - * creating a lazy-function for every node, which is then put into the lazy-function graph. Then - * the nodes in the new graph are linked based on links in the original #bNodeTree. Some additional - * nodes are inserted for things like type conversions and multi-input sockets. + * This file mainly converts a #bNodeTree into a lazy-function graph, that can then be evaluated to + * execute geometry nodes. This generally works by creating a lazy-function for every node, which + * is then put into the lazy-function graph. Then the nodes in the new graph are linked based on + * links in the original #bNodeTree. Some additional nodes are inserted for things like type + * conversions and multi-input sockets. + * + * If the #bNodeTree contains zones, those are turned into separate lazy-functions first. + * Essentially, a separate lazy-function graph is created for every zone that is than called by the + * parent zone or by the root graph. * * Currently, lazy-functions are even created for nodes that don't strictly require it, like * reroutes or muted nodes. In the future we could avoid that at the cost of additional code @@ -34,6 +39,7 @@ #include "BKE_compute_contexts.hh" #include "BKE_geometry_set.hh" #include "BKE_node_tree_anonymous_attributes.hh" +#include "BKE_node_tree_zones.hh" #include "BKE_type_conversions.hh" #include "FN_field_cpp_type.hh" @@ -45,6 +51,9 @@ namespace blender::nodes { +namespace aai = bke::anonymous_attribute_inferencing; +using bke::bNodeTreeZone; +using bke::bNodeTreeZones; using fn::ValueOrField; using fn::ValueOrFieldCPPType; @@ -1166,13 +1175,24 @@ class LazyFunctionForAnonymousAttributeSetExtract : public lf::LazyFunction { LazyFunctionForAnonymousAttributeSetExtract(const ValueOrFieldCPPType &type) : type_(type) { debug_name_ = "Extract Attribute Set"; - inputs_.append_as("Field", type.self); + inputs_.append_as("Use", CPPType::get()); + inputs_.append_as("Field", type.self, lf::ValueUsage::Maybe); outputs_.append_as("Attributes", CPPType::get()); } void execute_impl(lf::Params ¶ms, const lf::Context & /*context*/) const override { - const void *value_or_field = params.try_get_input_data_ptr(0); + const bool use = params.get_input(0); + if (!use) { + params.set_output(0, {}); + return; + } + const void *value_or_field = params.try_get_input_data_ptr_or_request(1); + if (value_or_field == nullptr) { + /* Wait until the field is computed. */ + return; + } + bke::AnonymousAttributeSet attributes; if (type_.is_field(value_or_field)) { const GField &field = *type_.get_field_ptr(value_or_field); @@ -1263,8 +1283,8 @@ class LazyFunctionForAnonymousAttributeSetJoin : public lf::LazyFunction { /** * Cache for functions small amounts to avoid to avoid building them many times. */ - static const LazyFunctionForAnonymousAttributeSetJoin &get_cached( - const int amount, Vector> &r_functions) + static const LazyFunctionForAnonymousAttributeSetJoin &get_cached(const int amount, + ResourceScope &scope) { constexpr int cache_amount = 16; static std::array cached_functions = @@ -1273,10 +1293,7 @@ class LazyFunctionForAnonymousAttributeSetJoin : public lf::LazyFunction { return cached_functions[amount]; } - auto fn = std::make_unique(amount); - const auto &fn_ref = *fn; - r_functions.append(std::move(fn)); - return fn_ref; + return scope.construct(amount); } private: @@ -1288,6 +1305,122 @@ class LazyFunctionForAnonymousAttributeSetJoin : public lf::LazyFunction { } }; +class LazyFunctionForSimulationZone : public LazyFunction { + private: + const bNode &sim_output_bnode_; + const LazyFunction &fn_; + + public: + LazyFunctionForSimulationZone(const bNode &sim_output_bnode, const LazyFunction &fn) + : sim_output_bnode_(sim_output_bnode), fn_(fn) + { + debug_name_ = "Simulation Zone"; + inputs_ = fn.inputs(); + outputs_ = fn.outputs(); + } + + void execute_impl(lf::Params ¶ms, const lf::Context &context) const override + { + GeoNodesLFUserData &user_data = *static_cast(context.user_data); + + bke::SimulationZoneComputeContext compute_context{user_data.compute_context, + sim_output_bnode_}; + + GeoNodesLFUserData zone_user_data = user_data; + zone_user_data.compute_context = &compute_context; + if (user_data.modifier_data->socket_log_contexts) { + zone_user_data.log_socket_values = user_data.modifier_data->socket_log_contexts->contains( + compute_context.hash()); + } + GeoNodesLFLocalUserData zone_local_user_data{zone_user_data}; + + lf::Context zone_context{context.storage, &zone_user_data, &zone_local_user_data}; + fn_.execute(params, zone_context); + } + + void *init_storage(LinearAllocator<> &allocator) const override + { + return fn_.init_storage(allocator); + } + + void destruct_storage(void *storage) const override + { + fn_.destruct_storage(storage); + } + + std::string input_name(const int i) const override + { + return fn_.input_name(i); + } + + std::string output_name(const int i) const override + { + return fn_.output_name(i); + } +}; + +using JoinAttributeSetsCache = Map, lf::OutputSocket *>; + +struct BuildGraphParams { + /** Lazy-function graph that nodes and links should be inserted into. */ + lf::Graph &lf_graph; + /** Map #bNodeSocket to newly generated sockets. Those maps are later used to insert links. */ + MultiValueMap lf_inputs_by_bsocket; + Map lf_output_by_bsocket; + /** + * Maps sockets to corresponding generated boolean sockets that indicate whether the socket is + * used or not. + */ + Map usage_by_bsocket; + /** + * Nodes that propagate anonymous attributes have to know which of those attributes to propagate. + * For that they have an attribute set input for each geometry output. + */ + Map lf_attribute_set_input_by_output_geometry_bsocket; + /** + * Multi-input sockets are split into a separate node that collects all the individual values and + * then passes them to the main node function as list. + */ + Map multi_input_socket_nodes; + /** + * This is similar to #lf_inputs_by_bsocket but contains more relevant information when border + * links are linked to multi-input sockets. + */ + Map lf_input_by_border_link; + /** + * Keeps track of all boolean inputs that indicate whether a socket is used. Links to those + * sockets may be replaced with a constant-true if necessary to break dependency cycles in + * #fix_link_cycles. + */ + Set socket_usage_inputs; + /** + * Collect input sockets that anonymous attribute sets based on fields or group inputs have to be + * linked to later. + */ + MultiValueMap lf_attribute_set_input_by_field_source_index; + MultiValueMap lf_attribute_set_input_by_caller_propagation_index; + /** */ + /** Cache to avoid building the same socket combinations multiple times. */ + Map, lf::OutputSocket *> socket_usages_combination_cache; +}; + +struct ZoneBuildInfo { + /** The lazy function that contains the zone. */ + const LazyFunction *lazy_function = nullptr; + + /** Information about what the various inputs and outputs of the lazy-function are. */ + IndexRange main_input_indices; + IndexRange main_output_indices; + IndexRange border_link_input_indices; + + IndexRange main_input_usage_indices; + IndexRange main_output_usage_indices; + IndexRange border_link_input_usage_indices; + + Map attribute_set_input_by_field_source_index; + Map attribute_set_input_by_caller_propagation_index; +}; + /** * Utility class to build a lazy-function graph based on a geometry nodes tree. * This is mainly a separate class because it makes it easier to have variables that can be @@ -1296,33 +1429,12 @@ class LazyFunctionForAnonymousAttributeSetJoin : public lf::LazyFunction { struct GeometryNodesLazyFunctionGraphBuilder { private: const bNodeTree &btree_; + const aai::AnonymousAttributeInferencingResult &attribute_inferencing_; + ResourceScope &scope_; + NodeMultiFunctions &node_multi_functions_; GeometryNodesLazyFunctionGraphInfo *lf_graph_info_; - lf::Graph *lf_graph_; GeometryNodeLazyFunctionGraphMapping *mapping_; - MultiValueMap input_socket_map_; - Map output_socket_map_; - Map multi_input_socket_nodes_; const bke::DataTypeConversions *conversions_; - /** - * Maps bsockets to boolean sockets in the graph whereby each boolean socket indicates whether - * the bsocket is used. Sockets not contained in this map are not used. - * This is indexed by `bNodeSocket::index_in_tree()`. - */ - Array socket_is_used_map_; - /** - * Some built-in nodes get additional boolean inputs that indicate whether certain outputs are - * used (field output sockets that contain new anonymous attribute references). - */ - Vector> output_used_sockets_for_builtin_nodes_; - /** - * Maps from output geometry sockets to corresponding attribute set inputs. - */ - Map attribute_set_propagation_map_; - /** - * Boolean inputs that tell a node if some socket (of the same or another node) is used. If this - * socket is in a link-cycle, its input can become a constant true. - */ - Set socket_usage_inputs_; /** * All group input nodes are combined into one dummy node in the lazy-function graph. @@ -1333,12 +1445,19 @@ struct GeometryNodesLazyFunctionGraphBuilder { */ Map simulation_inputs_usage_nodes_; + const bNodeTreeZones *tree_zones_; + Array zone_build_infos_; + friend class UsedSocketVisualizeOptions; public: GeometryNodesLazyFunctionGraphBuilder(const bNodeTree &btree, GeometryNodesLazyFunctionGraphInfo &lf_graph_info) - : btree_(btree), lf_graph_info_(&lf_graph_info) + : btree_(btree), + attribute_inferencing_(*btree.runtime->anonymous_attribute_inferencing), + scope_(lf_graph_info.scope), + node_multi_functions_(lf_graph_info.scope.construct(btree)), + lf_graph_info_(&lf_graph_info) { } @@ -1346,12 +1465,18 @@ struct GeometryNodesLazyFunctionGraphBuilder { { btree_.ensure_topology_cache(); - lf_graph_ = &lf_graph_info_->graph; mapping_ = &lf_graph_info_->mapping; conversions_ = &bke::get_implicit_type_conversions(); + tree_zones_ = btree_.zones(); + + this->initialize_mapping_arrays(); + this->build_zone_functions(); + this->build_root_graph(); + } - socket_is_used_map_.reinitialize(btree_.all_sockets().size()); - socket_is_used_map_.fill(nullptr); + private: + void initialize_mapping_arrays() + { mapping_->lf_input_index_for_output_bsocket_usage.reinitialize( btree_.all_output_sockets().size()); mapping_->lf_input_index_for_output_bsocket_usage.fill(-1); @@ -1360,263 +1485,921 @@ struct GeometryNodesLazyFunctionGraphBuilder { mapping_->lf_input_index_for_attribute_propagation_to_output.fill(-1); mapping_->lf_index_by_bsocket.reinitialize(btree_.all_sockets().size()); mapping_->lf_index_by_bsocket.fill(-1); + } - this->prepare_node_multi_functions(); - this->build_group_input_node(); - if (btree_.group_output_node() == nullptr) { - this->build_fallback_output_node(); - } - this->handle_nodes(); - this->handle_links(); - this->add_default_inputs(); - - this->build_attribute_propagation_input_node(); - this->build_output_usage_input_node(); - this->build_input_usage_output_node(); - this->build_socket_usages(); - - this->build_attribute_propagation_sets(); - this->fix_link_cycles(); + /** + * Builds lazy-functions for all zones in the node tree. + */ + void build_zone_functions() + { + zone_build_infos_.reinitialize(tree_zones_->zones.size()); - // this->print_graph(); + const Array zone_build_order = this->compute_zone_build_order(); - lf_graph_->update_node_indices(); - lf_graph_info_->num_inline_nodes_approximate += lf_graph_->nodes().size(); + for (const int zone_i : zone_build_order) { + const bNodeTreeZone &zone = *tree_zones_->zones[zone_i]; + BLI_assert(zone.output_node->type == GEO_NODE_SIMULATION_OUTPUT); + this->build_simulation_zone_function(zone); + } } - private: - void prepare_node_multi_functions() + Array compute_zone_build_order() { - lf_graph_info_->node_multi_functions = std::make_unique(btree_); + /* Build nested zones first. */ + Array zone_build_order(tree_zones_->zones.size()); + std::iota(zone_build_order.begin(), zone_build_order.end(), 0); + std::sort( + zone_build_order.begin(), zone_build_order.end(), [&](const int zone_a, const int zone_b) { + return tree_zones_->zones[zone_a]->depth > tree_zones_->zones[zone_b]->depth; + }); + return zone_build_order; } - void build_group_input_node() + /** + * Builds a lazy-function for a simulation zone. + * Internally, the generated lazy-function is just another graph. + */ + void build_simulation_zone_function(const bNodeTreeZone &zone) { - Vector input_cpp_types; - const Span interface_inputs = btree_.interface_inputs(); - for (const bNodeSocket *interface_input : interface_inputs) { - input_cpp_types.append(interface_input->typeinfo->geometry_nodes_cpp_type); + const int zone_i = zone.index; + ZoneBuildInfo &zone_info = zone_build_infos_[zone_i]; + lf::Graph &lf_graph = scope_.construct(); + + lf::Node *lf_zone_input_node = nullptr; + lf::Node *lf_main_input_usage_node = nullptr; + if (zone.input_node != nullptr) { + lf_zone_input_node = &this->build_dummy_node_for_sockets( + "Zone Input", {}, zone.input_node->input_sockets().drop_back(1), lf_graph); + lf_main_input_usage_node = &this->build_dummy_node_for_socket_usages( + "Input Usages", zone.input_node->input_sockets().drop_back(1), {}, lf_graph); } + lf::Node &lf_border_link_input_node = this->build_zone_border_links_input_node(zone, lf_graph); + lf::Node &lf_zone_output_node = this->build_dummy_node_for_sockets( + "Zone Output", zone.output_node->output_sockets().drop_back(1), {}, lf_graph); + lf::Node &lf_main_output_usage_node = this->build_dummy_node_for_socket_usages( + "Output Usages", {}, zone.output_node->output_sockets().drop_back(1), lf_graph); + lf::Node &lf_border_link_usage_node = this->build_border_link_input_usage_node(zone, lf_graph); - /* Create a dummy node for the group inputs. */ - auto debug_info = std::make_unique(); - group_input_lf_node_ = &lf_graph_->add_dummy({}, input_cpp_types, debug_info.get()); + lf::Node &lf_simulation_usage_node = [&]() -> lf::Node & { + auto &lazy_function = scope_.construct(); + lf::Node &lf_node = lf_graph.add_function(lazy_function); - for (const int i : interface_inputs.index_range()) { - mapping_->group_input_sockets.append(&group_input_lf_node_->output(i)); - debug_info->socket_names.append(interface_inputs[i]->name); + if (lf_main_input_usage_node) { + for (const int i : lf_main_input_usage_node->inputs().index_range()) { + lf_graph.add_link(lf_node.output(0), lf_main_input_usage_node->input(i)); + } + } + return lf_node; + }(); + + BuildGraphParams graph_params{lf_graph}; + + lf::FunctionNode *lf_simulation_input = nullptr; + if (zone.input_node) { + lf_simulation_input = this->insert_simulation_input_node( + btree_, *zone.input_node, graph_params); } - lf_graph_info_->dummy_debug_infos_.append(std::move(debug_info)); - } + lf::FunctionNode &lf_simulation_output = this->insert_simulation_output_node(*zone.output_node, + graph_params); - /** - * Build an output node that just outputs default values in the case when there is no Group - * Output node in the tree. - */ - void build_fallback_output_node() - { - Vector output_cpp_types; - auto debug_info = std::make_unique(); - for (const bNodeSocket *interface_output : btree_.interface_outputs()) { - output_cpp_types.append(interface_output->typeinfo->geometry_nodes_cpp_type); - debug_info->socket_names.append(interface_output->name); + for (const bNodeSocket *bsocket : zone.output_node->input_sockets().drop_back(1)) { + graph_params.usage_by_bsocket.add(bsocket, &lf_simulation_usage_node.output(1)); } - lf::Node &lf_node = lf_graph_->add_dummy(output_cpp_types, {}, debug_info.get()); - for (lf::InputSocket *lf_socket : lf_node.inputs()) { - const CPPType &type = lf_socket->type(); - lf_socket->set_default_value(type.default_value()); + this->insert_nodes_and_zones(zone.child_nodes, zone.child_zones, graph_params); + + if (zone.input_node) { + this->build_output_socket_usages(*zone.input_node, graph_params); } - mapping_->standard_group_output_sockets = lf_node.inputs(); + for (const auto item : graph_params.lf_output_by_bsocket.items()) { + this->insert_links_from_socket(*item.key, *item.value, graph_params); + } + + this->link_border_link_inputs_and_usages( + zone, lf_border_link_input_node, lf_border_link_usage_node, graph_params); + + if (lf_zone_input_node != nullptr) { + for (const int i : lf_zone_input_node->outputs().index_range()) { + lf_graph.add_link(lf_zone_input_node->output(i), lf_simulation_input->input(i)); + } + } + for (const int i : lf_zone_output_node.inputs().index_range()) { + lf_graph.add_link(lf_simulation_output.output(i), lf_zone_output_node.input(i)); + } + + this->add_default_inputs(graph_params); + + Vector lf_zone_inputs; + if (lf_zone_input_node) { + lf_zone_inputs.extend(lf_zone_input_node->outputs()); + zone_info.main_input_indices = lf_zone_inputs.index_range(); + } + lf_zone_inputs.extend(lf_border_link_input_node.outputs()); + zone_info.border_link_input_indices = lf_zone_inputs.index_range().take_back( + lf_border_link_input_node.outputs().size()); + + lf_zone_inputs.extend(lf_main_output_usage_node.outputs()); + zone_info.main_output_usage_indices = lf_zone_inputs.index_range().take_back( + lf_main_output_usage_node.outputs().size()); + + Map lf_attribute_set_by_field_source_index; + Map lf_attribute_set_by_caller_propagation_index; + this->build_attribute_set_inputs_for_zone(graph_params, + zone_info, + lf_attribute_set_by_field_source_index, + lf_attribute_set_by_caller_propagation_index, + lf_zone_inputs); + this->link_attribute_set_inputs(lf_graph, + graph_params, + lf_attribute_set_by_field_source_index, + lf_attribute_set_by_caller_propagation_index); + this->fix_link_cycles(lf_graph, graph_params.socket_usage_inputs); + + Vector lf_zone_outputs; + lf_zone_outputs.extend(lf_zone_output_node.inputs()); + zone_info.main_output_indices = lf_zone_outputs.index_range(); + + if (lf_main_input_usage_node) { + lf_zone_outputs.extend(lf_main_input_usage_node->inputs()); + zone_info.main_input_usage_indices = lf_zone_outputs.index_range().take_back( + lf_main_input_usage_node->inputs().size()); + } + + lf_zone_outputs.extend(lf_border_link_usage_node.inputs()); + zone_info.border_link_input_usage_indices = lf_zone_outputs.index_range().take_back( + lf_border_link_usage_node.inputs().size()); + + lf_graph.update_node_indices(); + + auto &logger = scope_.construct(*lf_graph_info_); + auto &side_effect_provider = scope_.construct(); + + const auto &lf_graph_fn = scope_.construct( + lf_graph, lf_zone_inputs, lf_zone_outputs, &logger, &side_effect_provider); + const auto &zone_function = scope_.construct(*zone.output_node, + lf_graph_fn); + zone_info.lazy_function = &zone_function; - lf_graph_info_->dummy_debug_infos_.append(std::move(debug_info)); + // std::cout << "\n\n" << lf_graph.to_dot() << "\n\n"; } - void handle_nodes() + lf::DummyNode &build_zone_border_links_input_node(const bNodeTreeZone &zone, lf::Graph &lf_graph) { - /* Insert all nodes into the lazy function graph. */ - for (const bNode *bnode : btree_.all_nodes()) { - const bNodeType *node_type = bnode->typeinfo; - if (node_type == nullptr) { - continue; - } - if (bnode->is_muted()) { - this->handle_muted_node(*bnode); - continue; + auto &debug_info = scope_.construct(); + debug_info.name = "Border Links"; + Vector border_link_types; + for (const bNodeLink *border_link : zone.border_links) { + border_link_types.append(border_link->tosock->typeinfo->geometry_nodes_cpp_type); + debug_info.output_names.append(StringRef("Link from ") + border_link->fromsock->identifier); + } + lf::DummyNode &node = lf_graph.add_dummy({}, border_link_types, &debug_info); + return node; + } + + lf::DummyNode &build_border_link_input_usage_node(const bNodeTreeZone &zone, lf::Graph &lf_graph) + { + auto &debug_info = scope_.construct(); + debug_info.name = "Border Link Usages"; + Vector types; + types.append_n_times(&CPPType::get(), zone.border_links.size()); + debug_info.input_names.append_n_times("Usage", types.size()); + lf::DummyNode &node = lf_graph.add_dummy(types, {}, &debug_info); + return node; + } + + void build_attribute_set_inputs_for_zone( + BuildGraphParams &graph_params, + ZoneBuildInfo &zone_info, + Map &lf_attribute_set_by_field_source_index, + Map &lf_attribute_set_by_caller_propagation_index, + Vector &lf_zone_inputs) + { + const Vector all_required_field_sources = this->find_all_required_field_source_indices( + graph_params.lf_attribute_set_input_by_output_geometry_bsocket, + graph_params.lf_attribute_set_input_by_field_source_index); + const Vector all_required_caller_propagation_indices = + this->find_all_required_caller_propagation_indices( + graph_params.lf_attribute_set_input_by_output_geometry_bsocket, + graph_params.lf_attribute_set_input_by_caller_propagation_index); + + Map input_by_field_source_index; + + for (const int field_source_index : all_required_field_sources) { + const aai::FieldSource &field_source = + attribute_inferencing_.all_field_sources[field_source_index]; + if ([[maybe_unused]] const auto *input_field_source = std::get_if( + &field_source.data)) + { + input_by_field_source_index.add_new(field_source_index, + input_by_field_source_index.size()); } - switch (node_type->type) { - case NODE_FRAME: { - /* Ignored. */ - break; - } - case NODE_REROUTE: { - this->handle_reroute_node(*bnode); - break; - } - case NODE_GROUP_INPUT: { - this->handle_group_input_node(*bnode); - break; - } - case NODE_GROUP_OUTPUT: { - this->handle_group_output_node(*bnode); - break; - } - case NODE_CUSTOM_GROUP: - case NODE_GROUP: { - this->handle_group_node(*bnode); - break; - } - case GEO_NODE_VIEWER: { - this->handle_viewer_node(*bnode); - break; - } - case GEO_NODE_SIMULATION_INPUT: { - this->handle_simulation_input_node(btree_, *bnode); - break; - } - case GEO_NODE_SIMULATION_OUTPUT: { - this->handle_simulation_output_node(*bnode); - break; - } - case GEO_NODE_SWITCH: { - this->handle_switch_node(*bnode); - break; + else { + const auto &socket_field_source = std::get(field_source.data); + const bNodeSocket &bsocket = *socket_field_source.socket; + if (lf::OutputSocket *lf_field_socket = graph_params.lf_output_by_bsocket.lookup_default( + &bsocket, nullptr)) + { + lf::OutputSocket *lf_usage_socket = graph_params.usage_by_bsocket.lookup_default( + &bsocket, nullptr); + lf::OutputSocket &lf_attribute_set_socket = this->get_extracted_attributes( + *lf_field_socket, + lf_usage_socket, + graph_params.lf_graph, + graph_params.socket_usage_inputs); + lf_attribute_set_by_field_source_index.add(field_source_index, &lf_attribute_set_socket); } - default: { - if (node_type->geometry_node_execute) { - this->handle_geometry_node(*bnode); - break; - } - const NodeMultiFunctions::Item &fn_item = lf_graph_info_->node_multi_functions->try_get( - *bnode); - if (fn_item.fn != nullptr) { - this->handle_multi_function_node(*bnode, fn_item); - break; - } - if (node_type == &bke::NodeTypeUndefined) { - this->handle_undefined_node(*bnode); - break; - } - /* Nodes that don't match any of the criteria above are just ignored. */ - break; + else { + input_by_field_source_index.add_new(field_source_index, + input_by_field_source_index.size()); } } } + + { + auto &debug_info = scope_.construct(); + debug_info.name = "Attribute Sets"; + Vector types; + const int num = input_by_field_source_index.size() + + all_required_caller_propagation_indices.size(); + types.append_n_times(&CPPType::get(), num); + debug_info.output_names.append_n_times("Set", num); + lf::DummyNode &node = graph_params.lf_graph.add_dummy({}, types, &debug_info); + + for (const auto item : input_by_field_source_index.items()) { + const int field_source_index = item.key; + const int attribute_set_index = item.value; + lf::OutputSocket &lf_attribute_set_socket = node.output(attribute_set_index); + lf_attribute_set_by_field_source_index.add(field_source_index, &lf_attribute_set_socket); + + const int zone_input_index = lf_zone_inputs.append_and_get_index(&lf_attribute_set_socket); + zone_info.attribute_set_input_by_field_source_index.add(field_source_index, + zone_input_index); + } + for (const int i : all_required_caller_propagation_indices.index_range()) { + const int caller_propagation_index = all_required_caller_propagation_indices[i]; + lf::OutputSocket &lf_attribute_set_socket = node.output( + input_by_field_source_index.size() + i); + lf_attribute_set_by_caller_propagation_index.add_new(caller_propagation_index, + &lf_attribute_set_socket); + const int zone_input_index = lf_zone_inputs.append_and_get_index(&lf_attribute_set_socket); + zone_info.attribute_set_input_by_caller_propagation_index.add(caller_propagation_index, + zone_input_index); + } + } } - void handle_muted_node(const bNode &bnode) + /** + * Build the graph that contains all nodes that are not contained in any zone. This graph is + * called when this geometry nodes node group is evaluated. + */ + void build_root_graph() { - auto lazy_function = std::make_unique(bnode, - mapping_->lf_index_by_bsocket); - lf::Node &lf_node = lf_graph_->add_function(*lazy_function); - lf_graph_info_->functions.append(std::move(lazy_function)); - for (const bNodeSocket *bsocket : bnode.input_sockets()) { - const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()]; - if (lf_index == -1) { - continue; - } - lf::InputSocket &lf_socket = lf_node.input(lf_index); - input_socket_map_.add(bsocket, &lf_socket); - mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket); + lf::Graph &lf_graph = lf_graph_info_->graph; + + this->build_group_input_node(lf_graph); + if (btree_.group_output_node() == nullptr) { + this->build_fallback_output_node(lf_graph); } - for (const bNodeSocket *bsocket : bnode.output_sockets()) { - const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()]; - if (lf_index == -1) { - continue; + + lf::Node &lf_output_usage_node = this->build_output_usage_input_node(lf_graph); + this->build_input_usage_output_node(lf_graph); + + BuildGraphParams graph_params{lf_graph}; + if (const bNode *group_output_bnode = btree_.group_output_node()) { + for (const bNodeSocket *bsocket : group_output_bnode->input_sockets().drop_back(1)) { + graph_params.usage_by_bsocket.add(bsocket, &lf_output_usage_node.output(bsocket->index())); } - lf::OutputSocket &lf_socket = lf_node.output(lf_index); - output_socket_map_.add_new(bsocket, &lf_socket); - mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket); } - } - void handle_reroute_node(const bNode &bnode) - { - const bNodeSocket &input_bsocket = bnode.input_socket(0); - const bNodeSocket &output_bsocket = bnode.output_socket(0); - const CPPType *type = get_socket_cpp_type(input_bsocket); - if (type == nullptr) { - return; + this->insert_nodes_and_zones( + tree_zones_->nodes_outside_zones, tree_zones_->root_zones, graph_params); + + for (const auto item : graph_params.lf_output_by_bsocket.items()) { + this->insert_links_from_socket(*item.key, *item.value, graph_params); } + this->build_group_input_usages(graph_params); + this->add_default_inputs(graph_params); - auto lazy_function = std::make_unique(*type); - lf::Node &lf_node = lf_graph_->add_function(*lazy_function); - lf_graph_info_->functions.append(std::move(lazy_function)); + this->build_attribute_propagation_input_node(lf_graph); - lf::InputSocket &lf_input = lf_node.input(0); - lf::OutputSocket &lf_output = lf_node.output(0); - input_socket_map_.add(&input_bsocket, &lf_input); - output_socket_map_.add_new(&output_bsocket, &lf_output); - mapping_->bsockets_by_lf_socket_map.add(&lf_input, &input_bsocket); - mapping_->bsockets_by_lf_socket_map.add(&lf_output, &output_bsocket); + Map lf_attribute_set_by_field_source_index; + Map lf_attribute_set_by_caller_propagation_index; + this->build_attribute_set_inputs_outside_of_zones( + graph_params, + lf_attribute_set_by_field_source_index, + lf_attribute_set_by_caller_propagation_index); + this->link_attribute_set_inputs(lf_graph, + graph_params, + lf_attribute_set_by_field_source_index, + lf_attribute_set_by_caller_propagation_index); + + this->fix_link_cycles(lf_graph, graph_params.socket_usage_inputs); + + // std::cout << "\n\n" << lf_graph.to_dot() << "\n\n"; + + lf_graph.update_node_indices(); + lf_graph_info_->num_inline_nodes_approximate += lf_graph.nodes().size(); } - void handle_group_input_node(const bNode &bnode) + void build_attribute_set_inputs_outside_of_zones( + BuildGraphParams &graph_params, + Map &lf_attribute_set_by_field_source_index, + Map &lf_attribute_set_by_caller_propagation_index) { - for (const int i : btree_.interface_inputs().index_range()) { - const bNodeSocket &bsocket = bnode.output_socket(i); - lf::OutputSocket &lf_socket = group_input_lf_node_->output(i); - output_socket_map_.add_new(&bsocket, &lf_socket); - mapping_->dummy_socket_map.add_new(&bsocket, &lf_socket); - mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket); + const Vector all_required_field_sources = this->find_all_required_field_source_indices( + graph_params.lf_attribute_set_input_by_output_geometry_bsocket, + graph_params.lf_attribute_set_input_by_field_source_index); + + for (const int field_source_index : all_required_field_sources) { + const aai::FieldSource &field_source = + attribute_inferencing_.all_field_sources[field_source_index]; + lf::OutputSocket *lf_attribute_set_socket; + if (const auto *input_field_source = std::get_if(&field_source.data)) + { + const int input_index = input_field_source->input_index; + lf::OutputSocket &lf_field_socket = const_cast( + *mapping_->group_input_sockets[input_index]); + lf::OutputSocket *lf_usage_socket = const_cast( + mapping_->group_input_usage_sockets[input_index]->origin()); + lf_attribute_set_socket = &this->get_extracted_attributes( + lf_field_socket, + lf_usage_socket, + graph_params.lf_graph, + graph_params.socket_usage_inputs); + } + else { + const auto &socket_field_source = std::get(field_source.data); + const bNodeSocket &bsocket = *socket_field_source.socket; + lf::OutputSocket &lf_field_socket = *graph_params.lf_output_by_bsocket.lookup(&bsocket); + lf::OutputSocket *lf_usage_socket = graph_params.usage_by_bsocket.lookup_default(&bsocket, + nullptr); + lf_attribute_set_socket = &this->get_extracted_attributes( + lf_field_socket, + lf_usage_socket, + graph_params.lf_graph, + graph_params.socket_usage_inputs); + } + lf_attribute_set_by_field_source_index.add_new(field_source_index, lf_attribute_set_socket); + } + + for (const int caller_propagation_index : + attribute_inferencing_.propagated_output_geometry_indices) + { + const int group_output_index = + attribute_inferencing_.propagated_output_geometry_indices[caller_propagation_index]; + lf::OutputSocket &lf_attribute_set_socket = const_cast( + *mapping_->attribute_set_by_geometry_output.lookup(group_output_index)); + lf_attribute_set_by_caller_propagation_index.add(caller_propagation_index, + &lf_attribute_set_socket); } } - void handle_group_output_node(const bNode &bnode) + Vector find_all_required_field_source_indices( + const Map + &lf_attribute_set_input_by_output_geometry_bsocket, + const MultiValueMap &lf_attribute_set_input_by_field_source_index) { - Vector output_cpp_types; - auto debug_info = std::make_unique(); - for (const bNodeSocket *interface_input : btree_.interface_outputs()) { - output_cpp_types.append(interface_input->typeinfo->geometry_nodes_cpp_type); - debug_info->socket_names.append(interface_input->name); + BitVector<> all_required_field_sources(attribute_inferencing_.all_field_sources.size(), false); + for (const bNodeSocket *geometry_output_bsocket : + lf_attribute_set_input_by_output_geometry_bsocket.keys()) + { + all_required_field_sources |= + attribute_inferencing_ + .required_fields_by_geometry_socket[geometry_output_bsocket->index_in_tree()]; + } + for (const int field_source_index : lf_attribute_set_input_by_field_source_index.keys()) { + all_required_field_sources[field_source_index].set(); } - lf::DummyNode &group_output_lf_node = lf_graph_->add_dummy( - output_cpp_types, {}, debug_info.get()); + Vector indices; + bits::foreach_1_index(all_required_field_sources, [&](const int i) { indices.append(i); }); + return indices; + } - for (const int i : group_output_lf_node.inputs().index_range()) { - const bNodeSocket &bsocket = bnode.input_socket(i); - lf::InputSocket &lf_socket = group_output_lf_node.input(i); - input_socket_map_.add(&bsocket, &lf_socket); - mapping_->dummy_socket_map.add(&bsocket, &lf_socket); - mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket); + Vector find_all_required_caller_propagation_indices( + const Map + &lf_attribute_set_input_by_output_geometry_bsocket, + const MultiValueMap + &lf_attribute_set_input_by_caller_propagation_index) + { + BitVector<> all_required_caller_propagation_indices( + attribute_inferencing_.propagated_output_geometry_indices.size(), false); + for (const bNodeSocket *geometry_output_bs : + lf_attribute_set_input_by_output_geometry_bsocket.keys()) + { + all_required_caller_propagation_indices |= + attribute_inferencing_ + .propagate_to_output_by_geometry_socket[geometry_output_bs->index_in_tree()]; } - - if (&bnode == btree_.group_output_node()) { - mapping_->standard_group_output_sockets = group_output_lf_node.inputs(); + for (const int caller_propagation_index : + lf_attribute_set_input_by_caller_propagation_index.keys()) + { + all_required_caller_propagation_indices[caller_propagation_index].set(); } - lf_graph_info_->dummy_debug_infos_.append(std::move(debug_info)); + Vector indices; + bits::foreach_1_index(all_required_caller_propagation_indices, + [&](const int i) { indices.append(i); }); + return indices; } - void handle_group_node(const bNode &bnode) + void link_attribute_set_inputs( + lf::Graph &lf_graph, + BuildGraphParams &graph_params, + const Map &lf_attribute_set_by_field_source_index, + const Map &lf_attribute_set_by_caller_propagation_index) { - const bNodeTree *group_btree = reinterpret_cast(bnode.id); - if (group_btree == nullptr) { - return; - } - const GeometryNodesLazyFunctionGraphInfo *group_lf_graph_info = - ensure_geometry_nodes_lazy_function_graph(*group_btree); - if (group_lf_graph_info == nullptr) { - return; - } + JoinAttributeSetsCache join_attribute_sets_cache; - auto lazy_function = std::make_unique( - bnode, *group_lf_graph_info, *lf_graph_info_); - lf::FunctionNode &lf_node = lf_graph_->add_function(*lazy_function); + for (const MapItem item : + graph_params.lf_attribute_set_input_by_output_geometry_bsocket.items()) + { + const bNodeSocket &geometry_output_bsocket = *item.key; + lf::InputSocket &lf_attribute_set_input = *item.value; - for (const int i : bnode.input_sockets().index_range()) { - const bNodeSocket &bsocket = bnode.input_socket(i); - BLI_assert(!bsocket.is_multi_input()); - lf::InputSocket &lf_socket = lf_node.input(i); - input_socket_map_.add(&bsocket, &lf_socket); - mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket); - } - for (const int i : bnode.output_sockets().index_range()) { - const bNodeSocket &bsocket = bnode.output_socket(i); - lf::OutputSocket &lf_socket = lf_node.output(i); - output_socket_map_.add_new(&bsocket, &lf_socket); - mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket); + Vector lf_attribute_set_sockets; + + const BoundedBitSpan required_fields = + attribute_inferencing_ + .required_fields_by_geometry_socket[geometry_output_bsocket.index_in_tree()]; + bits::foreach_1_index(required_fields, [&](const int field_source_index) { + const auto &field_source = attribute_inferencing_.all_field_sources[field_source_index]; + if (const auto *socket_field_source = std::get_if( + &field_source.data)) { + if (&socket_field_source->socket->owner_node() == &geometry_output_bsocket.owner_node()) + { + return; + } + } + lf_attribute_set_sockets.append( + lf_attribute_set_by_field_source_index.lookup(field_source_index)); + }); + + const BoundedBitSpan required_caller_propagations = + attribute_inferencing_ + .propagate_to_output_by_geometry_socket[geometry_output_bsocket.index_in_tree()]; + bits::foreach_1_index(required_caller_propagations, [&](const int caller_propagation_index) { + lf_attribute_set_sockets.append( + lf_attribute_set_by_caller_propagation_index.lookup(caller_propagation_index)); + }); + + if (lf::OutputSocket *lf_attribute_set = this->join_attribute_sets( + lf_attribute_set_sockets, + join_attribute_sets_cache, + lf_graph, + graph_params.socket_usage_inputs)) + { + lf_graph.add_link(*lf_attribute_set, lf_attribute_set_input); + } + else { + static const bke::AnonymousAttributeSet empty_set; + lf_attribute_set_input.set_default_value(&empty_set); + } + } + + for (const auto item : graph_params.lf_attribute_set_input_by_field_source_index.items()) { + const int field_source_index = item.key; + lf::OutputSocket &lf_attribute_set_socket = *lf_attribute_set_by_field_source_index.lookup( + field_source_index); + for (lf::InputSocket *lf_attribute_set_input : item.value) { + lf_graph.add_link(lf_attribute_set_socket, *lf_attribute_set_input); + } + } + for (const auto item : graph_params.lf_attribute_set_input_by_caller_propagation_index.items()) + { + const int caller_propagation_index = item.key; + lf::OutputSocket &lf_attribute_set_socket = + *lf_attribute_set_by_caller_propagation_index.lookup(caller_propagation_index); + for (lf::InputSocket *lf_attribute_set_input : item.value) { + lf_graph.add_link(lf_attribute_set_socket, *lf_attribute_set_input); + } + } + } + + void insert_nodes_and_zones(const Span bnodes, + const Span zones, + BuildGraphParams &graph_params) + { + Vector nodes_to_insert = bnodes; + Map zone_by_output; + for (const bNodeTreeZone *zone : zones) { + nodes_to_insert.append(zone->output_node); + zone_by_output.add(zone->output_node, zone); + } + /* Insert nodes from right to left so that usage sockets can be build in the same pass. */ + std::sort(nodes_to_insert.begin(), nodes_to_insert.end(), [](const bNode *a, const bNode *b) { + return a->runtime->toposort_right_to_left_index < b->runtime->toposort_right_to_left_index; + }); + + for (const bNode *bnode : nodes_to_insert) { + this->build_output_socket_usages(*bnode, graph_params); + if (const bNodeTreeZone *zone = zone_by_output.lookup_default(bnode, nullptr)) { + this->insert_child_zone_node(*zone, graph_params); + } + else { + this->insert_node_in_graph(*bnode, graph_params); + } + } + } + + void link_border_link_inputs_and_usages(const bNodeTreeZone &zone, + lf::Node &lf_border_link_input_node, + lf::Node &lf_border_link_usage_node, + BuildGraphParams &graph_params) + { + lf::Graph &lf_graph = graph_params.lf_graph; + for (const int border_link_i : zone.border_links.index_range()) { + const bNodeLink &border_link = *zone.border_links[border_link_i]; + lf::OutputSocket &lf_from = lf_border_link_input_node.output(border_link_i); + const Vector lf_link_targets = this->find_link_targets(border_link, + graph_params); + for (lf::InputSocket *lf_to : lf_link_targets) { + lf_graph.add_link(lf_from, *lf_to); + } + lf::InputSocket &lf_usage_output = lf_border_link_usage_node.input(border_link_i); + if (lf::OutputSocket *lf_usage = graph_params.usage_by_bsocket.lookup_default( + border_link.tosock, nullptr)) + { + lf_graph.add_link(*lf_usage, lf_usage_output); + } + else { + static const bool static_false = false; + lf_usage_output.set_default_value(&static_false); + } + } + } + + lf::OutputSocket &get_extracted_attributes(lf::OutputSocket &lf_field_socket, + lf::OutputSocket *lf_usage_socket, + lf::Graph &lf_graph, + Set &socket_usage_inputs) + { + const ValueOrFieldCPPType &type = *ValueOrFieldCPPType::get_from_self(lf_field_socket.type()); + auto &lazy_function = scope_.construct(type); + lf::Node &lf_node = lf_graph.add_function(lazy_function); + lf::InputSocket &lf_use_input = lf_node.input(0); + lf::InputSocket &lf_field_input = lf_node.input(1); + socket_usage_inputs.add_new(&lf_use_input); + if (lf_usage_socket) { + lf_graph.add_link(*lf_usage_socket, lf_use_input); + } + else { + static const bool static_false = false; + lf_use_input.set_default_value(&static_false); + } + lf_graph.add_link(lf_field_socket, lf_field_input); + return lf_node.output(0); + } + + /** + * Join multiple attributes set into a single attribute set that can be passed into a node. + */ + lf::OutputSocket *join_attribute_sets(const Span lf_attribute_set_sockets, + JoinAttributeSetsCache &cache, + lf::Graph &lf_graph, + Set &socket_usage_inputs) + { + if (lf_attribute_set_sockets.is_empty()) { + return nullptr; + } + if (lf_attribute_set_sockets.size() == 1) { + return lf_attribute_set_sockets[0]; + } + + Vector key = lf_attribute_set_sockets; + std::sort(key.begin(), key.end()); + return cache.lookup_or_add_cb(key, [&]() { + const auto &lazy_function = LazyFunctionForAnonymousAttributeSetJoin::get_cached( + lf_attribute_set_sockets.size(), scope_); + lf::Node &lf_node = lf_graph.add_function(lazy_function); + for (const int i : lf_attribute_set_sockets.index_range()) { + lf::OutputSocket &lf_attribute_set_socket = *lf_attribute_set_sockets[i]; + lf::InputSocket &lf_use_input = lf_node.input(lazy_function.get_use_input(i)); + + /* Some attribute sets could potentially be set unused in the future based on more dynamic + * analysis of the node tree. */ + static const bool static_true = true; + lf_use_input.set_default_value(&static_true); + + socket_usage_inputs.add(&lf_use_input); + lf::InputSocket &lf_attribute_set_input = lf_node.input( + lazy_function.get_attribute_set_input(i)); + lf_graph.add_link(lf_attribute_set_socket, lf_attribute_set_input); + } + return &lf_node.output(0); + }); + } + + void insert_child_zone_node(const bNodeTreeZone &child_zone, BuildGraphParams &graph_params) + { + const int child_zone_i = child_zone.index; + ZoneBuildInfo &child_zone_info = zone_build_infos_[child_zone_i]; + lf::FunctionNode &child_zone_node = graph_params.lf_graph.add_function( + *child_zone_info.lazy_function); + mapping_->zone_node_map.add_new(&child_zone, &child_zone_node); + + for (const int i : child_zone_info.main_input_indices.index_range()) { + const bNodeSocket &bsocket = child_zone.input_node->input_socket(i); + lf::InputSocket &lf_input_socket = child_zone_node.input( + child_zone_info.main_input_indices[i]); + lf::OutputSocket &lf_usage_socket = child_zone_node.output( + child_zone_info.main_input_usage_indices[i]); + mapping_->bsockets_by_lf_socket_map.add(&lf_input_socket, &bsocket); + graph_params.lf_inputs_by_bsocket.add(&bsocket, &lf_input_socket); + graph_params.usage_by_bsocket.add(&bsocket, &lf_usage_socket); + } + for (const int i : child_zone_info.main_output_indices.index_range()) { + const bNodeSocket &bsocket = child_zone.output_node->output_socket(i); + lf::OutputSocket &lf_output_socket = child_zone_node.output( + child_zone_info.main_output_indices[i]); + lf::InputSocket &lf_usage_input = child_zone_node.input( + child_zone_info.main_output_usage_indices[i]); + mapping_->bsockets_by_lf_socket_map.add(&lf_output_socket, &bsocket); + graph_params.lf_output_by_bsocket.add(&bsocket, &lf_output_socket); + graph_params.socket_usage_inputs.add(&lf_usage_input); + if (lf::OutputSocket *lf_usage = graph_params.usage_by_bsocket.lookup_default(&bsocket, + nullptr)) { + graph_params.lf_graph.add_link(*lf_usage, lf_usage_input); + } + else { + static const bool static_false = false; + lf_usage_input.set_default_value(&static_false); + } + } + + const Span child_border_links = child_zone.border_links; + for (const int child_border_link_i : child_border_links.index_range()) { + lf::InputSocket &child_border_link_input = child_zone_node.input( + child_zone_info.border_link_input_indices[child_border_link_i]); + const bNodeLink &link = *child_border_links[child_border_link_i]; + graph_params.lf_input_by_border_link.add(&link, &child_border_link_input); + lf::OutputSocket &lf_usage = child_zone_node.output( + child_zone_info.border_link_input_usage_indices[child_border_link_i]); + graph_params.lf_inputs_by_bsocket.add(link.tosock, &child_border_link_input); + graph_params.usage_by_bsocket.add(link.tosock, &lf_usage); + } + + for (const auto item : child_zone_info.attribute_set_input_by_field_source_index.items()) { + const int field_source_index = item.key; + const int child_zone_input_index = item.value; + lf::InputSocket &lf_attribute_set_input = child_zone_node.input(child_zone_input_index); + graph_params.lf_attribute_set_input_by_field_source_index.add(field_source_index, + &lf_attribute_set_input); + } + for (const auto item : child_zone_info.attribute_set_input_by_caller_propagation_index.items()) + { + const int caller_propagation_index = item.key; + const int child_zone_input_index = item.value; + lf::InputSocket &lf_attribute_set_input = child_zone_node.input(child_zone_input_index); + graph_params.lf_attribute_set_input_by_caller_propagation_index.add(caller_propagation_index, + &lf_attribute_set_input); + } + } + + void build_group_input_node(lf::Graph &lf_graph) + { + Vector input_cpp_types; + const Span interface_inputs = btree_.interface_inputs(); + for (const bNodeSocket *interface_input : interface_inputs) { + input_cpp_types.append(interface_input->typeinfo->geometry_nodes_cpp_type); + } + + /* Create a dummy node for the group inputs. */ + auto &debug_info = scope_.construct(); + group_input_lf_node_ = &lf_graph.add_dummy({}, input_cpp_types, &debug_info); + + for (const int i : interface_inputs.index_range()) { + mapping_->group_input_sockets.append(&group_input_lf_node_->output(i)); + debug_info.socket_names.append(interface_inputs[i]->name); + } + } + + /** + * Build an output node that just outputs default values in the case when there is no Group + * Output node in the tree. + */ + void build_fallback_output_node(lf::Graph &lf_graph) + { + Vector output_cpp_types; + auto &debug_info = scope_.construct(); + for (const bNodeSocket *interface_output : btree_.interface_outputs()) { + output_cpp_types.append(interface_output->typeinfo->geometry_nodes_cpp_type); + debug_info.socket_names.append(interface_output->name); + } + + lf::Node &lf_node = lf_graph.add_dummy(output_cpp_types, {}, &debug_info); + for (lf::InputSocket *lf_socket : lf_node.inputs()) { + const CPPType &type = lf_socket->type(); + lf_socket->set_default_value(type.default_value()); + } + mapping_->standard_group_output_sockets = lf_node.inputs(); + } + + void insert_node_in_graph(const bNode &bnode, BuildGraphParams &graph_params) + { + const bNodeType *node_type = bnode.typeinfo; + if (node_type == nullptr) { + return; + } + if (bnode.is_muted()) { + this->build_muted_node(bnode, graph_params); + return; + } + switch (node_type->type) { + case NODE_FRAME: { + /* Ignored. */ + break; + } + case NODE_REROUTE: { + this->build_reroute_node(bnode, graph_params); + break; + } + case NODE_GROUP_INPUT: { + this->handle_group_input_node(bnode, graph_params); + break; + } + case NODE_GROUP_OUTPUT: { + this->build_group_output_node(bnode, graph_params); + break; + } + case NODE_CUSTOM_GROUP: + case NODE_GROUP: { + this->build_group_node(bnode, graph_params); + break; + } + case GEO_NODE_VIEWER: { + this->build_viewer_node(bnode, graph_params); + break; + } + case GEO_NODE_SWITCH: { + this->build_switch_node(bnode, graph_params); + break; + } + default: { + if (node_type->geometry_node_execute) { + this->build_geometry_node(bnode, graph_params); + break; + } + const NodeMultiFunctions::Item &fn_item = node_multi_functions_.try_get(bnode); + if (fn_item.fn != nullptr) { + this->build_multi_function_node(bnode, fn_item, graph_params); + break; + } + if (node_type == &bke::NodeTypeUndefined) { + this->build_undefined_node(bnode, graph_params); + break; + } + /* Nodes that don't match any of the criteria above are just ignored. */ + break; + } + } + } + + void build_muted_node(const bNode &bnode, BuildGraphParams &graph_params) + { + auto &lazy_function = scope_.construct( + bnode, mapping_->lf_index_by_bsocket); + lf::Node &lf_node = graph_params.lf_graph.add_function(lazy_function); + for (const bNodeSocket *bsocket : bnode.input_sockets()) { + const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()]; + if (lf_index == -1) { + continue; + } + lf::InputSocket &lf_socket = lf_node.input(lf_index); + graph_params.lf_inputs_by_bsocket.add(bsocket, &lf_socket); + mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket); + } + for (const bNodeSocket *bsocket : bnode.output_sockets()) { + const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()]; + if (lf_index == -1) { + continue; + } + lf::OutputSocket &lf_socket = lf_node.output(lf_index); + graph_params.lf_output_by_bsocket.add_new(bsocket, &lf_socket); + mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket); + } + + this->build_muted_node_usages(bnode, graph_params); + } + + /** + * An input of a muted node is used when any of its internally linked outputs is used. + */ + void build_muted_node_usages(const bNode &bnode, BuildGraphParams &graph_params) + { + /* Find all outputs that use a specific input. */ + MultiValueMap outputs_by_input; + for (const bNodeLink &blink : bnode.internal_links()) { + outputs_by_input.add(blink.fromsock, blink.tosock); + } + for (const auto item : outputs_by_input.items()) { + const bNodeSocket &input_bsocket = *item.key; + const Span output_bsockets = item.value; + + /* The input is used if any of the internally linked outputs is used. */ + Vector lf_socket_usages; + for (const bNodeSocket *output_bsocket : output_bsockets) { + if (lf::OutputSocket *lf_socket = graph_params.usage_by_bsocket.lookup_default( + output_bsocket, nullptr)) + { + lf_socket_usages.append(lf_socket); + } + } + graph_params.usage_by_bsocket.add(&input_bsocket, + this->or_socket_usages(lf_socket_usages, graph_params)); + } + } + + void build_reroute_node(const bNode &bnode, BuildGraphParams &graph_params) + { + const bNodeSocket &input_bsocket = bnode.input_socket(0); + const bNodeSocket &output_bsocket = bnode.output_socket(0); + const CPPType *type = get_socket_cpp_type(input_bsocket); + if (type == nullptr) { + return; + } + + auto &lazy_function = scope_.construct(*type); + lf::Node &lf_node = graph_params.lf_graph.add_function(lazy_function); + + lf::InputSocket &lf_input = lf_node.input(0); + lf::OutputSocket &lf_output = lf_node.output(0); + graph_params.lf_inputs_by_bsocket.add(&input_bsocket, &lf_input); + graph_params.lf_output_by_bsocket.add_new(&output_bsocket, &lf_output); + mapping_->bsockets_by_lf_socket_map.add(&lf_input, &input_bsocket); + mapping_->bsockets_by_lf_socket_map.add(&lf_output, &output_bsocket); + + if (lf::OutputSocket *lf_usage = graph_params.usage_by_bsocket.lookup_default( + &bnode.output_socket(0), nullptr)) + { + graph_params.usage_by_bsocket.add(&bnode.input_socket(0), lf_usage); + } + } + + void handle_group_input_node(const bNode &bnode, BuildGraphParams &graph_params) + { + for (const int i : btree_.interface_inputs().index_range()) { + const bNodeSocket &bsocket = bnode.output_socket(i); + lf::OutputSocket &lf_socket = group_input_lf_node_->output(i); + graph_params.lf_output_by_bsocket.add_new(&bsocket, &lf_socket); + mapping_->dummy_socket_map.add_new(&bsocket, &lf_socket); + mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket); + } + } + + void build_group_output_node(const bNode &bnode, BuildGraphParams &graph_params) + { + Vector output_cpp_types; + auto &debug_info = scope_.construct(); + for (const bNodeSocket *interface_input : btree_.interface_outputs()) { + output_cpp_types.append(interface_input->typeinfo->geometry_nodes_cpp_type); + debug_info.socket_names.append(interface_input->name); + } + + lf::DummyNode &group_output_lf_node = graph_params.lf_graph.add_dummy( + output_cpp_types, {}, &debug_info); + + for (const int i : group_output_lf_node.inputs().index_range()) { + const bNodeSocket &bsocket = bnode.input_socket(i); + lf::InputSocket &lf_socket = group_output_lf_node.input(i); + graph_params.lf_inputs_by_bsocket.add(&bsocket, &lf_socket); + mapping_->dummy_socket_map.add(&bsocket, &lf_socket); + mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket); + } + + if (&bnode == btree_.group_output_node()) { + mapping_->standard_group_output_sockets = group_output_lf_node.inputs(); + } + } + + void build_group_node(const bNode &bnode, BuildGraphParams &graph_params) + { + const bNodeTree *group_btree = reinterpret_cast(bnode.id); + if (group_btree == nullptr) { + return; + } + const GeometryNodesLazyFunctionGraphInfo *group_lf_graph_info = + ensure_geometry_nodes_lazy_function_graph(*group_btree); + if (group_lf_graph_info == nullptr) { + return; + } + + auto &lazy_function = scope_.construct( + bnode, *group_lf_graph_info, *lf_graph_info_); + lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(lazy_function); + + for (const int i : bnode.input_sockets().index_range()) { + const bNodeSocket &bsocket = bnode.input_socket(i); + BLI_assert(!bsocket.is_multi_input()); + lf::InputSocket &lf_socket = lf_node.input(i); + graph_params.lf_inputs_by_bsocket.add(&bsocket, &lf_socket); + mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket); + } + for (const int i : bnode.output_sockets().index_range()) { + const bNodeSocket &bsocket = bnode.output_socket(i); + lf::OutputSocket &lf_socket = lf_node.output(i); + graph_params.lf_output_by_bsocket.add_new(&bsocket, &lf_socket); + mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket); } mapping_->group_node_map.add(&bnode, &lf_node); lf_graph_info_->num_inline_nodes_approximate += @@ -1629,7 +2412,7 @@ struct GeometryNodesLazyFunctionGraphBuilder { if (lf_input_index != -1) { lf::InputSocket &lf_input = lf_node.input(lf_input_index); lf_input.set_default_value(&static_false); - socket_usage_inputs_.add(&lf_input); + graph_params.socket_usage_inputs.add(&lf_input); } } { @@ -1638,17 +2421,82 @@ struct GeometryNodesLazyFunctionGraphBuilder { [bsocket->index_in_all_outputs()]; if (lf_input_index != -1) { lf::InputSocket &lf_input = lf_node.input(lf_input_index); - attribute_set_propagation_map_.add(bsocket, &lf_input); + graph_params.lf_attribute_set_input_by_output_geometry_bsocket.add(bsocket, &lf_input); } } } - lf_graph_info_->functions.append(std::move(lazy_function)); + + this->build_group_node_socket_usage(bnode, lf_node, graph_params); } - void handle_geometry_node(const bNode &bnode) + void build_group_node_socket_usage(const bNode &bnode, + lf::FunctionNode &lf_group_node, + BuildGraphParams &graph_params) { - auto lazy_function = std::make_unique(bnode, *lf_graph_info_); - lf::Node &lf_node = lf_graph_->add_function(*lazy_function); + const bNodeTree *bgroup = reinterpret_cast(bnode.id); + if (bgroup == nullptr) { + return; + } + const GeometryNodesLazyFunctionGraphInfo *group_lf_graph_info = + ensure_geometry_nodes_lazy_function_graph(*bgroup); + if (group_lf_graph_info == nullptr) { + return; + } + const auto &fn = static_cast(lf_group_node.function()); + + for (const bNodeSocket *input_bsocket : bnode.input_sockets()) { + const int input_index = input_bsocket->index(); + const InputUsageHint &input_usage_hint = + group_lf_graph_info->mapping.group_input_usage_hints[input_index]; + switch (input_usage_hint.type) { + case InputUsageHintType::Never: { + /* Nothing to do. */ + break; + } + case InputUsageHintType::DependsOnOutput: { + Vector output_usages; + for (const int i : input_usage_hint.output_dependencies) { + if (lf::OutputSocket *lf_socket = graph_params.usage_by_bsocket.lookup_default( + &bnode.output_socket(i), nullptr)) + { + output_usages.append(lf_socket); + } + } + graph_params.usage_by_bsocket.add(input_bsocket, + this->or_socket_usages(output_usages, graph_params)); + break; + } + case InputUsageHintType::DynamicSocket: { + graph_params.usage_by_bsocket.add( + input_bsocket, + &lf_group_node.output(fn.lf_output_for_input_bsocket_usage_.lookup(input_index))); + break; + } + } + } + + for (const bNodeSocket *output_bsocket : bnode.output_sockets()) { + const int lf_input_index = + mapping_ + ->lf_input_index_for_output_bsocket_usage[output_bsocket->index_in_all_outputs()]; + BLI_assert(lf_input_index >= 0); + lf::InputSocket &lf_socket = lf_group_node.input(lf_input_index); + if (lf::OutputSocket *lf_output_is_used = graph_params.usage_by_bsocket.lookup_default( + output_bsocket, nullptr)) + { + graph_params.lf_graph.add_link(*lf_output_is_used, lf_socket); + } + else { + static const bool static_false = false; + lf_socket.set_default_value(&static_false); + } + } + } + + void build_geometry_node(const bNode &bnode, BuildGraphParams &graph_params) + { + auto &lazy_function = scope_.construct(bnode, *lf_graph_info_); + lf::Node &lf_node = graph_params.lf_graph.add_function(lazy_function); for (const bNodeSocket *bsocket : bnode.input_sockets()) { const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()]; @@ -1658,11 +2506,11 @@ struct GeometryNodesLazyFunctionGraphBuilder { lf::InputSocket &lf_socket = lf_node.input(lf_index); if (bsocket->is_multi_input()) { - auto multi_input_lazy_function = std::make_unique(*bsocket); - lf::Node &lf_multi_input_node = lf_graph_->add_function(*multi_input_lazy_function); - lf_graph_info_->functions.append(std::move(multi_input_lazy_function)); - lf_graph_->add_link(lf_multi_input_node.output(0), lf_socket); - multi_input_socket_nodes_.add_new(bsocket, &lf_multi_input_node); + auto &multi_input_lazy_function = scope_.construct(*bsocket); + lf::Node &lf_multi_input_node = graph_params.lf_graph.add_function( + multi_input_lazy_function); + graph_params.lf_graph.add_link(lf_multi_input_node.output(0), lf_socket); + graph_params.multi_input_socket_nodes.add_new(bsocket, &lf_multi_input_node); for (lf::InputSocket *lf_multi_input_socket : lf_multi_input_node.inputs()) { mapping_->bsockets_by_lf_socket_map.add(lf_multi_input_socket, bsocket); const void *default_value = lf_multi_input_socket->type().default_value(); @@ -1670,7 +2518,7 @@ struct GeometryNodesLazyFunctionGraphBuilder { } } else { - input_socket_map_.add(bsocket, &lf_socket); + graph_params.lf_inputs_by_bsocket.add(bsocket, &lf_socket); mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket); } } @@ -1680,7 +2528,7 @@ struct GeometryNodesLazyFunctionGraphBuilder { continue; } lf::OutputSocket &lf_socket = lf_node.output(lf_index); - output_socket_map_.add_new(bsocket, &lf_socket); + graph_params.lf_output_by_bsocket.add_new(bsocket, &lf_socket); mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket); } @@ -1689,9 +2537,16 @@ struct GeometryNodesLazyFunctionGraphBuilder { const int lf_input_index = mapping_->lf_input_index_for_output_bsocket_usage[bsocket->index_in_all_outputs()]; if (lf_input_index != -1) { - output_used_sockets_for_builtin_nodes_.append_as(bsocket, - &lf_node.input(lf_input_index)); - socket_usage_inputs_.add_new(&lf_node.input(lf_input_index)); + lf::InputSocket &lf_input_socket = lf_node.input(lf_input_index); + if (lf::OutputSocket *lf_usage = graph_params.usage_by_bsocket.lookup_default(bsocket, + nullptr)) { + graph_params.lf_graph.add_link(*lf_usage, lf_input_socket); + } + else { + static const bool static_false = false; + lf_input_socket.set_default_value(&static_false); + } + graph_params.socket_usage_inputs.add_new(&lf_node.input(lf_input_index)); } } { @@ -1699,20 +2554,53 @@ struct GeometryNodesLazyFunctionGraphBuilder { const int lf_input_index = mapping_->lf_input_index_for_attribute_propagation_to_output [bsocket->index_in_all_outputs()]; if (lf_input_index != -1) { - attribute_set_propagation_map_.add(bsocket, &lf_node.input(lf_input_index)); + graph_params.lf_attribute_set_input_by_output_geometry_bsocket.add( + bsocket, &lf_node.input(lf_input_index)); } } } - lf_graph_info_->functions.append(std::move(lazy_function)); + this->build_standard_node_input_socket_usage(bnode, graph_params); + } + + void build_standard_node_input_socket_usage(const bNode &bnode, BuildGraphParams &graph_params) + { + if (bnode.input_sockets().is_empty()) { + return; + } + + Vector output_usages; + for (const bNodeSocket *output_socket : bnode.output_sockets()) { + if (!output_socket->is_available()) { + continue; + } + if (lf::OutputSocket *is_used_socket = graph_params.usage_by_bsocket.lookup_default( + output_socket, nullptr)) + { + output_usages.append_non_duplicates(is_used_socket); + } + } + + /* Assume every input is used when any output is used. */ + lf::OutputSocket *lf_usage = this->or_socket_usages(output_usages, graph_params); + if (lf_usage == nullptr) { + return; + } + + for (const bNodeSocket *input_socket : bnode.input_sockets()) { + if (input_socket->is_available()) { + graph_params.usage_by_bsocket.add(input_socket, lf_usage); + } + } } - void handle_multi_function_node(const bNode &bnode, const NodeMultiFunctions::Item &fn_item) + void build_multi_function_node(const bNode &bnode, + const NodeMultiFunctions::Item &fn_item, + BuildGraphParams &graph_params) { - auto lazy_function = std::make_unique( + auto &lazy_function = scope_.construct( bnode, fn_item, mapping_->lf_index_by_bsocket); - lf::Node &lf_node = lf_graph_->add_function(*lazy_function); - lf_graph_info_->functions.append(std::move(lazy_function)); + lf::Node &lf_node = graph_params.lf_graph.add_function(lazy_function); for (const bNodeSocket *bsocket : bnode.input_sockets()) { const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()]; @@ -1721,7 +2609,7 @@ struct GeometryNodesLazyFunctionGraphBuilder { } BLI_assert(!bsocket->is_multi_input()); lf::InputSocket &lf_socket = lf_node.input(lf_index); - input_socket_map_.add(bsocket, &lf_socket); + graph_params.lf_inputs_by_bsocket.add(bsocket, &lf_socket); mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket); } for (const bNodeSocket *bsocket : bnode.output_sockets()) { @@ -1730,96 +2618,112 @@ struct GeometryNodesLazyFunctionGraphBuilder { continue; } lf::OutputSocket &lf_socket = lf_node.output(lf_index); - output_socket_map_.add(bsocket, &lf_socket); + graph_params.lf_output_by_bsocket.add(bsocket, &lf_socket); mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket); } + + this->build_standard_node_input_socket_usage(bnode, graph_params); } - void handle_viewer_node(const bNode &bnode) + void build_viewer_node(const bNode &bnode, BuildGraphParams &graph_params) { - auto lazy_function = std::make_unique( + auto &lazy_function = scope_.construct( bnode, mapping_->lf_index_by_bsocket); - lf::FunctionNode &lf_node = lf_graph_->add_function(*lazy_function); - lf_graph_info_->functions.append(std::move(lazy_function)); + lf::FunctionNode &lf_viewer_node = graph_params.lf_graph.add_function(lazy_function); for (const bNodeSocket *bsocket : bnode.input_sockets()) { const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()]; if (lf_index == -1) { continue; } - lf::InputSocket &lf_socket = lf_node.input(lf_index); - input_socket_map_.add(bsocket, &lf_socket); + lf::InputSocket &lf_socket = lf_viewer_node.input(lf_index); + graph_params.lf_inputs_by_bsocket.add(bsocket, &lf_socket); mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket); } - mapping_->viewer_node_map.add(&bnode, &lf_node); + mapping_->viewer_node_map.add(&bnode, &lf_viewer_node); + + { + auto &usage_lazy_function = scope_.construct( + lf_viewer_node); + lf::FunctionNode &lf_usage_node = graph_params.lf_graph.add_function(usage_lazy_function); + + for (const bNodeSocket *bsocket : bnode.input_sockets()) { + if (bsocket->is_available()) { + graph_params.usage_by_bsocket.add(bsocket, &lf_usage_node.output(0)); + } + } + } } - void handle_simulation_input_node(const bNodeTree &node_tree, const bNode &bnode) + lf::FunctionNode *insert_simulation_input_node(const bNodeTree &node_tree, + const bNode &bnode, + BuildGraphParams &graph_params) { const NodeGeometrySimulationInput *storage = static_cast( bnode.storage); if (node_tree.node_by_id(storage->output_node_id) == nullptr) { - return; + return nullptr; } std::unique_ptr lazy_function = get_simulation_input_lazy_function( node_tree, bnode, *lf_graph_info_); - lf::FunctionNode &lf_node = lf_graph_->add_function(*lazy_function); - lf_graph_info_->functions.append(std::move(lazy_function)); + lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(*lazy_function); + scope_.add(std::move(lazy_function)); for (const int i : bnode.input_sockets().index_range().drop_back(1)) { const bNodeSocket &bsocket = bnode.input_socket(i); lf::InputSocket &lf_socket = lf_node.input( mapping_->lf_index_by_bsocket[bsocket.index_in_tree()]); - input_socket_map_.add(&bsocket, &lf_socket); + graph_params.lf_inputs_by_bsocket.add(&bsocket, &lf_socket); mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket); } for (const int i : bnode.output_sockets().index_range().drop_back(1)) { const bNodeSocket &bsocket = bnode.output_socket(i); lf::OutputSocket &lf_socket = lf_node.output( mapping_->lf_index_by_bsocket[bsocket.index_in_tree()]); - output_socket_map_.add(&bsocket, &lf_socket); + graph_params.lf_output_by_bsocket.add(&bsocket, &lf_socket); mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket); } + return &lf_node; } - void handle_simulation_output_node(const bNode &bnode) + lf::FunctionNode &insert_simulation_output_node(const bNode &bnode, + BuildGraphParams &graph_params) { std::unique_ptr lazy_function = get_simulation_output_lazy_function( bnode, *lf_graph_info_); - lf::FunctionNode &lf_node = lf_graph_->add_function(*lazy_function); - lf_graph_info_->functions.append(std::move(lazy_function)); + lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(*lazy_function); + scope_.add(std::move(lazy_function)); for (const int i : bnode.input_sockets().index_range().drop_back(1)) { const bNodeSocket &bsocket = bnode.input_socket(i); lf::InputSocket &lf_socket = lf_node.input( mapping_->lf_index_by_bsocket[bsocket.index_in_tree()]); - input_socket_map_.add(&bsocket, &lf_socket); + graph_params.lf_inputs_by_bsocket.add(&bsocket, &lf_socket); mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket); } for (const int i : bnode.output_sockets().index_range().drop_back(1)) { const bNodeSocket &bsocket = bnode.output_socket(i); lf::OutputSocket &lf_socket = lf_node.output( mapping_->lf_index_by_bsocket[bsocket.index_in_tree()]); - output_socket_map_.add(&bsocket, &lf_socket); + graph_params.lf_output_by_bsocket.add(&bsocket, &lf_socket); mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket); } - - mapping_->sim_output_node_map.add(&bnode, &lf_node); + return lf_node; } - void handle_switch_node(const bNode &bnode) + void build_switch_node(const bNode &bnode, BuildGraphParams &graph_params) { std::unique_ptr lazy_function = get_switch_node_lazy_function(bnode); - lf::FunctionNode &lf_node = lf_graph_->add_function(*lazy_function); - lf_graph_info_->functions.append(std::move(lazy_function)); + lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(*lazy_function); + scope_.add(std::move(lazy_function)); int input_index = 0; for (const bNodeSocket *bsocket : bnode.input_sockets()) { if (bsocket->is_available()) { lf::InputSocket &lf_socket = lf_node.input(input_index); - input_socket_map_.add(bsocket, &lf_socket); + graph_params.lf_inputs_by_bsocket.add(bsocket, &lf_socket); mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket); input_index++; } @@ -1827,19 +2731,70 @@ struct GeometryNodesLazyFunctionGraphBuilder { for (const bNodeSocket *bsocket : bnode.output_sockets()) { if (bsocket->is_available()) { lf::OutputSocket &lf_socket = lf_node.output(0); - output_socket_map_.add(bsocket, &lf_socket); + graph_params.lf_output_by_bsocket.add(bsocket, &lf_socket); mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket); break; } } + + this->build_switch_node_socket_usage(bnode, graph_params); } - void handle_undefined_node(const bNode &bnode) + void build_switch_node_socket_usage(const bNode &bnode, BuildGraphParams &graph_params) { - auto lazy_function = std::make_unique( + const bNodeSocket *switch_input_bsocket = nullptr; + const bNodeSocket *false_input_bsocket = nullptr; + const bNodeSocket *true_input_bsocket = nullptr; + const bNodeSocket *output_bsocket = nullptr; + for (const bNodeSocket *socket : bnode.input_sockets()) { + if (!socket->is_available()) { + continue; + } + if (socket->name == StringRef("Switch")) { + switch_input_bsocket = socket; + } + else if (socket->name == StringRef("False")) { + false_input_bsocket = socket; + } + else if (socket->name == StringRef("True")) { + true_input_bsocket = socket; + } + } + for (const bNodeSocket *socket : bnode.output_sockets()) { + if (socket->is_available()) { + output_bsocket = socket; + break; + } + } + lf::OutputSocket *output_is_used_socket = graph_params.usage_by_bsocket.lookup_default( + output_bsocket, nullptr); + if (output_is_used_socket == nullptr) { + return; + } + graph_params.usage_by_bsocket.add(switch_input_bsocket, output_is_used_socket); + if (switch_input_bsocket->is_directly_linked()) { + /* The condition input is dynamic, so the usage of the other inputs is as well. */ + static const LazyFunctionForSwitchSocketUsage switch_socket_usage_fn; + lf::Node &lf_node = graph_params.lf_graph.add_function(switch_socket_usage_fn); + graph_params.lf_inputs_by_bsocket.add(switch_input_bsocket, &lf_node.input(0)); + graph_params.usage_by_bsocket.add(false_input_bsocket, &lf_node.output(0)); + graph_params.usage_by_bsocket.add(true_input_bsocket, &lf_node.output(1)); + } + else { + if (switch_input_bsocket->default_value_typed()->value) { + graph_params.usage_by_bsocket.add(true_input_bsocket, output_is_used_socket); + } + else { + graph_params.usage_by_bsocket.add(false_input_bsocket, output_is_used_socket); + } + } + } + + void build_undefined_node(const bNode &bnode, BuildGraphParams &graph_params) + { + auto &lazy_function = scope_.construct( bnode, mapping_->lf_index_by_bsocket); - lf::FunctionNode &lf_node = lf_graph_->add_function(*lazy_function); - lf_graph_info_->functions.append(std::move(lazy_function)); + lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(lazy_function); for (const bNodeSocket *bsocket : bnode.output_sockets()) { const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()]; @@ -1847,32 +2802,97 @@ struct GeometryNodesLazyFunctionGraphBuilder { continue; } lf::OutputSocket &lf_socket = lf_node.output(lf_index); - output_socket_map_.add(bsocket, &lf_socket); + graph_params.lf_output_by_bsocket.add(bsocket, &lf_socket); mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket); } } - void handle_links() + lf::DummyNode &build_dummy_node_for_sockets(const StringRef name, + const Span input_bsockets, + const Span output_bsockets, + lf::Graph &lf_graph) + { + auto &debug_info = scope_.construct(); + debug_info.name = name; + Vector input_types; + Vector output_types; + for (const bNodeSocket *bsocket : input_bsockets) { + input_types.append(bsocket->typeinfo->geometry_nodes_cpp_type); + debug_info.input_names.append(bsocket->identifier); + } + for (const bNodeSocket *bsocket : output_bsockets) { + output_types.append(bsocket->typeinfo->geometry_nodes_cpp_type); + debug_info.output_names.append(bsocket->identifier); + } + lf::DummyNode &node = lf_graph.add_dummy(input_types, output_types, &debug_info); + return node; + } + + lf::DummyNode &build_dummy_node_for_socket_usages( + const StringRef name, + const Span input_bsockets, + const Span output_bsockets, + lf::Graph &lf_graph) { - for (const auto item : output_socket_map_.items()) { - this->insert_links_from_socket(*item.key, *item.value); + auto &debug_info = scope_.construct(); + debug_info.name = name; + const CPPType &bool_cpp_type = CPPType::get(); + Vector input_types(input_bsockets.size(), &bool_cpp_type); + Vector output_types(output_bsockets.size(), &bool_cpp_type); + for (const bNodeSocket *bsocket : input_bsockets) { + debug_info.input_names.append(bsocket->identifier); + } + for (const bNodeSocket *bsocket : output_bsockets) { + debug_info.output_names.append(bsocket->identifier); + } + lf::DummyNode &node = lf_graph.add_dummy(input_types, output_types, &debug_info); + return node; + } + + struct TypeWithLinks { + const CPPType *type; + Vector links; + }; + + void insert_links_from_socket(const bNodeSocket &from_bsocket, + lf::OutputSocket &from_lf_socket, + BuildGraphParams &graph_params) + { + if (bke::nodeIsDanglingReroute(&btree_, &from_bsocket.owner_node())) { + return; + } + + /* Group available target sockets by type so that they can be handled together. */ + const Vector types_with_links = this->group_link_targets_by_type(from_bsocket); + + for (const TypeWithLinks &type_with_links : types_with_links) { + const CPPType &to_type = *type_with_links.type; + const Span links = type_with_links.links; + + lf::OutputSocket *converted_from_lf_socket = this->insert_type_conversion_if_necessary( + from_lf_socket, to_type, graph_params.lf_graph); + + for (const bNodeLink *link : links) { + const Vector lf_link_targets = this->find_link_targets(*link, + graph_params); + if (converted_from_lf_socket == nullptr) { + const void *default_value = to_type.default_value(); + for (lf::InputSocket *to_lf_socket : lf_link_targets) { + to_lf_socket->set_default_value(default_value); + } + } + else { + for (lf::InputSocket *to_lf_socket : lf_link_targets) { + graph_params.lf_graph.add_link(*converted_from_lf_socket, *to_lf_socket); + } + } + } } } - void insert_links_from_socket(const bNodeSocket &from_bsocket, lf::OutputSocket &from_lf_socket) + Vector group_link_targets_by_type(const bNodeSocket &from_bsocket) { - if (bke::nodeIsDanglingReroute(&btree_, &from_bsocket.owner_node())) { - return; - } - const Span links_from_bsocket = from_bsocket.directly_linked_links(); - - struct TypeWithLinks { - const CPPType *type; - Vector links; - }; - - /* Group available target sockets by type so that they can be handled together. */ Vector types_with_links; for (const bNodeLink *link : links_from_bsocket) { if (link->is_muted()) { @@ -1899,67 +2919,56 @@ struct GeometryNodesLazyFunctionGraphBuilder { } types_with_links.append({to_type, {link}}); } + return types_with_links; + } - for (const TypeWithLinks &type_with_links : types_with_links) { - const CPPType &to_type = *type_with_links.type; - const Span links = type_with_links.links; - - lf::OutputSocket *converted_from_lf_socket = this->insert_type_conversion_if_necessary( - from_lf_socket, to_type); + Vector find_link_targets(const bNodeLink &link, + const BuildGraphParams &graph_params) + { + if (lf::InputSocket *lf_input_socket = graph_params.lf_input_by_border_link.lookup_default( + &link, nullptr)) + { + return {lf_input_socket}; + } - auto make_input_link_or_set_default = [&](lf::InputSocket &to_lf_socket) { - if (converted_from_lf_socket == nullptr) { - const void *default_value = to_type.default_value(); - to_lf_socket.set_default_value(default_value); + const bNodeSocket &to_bsocket = *link.tosock; + if (to_bsocket.is_multi_input()) { + /* TODO: Cache this index on the link. */ + int link_index = 0; + for (const bNodeLink *multi_input_link : to_bsocket.directly_linked_links()) { + if (multi_input_link == &link) { + break; } - else { - lf_graph_->add_link(*converted_from_lf_socket, to_lf_socket); + if (multi_input_link->is_muted() || !multi_input_link->fromsock->is_available() || + bke::nodeIsDanglingReroute(&btree_, multi_input_link->fromnode)) + { + continue; } - }; - - for (const bNodeLink *link : links) { - const bNodeSocket &to_bsocket = *link->tosock; - if (to_bsocket.is_multi_input()) { - /* TODO: Cache this index on the link. */ - int link_index = 0; - for (const bNodeLink *multi_input_link : to_bsocket.directly_linked_links()) { - if (multi_input_link == link) { - break; - } - if (multi_input_link->is_muted() || !multi_input_link->fromsock->is_available() || - bke::nodeIsDanglingReroute(&btree_, multi_input_link->fromnode)) - { - continue; - } - link_index++; - } - if (to_bsocket.owner_node().is_muted()) { - if (link_index == 0) { - for (lf::InputSocket *to_lf_socket : input_socket_map_.lookup(&to_bsocket)) { - make_input_link_or_set_default(*to_lf_socket); - } - } - } - else { - lf::Node *multi_input_lf_node = multi_input_socket_nodes_.lookup_default(&to_bsocket, - nullptr); - if (multi_input_lf_node == nullptr) { - continue; - } - make_input_link_or_set_default(multi_input_lf_node->input(link_index)); - } + link_index++; + } + if (to_bsocket.owner_node().is_muted()) { + if (link_index == 0) { + return Vector(graph_params.lf_inputs_by_bsocket.lookup(&to_bsocket)); } - else { - for (lf::InputSocket *to_lf_socket : input_socket_map_.lookup(&to_bsocket)) { - make_input_link_or_set_default(*to_lf_socket); - } + } + else { + lf::Node *multi_input_lf_node = graph_params.multi_input_socket_nodes.lookup_default( + &to_bsocket, nullptr); + if (multi_input_lf_node == nullptr) { + return {}; } + return {&multi_input_lf_node->input(link_index)}; } } + else { + return Vector(graph_params.lf_inputs_by_bsocket.lookup(&to_bsocket)); + } + return {}; } lf::OutputSocket *insert_type_conversion_if_necessary(lf::OutputSocket &from_socket, - const CPPType &to_type) + const CPPType &to_type, + lf::Graph &lf_graph) { const CPPType &from_type = from_socket.type(); if (from_type == to_type) { @@ -1972,20 +2981,19 @@ struct GeometryNodesLazyFunctionGraphBuilder { const MultiFunction &multi_fn = *conversions_->get_conversion_multi_function( mf::DataType::ForSingle(from_field_type->value), mf::DataType::ForSingle(to_field_type->value)); - auto fn = std::make_unique( + auto &fn = scope_.construct( multi_fn, *from_field_type, *to_field_type); - lf::Node &conversion_node = lf_graph_->add_function(*fn); - lf_graph_info_->functions.append(std::move(fn)); - lf_graph_->add_link(from_socket, conversion_node.input(0)); + lf::Node &conversion_node = lf_graph.add_function(fn); + lf_graph.add_link(from_socket, conversion_node.input(0)); return &conversion_node.output(0); } } return nullptr; } - void add_default_inputs() + void add_default_inputs(BuildGraphParams &graph_params) { - for (auto item : input_socket_map_.items()) { + for (auto item : graph_params.lf_inputs_by_bsocket.items()) { const bNodeSocket &bsocket = *item.key; const Span lf_sockets = item.value; for (lf::InputSocket *lf_socket : lf_sockets) { @@ -1993,488 +3001,184 @@ struct GeometryNodesLazyFunctionGraphBuilder { /* Is linked already. */ continue; } - this->add_default_input(bsocket, *lf_socket); - } - } - } - - void add_default_input(const bNodeSocket &input_bsocket, lf::InputSocket &input_lf_socket) - { - if (this->try_add_implicit_input(input_bsocket, input_lf_socket)) { - return; - } - GMutablePointer value = get_socket_default_value(lf_graph_info_->allocator, input_bsocket); - if (value.get() == nullptr) { - /* Not possible to add a default value. */ - return; - } - input_lf_socket.set_default_value(value.get()); - if (!value.type()->is_trivially_destructible()) { - lf_graph_info_->values_to_destruct.append(value); - } - } - - bool try_add_implicit_input(const bNodeSocket &input_bsocket, lf::InputSocket &input_lf_socket) - { - const bNode &bnode = input_bsocket.owner_node(); - const SocketDeclaration *socket_decl = input_bsocket.runtime->declaration; - if (socket_decl == nullptr) { - return false; - } - if (socket_decl->input_field_type != InputSocketFieldType::Implicit) { - return false; - } - const ImplicitInputValueFn *implicit_input_fn = socket_decl->implicit_input_fn(); - if (implicit_input_fn == nullptr) { - return false; - } - std::function init_fn = [&bnode, implicit_input_fn](void *r_value) { - (*implicit_input_fn)(bnode, r_value); - }; - const CPPType &type = input_lf_socket.type(); - auto lazy_function = std::make_unique(type, std::move(init_fn)); - lf::Node &lf_node = lf_graph_->add_function(*lazy_function); - lf_graph_info_->functions.append(std::move(lazy_function)); - lf_graph_->add_link(lf_node.output(0), input_lf_socket); - return true; - } - - /** - * Every output geometry socket that may propagate attributes has to know which attributes should - * be propagated. Therefore, every one of these outputs gets a corresponding attribute set input. - */ - void build_attribute_propagation_input_node() - { - const aal::RelationsInNode &tree_relations = - btree_.runtime->anonymous_attribute_inferencing->tree_relations; - Vector output_indices; - for (const aal::PropagateRelation &relation : tree_relations.propagate_relations) { - output_indices.append_non_duplicates(relation.to_geometry_output); - } - Vector cpp_types; - auto debug_info = std::make_unique(); - debug_info->name = "Attributes to Propagate to Output"; - cpp_types.append_n_times(&CPPType::get(), output_indices.size()); - lf::Node &lf_node = lf_graph_->add_dummy({}, cpp_types, debug_info.get()); - for (const int i : output_indices.index_range()) { - const int output_index = output_indices[i]; - mapping_->attribute_set_by_geometry_output.add(output_index, &lf_node.output(i)); - debug_info->output_names.append(btree_.interface_outputs()[output_index]->name); - } - lf_graph_info_->dummy_debug_infos_.append(std::move(debug_info)); - } - - /** - * Build new boolean group inputs that indicate which group outputs are used. - */ - void build_output_usage_input_node() - { - const Span interface_outputs = btree_.interface_outputs(); - - Vector cpp_types; - cpp_types.append_n_times(&CPPType::get(), interface_outputs.size()); - auto debug_info = std::make_unique(); - debug_info->name = "Output Socket Usage"; - lf::Node &lf_node = lf_graph_->add_dummy({}, cpp_types, debug_info.get()); - for (const int i : interface_outputs.index_range()) { - mapping_->group_output_used_sockets.append(&lf_node.output(i)); - debug_info->output_names.append(interface_outputs[i]->name); - } - lf_graph_info_->dummy_debug_infos_.append(std::move(debug_info)); - } - - /** - * Build new boolean group outputs that indicate which group inputs are used depending on other - * group inputs. - */ - void build_input_usage_output_node() - { - const Span interface_inputs = btree_.interface_inputs(); - - Vector cpp_types; - cpp_types.append_n_times(&CPPType::get(), interface_inputs.size()); - auto debug_info = std::make_unique(); - debug_info->name = "Input Socket Usage"; - lf::Node &lf_node = lf_graph_->add_dummy(cpp_types, {}, debug_info.get()); - for (const int i : interface_inputs.index_range()) { - mapping_->group_input_usage_sockets.append(&lf_node.input(i)); - debug_info->input_names.append(interface_inputs[i]->name); - } - lf_graph_info_->dummy_debug_infos_.append(std::move(debug_info)); - } - - /** - * For every socket we want to determine if it will be used depending on the inputs of the node - * group (just static analysis is not enough when there are e.g. Switch nodes). This function - * populates #socket_is_used_map_ with that information. - */ - void build_socket_usages() - { - OrSocketUsagesCache or_socket_usages_cache; - - if (const bNode *group_output_bnode = btree_.group_output_node()) { - /* Whether a group output is used is determined by a group input that has been created - * exactly for this purpose. */ - for (const bNodeSocket *bsocket : group_output_bnode->input_sockets().drop_back(1)) { - const int index = bsocket->index(); - socket_is_used_map_[bsocket->index_in_tree()] = const_cast( - mapping_->group_output_used_sockets[index]); - } - } - - /* Iterate over all nodes from right to left to determine when which sockets are used. */ - for (const bNode *bnode : btree_.toposort_right_to_left()) { - const bNodeType *node_type = bnode->typeinfo; - if (node_type == nullptr) { - /* Ignore. */ - continue; - } - - this->build_output_socket_usages(*bnode, or_socket_usages_cache); - - if (bnode->is_muted()) { - this->build_muted_node_usages(*bnode, or_socket_usages_cache); - continue; - } - - switch (node_type->type) { - case NODE_GROUP_OUTPUT: { - /* Handled before this loop already. */ - break; - } - case NODE_GROUP_INPUT: { - /* Handled after this loop. */ - break; - } - case NODE_FRAME: { - /* Ignored. */ - break; - } - case NODE_REROUTE: { - /* The input is used exactly when the output is used. */ - socket_is_used_map_[bnode->input_socket(0).index_in_tree()] = - socket_is_used_map_[bnode->output_socket(0).index_in_tree()]; - break; - } - case GEO_NODE_SWITCH: { - this->build_switch_node_socket_usage(*bnode); - break; - } - case GEO_NODE_VIEWER: { - this->build_viewer_node_socket_usage(*bnode); - break; - } - case GEO_NODE_SIMULATION_INPUT: { - this->build_simulation_input_socket_usage(*bnode); - break; - } - case GEO_NODE_SIMULATION_OUTPUT: { - this->build_simulation_output_socket_usage(*bnode); - break; - } - case NODE_GROUP: - case NODE_CUSTOM_GROUP: { - this->build_group_node_socket_usage(*bnode, or_socket_usages_cache); - break; - } - default: { - this->build_standard_node_input_socket_usage(*bnode, or_socket_usages_cache); - break; - } - } - } - - this->build_group_input_usages(or_socket_usages_cache); - this->link_output_used_sockets_for_builtin_nodes(); - } - - using OrSocketUsagesCache = Map, lf::OutputSocket *>; - - /** - * Combine multiple socket usages with a logical or. Inserts a new node for that purpose if - * necessary. - */ - lf::OutputSocket *or_socket_usages(MutableSpan usages, - OrSocketUsagesCache &cache) - { - if (usages.is_empty()) { - return nullptr; - } - if (usages.size() == 1) { - return usages[0]; - } - - std::sort(usages.begin(), usages.end()); - return cache.lookup_or_add_cb_as(usages, [&]() { - auto logical_or_fn = std::make_unique(usages.size()); - lf::Node &logical_or_node = lf_graph_->add_function(*logical_or_fn); - lf_graph_info_->functions.append(std::move(logical_or_fn)); - - for (const int i : usages.index_range()) { - lf_graph_->add_link(*usages[i], logical_or_node.input(i)); - } - return &logical_or_node.output(0); - }); - } - - void build_output_socket_usages(const bNode &bnode, OrSocketUsagesCache &or_socket_usages_cache) - { - /* Output sockets are used when any of their linked inputs are used. */ - for (const bNodeSocket *socket : bnode.output_sockets()) { - if (!socket->is_available()) { - continue; - } - /* Determine when linked target sockets are used. */ - Vector target_usages; - for (const bNodeLink *link : socket->directly_linked_links()) { - if (!link->is_used()) { - continue; - } - const bNodeSocket &target_socket = *link->tosock; - if (lf::OutputSocket *is_used_socket = socket_is_used_map_[target_socket.index_in_tree()]) - { - target_usages.append_non_duplicates(is_used_socket); - } - } - /* Combine target socket usages into the usage of the current socket. */ - socket_is_used_map_[socket->index_in_tree()] = this->or_socket_usages( - target_usages, or_socket_usages_cache); - } - } - - /** - * An input of a muted node is used when any of its internally linked outputs is used. - */ - void build_muted_node_usages(const bNode &bnode, OrSocketUsagesCache &or_socket_usages_cache) - { - /* Find all outputs that use a specific input. */ - MultiValueMap outputs_by_input; - for (const bNodeLink &blink : bnode.internal_links()) { - outputs_by_input.add(blink.fromsock, blink.tosock); - } - for (const auto item : outputs_by_input.items()) { - const bNodeSocket &input_bsocket = *item.key; - const Span output_bsockets = item.value; - - /* The input is used if any of the internally linked outputs is used. */ - Vector lf_socket_usages; - for (const bNodeSocket *output_bsocket : output_bsockets) { - if (lf::OutputSocket *lf_socket = socket_is_used_map_[output_bsocket->index_in_tree()]) { - lf_socket_usages.append(lf_socket); - } + this->add_default_input(bsocket, *lf_socket, graph_params); } - socket_is_used_map_[input_bsocket.index_in_tree()] = this->or_socket_usages( - lf_socket_usages, or_socket_usages_cache); } } - - void build_switch_node_socket_usage(const bNode &bnode) - { - const bNodeSocket *switch_input_bsocket = nullptr; - const bNodeSocket *false_input_bsocket = nullptr; - const bNodeSocket *true_input_bsocket = nullptr; - const bNodeSocket *output_bsocket = nullptr; - for (const bNodeSocket *socket : bnode.input_sockets()) { - if (!socket->is_available()) { - continue; - } - if (socket->name == StringRef("Switch")) { - switch_input_bsocket = socket; - } - else if (socket->name == StringRef("False")) { - false_input_bsocket = socket; - } - else if (socket->name == StringRef("True")) { - true_input_bsocket = socket; - } - } - for (const bNodeSocket *socket : bnode.output_sockets()) { - if (socket->is_available()) { - output_bsocket = socket; - break; - } - } - lf::OutputSocket *output_is_used_socket = socket_is_used_map_[output_bsocket->index_in_tree()]; - if (output_is_used_socket == nullptr) { + + void add_default_input(const bNodeSocket &input_bsocket, + lf::InputSocket &input_lf_socket, + BuildGraphParams &graph_params) + { + if (this->try_add_implicit_input(input_bsocket, input_lf_socket, graph_params)) { return; } - socket_is_used_map_[switch_input_bsocket->index_in_tree()] = output_is_used_socket; - lf::InputSocket *lf_switch_input = input_socket_map_.lookup(switch_input_bsocket)[0]; - if (lf::OutputSocket *lf_switch_origin = lf_switch_input->origin()) { - /* The condition input is dynamic, so the usage of the other inputs is as well. */ - static const LazyFunctionForSwitchSocketUsage switch_socket_usage_fn; - lf::Node &lf_node = lf_graph_->add_function(switch_socket_usage_fn); - lf_graph_->add_link(*lf_switch_origin, lf_node.input(0)); - socket_is_used_map_[false_input_bsocket->index_in_tree()] = &lf_node.output(0); - socket_is_used_map_[true_input_bsocket->index_in_tree()] = &lf_node.output(1); + GMutablePointer value = get_socket_default_value(scope_.linear_allocator(), input_bsocket); + if (value.get() == nullptr) { + /* Not possible to add a default value. */ + return; } - else { - if (switch_input_bsocket->default_value_typed()->value) { - socket_is_used_map_[true_input_bsocket->index_in_tree()] = output_is_used_socket; - } - else { - socket_is_used_map_[false_input_bsocket->index_in_tree()] = output_is_used_socket; - } + input_lf_socket.set_default_value(value.get()); + if (!value.type()->is_trivially_destructible()) { + scope_.add_destruct_call([value]() mutable { value.destruct(); }); } } - void build_viewer_node_socket_usage(const bNode &bnode) + bool try_add_implicit_input(const bNodeSocket &input_bsocket, + lf::InputSocket &input_lf_socket, + BuildGraphParams &graph_params) { - const lf::FunctionNode &lf_viewer_node = *mapping_->viewer_node_map.lookup(&bnode); - auto lazy_function = std::make_unique(lf_viewer_node); - lf::Node &lf_node = lf_graph_->add_function(*lazy_function); - lf_graph_info_->functions.append(std::move(lazy_function)); - - for (const bNodeSocket *bsocket : bnode.input_sockets()) { - if (bsocket->is_available()) { - socket_is_used_map_[bsocket->index_in_tree()] = &lf_node.output(0); - } + const bNode &bnode = input_bsocket.owner_node(); + const SocketDeclaration *socket_decl = input_bsocket.runtime->declaration; + if (socket_decl == nullptr) { + return false; + } + if (socket_decl->input_field_type != InputSocketFieldType::Implicit) { + return false; + } + const ImplicitInputValueFn *implicit_input_fn = socket_decl->implicit_input_fn(); + if (implicit_input_fn == nullptr) { + return false; } + std::function init_fn = [&bnode, implicit_input_fn](void *r_value) { + (*implicit_input_fn)(bnode, r_value); + }; + const CPPType &type = input_lf_socket.type(); + auto &lazy_function = scope_.construct(type, std::move(init_fn)); + lf::Node &lf_node = graph_params.lf_graph.add_function(lazy_function); + graph_params.lf_graph.add_link(lf_node.output(0), input_lf_socket); + return true; } - void build_simulation_input_socket_usage(const bNode &bnode) + /** + * Every output geometry socket that may propagate attributes has to know which attributes + * should be propagated. Therefore, every one of these outputs gets a corresponding attribute + * set input. + */ + void build_attribute_propagation_input_node(lf::Graph &lf_graph) { - const NodeGeometrySimulationInput *storage = static_cast( - bnode.storage); - const bNode *sim_output_node = btree_.node_by_id(storage->output_node_id); - if (sim_output_node == nullptr) { - return; + const aal::RelationsInNode &tree_relations = + btree_.runtime->anonymous_attribute_inferencing->tree_relations; + Vector output_indices; + for (const aal::PropagateRelation &relation : tree_relations.propagate_relations) { + output_indices.append_non_duplicates(relation.to_geometry_output); } - lf::Node &lf_node = this->get_simulation_inputs_usage_node(*sim_output_node); - for (const bNodeSocket *bsocket : bnode.input_sockets()) { - if (bsocket->is_available()) { - socket_is_used_map_[bsocket->index_in_tree()] = &lf_node.output(0); - } + Vector cpp_types; + auto &debug_info = scope_.construct(); + debug_info.name = "Attributes to Propagate to Output"; + cpp_types.append_n_times(&CPPType::get(), output_indices.size()); + lf::Node &lf_node = lf_graph.add_dummy({}, cpp_types, &debug_info); + for (const int i : output_indices.index_range()) { + const int output_index = output_indices[i]; + mapping_->attribute_set_by_geometry_output.add(output_index, &lf_node.output(i)); + debug_info.output_names.append(btree_.interface_outputs()[output_index]->name); } } - void build_simulation_output_socket_usage(const bNode &bnode) + /** + * Build new boolean group inputs that indicate which group outputs are used. + */ + lf::DummyNode &build_output_usage_input_node(lf::Graph &lf_graph) { - lf::Node &lf_node = this->get_simulation_inputs_usage_node(bnode); - for (const bNodeSocket *bsocket : bnode.input_sockets()) { - if (bsocket->is_available()) { - socket_is_used_map_[bsocket->index_in_tree()] = &lf_node.output(1); - } + const Span interface_outputs = btree_.interface_outputs(); + + Vector cpp_types; + cpp_types.append_n_times(&CPPType::get(), interface_outputs.size()); + auto &debug_info = scope_.construct(); + debug_info.name = "Output Socket Usage"; + lf::DummyNode &lf_node = lf_graph.add_dummy({}, cpp_types, &debug_info); + for (const int i : interface_outputs.index_range()) { + mapping_->group_output_used_sockets.append(&lf_node.output(i)); + debug_info.output_names.append(interface_outputs[i]->name); } + return lf_node; } - lf::Node &get_simulation_inputs_usage_node(const bNode &sim_output_bnode) + /** + * Build new boolean group outputs that indicate which group inputs are used depending on other + * group inputs. + */ + void build_input_usage_output_node(lf::Graph &lf_graph) { - BLI_assert(sim_output_bnode.type == GEO_NODE_SIMULATION_OUTPUT); - return *simulation_inputs_usage_nodes_.lookup_or_add_cb(&sim_output_bnode, [&]() { - auto lazy_function = std::make_unique(); - lf::Node &lf_node = lf_graph_->add_function(*lazy_function); - lf_graph_info_->functions.append(std::move(lazy_function)); - return &lf_node; - }); + const Span interface_inputs = btree_.interface_inputs(); + + Vector cpp_types; + cpp_types.append_n_times(&CPPType::get(), interface_inputs.size()); + auto &debug_info = scope_.construct(); + debug_info.name = "Input Socket Usage"; + lf::Node &lf_node = lf_graph.add_dummy(cpp_types, {}, &debug_info); + for (const int i : interface_inputs.index_range()) { + mapping_->group_input_usage_sockets.append(&lf_node.input(i)); + debug_info.input_names.append(interface_inputs[i]->name); + } } - void build_group_node_socket_usage(const bNode &bnode, - OrSocketUsagesCache &or_socket_usages_cache) + /** + * Combine multiple socket usages with a logical or. Inserts a new node for that purpose if + * necessary. + */ + lf::OutputSocket *or_socket_usages(MutableSpan usages, + BuildGraphParams &graph_params) { - const bNodeTree *bgroup = reinterpret_cast(bnode.id); - if (bgroup == nullptr) { - return; + if (usages.is_empty()) { + return nullptr; } - const GeometryNodesLazyFunctionGraphInfo *group_lf_graph_info = - ensure_geometry_nodes_lazy_function_graph(*bgroup); - if (group_lf_graph_info == nullptr) { - return; + if (usages.size() == 1) { + return usages[0]; } - lf::FunctionNode &lf_group_node = const_cast( - *mapping_->group_node_map.lookup(&bnode)); - const auto &fn = static_cast(lf_group_node.function()); - for (const bNodeSocket *input_bsocket : bnode.input_sockets()) { - const int input_index = input_bsocket->index(); - const InputUsageHint &input_usage_hint = - group_lf_graph_info->mapping.group_input_usage_hints[input_index]; - switch (input_usage_hint.type) { - case InputUsageHintType::Never: { - /* Nothing to do. */ - break; - } - case InputUsageHintType::DependsOnOutput: { - Vector output_usages; - for (const int i : input_usage_hint.output_dependencies) { - if (lf::OutputSocket *lf_socket = - socket_is_used_map_[bnode.output_socket(i).index_in_tree()]) { - output_usages.append(lf_socket); - } - } - socket_is_used_map_[input_bsocket->index_in_tree()] = this->or_socket_usages( - output_usages, or_socket_usages_cache); - break; - } - case InputUsageHintType::DynamicSocket: { - socket_is_used_map_[input_bsocket->index_in_tree()] = &const_cast( - lf_group_node.output(fn.lf_output_for_input_bsocket_usage_.lookup(input_index))); - break; - } - } - } + std::sort(usages.begin(), usages.end()); + return graph_params.socket_usages_combination_cache.lookup_or_add_cb_as(usages, [&]() { + auto &logical_or_fn = scope_.construct(usages.size()); + lf::Node &logical_or_node = graph_params.lf_graph.add_function(logical_or_fn); - for (const bNodeSocket *output_bsocket : bnode.output_sockets()) { - const int lf_input_index = - mapping_ - ->lf_input_index_for_output_bsocket_usage[output_bsocket->index_in_all_outputs()]; - BLI_assert(lf_input_index >= 0); - lf::InputSocket &lf_socket = lf_group_node.input(lf_input_index); - if (lf::OutputSocket *lf_output_is_used = - socket_is_used_map_[output_bsocket->index_in_tree()]) { - lf_graph_->add_link(*lf_output_is_used, lf_socket); - } - else { - static const bool static_false = false; - lf_socket.set_default_value(&static_false); + for (const int i : usages.index_range()) { + graph_params.lf_graph.add_link(*usages[i], logical_or_node.input(i)); } - } + return &logical_or_node.output(0); + }); } - void build_standard_node_input_socket_usage(const bNode &bnode, - OrSocketUsagesCache &or_socket_usages_cache) + void build_output_socket_usages(const bNode &bnode, BuildGraphParams &graph_params) { - if (bnode.input_sockets().is_empty()) { - return; - } - - Vector output_usages; - for (const bNodeSocket *output_socket : bnode.output_sockets()) { - if (!output_socket->is_available()) { + /* Output sockets are used when any of their linked inputs are used. */ + for (const bNodeSocket *socket : bnode.output_sockets()) { + if (!socket->is_available()) { continue; } - if (lf::OutputSocket *is_used_socket = socket_is_used_map_[output_socket->index_in_tree()]) { - output_usages.append_non_duplicates(is_used_socket); - } - } - - /* Assume every input is used when any output is used. */ - lf::OutputSocket *lf_usage = this->or_socket_usages(output_usages, or_socket_usages_cache); - if (lf_usage == nullptr) { - return; - } - - for (const bNodeSocket *input_socket : bnode.input_sockets()) { - if (input_socket->is_available()) { - socket_is_used_map_[input_socket->index_in_tree()] = lf_usage; + /* Determine when linked target sockets are used. */ + Vector target_usages; + for (const bNodeLink *link : socket->directly_linked_links()) { + if (!link->is_used()) { + continue; + } + const bNodeSocket &target_socket = *link->tosock; + if (lf::OutputSocket *is_used_socket = graph_params.usage_by_bsocket.lookup_default( + &target_socket, nullptr)) + { + target_usages.append_non_duplicates(is_used_socket); + } } + /* Combine target socket usages into the usage of the current socket. */ + graph_params.usage_by_bsocket.add(socket, + this->or_socket_usages(target_usages, graph_params)); } } - void build_group_input_usages(OrSocketUsagesCache &or_socket_usages_cache) + void build_group_input_usages(BuildGraphParams &graph_params) { const Span group_input_nodes = btree_.group_input_nodes(); for (const int i : btree_.interface_inputs().index_range()) { Vector target_usages; for (const bNode *group_input_node : group_input_nodes) { - if (lf::OutputSocket *lf_socket = - socket_is_used_map_[group_input_node->output_socket(i).index_in_tree()]) + if (lf::OutputSocket *lf_socket = graph_params.usage_by_bsocket.lookup_default( + &group_input_node->output_socket(i), nullptr)) { target_usages.append_non_duplicates(lf_socket); } } - lf::OutputSocket *lf_socket = this->or_socket_usages(target_usages, or_socket_usages_cache); + lf::OutputSocket *lf_socket = this->or_socket_usages(target_usages, graph_params); lf::InputSocket *lf_group_output = const_cast( mapping_->group_input_usage_sockets[i]); InputUsageHint input_usage_hint; @@ -2484,7 +3188,7 @@ struct GeometryNodesLazyFunctionGraphBuilder { input_usage_hint.type = InputUsageHintType::Never; } else { - lf_graph_->add_link(*lf_socket, *lf_group_output); + graph_params.lf_graph.add_link(*lf_socket, *lf_group_output); if (lf_socket->node().is_dummy()) { /* Can support slightly more complex cases where it depends on more than one output in * the future. */ @@ -2500,154 +3204,21 @@ struct GeometryNodesLazyFunctionGraphBuilder { } } - void link_output_used_sockets_for_builtin_nodes() - { - for (const auto &[output_bsocket, lf_input] : output_used_sockets_for_builtin_nodes_) { - if (lf::OutputSocket *lf_is_used = socket_is_used_map_[output_bsocket->index_in_tree()]) { - lf_graph_->add_link(*lf_is_used, *lf_input); - } - else { - static const bool static_false = false; - lf_input->set_default_value(&static_false); - } - } - } - - using JoinAttibuteSetsCache = Map, lf::OutputSocket *>; - - void build_attribute_propagation_sets() - { - using namespace bke::anonymous_attribute_inferencing; - - const AnonymousAttributeInferencingResult &result = - *btree_.runtime->anonymous_attribute_inferencing; - - JoinAttibuteSetsCache join_attribute_sets_cache; - - Map get_attributes_node_cache; - - auto add_get_attributes_node = [&](lf::OutputSocket &lf_field_socket) -> lf::OutputSocket & { - return *get_attributes_node_cache.lookup_or_add_cb(&lf_field_socket, [&]() { - const ValueOrFieldCPPType &type = *ValueOrFieldCPPType::get_from_self( - lf_field_socket.type()); - auto lazy_function = std::make_unique(type); - lf::Node &lf_node = lf_graph_->add_function(*lazy_function); - lf_graph_->add_link(lf_field_socket, lf_node.input(0)); - lf_graph_info_->functions.append(std::move(lazy_function)); - return &lf_node.output(0); - }); - }; - - for (const MapItem item : - attribute_set_propagation_map_.items()) - { - const bNodeSocket &geometry_output_bsocket = *item.key; - lf::InputSocket &lf_attribute_set_input = *item.value; - - const BoundedBitSpan required_fields = - result.required_fields_by_geometry_socket[geometry_output_bsocket.index_in_tree()]; - const BoundedBitSpan required_output_propagations = - result.propagate_to_output_by_geometry_socket[geometry_output_bsocket.index_in_tree()]; - - Vector attribute_set_sockets; - Vector used_sockets; - - bits::foreach_1_index(required_fields, [&](const int field_source_index) { - const FieldSource &field_source = result.all_field_sources[field_source_index]; - lf::OutputSocket *lf_socket_usage = nullptr; - lf::OutputSocket *lf_attribute_set_socket = nullptr; - if (const auto *input_field = std::get_if(&field_source.data)) { - lf_socket_usage = const_cast( - mapping_->group_input_usage_sockets[input_field->input_index]) - ->origin(); - lf::OutputSocket *lf_field_socket = const_cast( - mapping_->group_input_sockets[input_field->input_index]); - lf_attribute_set_socket = &add_get_attributes_node(*lf_field_socket); - } - else { - const auto &socket_field = std::get(field_source.data); - if (&socket_field.socket->owner_node() == &geometry_output_bsocket.owner_node()) { - return; - } - lf::OutputSocket *lf_field_socket = output_socket_map_.lookup(socket_field.socket); - lf_socket_usage = socket_is_used_map_[socket_field.socket->index_in_tree()]; - lf_attribute_set_socket = &add_get_attributes_node(*lf_field_socket); - } - if (lf_socket_usage) { - attribute_set_sockets.append(lf_attribute_set_socket); - used_sockets.append(lf_socket_usage); - } - }); - bits::foreach_1_index(required_output_propagations, [&](const int i) { - const int output_geometry_index = result.propagated_output_geometry_indices[i]; - lf::OutputSocket *lf_socket_usage = const_cast( - mapping_->group_output_used_sockets[output_geometry_index]); - if (lf_socket_usage) { - lf::OutputSocket *lf_attribute_set_socket = const_cast( - mapping_->attribute_set_by_geometry_output.lookup(output_geometry_index)); - attribute_set_sockets.append(lf_attribute_set_socket); - used_sockets.append(lf_socket_usage); - } - }); - if (lf::OutputSocket *joined_attribute_set = this->join_attribute_sets( - attribute_set_sockets, used_sockets, join_attribute_sets_cache)) - { - lf_graph_->add_link(*joined_attribute_set, lf_attribute_set_input); - } - else { - static const bke::AnonymousAttributeSet empty_set; - lf_attribute_set_input.set_default_value(&empty_set); - } - } - } - - /** - * Join multiple attributes set into a single attribute set that can be passed into a node. - */ - lf::OutputSocket *join_attribute_sets(const Span attribute_set_sockets, - const Span used_sockets, - JoinAttibuteSetsCache &cache) - { - BLI_assert(attribute_set_sockets.size() == used_sockets.size()); - if (attribute_set_sockets.is_empty()) { - return nullptr; - } - - Vector key; - key.extend(attribute_set_sockets); - key.extend(used_sockets); - std::sort(key.begin(), key.end()); - return cache.lookup_or_add_cb(key, [&]() { - const auto &lazy_function = LazyFunctionForAnonymousAttributeSetJoin::get_cached( - attribute_set_sockets.size(), lf_graph_info_->functions); - lf::Node &lf_node = lf_graph_->add_function(lazy_function); - for (const int i : attribute_set_sockets.index_range()) { - lf::InputSocket &lf_use_input = lf_node.input(lazy_function.get_use_input(i)); - socket_usage_inputs_.add(&lf_use_input); - lf::InputSocket &lf_attributes_input = lf_node.input( - lazy_function.get_attribute_set_input(i)); - lf_graph_->add_link(*used_sockets[i], lf_use_input); - lf_graph_->add_link(*attribute_set_sockets[i], lf_attributes_input); - } - return &lf_node.output(0); - }); - } - /** - * By depending on "the future" (whether a specific socket is used in the future), it is possible - * to introduce cycles in the graph. This function finds those cycles and breaks them by removing - * specific links. + * By depending on "the future" (whether a specific socket is used in the future), it is + * possible to introduce cycles in the graph. This function finds those cycles and breaks them + * by removing specific links. * * Example for a cycle: There is a `Distribute Points on Faces` node and its `Normal` output is - * only used when the number of generated points is larger than 1000 because of some switch node - * later in the tree. In this case, to know whether the `Normal` output is needed, one first has - * to compute the points, but for that one has to know whether the normal information has to be - * added to the points. The fix is to always add the normal information in this case. + * only used when the number of generated points is larger than 1000 because of some switch + * node later in the tree. In this case, to know whether the `Normal` output is needed, one + * first has to compute the points, but for that one has to know whether the normal information + * has to be added to the points. The fix is to always add the normal information in this case. */ - void fix_link_cycles() + void fix_link_cycles(lf::Graph &lf_graph, const Set &socket_usage_inputs) { - lf_graph_->update_socket_indices(); - const int sockets_num = lf_graph_->socket_num(); + lf_graph.update_socket_indices(); + const int sockets_num = lf_graph.socket_num(); struct SocketState { bool done = false; @@ -2657,7 +3228,7 @@ struct GeometryNodesLazyFunctionGraphBuilder { Array socket_states(sockets_num); Vector lf_sockets_to_check; - for (lf::Node *lf_node : lf_graph_->nodes()) { + for (lf::Node *lf_node : lf_graph.nodes()) { if (lf_node->is_function()) { for (lf::OutputSocket *lf_socket : lf_node->outputs()) { if (lf_socket->targets().is_empty()) { @@ -2713,8 +3284,8 @@ struct GeometryNodesLazyFunctionGraphBuilder { * computation later, but does not change correctness. * * After the cycle is broken, the cycle-detection is "rolled back" to the socket where - * the first socket of the cycle was found. This is necessary in case another cycle goes - * through this socket. */ + * the first socket of the cycle was found. This is necessary in case another cycle + * goes through this socket. */ detected_cycle = true; const int index_in_socket_stack = lf_socket_stack.first_index_of(lf_origin_socket); @@ -2726,9 +3297,9 @@ struct GeometryNodesLazyFunctionGraphBuilder { bool broke_cycle = false; for (lf::Socket *lf_cycle_socket : cycle) { if (lf_cycle_socket->is_input() && - socket_usage_inputs_.contains(&lf_cycle_socket->as_input())) { + socket_usage_inputs.contains(&lf_cycle_socket->as_input())) { lf::InputSocket &lf_cycle_input_socket = lf_cycle_socket->as_input(); - lf_graph_->clear_origin(lf_cycle_input_socket); + lf_graph.clear_origin(lf_cycle_input_socket); static const bool static_true = true; lf_cycle_input_socket.set_default_value(&static_true); broke_cycle = true; @@ -2765,82 +3336,8 @@ struct GeometryNodesLazyFunctionGraphBuilder { lf_socket_stack.pop_last(); } } - - void print_graph(); -}; - -class UsedSocketVisualizeOptions : public lf::Graph::ToDotOptions { - private: - const GeometryNodesLazyFunctionGraphBuilder &builder_; - Map socket_font_colors_; - Map socket_name_suffixes_; - - public: - UsedSocketVisualizeOptions(const GeometryNodesLazyFunctionGraphBuilder &builder) - : builder_(builder) - { - VectorSet found; - for (const int bsocket_index : builder_.socket_is_used_map_.index_range()) { - const bNodeSocket *bsocket = builder_.btree_.all_sockets()[bsocket_index]; - lf::OutputSocket *lf_used_socket = builder_.socket_is_used_map_[bsocket_index]; - if (lf_used_socket == nullptr) { - continue; - } - const float hue = BLI_hash_int_01(uintptr_t(lf_used_socket)); - std::stringstream ss; - ss.precision(3); - ss << hue << " 0.9 0.5"; - const std::string color_str = ss.str(); - const std::string suffix = " (" + std::to_string(found.index_of_or_add(lf_used_socket)) + - ")"; - socket_font_colors_.add(lf_used_socket, color_str); - socket_name_suffixes_.add(lf_used_socket, suffix); - - if (bsocket->is_input()) { - for (const lf::InputSocket *lf_socket : builder_.input_socket_map_.lookup(bsocket)) { - socket_font_colors_.add(lf_socket, color_str); - socket_name_suffixes_.add(lf_socket, suffix); - } - } - else if (lf::OutputSocket *lf_socket = builder_.output_socket_map_.lookup_default(bsocket, - nullptr)) - { - socket_font_colors_.add(lf_socket, color_str); - socket_name_suffixes_.add(lf_socket, suffix); - } - } - } - - std::optional socket_font_color(const lf::Socket &socket) const override - { - if (const std::string *color = socket_font_colors_.lookup_ptr(&socket)) { - return *color; - } - return std::nullopt; - } - - std::string socket_name(const lf::Socket &socket) const override - { - return socket.name() + socket_name_suffixes_.lookup_default(&socket, ""); - } - - void add_edge_attributes(const lf::OutputSocket & /*from*/, - const lf::InputSocket &to, - dot::DirectedEdge &dot_edge) const override - { - if (builder_.socket_usage_inputs_.contains_as(&to)) { - // dot_edge.attributes.set("constraint", "false"); - dot_edge.attributes.set("color", "#00000055"); - } - } }; -void GeometryNodesLazyFunctionGraphBuilder::print_graph() -{ - UsedSocketVisualizeOptions options{*this}; - std::cout << "\n\n" << lf_graph_->to_dot(options) << "\n\n"; -} - const GeometryNodesLazyFunctionGraphInfo *ensure_geometry_nodes_lazy_function_graph( const bNodeTree &btree) { @@ -2967,14 +3464,6 @@ Vector GeometryNodesLazyFunctionSideEffectProvider:: return modifier_data.side_effect_nodes->lookup(context_hash); } -GeometryNodesLazyFunctionGraphInfo::GeometryNodesLazyFunctionGraphInfo() = default; -GeometryNodesLazyFunctionGraphInfo::~GeometryNodesLazyFunctionGraphInfo() -{ - for (GMutablePointer &p : this->values_to_destruct) { - p.destruct(); - } -} - [[maybe_unused]] static void add_thread_id_debug_message( const GeometryNodesLazyFunctionGraphInfo &lf_graph_info, const lf::FunctionNode &node, diff --git a/source/blender/nodes/intern/geometry_nodes_log.cc b/source/blender/nodes/intern/geometry_nodes_log.cc index 80204233fa0a..fe5efb7a1a72 100644 --- a/source/blender/nodes/intern/geometry_nodes_log.cc +++ b/source/blender/nodes/intern/geometry_nodes_log.cc @@ -19,6 +19,8 @@ namespace blender::nodes::geo_eval_log { +using bke::bNodeTreeZone; +using bke::bNodeTreeZones; using fn::FieldInput; using fn::FieldInputs; @@ -518,46 +520,82 @@ static std::optional get_modifier_for_node_editor(const Space return ObjectAndModifier{object, used_modifier}; } -std::optional GeoModifierLog::get_compute_context_hash_for_node_editor( - const SpaceNode &snode, const StringRefNull modifier_name) +static void find_tree_zone_hash_recursive( + const bNodeTreeZone &zone, + ComputeContextBuilder &compute_context_builder, + Map &r_hash_by_zone) { - Vector tree_path = snode.treepath; + compute_context_builder.push(*zone.output_node); + r_hash_by_zone.add_new(&zone, compute_context_builder.hash()); + for (const bNodeTreeZone *child_zone : zone.child_zones) { + find_tree_zone_hash_recursive(*child_zone, compute_context_builder, r_hash_by_zone); + } + compute_context_builder.pop(); +} + +Map GeoModifierLog:: + get_context_hash_by_zone_for_node_editor(const SpaceNode &snode, StringRefNull modifier_name) +{ + const Vector tree_path = snode.treepath; if (tree_path.is_empty()) { - return std::nullopt; + return {}; } + ComputeContextBuilder compute_context_builder; compute_context_builder.push(modifier_name); + for (const int i : tree_path.index_range().drop_back(1)) { - /* The tree path contains the name of the node but not its ID. */ - const bNode *node = nodeFindNodebyName(tree_path[i]->nodetree, tree_path[i + 1]->node_name); - if (node == nullptr) { - /* The current tree path is invalid, probably because some parent group node has been - * deleted. */ - return std::nullopt; + bNodeTree *tree = tree_path[i]->nodetree; + const char *group_node_name = tree_path[i + 1]->node_name; + const bNode *group_node = nodeFindNodebyName(tree, group_node_name); + if (group_node == nullptr) { + return {}; + } + const bNodeTreeZones *tree_zones = tree->zones(); + if (tree_zones == nullptr) { + return {}; + } + const Vector zone_stack = tree_zones->get_zone_stack_for_node( + group_node->identifier); + for (const bNodeTreeZone *zone : zone_stack) { + compute_context_builder.push(*zone->output_node); } - compute_context_builder.push(*node); + compute_context_builder.push(*group_node); + } + + const bNodeTreeZones *tree_zones = snode.edittree->zones(); + if (tree_zones == nullptr) { + return {}; + } + Map hash_by_zone; + hash_by_zone.add_new(nullptr, compute_context_builder.hash()); + for (const bNodeTreeZone *zone : tree_zones->root_zones) { + find_tree_zone_hash_recursive(*zone, compute_context_builder, hash_by_zone); } - return compute_context_builder.hash(); + return hash_by_zone; } -GeoTreeLog *GeoModifierLog::get_tree_log_for_node_editor(const SpaceNode &snode) +Map GeoModifierLog::get_tree_log_by_zone_for_node_editor( + const SpaceNode &snode) { std::optional object_and_modifier = get_modifier_for_node_editor(snode); if (!object_and_modifier) { - return nullptr; + return {}; } GeoModifierLog *modifier_log = static_cast( object_and_modifier->nmd->runtime_eval_log); if (modifier_log == nullptr) { - return nullptr; + return {}; } - if (const std::optional hash = - GeoModifierLog::get_compute_context_hash_for_node_editor( - snode, object_and_modifier->nmd->modifier.name)) - { - return &modifier_log->get_tree_log(*hash); + const Map hash_by_zone = + GeoModifierLog::get_context_hash_by_zone_for_node_editor( + snode, object_and_modifier->nmd->modifier.name); + Map log_by_zone; + for (const auto item : hash_by_zone.items()) { + GeoTreeLog &tree_log = modifier_log->get_tree_log(item.value); + log_by_zone.add(item.key, &tree_log); } - return nullptr; + return log_by_zone; } const ViewerNodeLog *GeoModifierLog::find_viewer_node_log_for_path(const ViewerPath &viewer_path) @@ -587,8 +625,24 @@ const ViewerNodeLog *GeoModifierLog::find_viewer_node_log_for_path(const ViewerP ComputeContextBuilder compute_context_builder; compute_context_builder.push(parsed_path->modifier_name); - for (const int32_t group_node_id : parsed_path->group_node_ids) { - compute_context_builder.push(group_node_id); + for (const ViewerPathElem *elem : parsed_path->node_path) { + switch (elem->type) { + case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: { + const auto &typed_elem = *reinterpret_cast(elem); + compute_context_builder.push(typed_elem.node_id); + break; + } + case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: { + const auto &typed_elem = *reinterpret_cast(elem); + compute_context_builder.push( + typed_elem.sim_output_node_id); + break; + } + default: { + BLI_assert_unreachable(); + break; + } + } } const ComputeContextHash context_hash = compute_context_builder.hash(); nodes::geo_eval_log::GeoTreeLog &tree_log = modifier_log->get_tree_log(context_hash);